3 * @author Florian Corzilius <corzilius@cs.rwth-aachen.de>
10 #include <smtrat-common/model.h>
11 #include <carl-formula/model/Assignment.h>
13 #ifdef DEBUG_METHODS_TABLEAU
14 //#define DEBUG_METHODS_LRA_MODULE
16 //#define DEBUG_LRA_MODULE // this way no errors occur
18 using namespace smtrat::lra;
22 template<class Settings>
23 LRAModule<Settings>::LRAModule( const ModuleInput* _formula, Conditionals& _conditionals, Manager* _manager ):
24 Module( _formula, _conditionals, _manager ),
25 mInitialized( false ),
26 mAssignmentFullfilsNonlinearConstraints( false ),
27 mOptimumComputed( false),
28 mRationalModelComputed( false ),
29 mCheckedWithBackends( false ),
30 mTableau( passedFormulaEnd() ),
32 mNonlinearConstraints(),
33 mActiveResolvedNEQConstraints(),
34 mActiveUnresolvedNEQConstraints(),
35 mDelta( carl::fresh_real_variable( "delta_" + std::to_string( id() ) ) ),
36 mBoundCandidatesToPass(),
40 template<class Settings>
41 LRAModule<Settings>::~LRAModule()
44 template<class Settings>
45 bool LRAModule<Settings>::informCore( const FormulaT& _constraint )
47 #ifdef DEBUG_LRA_MODULE
48 std::cout << "LRAModule::inform " << "inform about " << _constraint << std::endl;
50 if( _constraint.type() == carl::FormulaType::CONSTRAINT )
52 const ConstraintT& constraint = _constraint.constraint();
53 if( !constraint.lhs().is_constant() && constraint.lhs().is_linear() )
55 mLinearConstraints.insert( _constraint );
56 setBound( _constraint );
58 return constraint.is_consistent() != 0;
63 template<class Settings>
64 void LRAModule<Settings>::deinformCore( const FormulaT& _constraint )
66 #ifdef DEBUG_LRA_MODULE
67 std::cout << "LRAModule::deinform " << "deinform about " << _constraint << std::endl;
69 if( _constraint.constraint().lhs().is_linear() )
71 mLinearConstraints.erase( _constraint );
72 mTableau.removeBound( _constraint );
76 template<class Settings>
77 bool LRAModule<Settings>::addCore( ModuleInput::const_iterator _subformula )
79 #ifdef DEBUG_LRA_MODULE
80 std::cout << "LRAModule::add " << _subformula->formula() << std::endl;
82 mOptimumComputed = false;
83 switch( _subformula->formula().type() )
85 case carl::FormulaType::FALSE:
87 FormulaSetT infSubSet;
88 infSubSet.insert( _subformula->formula() );
89 mInfeasibleSubsets.push_back( infSubSet );
90 #ifdef SMTRAT_DEVOPTION_Statistics
91 mStatistics.addConflict( mInfeasibleSubsets );
95 case carl::FormulaType::TRUE:
99 case carl::FormulaType::CONSTRAINT:
101 const FormulaT& formula = _subformula->formula();
102 const ConstraintT& constraint = formula.constraint();
103 #ifdef SMTRAT_DEVOPTION_Statistics
104 mStatistics.add( constraint );
106 // FormulaT constructor simplifies constraint if is_consistent() != 2
107 assert(constraint.is_consistent() == 2);
108 mAssignmentFullfilsNonlinearConstraints = false;
109 if( constraint.lhs().is_linear() )
111 // bool elementInserted = mLinearConstraints.insert( formula ).second;
112 // if( elementInserted && mInitialized )
114 // mTableau.newBound( formula );
116 if( constraint.relation() != carl::Relation::NEQ )
118 auto constrBoundIter = mTableau.constraintToBound().find( formula );
119 assert( constrBoundIter != mTableau.constraintToBound().end() );
120 const std::vector< const LRABound* >* bounds = constrBoundIter->second;
121 assert( bounds != NULL );
122 activateBound( *bounds->begin(), formula );
124 if( !(*bounds->begin())->neqRepresentation().is_true() )
126 auto pos = mActiveUnresolvedNEQConstraints.find( (*bounds->begin())->neqRepresentation() );
127 if( pos != mActiveUnresolvedNEQConstraints.end() )
129 auto entry = mActiveResolvedNEQConstraints.insert( *pos );
130 removeOrigin( pos->second.position, pos->second.origin );
131 entry.first->second.position = passedFormulaEnd();
132 mActiveUnresolvedNEQConstraints.erase( pos );
133 auto constrBoundIter = mTableau.constraintToBound().find( (*bounds->begin())->neqRepresentation() );
134 assert( constrBoundIter != mTableau.constraintToBound().end() );
135 const std::vector< const LRABound* >* boundsOfNeqConstraint = constrBoundIter->second;
136 if( *bounds->begin() == (*boundsOfNeqConstraint)[1] || *bounds->begin() == (*boundsOfNeqConstraint)[2] )
138 bool leqBoundActive = *bounds->begin() == (*boundsOfNeqConstraint)[1];
139 activateStrictBound( (*bounds->begin())->neqRepresentation(), **bounds->begin(), (*boundsOfNeqConstraint)[leqBoundActive ? 0 : 3] );
143 return mInfeasibleSubsets.empty();
147 auto constrBoundIter = mTableau.constraintToBound().find( formula );
148 if (constrBoundIter == mTableau.constraintToBound().end()) {
151 assert( constrBoundIter != mTableau.constraintToBound().end() );
152 const std::vector< const LRABound* >* bounds = constrBoundIter->second;
153 // bool intValued = constraint.integer_valued();
154 // if( (intValued && ((*bounds)[1]->isActive() || (*bounds)[2]->isActive()))
155 // || (!intValued && ((*bounds)[0]->isActive() || (*bounds)[1]->isActive() || (*bounds)[2]->isActive() || (*bounds)[3]->isActive())) )
156 if( (*bounds)[0]->isActive() || (*bounds)[1]->isActive() || (*bounds)[2]->isActive() || (*bounds)[3]->isActive() )
158 Context context( formula, passedFormulaEnd() );
159 mActiveResolvedNEQConstraints.insert( std::pair< FormulaT, Context >( formula, std::move(context) ) );
160 bool leqBoundActive = (*bounds)[1]->isActive();
161 if( leqBoundActive || (*bounds)[2]->isActive() )
163 activateStrictBound( formula, *(*bounds)[leqBoundActive ? 1 : 2], (*bounds)[leqBoundActive ? 0 : 3] );
168 Context context( formula, addSubformulaToPassedFormula( formula, formula ).first );
169 mActiveUnresolvedNEQConstraints.insert( std::pair< FormulaT, Context >( formula, std::move(context) ) );
176 addSubformulaToPassedFormula( formula, formula );
177 mNonlinearConstraints.insert( formula );
187 template<class Settings>
188 void LRAModule<Settings>::removeCore( ModuleInput::const_iterator _subformula )
190 #ifdef DEBUG_LRA_MODULE
191 std::cout << "LRAModule::remove " << _subformula->formula() << std::endl;
193 mOptimumComputed = false;
194 const FormulaT& formula = _subformula->formula();
195 if( formula.type() == carl::FormulaType::CONSTRAINT )
197 // Remove the mapping of the constraint to the sub-formula in the received formula
198 const ConstraintT& constraint = formula.constraint();
199 const FormulaT& pformula = _subformula->formula();
200 #ifdef SMTRAT_DEVOPTION_Statistics
201 mStatistics.remove( constraint );
203 // FormulaT constructor simplifies constraint if is_consistent() != 2
204 assert(constraint.is_consistent() == 2);
205 if( constraint.lhs().is_linear() )
207 // Deactivate the bounds regarding the given constraint
208 auto constrBoundIter = mTableau.constraintToBound().find( pformula );
209 assert( constrBoundIter != mTableau.rConstraintToBound().end() );
210 std::vector< const LRABound* >* bounds = constrBoundIter->second;
211 assert( bounds != NULL );
212 auto bound = bounds->begin();
214 int dontRemoveBeforePos = constraint.relation() == carl::Relation::NEQ ? 4 : 1;
215 while( bound != bounds->end() )
217 if( !(*bound)->origins().empty() )
219 auto origin = (*bound)->pOrigins()->begin();
220 bool mainOriginRemains = true;
221 while( origin != (*bound)->origins().end() )
223 if( origin->type() == carl::FormulaType::AND && origin->contains( pformula ) )
225 origin = (*bound)->pOrigins()->erase( origin );
227 else if( mainOriginRemains && *origin == pformula )
229 assert( origin->type() == carl::FormulaType::CONSTRAINT );
230 origin = (*bound)->pOrigins()->erase( origin );
231 // ensures that only one main origin is removed, in the case that a formula is contained more than once in the module input
232 mainOriginRemains = false;
239 if( (*bound)->origins().empty() )
241 if( !(*bound)->neqRepresentation().is_true() )
243 auto constrBoundIterB = mTableau.constraintToBound().find( (*bound)->neqRepresentation() );
244 assert( constrBoundIterB != mTableau.constraintToBound().end() );
245 const std::vector< const LRABound* >* uebounds = constrBoundIterB->second;
246 assert( uebounds != NULL );
247 assert( uebounds->size() >= 4 );
248 // bool intValued = (*bound)->neqRepresentation().constraint().integer_valued();
249 // if( (intValued && !(*uebounds)[1]->isActive() && !(*uebounds)[2]->isActive()) ||
250 // (!intValued && !(*uebounds)[0]->isActive() && !(*uebounds)[1]->isActive() && !(*uebounds)[2]->isActive() && !(*uebounds)[3]->isActive()) )
251 if( !(*uebounds)[0]->isActive() && !(*uebounds)[1]->isActive() && !(*uebounds)[2]->isActive() && !(*uebounds)[3]->isActive() )
253 auto pos = mActiveResolvedNEQConstraints.find( (*bound)->neqRepresentation() );
254 if( pos != mActiveResolvedNEQConstraints.end() )
256 auto entry = mActiveUnresolvedNEQConstraints.insert( *pos );
257 mActiveResolvedNEQConstraints.erase( pos );
258 entry.first->second.position = addSubformulaToPassedFormula( entry.first->first, entry.first->second.origin ).first;
262 LRAVariable& var = *(*bound)->pVariable();
263 if( var.deactivateBound( *bound, passedFormulaEnd() ) && !var.isBasic() )
265 if( var.supremum() < var.assignment() )
267 mTableau.updateBasicAssignments( var.position(), LRAValue( var.supremum().limit() - var.assignment() ) );
268 var.rAssignment() = var.supremum().limit();
270 else if( var.infimum() > var.assignment() )
272 mTableau.updateBasicAssignments( var.position(), LRAValue( var.infimum().limit() - var.assignment() ) );
273 var.rAssignment() = var.infimum().limit();
275 if( var.isConflicting() )
277 FormulaSetT infsubset;
278 collectOrigins( *var.supremum().origins().begin(), infsubset );
279 collectOrigins( *var.infimum().origins().begin(), infsubset );
280 mInfeasibleSubsets.push_back( std::move(infsubset) );
283 if( !(*bound)->pVariable()->pSupremum()->isInfinite() )
285 mBoundCandidatesToPass.push_back( (*bound)->pVariable()->pSupremum() );
287 if( !(*bound)->pVariable()->pInfimum()->isInfinite() )
289 mBoundCandidatesToPass.push_back( (*bound)->pVariable()->pInfimum() );
292 if( !is_minimizing() && !(*bound)->variable().hasBound() && (*bound)->variable().isBasic() && !(*bound)->variable().isOriginal() )
294 mTableau.deactivateBasicVar( (*bound)->pVariable() );
298 if( (*bound)->origins().empty() && pos >= dontRemoveBeforePos )
299 bound = bounds->erase( bound );
306 if( constraint.relation() == carl::Relation::NEQ )
308 if( mActiveResolvedNEQConstraints.erase( pformula ) == 0 )
310 auto iter = mActiveUnresolvedNEQConstraints.find( pformula );
311 if( iter != mActiveUnresolvedNEQConstraints.end() )
313 removeOrigin( iter->second.position, iter->second.origin );
314 mActiveUnresolvedNEQConstraints.erase( iter );
321 mNonlinearConstraints.erase( pformula );
326 template<class Settings>
327 Answer LRAModule<Settings>::checkCore()
329 #ifdef DEBUG_LRA_MODULE
330 std::cout << "LRAModule::check with is_minimizing() = " << is_minimizing() << std::endl;
331 for( const auto& f : rReceivedFormula() )
332 std::cout << f.formula() << std::endl;
334 bool containsIntegerValuedVariables = true;
335 if( !rReceivedFormula().is_constraint_conjunction() )
336 return processResult( UNKNOWN );
337 if( !mInfeasibleSubsets.empty() )
338 return processResult( UNSAT );
339 if( Settings::simple_theory_propagation )
340 simpleTheoryPropagation();
341 if( rReceivedFormula().is_real_constraint_conjunction() )
342 containsIntegerValuedVariables = false;
343 // if( mTableau.isConflicting() )
345 assert( !mTableau.isConflicting() );
347 mTableau.setBlandsRuleStart( 100 );//(unsigned) mTableau.columns().size() );
348 mTableau.compressRows();
349 mCheckedWithBackends = false;
351 // Nonbasic vars satisfy bound
354 #ifdef DEBUG_LRA_MODULE
355 mTableau.print(); mTableau.printVariables(); std::cout << "True" << std::endl;
358 #ifdef DEBUG_LRA_MODULE
361 // Check whether a module which has been called on the same instance in parallel, has found an answer.
362 if( anAnswerFound() )
363 return processResult( UNKNOWN );
364 // Find a pivoting element in the tableau.
365 if(Settings::use_SoI_simplex)
366 mTableau.setInfeasibilityRow();
367 std::pair<EntryID,bool> pivotingElement;
368 if(Settings::use_SoI_simplex)
369 pivotingElement = mTableau.nextPivotingElementInfeasibilities();
371 pivotingElement = mTableau.nextPivotingElement();
372 #ifdef DEBUG_LRA_MODULE
373 if( pivotingElement.second && pivotingElement.first != LAST_ENTRY_ID )
375 std::cout << std::endl; mTableau.print( pivotingElement.first, std::cout, " " ); std::cout << std::endl;
378 // If there is no conflict.
379 if(pivotingElement.second){
380 // If no basic variable violates its bounds (and hence no variable at all).
381 if( pivotingElement.first == lra::LAST_ENTRY_ID){
382 #ifdef DEBUG_LRA_MODULE
383 mTableau.print(); mTableau.printVariables(); std::cout << "True" << std::endl;
385 mTableau.storeAssignment();
386 mRationalModelComputed = false;
387 // If the current assignment also fulfills the nonlinear constraints.
388 if( checkAssignmentForNonlinearConstraint() )
390 if( containsIntegerValuedVariables )
392 if( branch_and_bound() ){
393 SMTRAT_LOG_DEBUG("smtrat", "Run in branch and bound");
394 return processResult( UNKNOWN );
397 return processResult( SAT );
399 // Otherwise, check the consistency of the formula consisting of the nonlinear constraints and the tightest bounds with the backends.
402 mCheckedWithBackends = true;
403 adaptPassedFormula();
404 Answer a = runBackends();
406 getInfeasibleSubsets();
408 return processResult( a );
412 // Pivot at the found pivoting entry.
413 #ifdef DEBUG_LRA_MODULE
414 auto oldVioSum = mTableau.violationSum();
416 mTableau.pivot( pivotingElement.first );
417 // update infeasibility row
418 #ifdef SMTRAT_DEVOPTION_Statistics
419 mStatistics.pivotStep();
421 if( Settings::learn_refinements ) // Learn all bounds which have been deduced during the pivoting process.
422 processLearnedBounds();
423 // Maybe an easy conflict occurred with the learned bounds.
424 if( !mInfeasibleSubsets.empty() )
425 return processResult( UNSAT );
426 if(Settings::use_SoI_simplex){
427 #ifdef DEBUG_LRA_MODULE
428 auto newVioSum = mTableau.violationSum();
429 SMTRAT_LOG_DEBUG("smtrat", "newVioSum " << newVioSum << " oldVioSum " << oldVioSum << " dVio " << mTableau.get_dVioSum() );
430 if(!mTableau.usedBlandsRule()){
431 assert(newVioSum <= oldVioSum);
432 assert(newVioSum == oldVioSum + mTableau.get_dVioSum());
438 // There is a conflict, namely a basic variable violating its bounds without any suitable non-basic variable.
441 // Create the infeasible subsets.
442 createInfeasibleSubsets( pivotingElement.first );
443 return processResult( UNSAT );
450 template<class Settings>
451 Answer LRAModule<Settings>::processResult( Answer _result )
453 if( _result == ABORTED )
457 if( Settings::learn_refinements )
459 #ifdef SMTRAT_DEVOPTION_Statistics
460 if( _result != UNKNOWN )
462 mStatistics.check( rReceivedFormula() );
463 if( _result == UNSAT )
464 mStatistics.addConflict( mInfeasibleSubsets );
465 mStatistics.setNumberOfTableauxEntries( mTableau.size() );
466 mStatistics.setTableauSize( mTableau.rows().size()*mTableau.columns().size() );
469 if( is_minimizing() )
470 _result = optimize( _result );
471 if( _result != UNKNOWN )
473 mTableau.resetNumberOfPivotingSteps();
474 if( _result == SAT && !mCheckedWithBackends )
475 _result = checkNotEqualConstraints( _result );
477 #ifdef DEBUG_LRA_MODULE
478 std::cout << std::endl; mTableau.print(); std::cout << std::endl; std::cout << _result << std::endl;
483 template<class Settings>
484 void LRAModule<Settings>::updateModel() const
486 if( !mModelComputed && !mOptimumComputed )
489 assert( solverState() != UNSAT );
490 if( mAssignmentFullfilsNonlinearConstraints )
492 const RationalAssignment& rationalAssignment = getRationalModel();
493 for( auto ratAss = rationalAssignment.begin(); ratAss != rationalAssignment.end(); ++ratAss )
494 mModel.insert(mModel.end(), std::make_pair(ratAss->first, ratAss->second) );
497 Module::getBackendsModel();
498 mModelComputed = true;
502 template<class Settings>
503 const RationalAssignment& LRAModule<Settings>::getRationalModel() const
505 if( !mRationalModelComputed )
507 mRationalAssignment = mTableau.getRationalAssignment();
508 mRationalModelComputed = true;
510 return mRationalAssignment;
513 template<class Settings>
514 unsigned LRAModule<Settings>::currentlySatisfied( const FormulaT& _formula ) const
516 switch( _formula.type() )
518 case carl::FormulaType::TRUE:
520 case carl::FormulaType::FALSE:
522 case carl::FormulaType::CONSTRAINT:
524 if( mCheckedWithBackends )
526 auto res = satisfies( model(), _formula );
531 if( _formula.constraint().lhs().is_linear() && _formula.constraint().relation() != carl::Relation::NEQ )
533 auto constrBoundIter = mTableau.constraintToBound().find( _formula );
534 if( constrBoundIter != mTableau.constraintToBound().end() )
536 const LRABound& bound = *constrBoundIter->second->front();
537 const LRAVariable& lravar = bound.variable();
538 if( lravar.hasBound() || (lravar.isOriginal() && receivedVariable( lravar.expression().single_variable() )) )
540 const auto& cd = mTableau.currentDelta();
541 if( bound.isSatisfied( cd ) )
554 const auto& m = getRationalModel();
555 return carl::satisfied_by(_formula, Model(m)); // TODO: Isn't this an unnecessary copy operation, Gereon?
566 template<class Settings>
567 Answer LRAModule<Settings>::optimize( Answer _result )
571 Poly objectivePoly(objective());
572 LRAVariable* optVar = mTableau.getObjectiveVariable( objectivePoly );
573 assert( optVar->isBasic() );
574 mTableau.activateBasicVar( optVar );
577 std::pair<EntryID,bool> pivotingElement = mTableau.nextPivotingElementForOptimizing( *optVar );
578 if( pivotingElement.second )
580 if( pivotingElement.first == lra::LAST_ENTRY_ID )
582 assert( optVar->infimum().isInfinite() );
583 #ifdef DEBUG_LRA_MODULE
584 std::cout << std::endl; mTableau.print(); std::cout << std::endl; std::cout << "Optimum: -oo" << std::endl;
587 mModel.insert(mModel.end(), std::make_pair(objective(), InfinityValue()) );
588 mOptimumComputed = true;
593 #ifdef DEBUG_LRA_MODULE
594 std::cout << std::endl; mTableau.print( pivotingElement.first, std::cout, " " ); std::cout << std::endl;
596 mTableau.pivot( pivotingElement.first, true );
601 mModelComputed = false;
602 mOptimumComputed = false;
604 const RationalAssignment& ratModel = getRationalModel();
605 Rational opti = carl::evaluate(optVar->expression(), ratModel );
606 #ifdef DEBUG_LRA_MODULE
607 std::cout << std::endl; mTableau.print(); std::cout << std::endl; std::cout << "Optimum: " << opti << std::endl;
609 mModel.insert(mModel.end(), std::make_pair(objective(), opti ) );
610 mOptimumComputed = true;
614 mTableau.deleteVariable( optVar, true );
617 // @todo Branch if assignment does not fulfill integer domains.
621 template<class Settings>
622 Answer LRAModule<Settings>::checkNotEqualConstraints( Answer _result )
624 // If there are unresolved notequal-constraints and the found satisfying assignment
625 // conflicts this constraint, resolve it by creating the lemma (p<0 or p>0) <-> p!=0 ) and return UNKNOWN.
626 const RationalAssignment& ass = getRationalModel();
627 for( auto iter = mActiveUnresolvedNEQConstraints.begin(); iter != mActiveUnresolvedNEQConstraints.end(); ++iter )
629 //unsigned consistency = iter->first.satisfiedBy( ass );
630 unsigned consistency = carl::satisfied_by(iter->first, Model(ass)); // TODO: Isn't this an unnecessary copy operation, Gereon?
631 assert( consistency != 2 );
632 if( consistency == 0 )
636 #ifdef SMTRAT_DEVOPTION_Statistics
637 mStatistics.splitUnequalConstraint();
639 splitUnequalConstraint( iter->first );
644 // TODO: This is a rather unfortunate hack, because I couldn't fix the efficient neq-constraint-handling with integer-valued constraints
645 if(true || (_result != UNKNOWN && !rReceivedFormula().is_real_constraint_conjunction()) )
647 for( auto iter = mActiveResolvedNEQConstraints.begin(); iter != mActiveResolvedNEQConstraints.end(); ++iter )
649 //unsigned consistency = iter->first.satisfiedBy( ass );
650 unsigned consistency = carl::satisfied_by(iter->first, Model(ass));
651 assert( consistency != 2 );
652 if( consistency == 0 )
656 #ifdef SMTRAT_DEVOPTION_Statistics
657 mStatistics.splitUnequalConstraint();
659 splitUnequalConstraint( iter->first );
665 assert( assignmentCorrect() );
669 template<class Settings>
670 void LRAModule<Settings>::processLearnedBounds()
672 while( !mTableau.rNewLearnedBounds().empty() )
675 typename LRATableau::LearnedBound& learnedBound = mTableau.rNewLearnedBounds().back()->second;
676 mTableau.rNewLearnedBounds().pop_back();
677 std::vector<const LRABound*>& bounds = learnedBound.premise;
678 for( auto bound = bounds.begin(); bound != bounds.end(); ++bound )
680 const FormulaT& boundOrigins = *(*bound)->origins().begin();
681 if( boundOrigins.type() == carl::FormulaType::AND )
683 originSet.insert( originSet.end(), boundOrigins.subformulas().begin(), boundOrigins.subformulas().end() );
684 for( auto origin = boundOrigins.subformulas().begin(); origin != boundOrigins.subformulas().end(); ++origin )
686 auto constrBoundIter = mTableau.rConstraintToBound().find( *origin );
687 assert( constrBoundIter != mTableau.constraintToBound().end() );
688 std::vector< const LRABound* >* constraintToBounds = constrBoundIter->second;
689 constraintToBounds->push_back( *learnedBound.nextWeakerBound );
690 #ifdef LRA_INTRODUCE_NEW_CONSTRAINTS
691 if( learnedBound.newBound != NULL ) constraintToBounds->push_back( learnedBound.newBound );
697 assert( boundOrigins.type() == carl::FormulaType::CONSTRAINT );
698 originSet.push_back( boundOrigins );
699 auto constrBoundIter = mTableau.rConstraintToBound().find( boundOrigins );
700 assert( constrBoundIter != mTableau.constraintToBound().end() );
701 std::vector< const LRABound* >* constraintToBounds = constrBoundIter->second;
702 constraintToBounds->push_back( *learnedBound.nextWeakerBound );
703 #ifdef LRA_INTRODUCE_NEW_CONSTRAINTS
704 if( learnedBound.newBound != NULL ) constraintToBounds->push_back( learnedBound.newBound );
708 FormulaT origin = FormulaT( carl::FormulaType::AND, std::move(originSet) );
709 activateBound( *learnedBound.nextWeakerBound, origin );
710 #ifdef LRA_INTRODUCE_NEW_CONSTRAINTS
711 if( learnedBound.newBound != NULL )
713 const FormulaT& newConstraint = learnedBound.newBound->asConstraint();
714 addConstraintToInform( newConstraint );
715 mLinearConstraints.insert( newConstraint );
716 std::vector< const LRABound* >* boundVector = new std::vector< const LRABound* >();
717 boundVector->push_back( learnedBound.newBound );
718 mConstraintToBound[newConstraint] = boundVector;
719 activateBound( learnedBound.newBound, origin );
725 template<class Settings>
726 void LRAModule<Settings>::createInfeasibleSubsets( EntryID _tableauEntry )
728 std::pair<EntryID,bool> conflictPair = mTableau.hasConflict();
729 if( Settings::one_conflict_reason )
731 std::vector< const LRABound* > conflict;
733 if(!conflictPair.second){
734 SMTRAT_LOG_DEBUG("smtrat", "In simple creation");
735 conflict = mTableau.getConflict( _tableauEntry );
738 SMTRAT_LOG_DEBUG("smtrat", "In multiline creation");
739 conflict = mTableau.getMultilineConflict();
741 FormulaSetT infSubSet;
742 for( auto bound = conflict.begin(); bound != conflict.end(); ++bound )
744 assert( (*bound)->isActive() );
745 collectOrigins( *(*bound)->origins().begin(), infSubSet );
747 mInfeasibleSubsets.push_back( infSubSet );
751 std::vector< std::vector< const LRABound* > > conflictingBounds;
752 if(!conflictPair.second){
753 SMTRAT_LOG_DEBUG("smtrat", "In simple creation");
754 conflictingBounds = mTableau.getConflictsFrom( _tableauEntry );
757 SMTRAT_LOG_DEBUG("smtrat", "In multiline creation");
758 assert(mTableau.hasMultilineConflict());
759 std::vector< const LRABound* > conflict = mTableau.getMultilineConflict();
760 conflictingBounds.push_back(conflict);
762 for( auto conflict = conflictingBounds.begin(); conflict != conflictingBounds.end(); ++conflict )
764 FormulaSetT infSubSet;
765 for( auto bound = conflict->begin(); bound != conflict->end(); ++bound )
767 assert( (*bound)->isActive() );
768 SMTRAT_LOG_DEBUG("smtrat","collected for " << *(*bound)->origins().begin());
769 collectOrigins( *(*bound)->origins().begin(), infSubSet );
771 mInfeasibleSubsets.push_back( infSubSet );
773 assert(!mInfeasibleSubsets.empty());
777 template<class Settings>
778 EvalRationalIntervalMap LRAModule<Settings>::getVariableBounds() const
780 EvalRationalIntervalMap result;
781 for( auto iter = mTableau.originalVars().begin(); iter != mTableau.originalVars().end(); ++iter )
783 const LRAVariable& var = *iter->second;
784 carl::BoundType lowerBoundType;
785 Rational lowerBoundValue;
786 carl::BoundType upperBoundType;
787 Rational upperBoundValue;
788 if( var.infimum().isInfinite() )
790 lowerBoundType = carl::BoundType::INFTY;
795 lowerBoundType = var.infimum().isWeak() ? carl::BoundType::WEAK : carl::BoundType::STRICT;
796 lowerBoundValue = Rational(var.infimum().limit().mainPart());
798 if( var.supremum().isInfinite() )
800 upperBoundType = carl::BoundType::INFTY;
805 upperBoundType = var.supremum().isWeak() ? carl::BoundType::WEAK : carl::BoundType::STRICT;
806 upperBoundValue = Rational(var.supremum().limit().mainPart());
808 RationalInterval interval = RationalInterval( lowerBoundValue, lowerBoundType, upperBoundValue, upperBoundType );
809 result.insert( std::pair< carl::Variable, RationalInterval >( iter->first, interval ) );
814 template<class Settings>
815 void LRAModule<Settings>::learnRefinements()
817 for( const auto& lbound : mTableau.rLearnedLowerBounds() )
818 learnRefinement( lbound.second, false );
819 mTableau.rLearnedLowerBounds().clear();
820 for( const auto& ubound : mTableau.rLearnedUpperBounds() )
821 learnRefinement( ubound.second, true );
822 mTableau.rLearnedUpperBounds().clear();
825 template<class Settings>
826 void LRAModule<Settings>::learnRefinement( const typename LRATableau::LearnedBound& _learnedBound, bool _upperBound )
828 bool premiseOnlyEqualities = true;
829 FormulasT subformulas = createPremise( _learnedBound.premise, premiseOnlyEqualities );
830 auto boundIter = _learnedBound.nextWeakerBound;
835 while( !(*boundIter)->isActive() )
837 const LRABound& bound = **boundIter;
838 if( bound.exists() && !bound.isComplementActive() )
840 if( bound.type() != LRABound::Type::EQUAL )
842 mTheoryPropagations.emplace_back( std::move(FormulasT(subformulas)), bound.asConstraint() );
843 SMTRAT_LOG_DEBUG("smtrat", "theory propagation [" << (_upperBound ? "upper" : "lower") << "]: " << mTheoryPropagations.back().mPremise << " => " << mTheoryPropagations.back().mConclusion );
845 else if( premiseOnlyEqualities )
847 SMTRAT_LOG_DEBUG("smtrat", _learnedBound.newLimit << " == " << bound.limit() );
848 if( _learnedBound.newLimit == bound.limit() )
850 mTheoryPropagations.emplace_back( std::move(FormulasT(subformulas)), bound.asConstraint() );
851 SMTRAT_LOG_DEBUG("smtrat", "### theory propagation [" << (_upperBound ? "upper" : "lower") << "]: " << mTheoryPropagations.back().mPremise << " => " << mTheoryPropagations.back().mConclusion );
855 mTheoryPropagations.emplace_back( std::move(FormulasT(subformulas)), bound.asConstraint().negated() );
856 SMTRAT_LOG_DEBUG("smtrat", "### theory propagation [" << (_upperBound ? "upper" : "lower") << "]: " << mTheoryPropagations.back().mPremise << " => " << mTheoryPropagations.back().mConclusion );
865 const LRABound& nextWeakerBound = **_learnedBound.nextWeakerBound;
866 if( nextWeakerBound.exists() && !nextWeakerBound.isComplementActive() )
868 if( nextWeakerBound.type() != LRABound::Type::EQUAL )
870 mTheoryPropagations.emplace_back( std::move(subformulas), nextWeakerBound.asConstraint() );
871 SMTRAT_LOG_DEBUG("smtrat", "theory propagation [" << (_upperBound ? "upper" : "lower") << "]: " << mTheoryPropagations.back().mPremise << " => " << mTheoryPropagations.back().mConclusion );
873 else if( premiseOnlyEqualities )
875 if( _learnedBound.newLimit == nextWeakerBound.limit() )
877 mTheoryPropagations.emplace_back( std::move(FormulasT(subformulas)), nextWeakerBound.asConstraint() );
878 SMTRAT_LOG_DEBUG("smtrat", "### theory propagation [" << (_upperBound ? "upper" : "lower") << "]: " << mTheoryPropagations.back().mPremise << " => " << mTheoryPropagations.back().mConclusion );
882 mTheoryPropagations.emplace_back( std::move(FormulasT(subformulas)), nextWeakerBound.asConstraint().negated() );
883 SMTRAT_LOG_DEBUG("smtrat", "### theory propagation [" << (_upperBound ? "upper" : "lower") << "]: " << mTheoryPropagations.back().mPremise << " => " << mTheoryPropagations.back().mConclusion );
887 #ifdef SMTRAT_DEVOPTION_Statistics
888 mStatistics.addRefinement();
889 mStatistics.propagateTheory();
893 template<class Settings>
894 FormulasT LRAModule<Settings>::createPremise( const std::vector< const LRABound*>& _premiseBounds, bool& _premiseOnlyEqualities ) const
896 FormulasT subformulas;
897 _premiseOnlyEqualities = true;
898 for( const LRABound* bound : _premiseBounds )
900 const FormulaT& origin = *bound->origins().begin();
901 if( origin.type() == carl::FormulaType::AND )
903 for( auto& subformula : origin.subformulas() )
905 assert( subformula.type() == carl::FormulaType::CONSTRAINT );
906 subformulas.push_back( subformula );
907 if( subformula.constraint().relation() != carl::Relation::EQ )
908 _premiseOnlyEqualities = false;
913 assert( origin.type() == carl::FormulaType::CONSTRAINT );
914 subformulas.push_back( origin );
915 if( origin.constraint().relation() != carl::Relation::EQ )
916 _premiseOnlyEqualities = false;
922 template<class Settings>
923 void LRAModule<Settings>::adaptPassedFormula()
925 for( const LRABound* bound : mBoundCandidatesToPass )
927 if( bound->pInfo()->updated > 0 )
929 bound->pInfo()->position = addSubformulaToPassedFormula( bound->asConstraint(), bound->pOrigins() ).first;
930 bound->pInfo()->updated = 0;
932 else if( bound->pInfo()->updated < 0 )
934 eraseSubformulaFromPassedFormula( bound->pInfo()->position, true );
935 bound->pInfo()->position = passedFormulaEnd();
936 bound->pInfo()->updated = 0;
939 mBoundCandidatesToPass.clear();
942 template<class Settings>
943 bool LRAModule<Settings>::checkAssignmentForNonlinearConstraint()
945 if( mNonlinearConstraints.empty() )
947 mAssignmentFullfilsNonlinearConstraints = true;
952 auto assignments = Model(getRationalModel()); // TODO: Isn't this an unnecessary copy operation, Gereon?
953 // Check whether the assignment satisfies the non linear constraints.
954 for( const auto& constraint : mNonlinearConstraints )
956 if( carl::satisfied_by(constraint, assignments) != 1 )
961 mAssignmentFullfilsNonlinearConstraints = true;
966 template<class Settings>
967 void LRAModule<Settings>::activateBound( const LRABound* _bound, const FormulaT& _formula )
969 // If the bounds constraint has already been passed to the backend, add the given formulas to it's origins
970 const LRAVariable& var = _bound->variable();
971 const LRABound* psup = var.pSupremum();
972 const LRABound& sup = *psup;
973 const LRABound* pinf = var.pInfimum();
974 const LRABound& inf = *pinf;
975 const LRABound& bound = *_bound;
976 mTableau.activateBound( _bound, _formula );
977 if( bound.isUpperBound() )
979 auto iter = var.lowerbounds().find( pinf );
980 while( /*(**iter).isActive() &&*/ (**iter) > bound.limit() )
982 if(!(*iter)->isActive())
987 //FormulaSetT infsubset;
988 //collectOrigins( *bound.origins().begin(), infsubset );
989 //collectOrigins( *(**iter).pOrigins()->begin(), infsubset );
990 //mInfeasibleSubsets.push_back( std::move(infsubset) );
991 for(const auto& o1 : bound.origins())
993 FormulaSetT infsubset;
994 collectOrigins( o1, infsubset );
995 for (const auto& o2: (*iter)->origins()) {
996 FormulaSetT infsubsetForO1(infsubset);
997 collectOrigins( o2, infsubsetForO1 );
998 mInfeasibleSubsets.push_back( std::move(infsubsetForO1) );
1001 assert( iter != var.lowerbounds().begin() );
1006 if( !sup.isInfinite() )
1007 mBoundCandidatesToPass.push_back( psup );
1008 mBoundCandidatesToPass.push_back( _bound );
1011 if( bound.isLowerBound() )
1013 auto iter = var.upperbounds().find( psup );
1014 while( /*(**iter).isActive() &&*/ (**iter) < bound.limit() )
1016 if (!(*iter)->isActive()) {
1020 //FormulaSetT infsubset;
1021 //collectOrigins( *bound.origins().begin(), infsubset );
1022 //collectOrigins( *(**iter).pOrigins()->begin(), infsubset );
1023 //mInfeasibleSubsets.push_back( std::move(infsubset) );
1024 for (const auto& o1 : bound.origins()) {
1025 FormulaSetT infsubset;
1026 collectOrigins( o1, infsubset );
1027 for (const auto& o2: (*iter)->origins()) {
1028 FormulaSetT infsubsetForO1(infsubset);
1029 collectOrigins( o2, infsubsetForO1 );
1030 mInfeasibleSubsets.push_back( std::move(infsubsetForO1) );
1034 assert( iter != var.upperbounds().end() );
1038 if( !inf.isInfinite() )
1039 mBoundCandidatesToPass.push_back( pinf );
1040 mBoundCandidatesToPass.push_back( _bound );
1043 assert( mInfeasibleSubsets.empty() || !mInfeasibleSubsets.begin()->empty() );
1044 #ifdef SMTRAT_DEVOPTION_Statistics
1045 if( !mInfeasibleSubsets.empty() )
1046 mStatistics.addConflict( mInfeasibleSubsets );
1050 template<class Settings>
1051 void LRAModule<Settings>::activateStrictBound( const FormulaT& _neqOrigin, const LRABound& _weakBound, const LRABound* _strictBound )
1053 FormulaSetT involvedConstraints;
1054 FormulasT originSet;
1055 originSet.push_back( _neqOrigin );
1056 auto iter = _weakBound.origins().begin();
1057 assert( iter != _weakBound.origins().end() );
1058 if( iter->type() == carl::FormulaType::AND )
1060 originSet.insert( originSet.end(), iter->subformulas().begin(), iter->subformulas().end() );
1061 involvedConstraints.insert( iter->subformulas().begin(), iter->subformulas().end() );
1065 assert( iter->type() == carl::FormulaType::CONSTRAINT );
1066 originSet.push_back( *iter );
1067 involvedConstraints.insert( *iter );
1069 FormulaT origin = FormulaT( carl::FormulaType::AND, std::move(originSet) );
1070 activateBound( _strictBound, origin );
1072 while( iter != _weakBound.origins().end() )
1074 FormulasT originSetB;
1075 originSetB.push_back( _neqOrigin );
1076 if( iter->type() == carl::FormulaType::AND )
1078 originSetB.insert( originSetB.end(), iter->subformulas().begin(), iter->subformulas().end() );
1079 involvedConstraints.insert( iter->subformulas().begin(), iter->subformulas().end() );
1083 assert( iter->type() == carl::FormulaType::CONSTRAINT );
1084 originSetB.push_back( *iter );
1085 involvedConstraints.insert( *iter );
1087 FormulaT originB = FormulaT( carl::FormulaType::AND, std::move(originSet) );
1088 _strictBound->pOrigins()->push_back( originB );
1091 for( const FormulaT& fconstraint : involvedConstraints )
1093 auto constrBoundIter = mTableau.rConstraintToBound().find( fconstraint );
1094 assert( constrBoundIter != mTableau.constraintToBound().end() );
1095 std::vector< const LRABound* >* constraintToBounds = constrBoundIter->second;
1096 constraintToBounds->push_back( _strictBound );
1100 template<class Settings>
1101 void LRAModule<Settings>::setBound( const FormulaT& _constraint )
1103 mTableau.newBound( _constraint );
1106 template<class Settings>
1107 void LRAModule<Settings>::simpleTheoryPropagation()
1109 for( const LRAVariable* rowVar : mTableau.rows() )
1111 if( rowVar != NULL )
1113 if( !rowVar->infimum().isInfinite() )
1114 simpleTheoryPropagation( rowVar->pInfimum() );
1115 if( !rowVar->supremum().isInfinite() && rowVar->supremum().type() != LRABound::Type::EQUAL )
1116 simpleTheoryPropagation( rowVar->pSupremum() );
1119 for( const LRAVariable* columnVar : mTableau.columns() )
1121 if( !columnVar->infimum().isInfinite() )
1122 simpleTheoryPropagation( columnVar->pInfimum() );
1123 if( !columnVar->supremum().isInfinite() && columnVar->supremum().type() != LRABound::Type::EQUAL )
1124 simpleTheoryPropagation( columnVar->pSupremum() );
1128 // #define LRA_DEBUG_SIMPLE_THEORY_PROPAGATION
1129 template<class Settings>
1130 void LRAModule<Settings>::simpleTheoryPropagation( const LRABound* _bound )
1132 if( !_bound->exists() || (!_bound->isActive() && !_bound->isComplementActive()) )
1136 switch( _bound->type() )
1138 case LRABound::Type::EQUAL:
1139 propagateEqualBound( _bound );
1141 case LRABound::Type::LOWER:
1142 propagateLowerBound( _bound );
1145 assert( _bound->type() == LRABound::Type::UPPER );
1146 propagateUpperBound( _bound );
1151 template<class Settings>
1152 void LRAModule<Settings>::propagate( const LRABound* _premise, const FormulaT& _conclusion )
1155 collectOrigins( *_premise->origins().begin(), premise );
1156 mTheoryPropagations.emplace_back( std::move(premise), _conclusion );
1157 #ifdef LRA_DEBUG_SIMPLE_THEORY_PROPAGATION
1158 std::cout << "theory propagation: " << mTheoryPropagations.back().mPremise << " => " << mTheoryPropagations.back().mConclusion << std::endl;
1160 #ifdef SMTRAT_DEVOPTION_Statistics
1161 mStatistics.propagateTheory();
1165 template<class Settings>
1166 void LRAModule<Settings>::propagateLowerBound( const LRABound* _bound )
1168 const LRAVariable& lraVar = _bound->variable();
1169 auto cbIter = lraVar.upperbounds().begin();
1170 for(; !(*cbIter)->isInfinite() && (*cbIter)->limit() < _bound->limit(); ++cbIter )
1172 if( (*cbIter)->isUnassigned() && (*cbIter)->type() != LRABound::Type::EQUAL )
1174 // p>b => not(p<c) if b>=c
1175 // p>b => not(p<=c) if b>=c
1176 // p>=b => not(p<c) if b>=c
1177 // p>=b => not(p<=c) if b>c
1178 propagate( _bound, (*cbIter)->asConstraint().negated() );
1181 cbIter = lraVar.lowerbounds().find( _bound );
1182 assert( cbIter != lraVar.lowerbounds().end() );
1183 assert( cbIter != lraVar.lowerbounds().begin() );
1187 if( (*cbIter)->isUnassigned() )
1189 if( (*cbIter)->type() == LRABound::Type::EQUAL )
1191 if( mActiveUnresolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveUnresolvedNEQConstraints.end()
1192 && mActiveResolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveResolvedNEQConstraints.end() )
1194 // p>b => not(p=c) if b>=c
1195 // p>=b => not(p=c) if b>c
1196 propagate( _bound, (*cbIter)->asConstraint().negated() );
1201 // p>b => p>c if b>c
1202 // p>b => p>=c if b>=c
1203 // p>=b => p>c if b>c
1204 // p>=b => p>=c if b>c
1205 propagate( _bound, (*cbIter)->asConstraint() );
1208 if( cbIter == lraVar.lowerbounds().begin() )
1214 template<class Settings>
1215 void LRAModule<Settings>::propagateUpperBound( const LRABound* _bound )
1217 const LRAVariable& lraVar = _bound->variable();
1218 auto cbIter = lraVar.lowerbounds().end();
1220 for(; !(*cbIter)->isInfinite() && (*cbIter)->limit() > _bound->limit(); --cbIter )
1222 if( (*cbIter)->isUnassigned() && (*cbIter)->type() != LRABound::Type::EQUAL )
1224 // p<b => not(p>c) if b<=c
1225 // p<b => not(p>=c) if b<=c
1226 // p<=b => not(p>c) if b<=c
1227 // p<=b => not(p>=c) if b<c
1228 propagate( _bound, (*cbIter)->asConstraint().negated() );
1231 cbIter = lraVar.upperbounds().find( _bound );
1232 assert( cbIter != lraVar.upperbounds().end() );
1234 for(; cbIter != lraVar.upperbounds().end(); ++cbIter )
1236 if( (*cbIter)->isUnassigned() )
1238 if( (*cbIter)->type() == LRABound::Type::EQUAL )
1240 if( mActiveUnresolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveUnresolvedNEQConstraints.end()
1241 && mActiveResolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveResolvedNEQConstraints.end() )
1243 // p<b => not(p=c) if b<=c
1244 // p<=b => not(p=c) if b<c
1245 propagate( _bound, (*cbIter)->asConstraint().negated() );
1250 // p<b => p<c if b<c
1251 // p<b => p<=c if b<=c
1252 // p<=b => p<c if b<c
1253 // p<=b => p<=c if b<c
1254 propagate( _bound, (*cbIter)->asConstraint() );
1260 template<class Settings>
1261 void LRAModule<Settings>::propagateEqualBound( const LRABound* _bound )
1263 const LRAVariable& lraVar = _bound->variable();
1264 auto cbIter = lraVar.lowerbounds().begin();
1265 for(; *cbIter != _bound; ++cbIter )
1267 if( (*cbIter)->isUnassigned() )
1269 if( (*cbIter)->type() == LRABound::Type::EQUAL )
1271 if( mActiveUnresolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveUnresolvedNEQConstraints.end()
1272 && mActiveResolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveResolvedNEQConstraints.end() )
1274 // p=b => not(p=c) if b>c
1275 propagate( _bound, (*cbIter)->asConstraint().negated() );
1280 // p=b => p>c if b>c
1281 // p=b => p>=c if b>=c
1282 propagate( _bound, (*cbIter)->asConstraint() );
1287 for(; cbIter != lraVar.lowerbounds().end(); ++cbIter )
1289 if( (*cbIter)->isUnassigned() )
1291 if( (*cbIter)->type() == LRABound::Type::EQUAL )
1293 if( mActiveUnresolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveUnresolvedNEQConstraints.end()
1294 && mActiveResolvedNEQConstraints.find( (*cbIter)->asConstraint().negated() ) == mActiveResolvedNEQConstraints.end() )
1296 // p=b => not(p=c) if b<c
1297 propagate( _bound, (*cbIter)->asConstraint().negated() );
1302 // p=b => not(p>c) if b<c
1303 // p=b => not(p>=c) if b<c
1304 propagate( _bound, (*cbIter)->asConstraint().negated() );
1308 cbIter = lraVar.upperbounds().begin();
1309 for(; *cbIter != _bound; ++cbIter )
1311 if( (*cbIter)->isUnassigned() && (*cbIter)->type() != LRABound::Type::EQUAL )
1313 // p=b => not(p<c) if b>c
1314 // [p=b => not(p=c) if b>c] is already covered as p=c us also a lower bound
1315 // p=b => not(p<=c) if b>c
1316 propagate( _bound, (*cbIter)->asConstraint().negated() );
1320 for(; cbIter != lraVar.upperbounds().end(); ++cbIter )
1322 if( (*cbIter)->isUnassigned() && (*cbIter)->type() != LRABound::Type::EQUAL )
1324 // p=b => p>c if b<c
1325 // [p=b => not(p=c) if b<c] is already covered as p=c us also a lower bound
1326 // p=b => p>=c if b<=c
1327 propagate( _bound, (*cbIter)->asConstraint() );
1332 template<class Settings>
1333 void LRAModule<Settings>::init()
1337 mInitialized = true;
1338 for( const FormulaT& constraint : mLinearConstraints )
1340 setBound( constraint );
1342 // mTableau.setSize( mTableau.slackVars().size(), mTableau.originalVars().size(), mLinearConstraints.size() );
1343 mTableau.setBlandsRuleStart( 100 );
1347 template<class Settings>
1348 bool LRAModule<Settings>::gomoryCut()
1350 const RationalAssignment& rMap_ = getRationalModel();
1351 bool all_int = true;
1352 for( LRAVariable* basicVar : mTableau.rows() )
1354 auto vars = carl::variables(basicVar->expression());
1355 // TODO JNE why should this hold? Doesn't this correspond to the variables of a tableu row?
1356 assert( !vars.empty() );
1357 auto found_ex = rMap_.find(*vars.begin());
1358 const Rational& ass = found_ex->second;
1359 if( !carl::is_integer( ass ) )
1362 const Poly::PolyType* gomory_poly = mTableau.gomoryCut(ass, basicVar);
1363 if( *gomory_poly != Rational(0) )
1365 ConstraintT gomory_constr = ConstraintT( *gomory_poly , carl::Relation::GEQ );
1366 ConstraintT neg_gomory_constr = ConstraintT( *gomory_poly - carl::evaluate(*gomory_poly, rMap_ ), carl::Relation::LESS );
1367 //std::cout << gomory_constr << std::endl;
1368 assert( !carl::satisfied_by( gomory_constr, rMap_ ) );
1369 assert( !carl::satisfied_by( neg_gomory_constr, rMap_ ) );
1370 FormulasT subformulas;
1371 mTableau.collect_premises( basicVar, subformulas );
1372 FormulasT premisesOrigins;
1373 for( const FormulaT& pf : subformulas )
1374 collectOrigins( pf, premisesOrigins );
1376 for( const FormulaT& pre : premisesOrigins )
1377 premise.push_back( pre.negated() );
1378 premise.push_back( FormulaT( gomory_constr ) );
1379 FormulaT lemma( carl::FormulaType::OR, std::move( premise ) );
1380 // std::cout << " >>> found gomory cut: " << lemma << std::endl;
1388 template<class Settings>
1389 bool LRAModule<Settings>::branch_and_bound()
1391 carl::Variables varsToExclude;
1392 return mostInfeasibleVar( Settings::use_gomory_cuts, varsToExclude );
1395 template<class Settings>
1396 bool LRAModule<Settings>::mostInfeasibleVar( bool _tryGomoryCut, carl::Variables& _varsToExclude )
1398 const RationalAssignment& _rMap = getRationalModel();
1399 auto branch_var = mTableau.originalVars().begin();
1401 bool result = false;
1403 for( auto map_iterator = _rMap.begin(); map_iterator != _rMap.end(); ++map_iterator )
1405 auto var = mTableau.originalVars().find( map_iterator->first );
1406 if( _varsToExclude.find( var->first ) != _varsToExclude.end() )
1408 assert( var->first == map_iterator->first );
1409 const Rational& ass = map_iterator->second;
1410 if( (var->first.type() == carl::VariableType::VT_INT || var->first.type() == carl::VariableType::VT_BOOL) && !carl::is_integer( ass ) )
1414 Rational curr_diff = carl::abs( Rational( Rational(ass - carl::floor(ass)) - Rational(1)/Rational(2)) );
1415 if( curr_diff < diff )
1429 // std::cout << "try to branch at (" << branch_var->second->expression() << ", " << ass_ << ")" << std::endl;
1430 if( probablyLooping( branch_var->second->expression(), ass_ ) )
1432 // std::cout << " >>> probably looping!" << std::endl;
1433 if( _tryGomoryCut && gomoryCut() )
1435 _varsToExclude.insert( branch_var->first );
1436 // std::cout << " >>> exclude variable " << branch_var->first << std::endl;
1437 return mostInfeasibleVar( false, _varsToExclude );
1439 // FormulaSetT premises;
1440 // mTableau.collect_premises( branch_var->second , premises );
1441 // FormulaSetT premisesOrigins;
1442 // for( auto& pf : premises )
1444 // collectOrigins( pf, premisesOrigins );
1446 branchAt( branch_var->second->expression(), true, ass_ );
1450 return !_varsToExclude.empty();
1453 template<class Settings>
1454 bool LRAModule<Settings>::assignmentConsistentWithTableau( const RationalAssignment& _assignment, const LRABoundType& _delta ) const
1456 for( auto slackVar : mTableau.slackVars() )
1458 Poly tmp = carl::substitute(*slackVar.first, _assignment );
1459 assert( tmp.is_constant() );
1460 LRABoundType slackVarAssignment = slackVar.second->assignment().mainPart() + slackVar.second->assignment().deltaPart() * _delta;
1461 if( !(tmp == Poly(Rational(slackVarAssignment))) )
1469 template<class Settings>
1470 bool LRAModule<Settings>::assignmentCorrect() const
1472 if( solverState() == UNSAT ) return true;
1473 if( !mAssignmentFullfilsNonlinearConstraints ) return true;
1474 const RationalAssignment& rmodel = getRationalModel();
1475 carl::carlVariables inputVars(carl::variable_type_filter::arithmetic());
1476 rReceivedFormula().gatherVariables( inputVars );
1477 for( auto ass = rmodel.begin(); ass != rmodel.end(); ++ass )
1479 if( ass->first.type() == carl::VariableType::VT_INT && !carl::is_integer( ass->second ) && inputVars.has( ass->first ) )
1484 if ( ass->first.type() == carl::VariableType::VT_BOOL && !(ass->second == Rational(0) || ass->second == Rational(1)) )
1489 for( auto iter = rReceivedFormula().begin(); iter != rReceivedFormula().end(); ++iter )
1491 unsigned sat = carl::satisfied_by(iter->formula(), Model(rmodel));
1500 #ifdef DEBUG_METHODS_LRA_MODULE
1502 template<class Settings>
1503 void LRAModule<Settings>::printLinearConstraints( std::ostream& _out, const std::string _init ) const
1505 _out << _init << "Linear constraints:" << std::endl;
1506 for( auto iter = mLinearConstraints.begin(); iter != mLinearConstraints.end(); ++iter )
1508 _out << _init << " " << *iter << std::endl;
1512 template<class Settings>
1513 void LRAModule<Settings>::printNonlinearConstraints( std::ostream& _out, const std::string _init ) const
1515 _out << _init << "Nonlinear constraints:" << std::endl;
1516 for( auto iter = mNonlinearConstraints.begin(); iter != mNonlinearConstraints.end(); ++iter )
1518 _out << _init << " " << *iter << std::endl;
1522 template<class Settings>
1523 void LRAModule<Settings>::printConstraintToBound( std::ostream& _out, const std::string _init ) const
1525 _out << _init << "Mapping of constraints to bounds:" << std::endl;
1526 for( auto iter = mTableau.constraintToBound().begin(); iter != mTableau.constraintToBound().end(); ++iter )
1528 _out << _init << " " << iter->first << std::endl;
1529 for( auto iter2 = iter->second->begin(); iter2 != iter->second->end(); ++iter2 )
1531 _out << _init << " ";
1532 (*iter2)->print( true, std::cout, true );
1538 template<class Settings>
1539 void LRAModule<Settings>::printBoundCandidatesToPass( std::ostream& _out, const std::string _init ) const
1541 _out << _init << "Bound candidates to pass:" << std::endl;
1542 for( auto iter = mBoundCandidatesToPass.begin(); iter != mBoundCandidatesToPass.end(); ++iter )
1544 _out << _init << " ";
1545 (*iter)->print( true, std::cout, true );
1546 _out << " [" << (*iter)->pInfo()->updated << "]" << std::endl;
1550 template<class Settings>
1551 void LRAModule<Settings>::printRationalModel( std::ostream& _out, const std::string _init ) const
1553 const RationalAssignment& rmodel = getRationalModel();
1554 _out << _init << "Rational model:" << std::endl;
1555 for( auto assign = rmodel.begin(); assign != rmodel.end(); ++assign )
1558 _out << std::setw(10) << assign->first;
1559 _out << " -> " << assign->second << std::endl;
1563 template<class Settings>
1564 void LRAModule<Settings>::printTableau( std::ostream& _out, const std::string _init ) const
1566 mTableau.print( LAST_ENTRY_ID, _out, _init );
1569 template<class Settings>
1570 void LRAModule<Settings>::printVariables( std::ostream& _out, const std::string _init ) const
1572 mTableau.printVariables( true, _out, _init );
1575 } // namespace smtrat