2 * @file IntEqModule.tpp
3 * @author Dustin Huetter <dustin.huetter@rwth-aachen.de>
6 * Created on 2014-10-17.
9 #include "IntEqModule.h"
11 #include <carl-formula/model/Assignment.h>
13 //#define DEBUG_IntEqModule
21 template<class Settings>
22 IntEqModule<Settings>::IntEqModule( const ModuleInput* _formula, Conditionals& _conditionals, Manager* _manager ):
23 Module( _formula, _conditionals, _manager ),
25 mRecent_Constraints(),
31 mNew_Substitution = false;
34 template<class Settings>
35 bool IntEqModule<Settings>::addCore( ModuleInput::const_iterator _subformula )
37 #ifdef DEBUG_IntEqModule
38 std::cout << "Assert: " << _subformula->formula() << std::endl;
40 if( _subformula->formula().is_false() )
42 FormulaSetT infSubSet;
43 infSubSet.insert( _subformula->formula() );
44 mInfeasibleSubsets.push_back( std::move( infSubSet ) );
47 else if( _subformula->formula().is_true() )
51 if( _subformula->formula().constraint().relation() == carl::Relation::EQ )
53 // Do substitutions that have already been determined and update origins accordingly
54 std::shared_ptr<std::vector<FormulaT>> origins( new std::vector<FormulaT>() );
55 origins->push_back( _subformula->formula() );
56 const ConstraintT& constr = _subformula->formula().constraint();
57 Poly new_poly( constr.lhs() );
58 if( mRecent_Constraints.empty() )
60 mRecent_Constraints.push_back( Formula_Origins() );
62 auto iter_recent = mRecent_Constraints.begin();
63 iter_recent->insert( std::make_pair( _subformula->formula(), origins ) );
65 auto iter_subs = mSubstitutions.begin();
66 while( iter_subs != mSubstitutions.end() )
68 Poly tmp_poly = new_poly;
69 new_poly = carl::substitute(new_poly, (iter_subs)->first, (iter_subs)->second );
70 if( tmp_poly != new_poly )
72 auto iter_var = mVariables.find( iter_subs->first );
73 assert( iter_var != mVariables.end() );
74 *origins = std::move( merge( *origins, *( iter_var->second ) ) );
76 #ifdef DEBUG_IntEqModule
77 std::cout << "After temporary substitution: " << new_poly << std::endl;
79 FormulaT temp_eq( ( ConstraintT( new_poly, carl::Relation::EQ ) ) );
80 if( !temp_eq.is_true() && !temp_eq.is_false() )
82 if( *iter_subs != mSubstitutions.back() )
84 if( iter_recent != mRecent_Constraints.end() )
86 iter_recent->insert( std::make_pair( temp_eq, origins ) );
91 // Check whether a new substitution has been found since the last addCore call
92 if( mNew_Substitution )
95 temp.emplace( temp_eq, origins );
96 mRecent_Constraints.push_back( temp );
97 mNew_Substitution = false;
101 auto iter_help = mRecent_Constraints.back().find( temp_eq );
102 if( iter_help == mRecent_Constraints.back().end() )
104 mRecent_Constraints.back().insert( std::make_pair( temp_eq, origins ) );
108 iter_help->second->insert( iter_help->second->end(), origins->begin(), origins->end() );
113 if( iter_recent != mRecent_Constraints.end() )
123 #ifdef DEBUG_IntEqModule
124 std::cout << "After substitution: " << new_poly << std::endl;
126 FormulaT newEq( ConstraintT( new_poly, carl::Relation::EQ ) );
127 // Return UNSAT if the newly obtained constraint is unsatisfiable
128 if( newEq.is_false() )
130 #ifdef DEBUG_IntEqModule
131 std::cout << "NewEq is invalid" << std::endl;
133 size_t i = determine_smallest_origin( *origins );
134 FormulaSetT infSubSet;
135 collectOrigins( origins->at(i), infSubSet );
136 mInfeasibleSubsets.push_back( infSubSet );
139 if( newEq.is_true() )
143 #ifdef DEBUG_IntEqModule
144 std::cout << mRecent_Constraints << std::endl;
146 mProc_Constraints = mRecent_Constraints.back();
151 template<class Settings>
152 void IntEqModule<Settings>::removeCore( ModuleInput::const_iterator _subformula )
154 #ifdef DEBUG_IntEqModule
155 std::cout << "Remove: " << _subformula->formula() << std::endl;
157 if( _subformula->formula().constraint().relation() == carl::Relation::EQ )
159 // Check whether _subformula was used to derive a substitution
160 auto iter_temp = mSubstitutions.begin();
161 auto iter_temp_two = mRecent_Constraints.begin();
162 bool derived_sub = false;
163 Poly maybe_sub = _subformula->formula().constraint().lhs();
164 while( iter_temp != mSubstitutions.end() )
166 if( carl::substitute(maybe_sub, iter_temp->first, iter_temp->second ) == Poly() )
169 #ifdef DEBUG_IntEqModule
170 std::cout << "Is a substitution" << std::endl;
175 if( iter_temp_two != mRecent_Constraints.end() )
182 while( iter_temp != mSubstitutions.end() )
184 auto iter_help = mVariables.find( iter_temp->first );
185 assert( iter_help != mVariables.end() );
186 mVariables.erase( iter_help );
187 iter_temp = mSubstitutions.erase( iter_temp );
189 if( iter_temp_two != mRecent_Constraints.end() )
191 mRecent_Constraints.erase( iter_temp_two, mRecent_Constraints.end() );
192 if( mRecent_Constraints.empty() )
194 mRecent_Constraints.push_back( Formula_Origins() );
198 /* Iterate through all the processed constraints and delete all corresponding sets
199 * in the latter containing the element that has to be deleted. Delete a processed
200 * constraint if the corresponding vector is empty
202 #ifdef DEBUG_IntEqModule
203 std::cout << "Size of mRecent_Constraints: " << mRecent_Constraints.size() << std::endl;
204 std::cout << mRecent_Constraints << std::endl;
206 auto iter_steps = mRecent_Constraints.begin();
207 while( iter_steps != mRecent_Constraints.end() )
209 auto iter_formula = iter_steps->begin();
210 while( iter_formula != iter_steps->end() )
212 auto iter_origins = iter_formula->second->begin();
213 while( iter_origins != iter_formula->second->end() )
215 bool contains = iter_origins->contains( _subformula->formula() );
216 if( contains || *iter_origins == _subformula->formula() )
218 iter_origins = iter_formula->second->erase( iter_origins );
225 if( iter_formula->second->empty() )
227 auto to_delete = iter_formula;
229 iter_steps->erase( to_delete );
236 if( iter_steps->empty() )
238 #ifdef DEBUG_IntEqModule
239 std::cout << "Delete all iteration steps from here on!" << std::endl;
241 mRecent_Constraints.erase( iter_steps, mRecent_Constraints.end() );
242 if( mRecent_Constraints.empty() )
244 mRecent_Constraints.push_back( Formula_Origins() );
253 // Now possibly delete iteration steps in the case that two
254 // adjacent steps are equal due to the fact that a deleted substitution
255 // is followed by another one. In this case two adjacent steps can be equal.
256 auto iter_recent = mRecent_Constraints.begin();
257 while( iter_recent != mRecent_Constraints.end() )
259 auto iter_next = iter_recent;
261 if( iter_next == mRecent_Constraints.end() )
265 if( *iter_next == *iter_recent )
267 iter_recent = mRecent_Constraints.erase( iter_recent );
274 // Do the same for the substitution data structure(s)
275 #ifdef DEBUG_IntEqModule
276 std::cout << "Size of mVariables: " << mVariables.size() << std::endl;
277 std::cout << "Size of mSubstitutions: " << mSubstitutions.size() << std::endl;
279 auto iter_substitutions = mVariables.begin();
280 while( iter_substitutions != mVariables.end() )
282 auto iter_origins = iter_substitutions->second->begin();
283 while( iter_origins != iter_substitutions->second->end() )
285 bool contains = iter_origins->contains( _subformula->formula() );
286 if( contains || *iter_origins == _subformula->formula() )
288 iter_origins = iter_substitutions->second->erase( iter_origins );
295 if( iter_substitutions->second->empty() )
297 auto var_to_be_deleted = iter_substitutions->first;
298 auto to_delete = iter_substitutions;
299 ++iter_substitutions;
300 mVariables.erase( to_delete );
301 auto iter_help = mSubstitutions.begin();
302 while( iter_help != mSubstitutions.end() )
304 if( iter_help->first == var_to_be_deleted )
306 mSubstitutions.erase( iter_help );
311 //assert( mSubstitutions.size() == mVariables.size() );
315 ++iter_substitutions;
318 if( mRecent_Constraints.back().size() == 1 )
320 // Check whether the one constraint in mRecent_Constraints.back() corresponds to a substitution
321 #ifdef DEBUG_IntEqModule
322 std::cout << "Check whether: " << mRecent_Constraints.back().begin()->first.constraint() << " corresponds to a substitution" << std::endl;
324 auto iter_temp = mSubstitutions.begin();
326 Poly maybe_sub = mRecent_Constraints.back().begin()->first.constraint().lhs();
327 while( iter_temp != mSubstitutions.end() )
329 #ifdef DEBUG_IntEqModule
330 std::cout << "Substitute: " << iter_temp->first << " by: " << iter_temp->second << std::endl;
332 if( carl::substitute(maybe_sub, iter_temp->first, iter_temp->second ) == Poly() )
339 #ifdef DEBUG_IntEqModule
340 std::cout << "Is a substitution: " << is_sub << std::endl;
344 mNew_Substitution = true;
345 #ifdef DEBUG_IntEqModule
346 std::cout << "mRecent_Constraints: " << mRecent_Constraints << std::endl;
350 #ifdef DEBUG_IntEqModule
351 std::cout << "Size of mVariables: " << mVariables.size() << std::endl;
352 std::cout << "Size of mSubstitutions: " << mSubstitutions.size() << std::endl;
353 std::cout << "Size of mRecent_Constraints: " << mRecent_Constraints.size() << std::endl;
355 //assert( mSubstitutions.empty() || mSubstitutions.size() == mRecent_Constraints.size() );
356 mProc_Constraints = mRecent_Constraints.back();
360 template<class Settings>
361 void IntEqModule<Settings>::updateModel() const
364 if( solverState() == SAT )
366 mModel = mTemp_Model;
370 template<class Settings>
371 Answer IntEqModule<Settings>::checkCore()
373 if( !rReceivedFormula().is_constraint_conjunction() )
377 // Check whether a module which has been called on the same instance in parallel, has found an answer
378 if( anAnswerFound() )
382 // Execute the algorithm until unsatisfiability or a parametric solution
384 #ifdef DEBUG_IntEqModule
385 std::cout << "Determine unsatisfiability or a parametric solution:" << std::endl;
387 auto constr_iter = mProc_Constraints.begin();
388 while( !mProc_Constraints.empty() )
390 /* Pick the first equation for the following step
391 * and determine the coefficient of the latter with
392 * the smallest absolute value
394 const ConstraintT& curr_constr = mProc_Constraints.begin()->first.constraint();
395 if( mProc_Constraints.begin()->first.is_false() )
397 size_t i = determine_smallest_origin( *( mProc_Constraints.begin()->second ) );
398 FormulaSetT infSubSet;
399 collectOrigins( mProc_Constraints.begin()->second->at(i), infSubSet );
400 mInfeasibleSubsets.push_back( std::move( infSubSet ) );
403 #ifdef DEBUG_IntEqModule
404 std::cout << mProc_Constraints.begin()->first.constraint() << " was chosen." << std::endl;
406 std::shared_ptr<std::vector<FormulaT>> origins = mProc_Constraints.begin()->second;
407 typename Poly::PolyType ccExpanded = (typename Poly::PolyType)curr_constr.lhs();
408 auto iter_coeff = ccExpanded.begin();
409 Rational smallest_abs_value = (Rational)(*iter_coeff).coeff();
410 carl::Variable corr_var;
411 bool value_negative = false;
412 if( (*iter_coeff).is_constant() )
414 corr_var = (*(++iter_coeff)).single_variable();
415 Rational coeff = (Rational)(*iter_coeff).coeff();
418 value_negative = true;
420 smallest_abs_value = carl::abs( coeff );
424 corr_var = (*(iter_coeff)).single_variable();
425 if( smallest_abs_value < 0 )
427 value_negative = true;
429 smallest_abs_value = carl::abs( smallest_abs_value );
431 while( iter_coeff != ccExpanded.end())
433 if( !(*iter_coeff).is_constant() )
435 Rational coeff = (Rational)(*iter_coeff).coeff();
436 carl::Variable var = (*iter_coeff).single_variable();
437 if( carl::abs(coeff) < smallest_abs_value )
441 value_negative = true;
445 value_negative = false;
447 smallest_abs_value = carl::abs(coeff);
453 // Proceed with the execution of the equation elimination
454 // depending on the value of the smallest absolute value of curr_constr
455 Poly* temp = new Poly();
457 Rational sign = (Rational)1;
462 iter_coeff = ccExpanded.begin();
463 if( smallest_abs_value == 1 )
465 while( iter_coeff != ccExpanded.end() )
467 if( !(*iter_coeff).is_constant() )
469 if( (*iter_coeff).single_variable() != corr_var )
471 carl::Variable var = (*iter_coeff).single_variable();
472 *temp += Poly(var)*Poly(Rational(-1)*sign*(Rational)(*iter_coeff).coeff());
477 *temp += (Rational)(-1)*sign*(Rational)(*iter_coeff).coeff();
481 #ifdef DEBUG_IntEqModule
482 std::cout << "Delete the constraint: " << mProc_Constraints.begin()->first.constraint() << std::endl;
484 mProc_Constraints.erase( mProc_Constraints.begin() );
488 assert( smallest_abs_value > 1 );
489 while( iter_coeff != ccExpanded.end() )
491 Rational coeff = (Rational)(*iter_coeff).coeff();
492 bool positive = (Rational)(*iter_coeff).coeff() > 0;
493 if( !(*iter_coeff).is_constant() )
495 if( (*iter_coeff).single_variable() != corr_var )
497 carl::Variable var = (*iter_coeff).single_variable();
500 *temp -= sign*Poly( Rational( carl::floor( carl::div( coeff, smallest_abs_value ) ) ) )*Poly(var);
504 *temp -= sign*Poly( (Rational)(-1)*Rational( carl::floor( carl::div( (Rational)(-1)*coeff, smallest_abs_value ) ) ) )*Poly(var);
512 *temp -= sign*Rational( carl::floor( carl::div( coeff, smallest_abs_value ) ) );
516 *temp -= sign*Rational( (-1)*carl::floor( carl::div( (Rational)(-1)*coeff, smallest_abs_value ) ) );
521 carl::Variable fresh_var = carl::fresh_variable( carl::VariableType::VT_INT );
522 mAuxiliaries.insert( fresh_var );
523 *temp += Poly(fresh_var);
525 // Substitute the reformulation of the found variable for all occurences
526 // of this variable in equations of mProc_Constraints
527 #ifdef DEBUG_IntEqModule
528 std::cout << "Substitute " << corr_var << " by: " << *temp << std::endl;
530 std::pair<carl::Variable, Poly>* new_pair = new std::pair<carl::Variable, Poly>(corr_var, *temp );
531 auto iter_help = mVariables.find( new_pair->first );
532 mNew_Substitution = true;
533 if( iter_help == mVariables.end() )
535 mSubstitutions.push_back( *new_pair );
536 mVariables[ new_pair->first ] = origins;
538 Formula_Origins temp_proc_constraints;
539 constr_iter = mProc_Constraints.begin();
540 while( constr_iter != mProc_Constraints.end() )
542 Poly new_poly = constr_iter->first.constraint().lhs();
543 Poly tmp_poly = new_poly;
544 new_poly = carl::substitute(new_poly, new_pair->first, new_pair->second );
545 std::shared_ptr<std::vector<FormulaT>> origins_new = constr_iter->second;
546 if( new_poly != tmp_poly )
548 auto iter_help = mVariables.find( new_pair->first );
549 assert( iter_help != mVariables.end() );
550 *origins_new = ( std::move( merge( *( iter_help->second ), *( constr_iter->second ) ) ) );
552 FormulaT newEq( ConstraintT( new_poly, carl::Relation::EQ ) );
553 // Check whether newEq is unsatisfiable
554 if( newEq.is_false() )
556 #ifdef DEBUG_IntEqModule
557 std::cout << "Constraint is invalid!" << std::endl;
559 size_t i = determine_smallest_origin( *origins_new );
560 FormulaSetT infSubSet;
561 collectOrigins( origins_new->at(i), infSubSet );
562 mInfeasibleSubsets.push_back( infSubSet );
565 auto iter_help = temp_proc_constraints.find( newEq );
566 if( iter_help == temp_proc_constraints.end() )
568 temp_proc_constraints.emplace( newEq, origins_new );
572 iter_help->second->insert( iter_help->second->end(), origins_new->begin(), origins_new->end() );
576 mProc_Constraints = temp_proc_constraints;
577 if( !mProc_Constraints.empty() )
579 mRecent_Constraints.push_back( mProc_Constraints );
581 #ifdef DEBUG_IntEqModule
582 std::cout << mRecent_Constraints << std::endl;
585 #ifdef DEBUG_IntEqModule
586 std::cout << "Substitute in the received inequalities:" << std::endl;
588 auto iter_formula = rReceivedFormula().begin();
589 // Iterate through the received constraints and remove the equations
590 // by substituting the expressions according to mSubstitutions in the inequalities
591 // and ignoring the equations
592 while( iter_formula != rReceivedFormula().end() )
594 #ifdef DEBUG_IntEqModule
595 //cout << "Substitute in: " << (*iter_formula).formula().constraint() << std::endl;
597 if( (*iter_formula).formula().constraint().relation() == carl::Relation::LEQ || (*iter_formula).formula().constraint().relation() == carl::Relation::NEQ )
599 const smtrat::ConstraintT constr = (*iter_formula).formula().constraint();
600 Poly new_poly = constr.lhs();
601 std::shared_ptr<std::vector<FormulaT>> origins( new std::vector<FormulaT>() );
602 origins->push_back( (*iter_formula).formula() );
603 auto iter_subs = mSubstitutions.begin();
604 while( iter_subs != mSubstitutions.end() )
606 Poly tmp_poly = new_poly;
607 new_poly = carl::substitute(new_poly, (iter_subs)->first, (iter_subs)->second );
608 if( tmp_poly != new_poly )
610 auto iter_help = mVariables.find( iter_subs->first );
611 assert( iter_help != mVariables.end() );
612 *origins = std::move( merge( *origins, *( iter_help->second ) ) );
616 #ifdef DEBUG_IntEqModule
617 //cout << "After substitution: " << new_poly << std::endl;
619 FormulaT formula_passed( ConstraintT( new_poly, (*iter_formula).formula().constraint().relation() ) );
620 if( formula_passed.is_false() )
622 #ifdef DEBUG_IntEqModule
623 std::cout << "The obtained formula is unsatisfiable" << std::endl;
624 std::cout << "Origins: " << *origins << std::endl;
626 size_t i = determine_smallest_origin( *origins );
627 FormulaSetT infSubSet;
628 collectOrigins( origins->at(i), infSubSet );
629 mInfeasibleSubsets.push_back( std::move( infSubSet ) );
632 addConstraintToInform( formula_passed );
633 addSubformulaToPassedFormula( formula_passed, origins );
635 else if( mSubstitutions.empty() )
637 addReceivedSubformulaToPassedFormula( iter_formula );
641 #ifdef DEBUG_IntEqModule
642 std::cout << "Run LRAModule" << std::endl;
644 Answer ans = runBackends();
647 getInfeasibleSubsets();
649 else if( ans == SAT )
651 if( !constructSolution() )
659 template<class Settings>
660 bool IntEqModule<Settings>::constructSolution()
663 Module::getBackendsModel();
664 auto iter_model = mModel.begin();
665 while( iter_model != mModel.end() )
667 mTemp_Model.emplace(iter_model->first, iter_model->second);
670 std::map<carl::Variable, Rational> temp_map;
672 all_rational = getRationalAssignmentsFromModel( mTemp_Model, temp_map );
673 assert( all_rational );
674 #ifdef DEBUG_IntEqModule
675 std::cout << "Model: " << mModel << std::endl;
676 std::cout << "Temp Model: " << mTemp_Model << std::endl;
677 std::cout << "Auxiliaries: " << mAuxiliaries << std::endl;
679 // Determine the assignments of the variables that haven't been passed
680 // to the backends i.e. all variables for which substitutions exist
681 auto iter_vars = mSubstitutions.end();
682 if( mSubstitutions.empty() )
692 #ifdef DEBUG_IntEqModule
693 std::cout << "Substitution: " << iter_vars->first << " by " << iter_vars->second << std::endl;
695 Poly value = iter_vars->second;
696 value = carl::substitute(value, temp_map);
697 assert( value.is_constant() );
698 temp_map[ iter_vars->first ] = (Rational)value.constant_part();
699 ModelValue assignment = carl::createSubstitution<Rational,Poly,ModelPolynomialSubstitution>( value );
700 mTemp_Model.emplace(iter_vars->first, assignment);
701 if( iter_vars != mSubstitutions.begin() )
710 // Delete the assignments of the auxiliary variables
711 auto iter_ass = mTemp_Model.begin();
712 while( iter_ass != mTemp_Model.end() )
714 auto iter_help = mAuxiliaries.find( iter_ass->first.asVariable() );
715 if( iter_help == mAuxiliaries.end() )
721 auto to_delete = iter_ass;
723 mTemp_Model.erase( to_delete );
726 #ifdef DEBUG_IntEqModule
727 std::cout << "Temp Model: " << mTemp_Model << std::endl;
729 temp_map = std::map<carl::Variable, Rational>();
730 all_rational = getRationalAssignmentsFromModel( mTemp_Model, temp_map );
731 #ifdef DEBUG_IntEqModule
732 std::cout << "temp_map: " << temp_map << std::endl;
734 auto iter = rReceivedFormula().begin();
735 while( iter != rReceivedFormula().end() )
737 if( carl::satisfied_by( iter->formula().constraint(),temp_map ) != 1 )
740 #ifdef DEBUG_IntEqModule
741 std::cout << iter->formula() << std::endl;