SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
ICPModule.tpp
Go to the documentation of this file.
1 /*
2  * @file ICPModule.cpp
3  * @author Stefan Schupp <stefan.schupp@rwth-aachen.de>
4  * @author Florian Corzilius <corzilius@cs.rwth-aachen.de>
5  *
6  * Created on October 16, 2012, 1:07 PM
7  */
8 
9 #include <map>
10 #include <iomanip>
11 #include "assert.h"
12 #include <smtrat-solver/Manager.h>
13 #include "ICPModule.h"
14 
15 //#define ICP_MODULE_DEBUG_METHODS
16 //#define ICP_MODULE_DEBUG_0
17 //#define ICP_MODULE_DEBUG_1
18 //#define ICP_MODULE_DEBUG_2
19 //#define ICP_MODULE_SHOW_PROGRESS
20 
21 #ifdef ICP_MODULE_DEBUG_2
22 #ifndef ICP_MODULE_DEBUG_1
23 #define ICP_MODULE_DEBUG_1
24 #endif
25 #endif
26 
27 #ifdef ICP_MODULE_DEBUG_1
28 #ifndef ICP_MODULE_DEBUG_0
29 #define ICP_MODULE_DEBUG_0
30 #endif
31 #endif
32 
33 namespace smtrat
34 {
35  template<class Settings>
36  ICPModule<Settings>::ICPModule( const ModuleInput* _formula, Conditionals& _conditionals, Manager* const _manager ):
37  Module( _formula, _conditionals, _manager ),
38  mContractors(),
39  mCandidateManager(),
40  mActiveNonlinearConstraints(),
41  mActiveLinearConstraints(),
42  mLinearConstraints(),
43  mNonlinearConstraints(),
44  mNotEqualConstraints(),
45  mVariables(),
46  mIntervals(),
47  mInitialIntervals(),
48  mIcpRelevantCandidates(),
49  mLinearizations(),
50  mDeLinearizations(),
51  mVariableLinearizations(),
52  mSubstitutions(),
53  mHistoryRoot(new icp::HistoryNode(mIntervals)),
54  mHistoryActual(nullptr),
55  mValidationFormula(new ModuleInput()),
56  mLRAFoundAnswer( std::vector< std::atomic_bool* >( 1, new std::atomic_bool( false ) ) ),
57  mLRA(mValidationFormula, mLRAFoundAnswer),
58  mBoxStorage(),
59  mIsIcpInitialized(false),
60  mSplitOccurred(false),
61  mInvalidBox(false),
62  mTargetDiameter(Settings::target_diameter_nra),
63  mContractionThreshold(Settings::contraction_threshold_nra),
64  mDefaultSplittingSize(Settings::default_splitting_size_nra),
65  mSplittingHeuristic(Settings::splitting_heuristic_nra),
66  mNumberOfReusagesAfterTargetDiameterReached(Settings::number_of_reusages_after_target_diameter_reached),
67  mRelativeContraction(0),
68  mAbsoluteContraction(0),
69  mCountBackendCalls(0),
70  mGlobalBoxSize(0.0),
71  mInitialBoxSize(0.0)
72  {
73  if( mpManager != nullptr && mpManager->logic() == carl::Logic::QF_NIA )
74  {
75  mTargetDiameter = Settings::target_diameter_nia;
76  mContractionThreshold = Settings::contraction_threshold_nia;
77  mDefaultSplittingSize = Settings::default_splitting_size_nia;
78  mSplittingHeuristic = Settings::splitting_heuristic_nia;
79  }
80  }
81 
82  template<class Settings>
83  ICPModule<Settings>::~ICPModule()
84  {
85  while( !mLRAFoundAnswer.empty() )
86  {
87  std::atomic_bool* toDel = mLRAFoundAnswer.back();
88  mLRAFoundAnswer.pop_back();
89  delete toDel;
90  }
91  mLRAFoundAnswer.clear();
92  delete mHistoryRoot;
93  delete mValidationFormula;
94  for( auto variableIt = mVariables.begin(); variableIt != mVariables.end(); ++variableIt )
95  delete (*variableIt).second;
96  mVariables.clear();
97  #ifdef ICP_MODULE_SHOW_PROGRESS
98  std::cout << std::endl;
99  #endif
100  }
101 
102  template<class Settings>
103  bool ICPModule<Settings>::informCore( const FormulaT& _constraint )
104  {
105  #ifdef ICP_MODULE_DEBUG_1
106  std::cout << "[ICP] inform: " << _constraint << std::endl;
107  #endif
108  if( _constraint.type() == carl::FormulaType::CONSTRAINT )
109  {
110  const ConstraintT& constraint = _constraint.constraint();
111  if( !constraint.integer_valued() )
112  mDefaultSplittingSize = 1000;
113  unsigned constraintConsistency = constraint.is_consistent();
114  if( constraintConsistency == 2 && _constraint.constraint().relation() != carl::Relation::NEQ )
115  addConstraint( _constraint );
116  return constraintConsistency != 0;
117  }
118  return true;
119  }
120 
121  template<class Settings>
122  bool ICPModule<Settings>::addCore( ModuleInput::const_iterator _formula )
123  {
124  switch( _formula->formula().type() )
125  {
126  case carl::FormulaType::FALSE:
127  {
128  FormulaSetT infSubSet;
129  infSubSet.insert( _formula->formula() );
130  mInfeasibleSubsets.push_back( infSubSet );
131  mFoundSolution.clear();
132  return false;
133  }
134  case carl::FormulaType::TRUE:
135  {
136  return true;
137  }
138  case carl::FormulaType::CONSTRAINT:
139  {
140  const ConstraintT& constr = _formula->formula().constraint();
141  // create and initialize slackvariables
142  if (carl::satisfied_by(constr, mFoundSolution) != 1 )
143  mFoundSolution.clear();
144  if( !mIsIcpInitialized )
145  {
146  // catch lemmas
147  mLRA.init();
148  mLRA.updateLemmas();
149  for( const auto& lem : mLRA.lemmas() )
150  {
151  #ifdef ICP_MODULE_DEBUG_2
152  std::cout << "Create lemma for: " << lem.mLemma << std::endl;
153  #endif
154  FormulaT lemma = getReceivedFormulas( lem.mLemma );
155  addLemma(lemma, lem.mLemmaType);
156  #ifdef ICP_MODULE_DEBUG_2
157  std::cout << "Passed lemma: " << lemma << std::endl;
158  #endif
159  }
160  mLRA.clearLemmas();
161  mIsIcpInitialized = true;
162  }
163  // Handle Not Equal separate
164  if( constr.relation() == carl::Relation::NEQ ) {
165  mNotEqualConstraints.insert(_formula->formula());
166  addReceivedSubformulaToPassedFormula(_formula);
167  return true;
168  }
169  #ifdef ICP_MODULE_DEBUG_1
170  std::cout << "[ICP] Assertion: " << constr << std::endl;
171  #endif
172  if( !carl::is_bound(_formula->formula().constraint()) )
173  {
174  // TODO: here or somewhere later in isConsistent: remove constraints from passed formula which are implied by the current box
175  addSubformulaToPassedFormula( _formula->formula(), _formula->formula() );
176  for( auto var : _formula->formula().constraint().variables() )
177  {
178  auto iter = mVariables.find( var );
179  if( Settings::original_polynomial_contraction && iter == mVariables.end() )
180  continue;
181  iter->second->addOriginalConstraint( _formula->formula() );
182  }
183  }
184  // activate associated nonlinear contraction candidates
185  if( !constr.lhs().is_linear() )
186  activateNonlinearConstraint( _formula->formula() );
187  // lookup corresponding linearization - in case the constraint is already linear, mReplacements holds the constraint as the linearized one
188  auto replacementIt = mLinearizations.find( _formula->formula() );
189  assert( replacementIt != mLinearizations.end() );
190  const FormulaT& replacementPtr = (*replacementIt).second;
191  assert( replacementPtr.type() == carl::FormulaType::CONSTRAINT );
192  if( carl::is_bound(replacementPtr.constraint()) )
193  {
194  // considered constraint is activated but has no slack variable -> it is a boundary constraint
195  auto res = mValidationFormula->add( replacementPtr );
196  #ifdef ICP_MODULE_DEBUG_1
197  std::cout << "[mLRA] Assert bound constraint: " << replacementPtr << std::endl;
198  #endif
199  // If the constraint has not yet been part of the lramodule's received formula, assert it. If the
200  // lramodule already detects inconsistency, process its infeasible subsets.
201  if( res.second && !mLRA.add( res.first ) )
202  {
203  remapAndSetLraInfeasibleSubsets();
204  assert( !mInfeasibleSubsets.empty() );
205  return false;
206  }
207  }
208  else
209  activateLinearConstraint( replacementPtr, _formula->formula() );
210  return true;
211  }
212  default:
213  {
214  return true;
215  }
216  }
217  return true;
218  }
219 
220  template<class Settings>
221  void ICPModule<Settings>::removeCore( ModuleInput::const_iterator _formula )
222  {
223  if( _formula->formula().type() != carl::FormulaType::CONSTRAINT )
224  return;
225  const ConstraintT& constr = _formula->formula().constraint();
226  #ifdef ICP_MODULE_DEBUG_1
227  std::cout << "[ICP] Remove Formula " << constr << std::endl;
228  #endif
229  assert( constr.is_consistent() == 2 );
230  if( constr.relation() == carl::Relation::NEQ ) {
231  mNotEqualConstraints.erase(_formula->formula());
232  return;
233  }
234  if( !carl::is_bound(constr) )
235  {
236  for( auto var : constr.variables() )
237  mVariables.at(var)->addOriginalConstraint( _formula->formula() );
238  }
239  // is it nonlinear?
240  auto iter = mNonlinearConstraints.find( constr );
241  if( iter != mNonlinearConstraints.end() )
242  {
243  #ifdef ICP_MODULE_DEBUG_1
244  std::cout << "Nonlinear." << std::endl;
245  #endif
246  for( icp::ContractionCandidate* cc : iter->second )
247  {
248  // remove candidate if counter == 1, else decrement counter.
249  assert( cc->isActive() );
250  // remove origin, no matter if constraint is active or not
251  cc->removeOrigin( _formula->formula() );
252  if( cc->activity() == 0 )
253  {
254  // reset History to point before this candidate was used
255  resetHistory( cc );
256  // clean up icpRelevantCandidates
257  removeCandidateFromRelevant( cc );
258  mActiveNonlinearConstraints.erase( cc );
259  }
260  }
261  }
262  // linear handling
263  auto linearization = mLinearizations.find( _formula->formula() );
264  assert( linearization != mLinearizations.end() );
265  const icp::LRAVariable* slackvariable = mLRA.getSlackVariable( linearization->second );
266  assert( slackvariable != nullptr );
267  // lookup if contraction candidates already exist - if so, add origins
268  auto iterB = mLinearConstraints.find( slackvariable );
269  if( iterB != mLinearConstraints.end() )
270  {
271  #ifdef ICP_MODULE_DEBUG_1
272  std::cout << "Linear." << std::endl;
273  #endif
274  for( icp::ContractionCandidate* cc : iterB->second )
275  {
276  // remove candidate if counter == 1, else decrement counter.
277  // TODO: as the origin has maybe already been removed with removing the origins of non-linear constraints
278  // we need to check the following before. This should be avoided differently.
279  if( cc->hasOrigin( _formula->formula() ) )
280  {
281  // remove origin, no matter if constraint is active or not
282  cc->removeOrigin( _formula->formula() );
283  if( cc->activity() == 0 )
284  {
285  // reset History to point before this candidate was used
286  resetHistory( cc );
287  // clean up icpRelevantCandidates
288  removeCandidateFromRelevant( cc );
289  mActiveLinearConstraints.erase( cc );
290  }
291  }
292  }
293  }
294  // remove constraint from mLRA module
295  auto replacementIt = mLinearizations.find( _formula->formula() );
296  assert( replacementIt != mLinearizations.end() );
297  auto validationFormulaIt = mValidationFormula->find( replacementIt->second );
298  if( validationFormulaIt != mValidationFormula->end() )
299  {
300  #ifdef ICP_MODULE_DEBUG_1
301  std::cout << "[mLRA] remove " << validationFormulaIt->formula().constraint() << std::endl;
302  #endif
303  mLRA.remove( validationFormulaIt );
304  mValidationFormula->erase( validationFormulaIt );
305  }
306  }
307 
308  template<class Settings>
309  Answer ICPModule<Settings>::checkCore()
310  {
311  #ifdef ICP_MODULE_DEBUG_0
312  std::cout << "##############################################################" << std::endl;
313  std::cout << "Start consistency check with the ICPModule on the constraints " << std::endl;
314  for( const auto& f : rReceivedFormula() )
315  std::cout << " " << f.formula().constraint() << std::endl;
316  #endif
317  mLRAFoundSolution = false;
318  if( !mFoundSolution.empty() )
319  {
320  #ifdef ICP_MODULE_DEBUG_0
321  std::cout << "Found solution still feasible." << std::endl << std::endl;
322  #endif
323  if( checkNotEqualConstraints() )
324  return SAT;
325  else
326  return UNKNOWN;
327  }
328  for(;;)
329  {
330  // Debug Outputs of linear and nonlinear Tables
331  #ifdef ICP_MODULE_DEBUG_0
332  #ifdef ICP_MODULE_DEBUG_1
333  printIcpVariables();
334  #else
335  std::cout << "Constraints after preprocessing:" << std::endl;
336  printPreprocessedInput( " " );
337  std::cout << std::endl;
338  #endif
339  #endif
340  for( icp::ContractionCandidate* cc : mActiveLinearConstraints )
341  cc->resetReusagesAfterTargetDiameterReached();
342  for( icp::ContractionCandidate* cc : mActiveNonlinearConstraints )
343  cc->resetReusagesAfterTargetDiameterReached();
344  Answer lraAnswer = UNKNOWN;
345  if( initialLinearCheck( lraAnswer ) )
346  {
347  if( lraAnswer == SAT )
348  {
349  assert( !Settings::just_contraction );
350  if( checkNotEqualConstraints() )
351  {
352  #ifdef ICP_MODULE_DEBUG_0
353  std::cout << "Found solution with internal LRAModule!" << std::endl;
354  #endif
355  mLRAFoundSolution = true;
356  return SAT;
357  }
358  else
359  return UNKNOWN;
360  }
361  else
362  {
363  #ifdef ICP_MODULE_DEBUG_0
364  std::cout << "Linear constraints not feasible!" << std::endl;
365  #endif
366  return lraAnswer;
367  }
368  }
369  #ifdef ICP_MODULE_SHOW_PROGRESS
370  if( mGlobalBoxSize == 0.0 ) mGlobalBoxSize = calculateCurrentBoxSize();
371  mInitialBoxSize = calculateCurrentBoxSize();
372  #endif
373  #ifdef ICP_MODULE_DEBUG_0
374  std::cout << "Start with the intervals" << std::endl;
375  printIntervals( false );
376  #endif
377  contractCurrentBox();
378  if( anAnswerFound() )
379  return ABORTED;
380  #ifdef ICP_MODULE_DEBUG_0
381  std::cout << std::endl;
382  #endif
383  // when one interval is empty, we can skip validation and chose next box.
384  if( mInvalidBox ) // box contains no solution
385  {
386  #ifdef ICP_MODULE_DEBUG_0
387  std::cout << "Whole box contains no solution! Return UNSAT." << std::endl;
388  #endif
389  // whole box forms infeasible subset
390  mInfeasibleSubsets.push_back( createPremiseDeductions() );
391  #ifdef ICP_MODULE_SHOW_PROGRESS
392  addProgress( mInitialBoxSize );
393  #endif
394  return UNSAT;
395  }
396  else
397  {
398  assert( !intervalsEmpty() );
399  if( mSplitOccurred )
400  {
401  #ifdef ICP_MODULE_DEBUG_0
402  std::cout << "Return unknown, raise lemmas for split." << std::endl;
403  #endif
404  return UNKNOWN;
405  }
406  if( !Settings::just_contraction && tryTestPoints() )
407  {
408  if( checkNotEqualConstraints() )
409  return SAT;
410  else
411  return UNKNOWN;
412  }
413  else
414  {
415  // create Bounds and set them, add to passedFormula
416  pushBoundsToPassedFormula();
417  // lazy call of the backends on found box
418  Answer lazyResult = callBackends( mFinalCheck, false, objective() );
419  if( lazyResult == ABORTED )
420  return lazyResult;
421  // if it led to a result or the backends require a splitting
422  if( lazyResult != UNKNOWN || !lemmas().empty() )
423  return lazyResult;
424  // Full call of the backends, if no box has target diameter
425  bool furtherContractionOccurred = false;
426  if( !performSplit( mOriginalVariableIntervalContracted, furtherContractionOccurred ) )
427  return callBackends( mFinalCheck, mFullCheck, objective() );
428  if( mInvalidBox )
429  {
430  #ifdef ICP_MODULE_DEBUG_0
431  std::cout << "Whole box contains no solution! Return UNSAT." << std::endl;
432  #endif
433  // whole box forms infeasible subset
434  mInfeasibleSubsets.push_back( createPremiseDeductions() );
435  #ifdef ICP_MODULE_SHOW_PROGRESS
436  addProgress( mInitialBoxSize );
437  #endif
438  return UNSAT;
439  }
440  if( furtherContractionOccurred )
441  continue;
442  return UNKNOWN;
443  }
444  }
445  }
446  }
447 
448  template<class Settings>
449  void ICPModule<Settings>::resetHistory( icp::ContractionCandidate* _cc )
450  {
451  if( mHistoryActual == nullptr )
452  return;
453  if(mHistoryActual->getCandidates().find(_cc) != mHistoryActual->getCandidates().end())
454  {
455  setBox(mHistoryRoot);
456  mHistoryActual->reset();
457  }
458  }
459 
460  template<class Settings>
461  void ICPModule<Settings>::addConstraint( const FormulaT& _formula )
462  {
463  assert( _formula.type() == carl::FormulaType::CONSTRAINT );
464  assert( _formula.constraint().is_consistent() == 2 );
465  const ConstraintT& constraint = _formula.constraint();
466  auto linearization = mLinearizations.find( _formula );
467  if( linearization == mLinearizations.end() ) // If this constraint has not been added before
468  {
469  const Poly& constr = constraint.lhs();
470  // add original variables to substitution mapping
471  for( auto var: constraint.variables() )
472  {
473  if( mSubstitutions.find( var ) == mSubstitutions.end() )
474  {
475  assert( mVariables.find(var) == mVariables.end() );
476  assert( mIntervals.find(var) == mIntervals.end() );
477  mSubstitutions.insert( std::make_pair( var, Poly(var) ) );
478  getIcpVariable( var, true, nullptr ); // note that we have to set the lra variable later
479  mHistoryRoot->addInterval( var, DoubleInterval::unbounded_interval() );
480  }
481  }
482  // actual preprocessing
483  FormulaT linearFormula = FormulaT( carl::FormulaType::TRUE );
484  if( constr.is_linear() )
485  linearFormula = _formula;
486  else
487  {
488  assert( mLinearizations.find( _formula ) == mLinearizations.end() );
489  std::vector<Poly> temporaryMonomes = icp::getNonlinearMonomials( constr );
490  assert( !temporaryMonomes.empty() );
491  Poly lhs = createNonlinearCCs( _formula.constraint(), temporaryMonomes );
492  linearFormula = FormulaT( lhs, constraint.relation() );
493  assert( linearFormula.constraint().lhs().is_linear() );
494  #ifdef ICP_MODULE_DEBUG_1
495  std::cout << "linearize constraint to " << linearFormula.constraint() << std::endl;
496  #endif
497  };
498  assert( !linearFormula.is_true() );
499  // store replacement for later comparison when asserting
500  assert( mDeLinearizations.find( linearFormula ) == mDeLinearizations.end() );
501  assert( mLinearizations.find( _formula ) == mLinearizations.end() );
502  mDeLinearizations[linearFormula] = _formula;
503  mLinearizations[_formula] = linearFormula;
504  // inform internal LRAmodule of the linearized constraint
505  mLRA.inform( linearFormula );
506  const ConstraintT& linearizedConstraint = linearFormula.constraint();
507  #ifdef ICP_MODULE_DEBUG_1
508  std::cout << "[mLRA] inform: " << linearizedConstraint << std::endl;
509  #endif
510  if( !carl::is_bound(linearizedConstraint) || (Settings::original_polynomial_contraction && !_formula.constraint().lhs().is_linear()) )
511  createLinearCCs( linearFormula, _formula );
512  // set the lra variables for the icp variables regarding variables (introduced and original ones)
513  // TODO: Refactor this last part - it seems to be too complicated
514  for( auto var: linearizedConstraint.variables() )
515  {
516  auto iter = mVariables.find( var );
517  if( Settings::original_polynomial_contraction && iter == mVariables.end() )
518  continue;
519  assert( iter != mVariables.end() );
520  if( iter->second->lraVar() == nullptr )
521  {
522  auto ovarIter = mLRA.originalVariables().find( var );
523  if( ovarIter != mLRA.originalVariables().end() )
524  iter->second->setLraVar( ovarIter->second );
525  }
526  }
527  }
528  }
529 
530  template<class Settings>
531  icp::IcpVariable* ICPModule<Settings>::getIcpVariable( carl::Variable::Arg _var, bool _original, const icp::LRAVariable* _lraVar )
532  {
533  auto iter = mVariables.find( _var );
534  if( iter != mVariables.end() )
535  return iter->second;
536  auto res = mIntervals.insert( std::make_pair( _var, DoubleInterval::unbounded_interval() ) );
537  assert( res.second );
538  icp::IcpVariable* icpVar = new icp::IcpVariable( _var, _original, passedFormulaEnd(), res.first, _lraVar );
539  mVariables.insert( std::make_pair( _var, icpVar ) );
540  return icpVar;
541  }
542 
543  template<class Settings>
544  void ICPModule<Settings>::activateNonlinearConstraint( const FormulaT& _formula )
545  {
546  assert( _formula.type() == carl::FormulaType::CONSTRAINT );
547  auto iter = mNonlinearConstraints.find( _formula.constraint() );
548  #ifdef ICP_MODULE_DEBUG_1
549  std::cout << "[ICP] Assertion (nonlinear)" << _formula.constraint() << std::endl;
550  std::cout << "mNonlinearConstraints.size: " << mNonlinearConstraints.size() << std::endl;
551  std::cout << "Number Candidates: " << iter->second.size() << std::endl;
552  #endif
553  for( auto candidateIt = iter->second.begin(); candidateIt != iter->second.end(); ++candidateIt )
554  {
555  if( (*candidateIt)->activity() == 0 )
556  {
557  mActiveNonlinearConstraints.insert( *candidateIt );
558  #ifdef ICP_MODULE_DEBUG_1
559  std::cout << "[ICP] Activated candidate: ";
560  (*candidateIt)->print();
561  #endif
562  }
563  (*candidateIt)->addOrigin( _formula );
564  #ifdef ICP_MODULE_DEBUG_1
565  std::cout << "[ICP] Increased candidate count: ";
566  (*candidateIt)->print();
567  #endif
568  }
569  }
570 
571  template<class Settings>
572  void ICPModule<Settings>::activateLinearConstraint( const FormulaT& _formula, const FormulaT& _origin )
573  {
574  assert( _formula.type() == carl::FormulaType::CONSTRAINT );
575  const icp::LRAVariable* slackvariable = mLRA.getSlackVariable( _formula );
576  assert( slackvariable != nullptr );
577  // lookup if contraction candidates already exist - if so, add origins
578  auto iter = mLinearConstraints.find( slackvariable );
579  assert( iter != mLinearConstraints.end() );
580  for ( auto candidateIt = iter->second.begin(); candidateIt != iter->second.end(); ++candidateIt )
581  {
582  #ifdef ICP_MODULE_DEBUG_2
583  std::cout << "[ICP] ContractionCandidates already exist: ";
584  slackvariable->print();
585  std::cout << ", Size Origins: " << (*candidateIt)->origin().size() << std::endl;
586  std::cout << _formula << std::endl;
587  (*candidateIt)->print();
588  std::cout << "Adding origin." << std::endl;
589  #endif
590  // set value in activeLinearConstraints
591  if( (*candidateIt)->activity() == 0 )
592  mActiveLinearConstraints.insert( *candidateIt );
593  // add origin
594  (*candidateIt)->addOrigin( _origin );
595  }
596 
597  // assert in mLRA
598  auto res = mValidationFormula->add( _formula );
599  if( res.second )
600  {
601  if( !mLRA.add( res.first ) )
602  remapAndSetLraInfeasibleSubsets();
603  #ifdef ICP_MODULE_DEBUG_1
604  std::cout << "[mLRA] Assert " << _formula << std::endl;
605  #endif
606  }
607  }
608 
609  template<class Settings>
610  bool ICPModule<Settings>::checkNotEqualConstraints()
611  {
612  for( auto& constraint : mNotEqualConstraints )
613  {
614  if( carl::satisfied_by(constraint, mFoundSolution) == 0 )
615  {
616  if( mFinalCheck )
617  {
618  splitUnequalConstraint(constraint);
619  #ifdef ICP_MODULE_DEBUG_0
620  std::cout << "Unresolved inequality " << constraint << " - Return unknown and raise lemmas for split." << std::endl;
621  #endif
622  }
623  return false;
624  }
625  }
626  return true;
627  }
628 
629  template<class Settings>
630  void ICPModule<Settings>::contractCurrentBox()
631  {
632  #ifdef ICP_MODULE_DEBUG_0
633  std::cout << __func__ << ":" << std::endl;
634  #endif
635  mInvalidBox = false;
636  mSplitOccurred = false;
637  mOriginalVariableIntervalContracted = false;
638  for( ; ; )
639  {
640  if( anAnswerFound() )
641  return;
642  while(!mBoxStorage.empty())
643  mBoxStorage.pop();
644  icp::set_icpVariable icpVariables;
645  carl::carlVariables originalRealVariables(carl::variable_type_filter::real());
646  rReceivedFormula().gatherVariables(originalRealVariables);
647  // TODO: store original variables as member, updating them efficiently with assert and remove
648  for( auto variablesIt = originalRealVariables.begin(); variablesIt != originalRealVariables.end(); ++variablesIt )
649  {
650  auto iter = mVariables.find(*variablesIt);
651  if( iter != mVariables.end() )
652  icpVariables.insert( iter->second );
653  }
654  FormulasT box = variableReasonHull(icpVariables);
655  mBoxStorage.push(box);
656  #ifdef ICP_MODULE_DEBUG_1
657  std::cout << "********************** [ICP] Contraction **********************" << std::endl;
658  //cout << "Subtree size: " << mHistoryRoot->sizeSubtree() << std::endl;
659  mHistoryActual->print();
660  #endif
661  // prepare IcpRelevantCandidates
662  fillCandidates();
663  while ( !mIcpRelevantCandidates.empty() && !mSplitOccurred )
664  {
665  icp::ContractionCandidate* candidate = chooseContractionCandidate();
666  assert(candidate != nullptr);
667  mRelativeContraction = -1; // TODO: try without this line
668  mAbsoluteContraction = 0; // TODO: try without this line
669  contraction( candidate );
670  // catch if new interval is empty -> we can drop box and chose next box
671  if ( mIntervals.at(candidate->derivationVar()).is_empty() )
672  {
673  #ifdef ICP_MODULE_DEBUG_0
674  std::cout << "Contracted to empty interval!" << std::endl;
675  #endif
676  mInvalidBox = true;
677  break;
678  }
679  if( (mRelativeContraction > 0 || mAbsoluteContraction > 0) && originalRealVariables.has( candidate->derivationVar() ) )
680  {
681  mOriginalVariableIntervalContracted = true;
682  }
683  // update weight of the candidate
684  removeCandidateFromRelevant(candidate);
685  candidate->setPayoff(mRelativeContraction);
686  candidate->calcRWA();
687  // only add nonlinear CCs as linear CCs should only be used once
688  if( !candidate->is_linear() )
689  addCandidateToRelevant(candidate); // TODO: Improve - no need to add irrelevant candidates (see below)
690  assert(mIntervals.find(candidate->derivationVar()) != mIntervals.end() );
691  /// TODO: compare against mRelativeContraction or candidate->RWA()
692  if ( (mRelativeContraction < mContractionThreshold && !mSplitOccurred) || fulfillsTarget(*candidate) )
693  removeCandidateFromRelevant(candidate);
694  else if ( mRelativeContraction >= mContractionThreshold )
695  {
696  // make sure all candidates which contain the variable of which the interval has significantly changed are contained in mIcpRelevantCandidates.
697  std::map<carl::Variable, icp::IcpVariable*>::iterator icpVar = mVariables.find(candidate->derivationVar());
698  assert(icpVar != mVariables.end());
699  for ( auto candidateIt = (*icpVar).second->candidates().begin(); candidateIt != (*icpVar).second->candidates().end(); ++candidateIt )
700  {
701  bool toAdd = true;
702  // TODO: there must be a better way to find out whether the candidate is already in the relevants
703  for ( auto relevantCandidateIt = mIcpRelevantCandidates.begin(); relevantCandidateIt != mIcpRelevantCandidates.end(); ++relevantCandidateIt )
704  {
705  if ( (*relevantCandidateIt).second == (*candidateIt)->id() )
706  toAdd = false;
707  }
708  if ( toAdd && (*candidateIt)->isActive() && !fulfillsTarget(**candidateIt) )
709  addCandidateToRelevant(*candidateIt);
710  }
711  }
712  } //while ( !mIcpRelevantCandidates.empty() && !mSplitOccurred)
713  // verify if the box is already invalid
714  if( !mInvalidBox && !mSplitOccurred )
715  {
716  mInvalidBox = !checkBoxAgainstLinearFeasibleRegion();
717  #ifdef ICP_MODULE_DEBUG_1
718  std::cout << "Invalid against linear region: " << (mInvalidBox ? "yes!" : "no!") << std::endl;
719  #endif
720  }
721  if( mInvalidBox )
722  return;
723  if( mSplitOccurred || mIcpRelevantCandidates.empty() ) // relevantCandidates is not empty, if we got new bounds from LRA during boxCheck
724  return;
725  }
726  assert( false ); // should not happen
727  }
728 
729  template<class Settings>
730  Answer ICPModule<Settings>::callBackends( bool _final, bool _full, carl::Variable _objective )
731  {
732  #ifdef ICP_MODULE_DEBUG_0
733  std::cout << "Ask backends " << (_full ? "full" : "lazy") << " for the satisfiability of:" << std::endl;
734  for( const auto& f : rPassedFormula() )
735  std::cout << " " << f.formula().constraint() << std::endl;
736  #endif
737  ++mCountBackendCalls;
738  Answer a = runBackends( _final, _full, _objective );
739  if( a == ABORTED )
740  return a;
741  updateLemmas();
742  std::vector<Module*>::const_iterator backend = usedBackends().begin();
743  while( backend != usedBackends().end() )
744  {
745  (*backend)->clearLemmas();
746  ++backend;
747  }
748  #ifdef ICP_MODULE_DEBUG_0
749  std::cout << " Backend's answer: " << a << std::endl;
750  #endif
751  if( a == UNSAT )
752  {
753  assert(infeasibleSubsets().empty());
754  FormulaSetT contractionConstraints = this->createPremiseDeductions();
755  backend = usedBackends().begin();
756  while( backend != usedBackends().end() )
757  {
758  assert( !(*backend)->infeasibleSubsets().empty() );
759  #ifdef ICP_MODULE_DEBUG_1
760  (*backend)->printInfeasibleSubsets();
761  #endif
762  for( auto infsubset = (*backend)->infeasibleSubsets().begin(); infsubset != (*backend)->infeasibleSubsets().end(); ++infsubset )
763  {
764  FormulaSetT newInfSubset;
765  for( auto subformula = infsubset->begin(); subformula != infsubset->end(); ++subformula )
766  {
767  if( !carl::is_bound(subformula->constraint()) )
768  newInfSubset.insert( *subformula );
769  }
770  newInfSubset.insert( contractionConstraints.begin(), contractionConstraints.end() );
771  mInfeasibleSubsets.push_back( std::move(newInfSubset) );
772  }
773  ++backend;
774  }
775  #ifdef ICP_MODULE_SHOW_PROGRESS
776  addProgress( mInitialBoxSize );
777  #endif
778  return UNSAT;
779  }
780  else // if a == SAT or a == UNKNOWN
781  {
782  assert( mHistoryActual != nullptr );
783  assert( mHistoryRoot != nullptr );
784  mHistoryActual->propagateStateInfeasibleConstraints(mHistoryRoot);
785  mHistoryActual->propagateStateInfeasibleVariables(mHistoryRoot);
786  #ifdef ICP_MODULE_SHOW_PROGRESS
787 // if( _full && a == UNKNOWN && !hasLemmas() )
788 // addProgress( mInitialBoxSize );
789  #endif
790  return a;
791  }
792  }
793 
794  template<class Settings>
795  Poly ICPModule<Settings>::createNonlinearCCs( const ConstraintT& _constraint, const std::vector<Poly>& _tempMonomes )
796  {
797  Poly linearizedConstraint;
798  ContractionCandidates ccs;
799  /*
800  * Create all icp variables and contraction candidates for the given non-linear constraint:
801  *
802  * a_1*m_1 + .. + a_k*m_k ~ b, with b and a_i being rationals and m_i being monomials (possibly linear)
803  */
804  for( auto& monom : _tempMonomes )
805  {
806  ContractionCandidates ccsOfMonomial;
807  auto iter = mVariableLinearizations.find( monom );
808  if( iter == mVariableLinearizations.end() ) // no linearization yet
809  {
810  // create mLinearzations entry
811  carl::carlVariables variables = carl::variables(monom);
812  bool hasRealVar = false;
813  for (auto var: variables) {
814  if (var.type() == carl::VariableType::VT_REAL) {
815  hasRealVar = true;
816  break;
817  }
818  }
819  carl::Variable newVar = hasRealVar ? carl::fresh_real_variable() : carl::fresh_integer_variable();
820  mVariableLinearizations.insert( std::make_pair( monom, newVar ) );
821  mSubstitutions.insert( std::make_pair( newVar, monom ) );
822  if( !Settings::original_polynomial_contraction )
823  {
824  assert( mVariables.find( newVar ) == mVariables.end() );
825  icp::IcpVariable* icpVar = getIcpVariable( newVar, false, nullptr );
826  mHistoryRoot->addInterval( newVar, DoubleInterval::unbounded_interval() );
827  #ifdef ICP_MODULE_DEBUG_1
828  std::cout << "New replacement: " << monom << " -> " << mVariableLinearizations.at(monom) << std::endl;
829  #endif
830  // Create equation m_i - v_i = 0, where m_i is the nonlinear monomial x_{i,1}^e_{i,1}*..*x_{i,n}^e_{i,n} being replaced by the freshly introduced variable v_i
831  Poly rhs = monom - Poly(newVar);
832  if( mContractors.find(rhs) == mContractors.end() )
833  {
834  mContractors.emplace( rhs, Contractor<carl::SimpleNewton>(rhs) );
835  }
836 
837  ConstraintT tmp = ConstraintT( rhs, carl::Relation::EQ );
838  for( auto varIndex = variables.begin(); varIndex != variables.end(); ++varIndex )
839  {
840  // create a contraction candidate for m_i-v_i regarding the variable x_{i,1}
841  icp::ContractionCandidate* tmpCandidate = mCandidateManager.createCandidate( newVar, rhs, tmp, *varIndex, mContractors.at( rhs ), Settings::use_propagation );
842  ccsOfMonomial.insert( ccsOfMonomial.end(), tmpCandidate );
843  tmpCandidate->setNonlinear();
844  // add the contraction candidate to the icp variable of v_i
845  auto tmpIcpVar = mVariables.find( newVar );
846  assert( tmpIcpVar != mVariables.end() );
847  tmpIcpVar->second->addCandidate( tmpCandidate );
848  }
849  // create a contraction candidate for m_i-v_i regarding the variable v_i
850  icp::ContractionCandidate* tmpCandidate = mCandidateManager.createCandidate( newVar, rhs, tmp, newVar, mContractors.at( rhs ), Settings::use_propagation );
851  tmpCandidate->setNonlinear();
852  icpVar->addCandidate( tmpCandidate );
853  ccsOfMonomial.insert( ccsOfMonomial.end(), tmpCandidate );
854  // add all contraction candidates for m_i-v_i to the icp variables of all x_{i,j}
855  for( auto var = variables.begin(); var != variables.end(); ++var )
856  {
857  auto origIcpVar = mVariables.find( *var );
858  assert( origIcpVar != mVariables.end() );
859  origIcpVar->second->addCandidates( ccsOfMonomial );
860  }
861  ccs.insert( ccsOfMonomial.begin(), ccsOfMonomial.end() );
862  }
863  }
864  else // already existing replacement/substitution/linearization
865  {
866  #ifdef ICP_MODULE_DEBUG_2
867  std::cout << "Existing replacement: " << monom << " -> " << mVariableLinearizations.at(monom) << std::endl;
868  #endif
869  auto iterB = mVariables.find( iter->second );
870  if( !Settings::original_polynomial_contraction || iterB != mVariables.end() )
871  {
872  assert( iterB != mVariables.end() );
873  // insert already created CCs into the current list of CCs
874  ccs.insert( iterB->second->candidates().begin(), iterB->second->candidates().end() );
875  }
876  }
877  }
878  // Construct the linearization
879  for( auto monomialIt = _constraint.lhs().polynomial().begin(); monomialIt != _constraint.lhs().polynomial().end(); ++monomialIt )
880  {
881  if( (monomialIt)->monomial() == nullptr || (monomialIt)->monomial()->isAtMostLinear() )
882  linearizedConstraint += Poly(typename Poly::PolyType(*monomialIt));
883  else
884  {
885  assert( mVariableLinearizations.find(Poly(typename Poly::PolyType((monomialIt)->monomial()))) != mVariableLinearizations.end() );
886  linearizedConstraint += (monomialIt)->coeff() * Poly((*mVariableLinearizations.find( Poly(typename Poly::PolyType((monomialIt)->monomial())) )).second);
887  }
888  }
889  mNonlinearConstraints.emplace( _constraint, std::move(ccs) );
890  linearizedConstraint *= _constraint.lhs().coefficient();
891  return linearizedConstraint;
892  }
893 
894  template<class Settings>
895  void ICPModule<Settings>::createLinearCCs( const FormulaT& _constraint, const FormulaT& _original )
896  {
897  /*
898  * Create all icp variables and contraction candidates for the given linear constraint:
899  *
900  * a_1*x_1 + .. + a_k*x_k ~ b, with b and a_i being rationals and x_i being variables
901  */
902  assert( _constraint.type() == carl::FormulaType::CONSTRAINT );
903  assert( _constraint.constraint().lhs().is_linear() );
904  const icp::LRAVariable* slackvariable = mLRA.getSlackVariable( _constraint );
905  assert( slackvariable != nullptr );
906  if( mLinearConstraints.find( slackvariable ) == mLinearConstraints.end() )
907  {
908  carl::Variables variables = Settings::original_polynomial_contraction ? _original.constraint().variables().as_set() : _constraint.constraint().variables().as_set();
909  bool hasRealVar = false;
910  for( auto var : variables )
911  {
912  if( var.type() == carl::VariableType::VT_REAL )
913  {
914  hasRealVar = true;
915  break;
916  }
917  }
918  carl::Variable newVar = hasRealVar ? carl::fresh_real_variable() : carl::fresh_integer_variable();
919  variables.insert( variables.end(), newVar );
920  mSubstitutions.insert( std::make_pair( newVar, Poly( newVar ) ) );
921  assert( mVariables.find( newVar ) == mVariables.end() );
922  icp::IcpVariable* icpVar = getIcpVariable( newVar, false, slackvariable );
923  mHistoryRoot->addInterval( newVar, DoubleInterval::unbounded_interval() );
924  // Create equation a_1'*x_1 + .. + a_k'*x_k = 0, with a_i' = a_i/gcd(a_1,..,a_k)*sgn(a_1)
925  Poly rhs = Poly(slackvariable->expression()) - Poly(newVar);
926  ConstraintT tmpConstr = ConstraintT( rhs, carl::Relation::EQ );
927  auto iter = mContractors.find( rhs );
928  if( iter == mContractors.end() )
929  {
930  iter = mContractors.emplace( rhs, Contractor<carl::SimpleNewton>(rhs, carl::substitute(rhs, mSubstitutions )) ).first;
931  }
932  ContractionCandidates ccs;
933  // Create candidates for every possible variable:
934  for( auto var = variables.begin(); var != variables.end(); ++var )
935  {
936  // create a contraction candidate for a_1'*x_1 + .. + a_k'*x_k - v regarding the variable x_i/v
937  icp::ContractionCandidate* newCandidate = mCandidateManager.createCandidate( newVar, rhs, tmpConstr, *var, iter->second, Settings::use_propagation && (!Settings::original_polynomial_contraction || _original.constraint().lhs().is_linear()) );
938  ccs.insert( ccs.end(), newCandidate );
939  newCandidate->setLinear();
940  }
941  // add all contraction candidates for a_1'*x_1 + .. + a_k'*x_k - v to the icp variables of all x_i/v
942  for( auto var = variables.begin(); var != variables.end(); ++var )
943  {
944  auto origIcpVar = mVariables.find( *var );
945  assert( origIcpVar != mVariables.end() );
946  origIcpVar->second->addCandidates( ccs );
947  }
948  mLinearConstraints.insert( std::pair<const icp::LRAVariable*, ContractionCandidates>( slackvariable, icpVar->candidates() ) );
949  }
950  }
951 
952  template<class Settings>
953  void ICPModule<Settings>::fillCandidates()
954  {
955  // fill mIcpRelevantCandidates with the nonlinear contractionCandidates
956  for ( icp::ContractionCandidate* nonlinearIt : mActiveNonlinearConstraints )
957  {
958  // check that assertions have been processed properly
959  assert( (*nonlinearIt).activity() == (*nonlinearIt).origin().size() );
960  if ( !fulfillsTarget(*nonlinearIt) )
961  addCandidateToRelevant( nonlinearIt );// only add if not already existing
962  else // the candidate is not relevant -> delete from icpRelevantCandidates
963  removeCandidateFromRelevant(nonlinearIt);
964  }
965  // fill mIcpRelevantCandidates with the active linear contractionCandidates
966  for ( icp::ContractionCandidate* linearIt : mActiveLinearConstraints )
967  {
968  // check that assertions have been processed properly
969  assert( (*linearIt).activity() == (*linearIt).origin().size() );
970  if ( (*linearIt).isActive() && !fulfillsTarget(*linearIt) )
971  addCandidateToRelevant( linearIt );
972  else // the candidate is not relevant -> delete from icpRelevantCandidates
973  removeCandidateFromRelevant( linearIt );
974  }
975  }
976 
977  template<class Settings>
978  bool ICPModule<Settings>::addCandidateToRelevant(icp::ContractionCandidate* _candidate)
979  {
980  if ( _candidate->isActive() )
981  {
982  mIcpRelevantCandidates.erase( std::pair<double, unsigned>( _candidate->lastRWA(), _candidate->id() ) );
983  std::pair<double, unsigned> target(_candidate->RWA(), _candidate->id());
984  if ( mIcpRelevantCandidates.find(target) == mIcpRelevantCandidates.end() )
985  {
986  #ifdef ICP_MODULE_DEBUG_1
987  std::cout << "add to relevant candidates: " << (*_candidate).rhs() << " in variable " << (*_candidate).derivationVar() << std::endl;
988  std::cout << " id: " << (*_candidate).id() << std::endl;
989  std::cout << " key: (" << target.first << ", " << target.second << ")" << std::endl;
990  #endif
991  mIcpRelevantCandidates.insert(target);
992  _candidate->updateLastRWA();
993  return true;
994  }
995  }
996  return false;
997  }
998 
999  template<class Settings>
1000  bool ICPModule<Settings>::removeCandidateFromRelevant(icp::ContractionCandidate* _candidate)
1001  {
1002  std::pair<double, unsigned> target(_candidate->lastRWA(), _candidate->id());
1003  auto iter = mIcpRelevantCandidates.find( target );
1004  if( iter != mIcpRelevantCandidates.end() )
1005  {
1006  #ifdef ICP_MODULE_DEBUG_1
1007  std::cout << "remove from relevant candidates: " << (*_candidate).rhs() << std::endl;
1008  std::cout << " id: " << (*_candidate).id() << " , Diameter: " << mIntervals[(*_candidate).derivationVar()].diameter() << std::endl;
1009  #endif
1010  mIcpRelevantCandidates.erase(iter);
1011  return true;
1012  }
1013  return false;
1014  }
1015 
1016  template<class Settings>
1017  void ICPModule<Settings>::updateRelevantCandidates(carl::Variable::Arg _var)
1018  {
1019  // update all candidates which contract in the dimension in which the split has happened
1020  std::set<icp::ContractionCandidate*> updatedCandidates;
1021  // iterate over all affected constraints
1022  std::map<carl::Variable, icp::IcpVariable*>::iterator icpVar = mVariables.find(_var);
1023  assert(icpVar != mVariables.end());
1024  for ( auto candidatesIt = (*icpVar).second->candidates().begin(); candidatesIt != (*icpVar).second->candidates().end(); ++candidatesIt)
1025  {
1026  if ( (*candidatesIt)->isActive() )
1027  {
1028  unsigned id = (*candidatesIt)->id();
1029  // search if candidate is already contained - erase if, else do nothing
1030  removeCandidateFromRelevant(*candidatesIt);
1031  // create new tuple for mIcpRelevantCandidates
1032  mCandidateManager.getCandidate(id)->setPayoff(mRelativeContraction );
1033  mCandidateManager.getCandidate(id)->calcRWA();
1034  updatedCandidates.insert(*candidatesIt);
1035  }
1036  }
1037  // re-insert tuples into icpRelevantCandidates
1038  for ( auto candidatesIt = updatedCandidates.begin(); candidatesIt != updatedCandidates.end(); ++candidatesIt )
1039  {
1040  if ( !fulfillsTarget(**candidatesIt) )
1041  addCandidateToRelevant(*candidatesIt);
1042  }
1043  }
1044 
1045  template<class Settings>
1046  icp::ContractionCandidate* ICPModule<Settings>::chooseContractionCandidate()
1047  {
1048  assert(!mIcpRelevantCandidates.empty());
1049  // as the map is sorted ascending, we can simply pick the last value
1050  for( auto candidateIt = mIcpRelevantCandidates.rbegin(); candidateIt != mIcpRelevantCandidates.rend(); ++candidateIt )
1051  {
1052  icp::ContractionCandidate* cc = mCandidateManager.getCandidate((*candidateIt).second);
1053  assert( cc != nullptr );
1054  if( cc->isActive() )//&& mIntervals[mCandidateManager.getCandidate((*candidateIt).second)->derivationVar()].diameter() != 0 )
1055  {
1056  cc->calcDerivative();
1057  #ifdef ICP_MODULE_DEBUG_1
1058  std::cout << "Choose Candidate: ";
1059  cc->print();
1060  std::cout << std::endl;
1061  #endif
1062  return cc;
1063  }
1064  }
1065  return nullptr;
1066  }
1067 
1068  template<class Settings>
1069  void ICPModule<Settings>::contraction( icp::ContractionCandidate* _selection )
1070  {
1071  DoubleInterval resultA;
1072  DoubleInterval resultB;
1073  // check if derivative is already calculated
1074  if(carl::is_zero(_selection->derivative()))
1075  _selection->calcDerivative();
1076  carl::Variable variable = _selection->derivationVar();
1077  assert( mVariables.find( variable ) != mVariables.end() );
1078  icp::IcpVariable& icpVar = *mVariables.find( variable )->second;
1079  DoubleInterval icpVarIntervalBefore = icpVar.interval();
1080  mSplitOccurred = _selection->contract( mIntervals, resultA, resultB );
1081  if( (!mFinalCheck || !Settings::split_by_division_with_zero) && mSplitOccurred )
1082  {
1083  mSplitOccurred = false;
1084  resultA = resultA.convex_hull( resultB );
1085  }
1086  if( mSplitOccurred )
1087  {
1088  assert( !resultB.is_empty() );
1089  #ifdef ICP_MODULE_DEBUG_2
1090  std::cout << "Split occurred: " << resultA << " and " << resultB << std::endl;
1091  #endif
1092  setContraction( _selection, icpVar, resultA.convex_hull( resultB ) );
1093  icp::set_icpVariable variables;
1094  for( auto variable: _selection->constraint().variables() )
1095  {
1096  assert(mVariables.find(variable) != mVariables.end());
1097  variables.insert(mVariables.at(variable));
1098  }
1099  mHistoryActual->addContraction(_selection, variables);
1100  /// create prequesites: ((oldBox AND CCs) -> newBox) in CNF: (oldBox OR CCs) OR newBox
1101  FormulasT subformulas;
1102  std::vector<FormulaT> splitPremise = createPremise();
1103  for( const FormulaT& subformula : splitPremise )
1104  subformulas.emplace_back( carl::FormulaType::NOT, subformula );
1105  // construct new box
1106  FormulasT boxFormulas = createBoxFormula( true );
1107  // push lemma
1108  if( !boxFormulas.empty() )
1109  {
1110  auto lastFormula = --boxFormulas.end();
1111  if( boxFormulas.size() > 1 )
1112  {
1113  for( auto iter = boxFormulas.begin(); iter != lastFormula; ++iter )
1114  mTheoryPropagations.emplace_back( std::move(FormulasT(subformulas)), *iter );
1115  }
1116  mTheoryPropagations.emplace_back( std::move(subformulas), *lastFormula );
1117  }
1118  #ifdef ICP_MODULE_SHOW_PROGRESS
1119  addProgress( mInitialBoxSize - calculateCurrentBoxSize() );
1120  #endif
1121  // create split: (not h_b OR (Not x<b AND x>=b) OR (x<b AND Not x>=b) )
1122  assert(resultA.upper_bound_type() != carl::BoundType::INFTY );
1123  Rational bound = carl::rationalize<Rational>( resultA.upper() );
1124  Module::branchAt( variable, bound, std::move(splitPremise), true, true );
1125  #ifdef ICP_MODULE_DEBUG_1
1126  std::cout << "division causes split on " << variable << " at " << bound << "!" << std::endl << std::endl;
1127  #endif
1128  #ifdef ICP_MODULE_DEBUG_0
1129  printContraction( *_selection, icpVarIntervalBefore, resultA, resultB );
1130  #endif
1131  }
1132  else
1133  {
1134  // set intervals
1135  setContraction( _selection, icpVar, resultA );
1136  }
1137  #ifdef ICP_MODULE_DEBUG_1
1138  std::cout << " Relative contraction: " << mRelativeContraction << std::endl;
1139  #endif
1140  }
1141 
1142  template<class Settings>
1143  void ICPModule<Settings>::setContraction( icp::ContractionCandidate* _selection, icp::IcpVariable& _icpVar, const DoubleInterval& _contractedInterval )
1144  {
1145  updateRelativeContraction( _icpVar.interval(), _contractedInterval );
1146  updateAbsoluteContraction( _icpVar.interval(), _contractedInterval );
1147  #ifdef ICP_MODULE_DEBUG_0
1148  printContraction( *_selection, _icpVar.interval(), _contractedInterval );
1149  #endif
1150  _icpVar.setInterval( _contractedInterval );
1151  if (mRelativeContraction > 0 || mAbsoluteContraction > 0)
1152  {
1153  mHistoryActual->addInterval(_selection->lhs(), mIntervals.at(_selection->lhs()));
1154  icp::set_icpVariable variables;
1155  for( auto variable: _selection->constraint().variables() )
1156  {
1157  if( Settings::original_polynomial_contraction && mVariables.find(variable) == mVariables.end() )
1158  continue;
1159  assert(mVariables.find(variable) != mVariables.end());
1160  variables.insert(mVariables.at(variable));
1161  }
1162  mHistoryActual->addContraction(_selection, variables);
1163  }
1164  }
1165 
1166  template<class Settings>
1167  void ICPModule<Settings>::setContraction( const FormulaT& _constraint, icp::IcpVariable& _icpVar, const DoubleInterval& _contractedInterval, bool _allCCs )
1168  {
1169  icp::ContractionCandidate* foundCC = nullptr;
1170  if( _constraint.constraint().lhs().is_linear() )
1171  {
1172  auto iter = mLinearConstraints.find( mLRA.getSlackVariable( _constraint ) );
1173  assert( iter != mLinearConstraints.end() );
1174  for( const auto& cc : iter->second )
1175  {
1176  if( _allCCs )
1177  setContraction( cc, _icpVar, _contractedInterval );
1178  else if( cc->derivationVar() == _icpVar.var() )
1179  {
1180  foundCC = cc;
1181  break;
1182  }
1183  }
1184  }
1185  if( foundCC == nullptr )
1186  {
1187  assert( _constraint.type() == carl::FormulaType::CONSTRAINT );
1188  auto iter = mNonlinearConstraints.find( _constraint.constraint() );
1189  assert( iter != mNonlinearConstraints.end() );
1190  for( const auto& cc : iter->second )
1191  {
1192  if( _allCCs )
1193  setContraction( cc, _icpVar, _contractedInterval );
1194  else if( cc->derivationVar() == _icpVar.var() )
1195  {
1196  foundCC = cc;
1197  break;
1198  }
1199  }
1200  }
1201  if( foundCC == nullptr && _constraint.constraint().maxDegree( _icpVar.var() ) == 1 )
1202  {
1203  auto linearization = mLinearizations.find( _constraint );
1204  assert( linearization != mLinearizations.end() );
1205  auto iter = mLinearConstraints.find( mLRA.getSlackVariable( linearization->second ) );
1206  assert( iter != mLinearConstraints.end() );
1207  for( const auto& cc : iter->second )
1208  {
1209  if( _allCCs )
1210  setContraction( cc, _icpVar, _contractedInterval );
1211  else if( cc->derivationVar() == _icpVar.var() )
1212  {
1213  foundCC = cc;
1214  break;
1215  }
1216  }
1217  }
1218  if( _allCCs )
1219  return;
1220  assert( foundCC != nullptr );
1221  setContraction( foundCC, _icpVar, _contractedInterval );
1222  }
1223 
1224  template<class Settings>
1225  void ICPModule<Settings>::updateRelativeContraction( const DoubleInterval& _interval, const DoubleInterval& _contractedInterval )
1226  {
1227  assert( _interval == _contractedInterval || _interval.contains( _contractedInterval ) );
1228  if( _contractedInterval.is_empty() )
1229  {
1230  mRelativeContraction = 1;
1231  return;
1232  }
1233  if( _interval == _contractedInterval )
1234  {
1235  mRelativeContraction = 0;
1236  return;
1237  }
1238  // If the interval lost an infinite part, give it a high valuation
1239  if( (_interval.lower_bound_type() == carl::BoundType::INFTY && _contractedInterval.lower_bound_type() != carl::BoundType::INFTY)
1240  || (_interval.upper_bound_type() == carl::BoundType::INFTY && _contractedInterval.upper_bound_type() != carl::BoundType::INFTY) )
1241  {
1242  mRelativeContraction = 1;
1243  return;
1244  }
1245  // If zero is split from the interval, give it a high valuation
1246  if( _interval.contains( (double) 0.0 ) && !_contractedInterval.contains( (double) 0.0 ) )
1247  {
1248  mRelativeContraction = 1;
1249  return;
1250  }
1251  // If the interval is still unbounded the relative contraction is 0
1252  if( _contractedInterval.lower_bound_type() == carl::BoundType::INFTY || _contractedInterval.upper_bound_type() == carl::BoundType::INFTY )
1253  {
1254  mRelativeContraction = 0;
1255  return;
1256  }
1257  assert( _interval.lower_bound_type() != carl::BoundType::INFTY );
1258  assert( _interval.upper_bound_type() != carl::BoundType::INFTY );
1259  assert( _contractedInterval.lower_bound_type() != carl::BoundType::INFTY );
1260  assert( _contractedInterval.upper_bound_type() != carl::BoundType::INFTY );
1261  mRelativeContraction = (double)1 - (_contractedInterval.diameter()/_interval.diameter());
1262  }
1263 
1264  template<class Settings>
1265  void ICPModule<Settings>::updateAbsoluteContraction( const DoubleInterval& _interval, const DoubleInterval& _contractedInterval )
1266  {
1267  assert( _interval == _contractedInterval || _interval.contains( _contractedInterval ) );
1268  if( _contractedInterval.is_empty() )
1269  {
1270  if( _interval.lower_bound_type() == carl::BoundType::INFTY || _interval.upper_bound_type() == carl::BoundType::INFTY )
1271  mAbsoluteContraction = std::numeric_limits<double>::infinity();
1272  else
1273  mAbsoluteContraction = _interval.diameter();
1274  return;
1275  }
1276  if( _interval == _contractedInterval )
1277  {
1278  mAbsoluteContraction = 0;
1279  return;
1280  }
1281  if( (_interval.lower_bound_type() == carl::BoundType::INFTY && _contractedInterval.lower_bound_type() != carl::BoundType::INFTY)
1282  || (_interval.upper_bound_type() == carl::BoundType::INFTY && _contractedInterval.upper_bound_type() != carl::BoundType::INFTY) )
1283  {
1284  mAbsoluteContraction = std::numeric_limits<double>::infinity();
1285  return;
1286  }
1287  if( _contractedInterval.lower_bound_type() == carl::BoundType::INFTY )
1288  {
1289  assert( _interval.upper_bound_type() != carl::BoundType::INFTY );
1290  assert( _contractedInterval.lower_bound_type() == carl::BoundType::INFTY );
1291  assert( _contractedInterval.upper_bound_type() != carl::BoundType::INFTY );
1292  assert( _interval.upper() >= _contractedInterval.upper() ); // >= as _contractedInterval.upper_bound_type() could be strict and _interval.upper_bound_type() weak
1293  mAbsoluteContraction = _interval.upper() - _contractedInterval.upper();
1294  if( _interval.upper_bound_type() == carl::BoundType::WEAK && _contractedInterval.upper_bound_type() == carl::BoundType::STRICT )
1295  mAbsoluteContraction = std::nextafter( mAbsoluteContraction, INFINITY );
1296  else if( _interval.upper_bound_type() == carl::BoundType::STRICT && _contractedInterval.upper_bound_type() == carl::BoundType::WEAK )
1297  mAbsoluteContraction = std::nextafter( mAbsoluteContraction, -INFINITY );
1298  return;
1299  }
1300  if( _contractedInterval.upper_bound_type() == carl::BoundType::INFTY )
1301  {
1302  assert( _interval.lower_bound_type() != carl::BoundType::INFTY );
1303  assert( _contractedInterval.upper_bound_type() == carl::BoundType::INFTY );
1304  assert( _contractedInterval.lower_bound_type() != carl::BoundType::INFTY );
1305  assert( _interval.lower() <= _contractedInterval.lower() ); // >= as _contractedInterval.lower_bound_type() could be strict and _interval.lower_bound_type() weak
1306  mAbsoluteContraction = _contractedInterval.lower() - _interval.lower();
1307  if( _interval.lower_bound_type() == carl::BoundType::WEAK && _contractedInterval.lower_bound_type() == carl::BoundType::STRICT )
1308  mAbsoluteContraction = std::nextafter( mAbsoluteContraction, INFINITY );
1309  else if( _interval.lower_bound_type() == carl::BoundType::STRICT && _contractedInterval.lower_bound_type() == carl::BoundType::WEAK )
1310  mAbsoluteContraction = std::nextafter( mAbsoluteContraction, -INFINITY );
1311  return;
1312  }
1313  assert( _interval.lower_bound_type() != carl::BoundType::INFTY );
1314  assert( _interval.upper_bound_type() != carl::BoundType::INFTY );
1315  assert( _contractedInterval.lower_bound_type() != carl::BoundType::INFTY );
1316  assert( _contractedInterval.upper_bound_type() != carl::BoundType::INFTY );
1317  mAbsoluteContraction = _interval.diameter() - _contractedInterval.diameter();
1318  }
1319 
1320  template<class Settings>
1321  std::map<carl::Variable, double> ICPModule<Settings>::createModel( bool antipoint ) const
1322  {
1323  // Note that we do not need to consider INFTY bounds in the calculation of the antipoint.
1324  std::map<carl::Variable, double> assignments;
1325  auto varIntervalIt = mIntervals.begin();
1326  auto varIt = mVariables.begin();
1327  if( Settings::original_polynomial_contraction )
1328  {
1329  while( varIntervalIt->first != varIt->first && varIt != mVariables.end() )
1330  ++varIt;
1331  }
1332  while( varIt != mVariables.end() )
1333  {
1334  if( !varIt->second->isOriginal() )
1335  {
1336  ++varIntervalIt;
1337  if( Settings::original_polynomial_contraction )
1338  {
1339  while( varIntervalIt->first != varIt->first && varIt != mVariables.end() )
1340  ++varIt;
1341  if( varIt == mVariables.end() )
1342  break;
1343  }
1344  else
1345  ++varIt;
1346  continue;
1347  }
1348  assert( varIntervalIt->first == varIt->first );
1349  assert( varIt->second->var() == varIt->first );
1350  double value = 0;
1351  const DoubleInterval& interv = varIntervalIt->second;
1352  if( !interv.is_infinite() )
1353  {
1354  bool takeLower = false;
1355  bool takeUpper = false;
1356  if( antipoint ) // Find a point within the interval bounds which is most likely NOT SATISFYING all constraints
1357  {
1358  switch( (*varIt).second->isInternalUpdated() )
1359  {
1360  case icp::Updated::BOTH:
1361  takeLower = true;
1362  break;
1363  case icp::Updated::LEFT:
1364  takeLower = true;
1365  break;
1366  case icp::Updated::RIGHT:
1367  takeUpper = true;
1368  break;
1369  default:
1370  takeLower = true;
1371  takeUpper = true;
1372  }
1373  }
1374  else // Find a point within the interval which is most likely SATISFYING all constraints
1375  {
1376  switch( (*varIt).second->isInternalUpdated() )
1377  {
1378  case icp::Updated::BOTH:
1379  takeLower = true;
1380  takeUpper = true;
1381  break;
1382  case icp::Updated::LEFT:
1383  takeUpper = true;
1384  break;
1385  case icp::Updated::RIGHT:
1386  takeLower = true;
1387  break;
1388  default:
1389  takeLower = true;
1390  }
1391  }
1392  if( takeLower && takeUpper )
1393  {
1394  if(interv.is_point_interval())
1395  {
1396  value = interv.lower();
1397  }
1398  else
1399  {
1400  value = carl::sample(interv,false);
1401  }
1402  }
1403  else if( takeLower )
1404  {
1405  if( interv.lower_bound_type() == carl::BoundType::INFTY )
1406  {
1407  if( interv.upper_bound_type() == carl::BoundType::WEAK )
1408  {
1409  value = interv.upper();
1410  }
1411  else
1412  {
1413  value = std::nextafter( interv.upper(), -INFINITY );
1414  }
1415  }
1416  else
1417  {
1418  if( interv.lower_bound_type() == carl::BoundType::WEAK )
1419  {
1420  value = interv.lower();
1421  }
1422  else if( interv.upper_bound_type() != carl::BoundType::INFTY )
1423  {
1424  value = std::nextafter( interv.lower(), INFINITY );
1425  // Check if the interval does contain any double. If not, return an empty model.
1426  if( value > interv.upper() || (interv.upper_bound_type() == carl::BoundType::STRICT && value == interv.upper()) )
1427  {
1428  return std::map<carl::Variable, double>();
1429  }
1430  }
1431  else
1432  {
1433  if( interv.lower() == std::numeric_limits<double>::max() )
1434  {
1435  return std::map<carl::Variable, double>();
1436  }
1437  value = std::nextafter( interv.lower(), INFINITY );
1438  }
1439  }
1440  }
1441  else
1442  {
1443  if( interv.upper_bound_type() == carl::BoundType::INFTY )
1444  {
1445  if( interv.lower_bound_type() == carl::BoundType::WEAK )
1446  {
1447  value = interv.lower();
1448  }
1449  else
1450  {
1451  value = std::nextafter( interv.lower(), INFINITY );
1452  }
1453  }
1454  else
1455  {
1456  if( interv.upper_bound_type() == carl::BoundType::WEAK )
1457  {
1458  value = interv.upper();
1459  }
1460  else if( interv.lower_bound_type() != carl::BoundType::INFTY )
1461  {
1462  value = std::nextafter( interv.upper(), -INFINITY );
1463  // Check if the interval does contain any double. If not, return an empty model.
1464  if( value < interv.lower() || (interv.lower_bound_type() == carl::BoundType::STRICT && value == interv.lower()) )
1465  {
1466  return std::map<carl::Variable, double>();
1467  }
1468  }
1469  else
1470  {
1471  if( interv.upper() == std::numeric_limits<double>::min() )
1472  {
1473  return std::map<carl::Variable, double>();
1474  }
1475  value = std::nextafter( interv.upper(), -INFINITY );
1476  }
1477  }
1478  }
1479  }
1480  assert( interv.contains( value ) );
1481  assignments[varIt->first] = value;
1482  ++varIt;
1483  ++varIntervalIt;
1484  }
1485  return assignments;
1486  }
1487 
1488  template<class Settings>
1489  void ICPModule<Settings>::updateModel() const
1490  {
1491  clearModel();
1492  if( solverState() == SAT )
1493  {
1494  if( mFoundSolution.empty() )
1495  {
1496  if( !mLRAFoundSolution )
1497  Module::getBackendsModel();
1498  RationalAssignment rationalAssignment = mLRA.getRationalModel();
1499  for( auto assignmentIt = rationalAssignment.begin(); assignmentIt != rationalAssignment.end(); ++assignmentIt )
1500  {
1501  auto varIt = mVariables.find((*assignmentIt).first);
1502  if( varIt != mVariables.end() && (*varIt).second->isOriginal() )
1503  {
1504  mModel.emplace( assignmentIt->first, assignmentIt->second );
1505  }
1506  }
1507  }
1508  else
1509  {
1510  for (const auto& assignment: mFoundSolution)
1511  {
1512  auto varIt = mVariables.find(assignment.first.asVariable());
1513  if( varIt != mVariables.end() && (*varIt).second->isOriginal() )
1514  {
1515  mModel.emplace(assignment.first, assignment.second);
1516  }
1517  }
1518  }
1519  }
1520  }
1521 
1522  template<class Settings>
1523  ModuleInput::iterator ICPModule<Settings>::eraseSubformulaFromPassedFormula( ModuleInput::iterator _subformula, bool _ignoreOrigins )
1524  {
1525  // TODO: check if the sub-formula is a bound, then take the variable, find its icp-variable and update it
1526  for( auto& varIcpvarPair : mVariables )
1527  {
1528  icp::IcpVariable& icpVar = *varIcpvarPair.second;
1529  assert( icpVar.externalLeftBound() == passedFormulaEnd() || icpVar.externalLeftBound() != icpVar.externalRightBound() );
1530  if( icpVar.externalLeftBound() == _subformula )
1531  {
1532  icpVar.setExternalLeftBound( passedFormulaEnd() );
1533  icpVar.setExternalModified();
1534  break;
1535  }
1536  else if( icpVar.externalRightBound() == _subformula )
1537  {
1538  icpVar.setExternalRightBound( passedFormulaEnd() );
1539  icpVar.setExternalModified();
1540  break;
1541  }
1542  }
1543  auto res = Module::eraseSubformulaFromPassedFormula( _subformula, _ignoreOrigins );
1544  return res;
1545  }
1546 
1547  template<class Settings>
1548  double ICPModule<Settings>::sizeBasedSplittingImpact( std::map<carl::Variable, icp::IcpVariable*>::const_iterator _varIcpVarMapIter ) const
1549  {
1550  const DoubleInterval& varInterval = _varIcpVarMapIter->second->interval();
1551  if( varInterval.lower_bound_type() == carl::BoundType::INFTY || varInterval.upper_bound_type() == carl::BoundType::INFTY )
1552  return std::numeric_limits<double>::infinity();
1553  double impact = 0;
1554  double originalDiameter = varInterval.diameter();
1555  switch(mSplittingStrategy)
1556  {
1557  case 1: // Select biggest interval
1558  {
1559  impact = originalDiameter;
1560  break;
1561  }
1562  case 2: // Rule of Hansen and Walster - select interval with most varying function values
1563  {
1564  EvalDoubleIntervalMap tmpIntervals = mIntervals;
1565  tmpIntervals.insert(std::make_pair(_varIcpVarMapIter->first,DoubleInterval(1)));
1566  DoubleInterval derivedEvalInterval = carl::evaluate((*_varIcpVarMapIter->second->candidates().begin())->derivative(), tmpIntervals); // TODO: WHY ANY DERIVATIVE??
1567  if( derivedEvalInterval.lower_bound_type() == carl::BoundType::INFTY || derivedEvalInterval.upper_bound_type() == carl::BoundType::INFTY )
1568  return std::numeric_limits<double>::infinity();
1569  impact = derivedEvalInterval.diameter() * originalDiameter;
1570  break;
1571  }
1572  case 3: // Rule of Ratz - minimize width of inclusion
1573  {
1574  EvalDoubleIntervalMap tmpIntervals = mIntervals;
1575  tmpIntervals.insert(std::make_pair(_varIcpVarMapIter->first,DoubleInterval(1)));
1576  DoubleInterval derivedEvalInterval = carl::evaluate((*_varIcpVarMapIter->second->candidates().begin())->derivative(), tmpIntervals); // TODO: WHY ANY DERIVATIVE??
1577  DoubleInterval negCenter = varInterval.inverse();
1578  negCenter = negCenter.add(varInterval);
1579  derivedEvalInterval = derivedEvalInterval.mul(negCenter);
1580  if( derivedEvalInterval.lower_bound_type() == carl::BoundType::INFTY || derivedEvalInterval.upper_bound_type() == carl::BoundType::INFTY )
1581  return std::numeric_limits<double>::infinity();
1582  impact = derivedEvalInterval.diameter();
1583  break;
1584  }
1585  case 4: // Select according to optimal machine representation of bounds
1586  {
1587  if( varInterval.contains(0) )
1588  impact = originalDiameter;
1589  else
1590  impact = originalDiameter/(varInterval.upper() > 0 ? varInterval.lower() : varInterval.upper());
1591  break;
1592  }
1593  default:
1594  {
1595  impact = originalDiameter;
1596  if( varInterval.lower_bound_type() == carl::BoundType::STRICT )
1597  impact = std::nextafter( impact, -INFINITY );
1598  if( varInterval.upper_bound_type() == carl::BoundType::STRICT )
1599  impact = std::nextafter( impact, -INFINITY );
1600  break;
1601  }
1602  }
1603  #ifdef ICP_MODULE_DEBUG_1
1604  std::cout << __PRETTY_FUNCTION__ << " Rule " << mSplittingStrategy << ": " << impact << std::endl;
1605  #endif
1606  return impact;
1607  }
1608 
1609  template<class Settings>
1610  FormulaSetT ICPModule<Settings>::createPremiseDeductions()
1611  {
1612  // collect applied contractions
1613  FormulaSetT contractions = mHistoryActual->appliedConstraints();
1614  // collect original box
1615  assert( mBoxStorage.size() > 0 );
1616  const FormulasT& box = mBoxStorage.front();
1617  for( auto& f : box )
1618  contractions.insert( f );
1619  mBoxStorage.pop();
1620  return contractions;
1621  }
1622 
1623  template<class Settings>
1624  FormulasT ICPModule<Settings>::createPremise()
1625  {
1626  // collect applied contractions
1627  FormulasT contractions;
1628  mHistoryActual->appliedConstraints( contractions );
1629  // collect original box
1630  assert( mBoxStorage.size() > 0 );
1631  contractions.insert( contractions.end(), mBoxStorage.front().begin(), mBoxStorage.front().end() );
1632  mBoxStorage.pop();
1633  return contractions;
1634  }
1635 
1636  template<class Settings>
1637  FormulasT ICPModule<Settings>::createBoxFormula( bool _onlyOriginalVariables )
1638  {
1639  carl::carlVariables originalRealVariables(carl::variable_type_filter::real());
1640  rReceivedFormula().gatherVariables(originalRealVariables);
1641  // TODO: store original variables as member, updating them efficiently with assert and remove
1642  FormulasT subformulas;
1643  for( auto intervalIt = mIntervals.begin(); intervalIt != mIntervals.end(); ++intervalIt )
1644  {
1645  if( !_onlyOriginalVariables || originalRealVariables.has( (*intervalIt).first ) )
1646  {
1647  std::pair<ConstraintT, ConstraintT> boundaries = icp::intervalToConstraint(Poly((*intervalIt).first), (*intervalIt).second);
1648  if( boundaries.first != ConstraintT() )
1649  subformulas.emplace_back( boundaries.first );
1650  if( boundaries.second != ConstraintT() )
1651  subformulas.emplace_back( boundaries.second );
1652  }
1653  }
1654  return subformulas;
1655  }
1656 
1657  template<class Settings>
1658  bool ICPModule<Settings>::performSplit( bool _contractionApplied, bool& _furtherContractionApplied )
1659  {
1660  assert( !intervalsEmpty() );
1661  Rational bound;
1662  bool leftCaseWeak = true;
1663  bool preferLeftCase = true;
1664  carl::Variable variable;
1665  switch( mSplittingHeuristic )
1666  {
1667  case SplittingHeuristic::SIZE:
1668  sizeBasedSplitting( variable, bound, leftCaseWeak, preferLeftCase );
1669  break;
1670  case SplittingHeuristic::UNSATISFIABILITY:
1671  _furtherContractionApplied = satBasedSplitting( variable, bound, leftCaseWeak, preferLeftCase );
1672  break;
1673  case SplittingHeuristic::SATISFIABILITY:
1674  _furtherContractionApplied = satBasedSplitting( variable, bound, leftCaseWeak, preferLeftCase );
1675  break;
1676  default:
1677  assert(false);
1678  }
1679  SMTRAT_LOG_DEBUG("smtrat.icp", "Contraction applied? " << _furtherContractionApplied);
1680  if( !_furtherContractionApplied && variable != carl::Variable::NO_VARIABLE )
1681  {
1682  SMTRAT_LOG_DEBUG("smtrat.icp", "Creating split");
1683  // create split: (not h_b OR (Not x<b AND x>=b) OR (x<b AND Not x>=b) )
1684  // first the premise: ((oldBox AND CCs) -> newBox) in CNF: (oldBox OR CCs) OR newBox
1685  std::vector<FormulaT> splitPremise = createPremise();
1686  if( _contractionApplied )
1687  {
1688  FormulasT subformulas;
1689  subformulas.reserve(splitPremise.size()+1);
1690  for( auto formulaIt = splitPremise.begin(); formulaIt != splitPremise.end(); ++formulaIt )
1691  subformulas.emplace_back( carl::FormulaType::NOT, *formulaIt );
1692  // construct new box
1693  subformulas.emplace_back( carl::FormulaType::AND, std::move( createBoxFormula( true ) ) ); // TODO: only add this lemma if any contraction took place!!!
1694  // push lemma
1695  addLemma( FormulaT( carl::FormulaType::OR, std::move(subformulas) ) );
1696  #ifdef ICP_MODULE_SHOW_PROGRESS
1697  addProgress( mInitialBoxSize - calculateCurrentBoxSize() );
1698  #endif
1699  }
1700  assert( variable != carl::Variable::NO_VARIABLE);
1701  Module::branchAt( variable, bound, std::move(splitPremise), leftCaseWeak, preferLeftCase );
1702  #ifdef ICP_MODULE_DEBUG_0
1703  std::cout << std::endl << "Force split on " << variable << " at " << bound << "!" << std::endl;
1704  printIntervals(true);
1705  #endif
1706  return true;
1707  }
1708  return false;
1709  }
1710 
1711  template<class Settings>
1712  bool ICPModule<Settings>::splitToBoundedIntervalsWithoutZero( carl::Variable& _variable, Rational& _value, bool& _leftCaseWeak, bool& _preferLeftCase, std::vector<std::map<carl::Variable, icp::IcpVariable*>::const_iterator>& _suitableVariables )
1713  {
1714  double valueAsDouble = 0;
1715  for( auto varIcpvarIter = mVariables.begin(); varIcpvarIter != mVariables.end(); ++varIcpvarIter )
1716  {
1717  const auto& varInterval = varIcpvarIter->second->interval();
1718  if( varIcpvarIter->second->isOriginal() && varIcpvarIter->second->isActive() && !varInterval.is_point_interval() )
1719  {
1720  if( varInterval.upper_bound_type() == carl::BoundType::INFTY )
1721  {
1722  if( varInterval.lower_bound_type() != carl::BoundType::INFTY )
1723  {
1724  // a is finite => if b = mDefaultSplittingSize is not in the interval give up otherwise split to <a,b] and (b,oo)
1725  assert( mDefaultSplittingSize > 0 );
1726  if( varInterval.lower() < mDefaultSplittingSize )
1727  {
1728  _variable = varIcpvarIter->first;
1729  valueAsDouble = mDefaultSplittingSize;
1730  _leftCaseWeak = true;
1731  _preferLeftCase = true;
1732  _suitableVariables.push_back(varIcpvarIter);
1733  }
1734  }
1735  else // otherwise the interval is (-oo,oo) so keep 0
1736  {
1737  _variable = varIcpvarIter->first;
1738  valueAsDouble = mDefaultSplittingSize;
1739  _leftCaseWeak = true;
1740  _preferLeftCase = true;
1741  _suitableVariables.push_back(varIcpvarIter);
1742  }
1743 
1744  }
1745  else if( varInterval.lower_bound_type() == carl::BoundType::INFTY ) // Variable interval is (-oo,a> and a finite
1746  {
1747  // if b = -mDefaultSplittingSize is not in the interval give up otherwise split to (-oo,b) and [b,a>
1748  if( varInterval.upper() > -mDefaultSplittingSize )
1749  {
1750  _variable = varIcpvarIter->first;
1751  valueAsDouble = -mDefaultSplittingSize;
1752  _preferLeftCase = false;
1753  _leftCaseWeak = false;
1754  _suitableVariables.push_back(varIcpvarIter);
1755  }
1756  }
1757  else if( varInterval.lower_bound_type() == carl::BoundType::WEAK && varInterval.lower() == 0 )
1758  {
1759  // Variable interval is [0,a> => split it to [0,0] and (0,a>
1760  _variable = varIcpvarIter->first;
1761  valueAsDouble = varInterval.lower();
1762  _preferLeftCase = true;
1763  _leftCaseWeak = true;
1764  _suitableVariables.push_back(varIcpvarIter);
1765  }
1766  else if( varInterval.upper_bound_type() == carl::BoundType::WEAK && varInterval.upper() == 0 )
1767  {
1768  // Variable interval is <a,0] => split it to <a,0) and [0,0]
1769  _variable = varIcpvarIter->first;
1770  valueAsDouble = varInterval.upper();
1771  _preferLeftCase = false;
1772  _leftCaseWeak = false;
1773  _suitableVariables.push_back(varIcpvarIter);
1774  }
1775  else
1776  {
1777  _suitableVariables.push_back(varIcpvarIter);
1778  }
1779  if( _variable != carl::Variable::NO_VARIABLE )
1780  {
1781  if( mSplittingHeuristic == SplittingHeuristic::SATISFIABILITY || mSplittingHeuristic == SplittingHeuristic::UNSATISFIABILITY )
1782  {
1783  FormulaT violatedConstraint;
1784  EvalDoubleIntervalMap intervals = mIntervals;
1785  DoubleInterval leftSide( varInterval.lower(), varInterval.lower_bound_type(), valueAsDouble, (_leftCaseWeak ? carl::BoundType::WEAK : carl::BoundType::STRICT) );
1786  DoubleInterval rightSide( valueAsDouble, (_leftCaseWeak ? carl::BoundType::STRICT : carl::BoundType::WEAK), varInterval.upper(), varInterval.upper_bound_type() );
1787  intervals[_variable] = leftSide;
1788  if( satBasedSplittingImpact( *varIcpvarIter->second, intervals, rightSide, false ) < 0 )
1789  {
1790  return true;
1791  }
1792  intervals[_variable] = rightSide;
1793  if( satBasedSplittingImpact( *varIcpvarIter->second, intervals, leftSide, false ) < 0 )
1794  {
1795  return true;
1796  }
1797  }
1798  _value = carl::rationalize<Rational>( valueAsDouble );
1799  return false;
1800  }
1801  }
1802  }
1803  return false;
1804  }
1805 
1806  template<class Settings>
1807  void ICPModule<Settings>::sizeBasedSplitting( carl::Variable& _variable, Rational& _value, bool& _leftCaseWeak, bool& _preferLeftCase )
1808  {
1809  _value = 0;
1810  _leftCaseWeak = true;
1811  _preferLeftCase = true;
1812  std::vector<std::map<carl::Variable, icp::IcpVariable*>::const_iterator> suitableVariables;
1813  splitToBoundedIntervalsWithoutZero( _variable, _value, _leftCaseWeak, _preferLeftCase, suitableVariables );
1814  if( suitableVariables.empty() || _variable != carl::Variable::NO_VARIABLE )
1815  return;
1816  assert( _variable == carl::Variable::NO_VARIABLE );
1817  double maximalImpact = 0;
1818  double valueAsDouble = 0;
1819  std::map<carl::Variable, icp::IcpVariable*>::const_iterator bestVar = mVariables.end();
1820  for( const auto& varIcpvarIter : suitableVariables )
1821  {
1822  if( varIcpvarIter->second->isOriginal() && varIcpvarIter->second->isActive() && !varIcpvarIter->second->interval().is_point_interval() )
1823  {
1824  if( !fulfillsTarget(varIcpvarIter->second->interval()) )
1825  {
1826  double actualImpact = sizeBasedSplittingImpact( varIcpvarIter );
1827  if( actualImpact > maximalImpact )
1828  {
1829  valueAsDouble = carl::sample(varIcpvarIter->second->interval(), false );
1830  if( valueAsDouble == std::numeric_limits<double>::infinity() || valueAsDouble == -std::numeric_limits<double>::infinity() )
1831  {
1832  continue;
1833  }
1834  bestVar = varIcpvarIter;
1835  maximalImpact = actualImpact;
1836  }
1837  }
1838  }
1839  }
1840  if( bestVar != mVariables.end() )
1841  {
1842  // split at a nice number c in the interval: <a,c] and (c,b>
1843  _variable = bestVar->first;
1844  assert( !Settings::first_split_to_bounded_intervals_without_zero || !bestVar->second->interval().is_unbounded() );
1845  _value = carl::rationalize<Rational>( valueAsDouble );
1846  }
1847  return;
1848  }
1849 
1850  template<class Settings>
1851  bool ICPModule<Settings>::satBasedSplitting( carl::Variable& _variable, Rational& _value, bool& _leftCaseWeak, bool& _preferLeftCase )
1852  {
1853  _value = 0;
1854  _leftCaseWeak = true;
1855  _preferLeftCase = true;
1856  std::vector<std::map<carl::Variable, icp::IcpVariable*>::const_iterator> suitableVariables;
1857  if( splitToBoundedIntervalsWithoutZero( _variable, _value, _leftCaseWeak, _preferLeftCase, suitableVariables ) )
1858  return true;
1859  if( suitableVariables.empty() || _variable != carl::Variable::NO_VARIABLE )
1860  return false;
1861  assert( _variable == carl::Variable::NO_VARIABLE );
1862  _leftCaseWeak = true;
1863  double valueAsDouble = 0;
1864  double maximalImpact = -1;
1865  for( const auto& varIcpvarIter : suitableVariables )
1866  {
1867  const auto& varInterval = varIcpvarIter->second->interval();
1868  if( !varIcpvarIter->second->isOriginal() || !varIcpvarIter->second->isActive()
1869  || varIcpvarIter->second->interval().is_point_interval() || fulfillsTarget(varInterval) )
1870  {
1871  continue;
1872  }
1873  assert( !Settings::first_split_to_bounded_intervals_without_zero || !varInterval.is_unbounded() );
1874  valueAsDouble = carl::sample( varInterval, false );
1875  if( valueAsDouble == std::numeric_limits<double>::infinity() || valueAsDouble == -std::numeric_limits<double>::infinity() )
1876  {
1877  continue;
1878  }
1879  bool leftCaseWeak = true;
1880  if( valueAsDouble == varInterval.upper() )
1881  leftCaseWeak = false;
1882  EvalDoubleIntervalMap intervals = mIntervals;
1883  DoubleInterval leftSide( varInterval.lower(), varInterval.lower_bound_type(), valueAsDouble, leftCaseWeak ? carl::BoundType::WEAK : carl::BoundType::STRICT );
1884  DoubleInterval rightSide( valueAsDouble, leftCaseWeak ? carl::BoundType::STRICT : carl::BoundType::WEAK, varInterval.upper(), varInterval.upper_bound_type() );
1885  intervals[varIcpvarIter->first] = leftSide;
1886  FormulaT violatedConstraint;
1887  double impactLeftCase = satBasedSplittingImpact( *varIcpvarIter->second, intervals, rightSide, true );
1888  if( impactLeftCase < 0 )
1889  {
1890  return true;
1891  }
1892  intervals[varIcpvarIter->first] = rightSide;
1893  double impactRightCase = satBasedSplittingImpact( *varIcpvarIter->second, intervals, leftSide, true );
1894  if( impactRightCase < 0 )
1895  {
1896  return true;
1897  }
1898  if( impactLeftCase > impactRightCase )
1899  {
1900  if( impactLeftCase > maximalImpact )
1901  {
1902  maximalImpact = impactLeftCase;
1903  _variable = varIcpvarIter->first;
1904  _preferLeftCase = true;
1905  _value = carl::rationalize<Rational>( valueAsDouble );
1906  }
1907  }
1908  else
1909  {
1910  if( impactRightCase > maximalImpact )
1911  {
1912  maximalImpact = impactRightCase;
1913  _variable = varIcpvarIter->first;
1914  _preferLeftCase = false;
1915  _value = carl::rationalize<Rational>( valueAsDouble );
1916  }
1917  }
1918  }
1919  return false;
1920  }
1921 
1922 // #define ICP_SAT_BASED_SPLITTING_DEBUG
1923 
1924  template<class Settings>
1925  double ICPModule<Settings>::satBasedSplittingImpact( icp::IcpVariable& _icpVar, const EvalDoubleIntervalMap& _intervals, const DoubleInterval& _seperatedPart, bool _calculateImpact )
1926  {
1927  assert( !intervalsEmpty( _intervals ) );
1928  assert( mSplittingHeuristic == SplittingHeuristic::SATISFIABILITY || mSplittingHeuristic == SplittingHeuristic::UNSATISFIABILITY );
1929  double result = 0;
1930  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
1931  std::cout << _intervals << std::endl;
1932  #endif
1933  for( const auto& rec : rReceivedFormula() )
1934  {
1935  assert( rec.formula().type() == carl::FormulaType::CONSTRAINT );
1936  const ConstraintT& constraint = rec.formula().constraint();
1937  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
1938  std::cout << constraint << std::endl;
1939  #endif
1940  DoubleInterval solutionSpace = carl::evaluate( constraint.lhs(), _intervals );
1941  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
1942  std::cout << solutionSpace << std::endl;
1943  #endif
1944  switch( constraint.relation() )
1945  {
1946  case carl::Relation::EQ:
1947  if( solutionSpace.contains( 0 ) )
1948  {
1949  if( mSplittingHeuristic == SplittingHeuristic::UNSATISFIABILITY )
1950  {
1951  if( solutionSpace.is_unbounded() )
1952  {
1953  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
1954  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
1955  #endif
1956  return std::numeric_limits<double>::infinity();
1957  }
1958  if( !_calculateImpact )
1959  break;
1960  assert( (solutionSpace.diameter()/ (double) rReceivedFormula().size()) >= (double) 0 );
1961  result += (solutionSpace.diameter()/ (double) rReceivedFormula().size());
1962  }
1963  }
1964  else
1965  {
1966  splittingBasedContraction( _icpVar, rec.formula(), _seperatedPart );
1967  return -1;
1968  }
1969  break;
1970  case carl::Relation::LEQ:
1971  if( solutionSpace > (double)0 )
1972  {
1973  splittingBasedContraction( _icpVar, rec.formula(), _seperatedPart );
1974  return -1;
1975  }
1976  else
1977  {
1978  if( mSplittingHeuristic == SplittingHeuristic::SATISFIABILITY )
1979  {
1980  if( solutionSpace.lower_bound_type() == carl::BoundType::INFTY )
1981  {
1982  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
1983  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
1984  #endif
1985  return std::numeric_limits<double>::infinity();
1986  }
1987  if( !_calculateImpact )
1988  break;
1989  if( solutionSpace.upper_bound_type() != carl::BoundType::INFTY && solutionSpace.upper() < (double) 0 )
1990  {
1991  assert( (solutionSpace.diameter()/ (double) rReceivedFormula().size()) >= (double) 0 );
1992  result += (solutionSpace.diameter()/ (double) rReceivedFormula().size());
1993  }
1994  else
1995  {
1996  assert( (-solutionSpace.lower()/ (double) rReceivedFormula().size()) >= (double) 0 );
1997  result += (-solutionSpace.lower()/ (double) rReceivedFormula().size());
1998  }
1999  }
2000  else
2001  {
2002  if( solutionSpace.upper_bound_type() == carl::BoundType::INFTY )
2003  {
2004  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2005  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
2006  #endif
2007  return std::numeric_limits<double>::infinity();
2008  }
2009  if( !_calculateImpact )
2010  break;
2011  if( solutionSpace.upper() > (double) 0 )
2012  {
2013  assert( solutionSpace.lower_bound_type() == carl::BoundType::INFTY || solutionSpace.lower() <= (double) 0 );
2014  assert( (solutionSpace.upper()/ (double) rReceivedFormula().size()) >= (double) 0 );
2015  result += (solutionSpace.upper()/ (double) rReceivedFormula().size());
2016  }
2017  }
2018  }
2019  break;
2020  case carl::Relation::GEQ:
2021  if( solutionSpace < (double)0 )
2022  {
2023  splittingBasedContraction( _icpVar, rec.formula(), _seperatedPart );
2024  return -1;
2025  }
2026  else
2027  {
2028  if( mSplittingHeuristic == SplittingHeuristic::SATISFIABILITY )
2029  {
2030  if( solutionSpace.upper_bound_type() == carl::BoundType::INFTY )
2031  {
2032  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2033  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
2034  #endif
2035  return std::numeric_limits<double>::infinity();
2036  }
2037  if( !_calculateImpact )
2038  break;
2039  if( solutionSpace.lower_bound_type() != carl::BoundType::INFTY && solutionSpace.lower() > (double) 0 )
2040  {
2041  assert( (solutionSpace.diameter()/ (double) rReceivedFormula().size()) >= (double) 0 );
2042  result += (solutionSpace.diameter()/ (double) rReceivedFormula().size());
2043  }
2044  else
2045  {
2046  assert( (solutionSpace.upper()/ (double) rReceivedFormula().size()) >= (double) 0 );
2047  result += (solutionSpace.upper()/ (double) rReceivedFormula().size());
2048  }
2049  }
2050  else
2051  {
2052  if( solutionSpace.lower_bound_type() == carl::BoundType::INFTY )
2053  {
2054  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2055  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
2056  #endif
2057  return std::numeric_limits<double>::infinity();
2058  }
2059  if( !_calculateImpact )
2060  break;
2061  if( solutionSpace.lower() < (double) 0 )
2062  {
2063  assert( solutionSpace.upper_bound_type() == carl::BoundType::INFTY || solutionSpace.upper() <= (double) 0 );
2064  assert( (-solutionSpace.lower()/ (double) rReceivedFormula().size()) >= (double) 0 );
2065  result += (-solutionSpace.lower()/ (double) rReceivedFormula().size());
2066  }
2067  }
2068  }
2069  break;
2070  case carl::Relation::LESS:
2071  if( solutionSpace >= (double)0 )
2072  {
2073  splittingBasedContraction( _icpVar, rec.formula(), _seperatedPart );
2074  return -1;
2075  }
2076  else
2077  {
2078  if( mSplittingHeuristic == SplittingHeuristic::SATISFIABILITY )
2079  {
2080  if( solutionSpace.lower_bound_type() == carl::BoundType::INFTY )
2081  {
2082  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2083  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
2084  #endif
2085  return std::numeric_limits<double>::infinity();
2086  }
2087  if( !_calculateImpact )
2088  break;
2089  if( solutionSpace.upper_bound_type() != carl::BoundType::INFTY && solutionSpace.upper() < (double) 0 )
2090  {
2091  assert( (solutionSpace.diameter()/ (double) rReceivedFormula().size()) >= (double) 0 );
2092  result += (solutionSpace.diameter()/ (double) rReceivedFormula().size());
2093  }
2094  else
2095  {
2096  assert( (-solutionSpace.lower()/ (double) rReceivedFormula().size()) >= (double) 0 );
2097  result += (-solutionSpace.lower()/ (double) rReceivedFormula().size());
2098  }
2099  }
2100  else
2101  {
2102  if( solutionSpace.upper_bound_type() == carl::BoundType::INFTY )
2103  {
2104  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2105  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
2106  #endif
2107  return std::numeric_limits<double>::infinity();
2108  }
2109  if( !_calculateImpact )
2110  break;
2111  if( solutionSpace.upper() > (double) 0 )
2112  {
2113  assert( solutionSpace.lower_bound_type() == carl::BoundType::INFTY || solutionSpace.lower() < (double) 0 );
2114  assert( (solutionSpace.upper()/ (double) rReceivedFormula().size()) >= (double) 0 );
2115  result += (solutionSpace.upper()/ (double) rReceivedFormula().size());
2116  }
2117  }
2118  }
2119  break;
2120  case carl::Relation::GREATER:
2121  if( solutionSpace <= (double)0 )
2122  {
2123  splittingBasedContraction( _icpVar, rec.formula(), _seperatedPart );
2124  return -1;
2125  }
2126  else
2127  {
2128  if( mSplittingHeuristic == SplittingHeuristic::SATISFIABILITY )
2129  {
2130  if( solutionSpace.upper_bound_type() == carl::BoundType::INFTY )
2131  {
2132  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2133  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
2134  #endif
2135  return std::numeric_limits<double>::infinity();
2136  }
2137  if( !_calculateImpact )
2138  break;
2139  if( solutionSpace.lower_bound_type() != carl::BoundType::INFTY && solutionSpace.lower() > (double) 0 )
2140  {
2141  assert( (solutionSpace.diameter()/ (double) rReceivedFormula().size()) >= (double) 0 );
2142  result += (solutionSpace.diameter()/ (double) rReceivedFormula().size());
2143  }
2144  else
2145  {
2146  assert( (solutionSpace.upper()/ (double) rReceivedFormula().size()) >= (double) 0 );
2147  result += (solutionSpace.upper()/ (double) rReceivedFormula().size());
2148  }
2149  }
2150  else
2151  {
2152  if( solutionSpace.lower_bound_type() == carl::BoundType::INFTY )
2153  {
2154  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2155  std::cout << "Result: " << std::numeric_limits<double>::infinity() << std::endl;
2156  #endif
2157  return std::numeric_limits<double>::infinity();
2158  }
2159  if( !_calculateImpact )
2160  break;
2161  if( solutionSpace.lower() < (double) 0 )
2162  {
2163  assert( solutionSpace.upper_bound_type() == carl::BoundType::INFTY || solutionSpace.upper() < (double) 0 );
2164  assert( (-solutionSpace.lower()/ (double) rReceivedFormula().size()) >= (double) 0 );
2165  result += (-solutionSpace.lower()/ (double) rReceivedFormula().size());
2166  }
2167  }
2168  }
2169  break;
2170  default: // carl::Relation::NEQ
2171  // ignore them
2172  break;
2173  }
2174  }
2175  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2176  std::cout << "Result: " << result << std::endl;
2177  #endif
2178  return result;
2179  }
2180 
2181  template<class Settings>
2182  void ICPModule<Settings>::splittingBasedContraction( icp::IcpVariable& _icpVar, const FormulaT& _violatedConstraint, const DoubleInterval& _contractedInterval )
2183  {
2184  #ifdef ICP_SAT_BASED_SPLITTING_DEBUG
2185  std::cout << "Result: -1" << std::endl;
2186  #endif
2187  assert( !carl::is_bound(_violatedConstraint.constraint()) );
2188  assert( _violatedConstraint.type() == carl::FormulaType::CONSTRAINT );
2189  bool constraintContainsSplittingVar = _violatedConstraint.constraint().variables().has( _icpVar.var() );
2190  setContraction( _violatedConstraint, _icpVar, (constraintContainsSplittingVar ? DoubleInterval::empty_interval() : _contractedInterval), constraintContainsSplittingVar );
2191  if( constraintContainsSplittingVar )
2192  mInvalidBox = true;
2193  }
2194 
2195  template<class Settings>
2196  bool ICPModule<Settings>::tryTestPoints()
2197  {
2198  // find a point within the intervals
2199  carl::carlVariables originalRealVariables(carl::variable_type_filter::real());
2200  rReceivedFormula().gatherVariables(originalRealVariables);
2201  // TODO: store original variables as member, updating them efficiently with assert and remove
2202  std::map<carl::Variable, double> antipoint = createModel( true );
2203  mFoundSolution.clear();
2204  #ifdef ICP_MODULE_DEBUG_0
2205  std::cout << __func__ << ":" << std::endl;
2206  #endif
2207  if( antipoint.empty() )
2208  {
2209  #ifdef ICP_MODULE_DEBUG_0
2210  std::cout << " Failed!" << std::endl << std::endl;
2211  #endif
2212  return false;
2213  }
2214  bool boxContainsOnlyOneSolution = true;
2215  auto origVarsIter = originalRealVariables.begin();
2216  for( auto iter = antipoint.begin(); iter != antipoint.end(); ++iter )
2217  {
2218  SMTRAT_LOG_TRACE("smtrat.module.icp", "Checking antipoint " << iter->first << " = " << iter->second);
2219  // Add an assignment for variables only occurring in constraints with != as relation symbol
2220  while( origVarsIter != originalRealVariables.end() && *origVarsIter < iter->first )
2221  {
2222  mFoundSolution.emplace(*origVarsIter, 0); // TODO: find a rational assignment which most probably satisfies this inequality
2223  ++origVarsIter;
2224  }
2225  if( origVarsIter != originalRealVariables.end() )
2226  ++origVarsIter;
2227  if (std::isinf(iter->second) || std::isnan(iter->second)) {
2228  continue;
2229  }
2230  assert(!std::isinf(iter->second) && !std::isnan(iter->second));
2231  // rationalize the found test point for the given dimension
2232  Rational value = carl::rationalize<Rational>( iter->second );
2233  // check if the test point, which has been generated for double intervals, does not satisfy the rational
2234  // original bounds in this dimension (might occur, as we over-approximated them)
2235  auto lraVarBoundsIter = mInitialIntervals.find( iter->first );
2236  if( lraVarBoundsIter != mInitialIntervals.end() )
2237  {
2238  const RationalInterval& varBounds = lraVarBoundsIter->second;
2239  assert( !varBounds.is_empty() );
2240  if( varBounds.is_point_interval() )
2241  {
2242  value = varBounds.lower();
2243  }
2244  else
2245  {
2246  assert( iter->first.type() != carl::VariableType::VT_INT || varBounds.is_unbounded() || varBounds.diameter() >= 1 );
2247  if( iter->first.type() != carl::VariableType::VT_INT )
2248  boxContainsOnlyOneSolution = false;
2249  if( varBounds.lower_bound_type() != carl::BoundType::INFTY && value < varBounds.lower() )
2250  {
2251  if( varBounds.lower_bound_type() == carl::BoundType::STRICT )
2252  {
2253  value = carl::sample( varBounds, false );
2254  }
2255  else
2256  {
2257  value = varBounds.lower();
2258  }
2259  }
2260  else if( varBounds.upper_bound_type() != carl::BoundType::INFTY && value > varBounds.upper() )
2261  {
2262  if( varBounds.upper_bound_type() == carl::BoundType::STRICT )
2263  {
2264  value = carl::sample( varBounds, false );
2265  }
2266  else
2267  {
2268  value = varBounds.upper();
2269  }
2270  }
2271  }
2272  assert( varBounds.contains( value ) );
2273  }
2274  #ifdef ICP_MODULE_DEBUG_0
2275  std::cout << " " << iter->first << " -> " << std::setprecision(10) << iter->second << " [" << value << "]" << std::endl;
2276  #endif
2277  mFoundSolution.emplace(iter->first, value);
2278  }
2279  bool has_unknown = false;
2280  bool has_conflict = false;
2281  for (const auto& rf : rReceivedFormula()) {
2282  assert( rf.formula().type() == carl::FormulaType::CONSTRAINT );
2283  unsigned isSatisfied = carl::satisfied_by(rf.formula().constraint(), mFoundSolution);
2284  if (isSatisfied == 2) has_unknown = true;
2285  else if (isSatisfied == 0) {
2286  has_conflict = true;
2287  if (boxContainsOnlyOneSolution) {
2288  // TODO: create infeasible subset and return UNSAT in checkCore
2289  }
2290  break;
2291  }
2292  }
2293  if(has_conflict)
2294  mFoundSolution.clear();
2295  #ifdef ICP_MODULE_DEBUG_0
2296  if( !has_conflict ) std::cout << " Success!" << std::endl << std::endl;
2297  #endif
2298  return !has_unknown && !has_conflict;
2299  }
2300 
2301  template<class Settings>
2302  bool ICPModule<Settings>::initialLinearCheck( Answer& _answer )
2303  {
2304  #ifdef ICP_MODULE_DEBUG_1
2305  std::cout << "Initial linear check:" << std::endl;
2306  #endif
2307  // call mLRA to check linear feasibility
2308  mLRA.clearLemmas();
2309  mValidationFormula->updateProperties();
2310  _answer = mLRA.check( mFinalCheck, true );
2311 
2312  // catch lemmas
2313  if( mFinalCheck )
2314  {
2315  for( const auto& lem : mLRA.lemmas() )
2316  {
2317  #ifdef ICP_MODULE_DEBUG_2
2318  std::cout << "Create lemma for: " << lem.mLemma << std::endl;
2319  #endif
2320  FormulaT lemma = getReceivedFormulas(lem.mLemma);
2321  addLemma(lemma, lem.mLemmaType);
2322  #ifdef ICP_MODULE_DEBUG_2
2323  std::cout << "Passed lemma: " << lemma << std::endl;
2324  #endif
2325  }
2326  }
2327  mLRA.clearLemmas();
2328  if( _answer == UNSAT )
2329  {
2330  // remap infeasible subsets to original constraints
2331  remapAndSetLraInfeasibleSubsets();
2332  #ifdef ICP_MODULE_DEBUG_1
2333  std::cout << "LRA: " << _answer << std::endl;
2334  #endif
2335  return true;
2336  }
2337  else if( !Settings::just_contraction && _answer == SAT ) // _answer == SAT, but no nonlinear constraints -> linear solution is a solution
2338  {
2339  #ifdef ICP_MODULE_DEBUG_1
2340  std::cout << "LRA: " << _answer << std::endl;
2341  #endif
2342  bool solutionFound = true;
2343  RationalAssignment sol = mLRA.getRationalModel();
2344  for( const auto& rf : rReceivedFormula() )
2345  {
2346  assert( rf.formula().type() == carl::FormulaType::CONSTRAINT );
2347  const ConstraintT& cons = rf.formula().constraint();
2348  assert( !cons.lhs().is_linear() || cons.relation() == carl::Relation::NEQ || carl::satisfied_by( cons,sol ) == 1 );
2349  if( (!cons.lhs().is_linear() || cons.relation() == carl::Relation::NEQ) && carl::satisfied_by( cons,sol ) != 1 )
2350  {
2351  solutionFound = false;
2352  break;
2353  }
2354  }
2355  if( solutionFound )
2356  return true;
2357  }
2358  if( !Settings::just_contraction && !lemmas().empty() && _answer == UNKNOWN )
2359  return true;
2360  // get intervals for initial variables
2361  mInitialIntervals = mLRA.getVariableBounds();
2362  #ifdef ICP_MODULE_DEBUG_1
2363  std::cout << "Newly obtained Intervals: " << std::endl;
2364  #endif
2365  for ( auto constraintIt = mInitialIntervals.begin(); constraintIt != mInitialIntervals.end(); ++constraintIt )
2366  {
2367  #ifdef ICP_MODULE_DEBUG_1
2368  std::cout << (*constraintIt).first << ": " << (*constraintIt).second << std::endl;
2369  #endif
2370  const RationalInterval& tmp = (*constraintIt).second;
2371  DoubleInterval newInterval = DoubleInterval(tmp.lower(), tmp.lower_bound_type(), tmp.upper(), tmp.upper_bound_type());
2372  mHistoryRoot->addInterval((*constraintIt).first, newInterval );
2373  if( Settings::original_polynomial_contraction && mVariables.find(constraintIt->first) == mVariables.end() )
2374  {
2375  mIntervals[(*constraintIt).first] = newInterval;
2376  }
2377  else
2378  {
2379  assert( mVariables.find(constraintIt->first) != mVariables.end() );
2380  mVariables.find((*constraintIt).first)->second->setInterval( newInterval );
2381  }
2382  }
2383  // get intervals for slackvariables
2384  const LRAModule<LRASettings1>::ExVariableMap slackVariables = mLRA.slackVariables();
2385  for( auto slackIt = slackVariables.begin(); slackIt != slackVariables.end(); ++slackIt )
2386  {
2387  std::map<const icp::LRAVariable*, ContractionCandidates>::iterator linIt = mLinearConstraints.find((*slackIt).second);
2388  if ( linIt != mLinearConstraints.end() )
2389  {
2390  // dirty hack: expect lhs to be set and take first item of set of CCs --> Todo: Check if it is really set in the constructors of the CCs during inform and assert
2391  RationalInterval tmp = (*slackIt).second->getVariableBounds();
2392  // keep root updated about the initial box.
2393  mHistoryRoot->rIntervals()[(*(*linIt).second.begin())->lhs()] = DoubleInterval(tmp.lower(), tmp.lower_bound_type(), tmp.upper(), tmp.upper_bound_type());
2394  // No need to propagate update-status in the icp-variable
2395  assert( mIntervals.find( (*(*linIt).second.begin())->lhs() ) != mIntervals.end() );
2396  mIntervals[(*(*linIt).second.begin())->lhs()] = DoubleInterval(tmp.lower(), tmp.lower_bound_type(), tmp.upper(), tmp.upper_bound_type());
2397  #ifdef ICP_MODULE_DEBUG_2
2398  std::cout << "Added interval (slackvariables): " << (*(*linIt).second.begin())->lhs() << " " << tmp << std::endl;
2399  #endif
2400  }
2401  }
2402  // temporary solution - an added linear constraint might have changed the box.
2403  setBox(mHistoryRoot);
2404  mHistoryRoot->rReasons().clear();
2405  mHistoryRoot->rStateInfeasibleConstraints().clear();
2406  mHistoryRoot->rStateInfeasibleVariables().clear();
2407  #ifdef ICP_MODULE_DEBUG_1
2408  std::cout << "actual box: ";
2409  mHistoryActual->print(std::cout);
2410  std::cout << std::endl;
2411  #endif
2412  return false;
2413  }
2414 
2415  template<class Settings>
2416  bool ICPModule<Settings>::checkBoxAgainstLinearFeasibleRegion()
2417  {
2418  FormulasT addedBoundaries = createConstraintsFromBounds(mIntervals,false);
2419  for( auto formulaIt = addedBoundaries.begin(); formulaIt != addedBoundaries.end(); )
2420  {
2421  auto res = mValidationFormula->add( *formulaIt );
2422  if( res.second )
2423  {
2424  mLRA.inform( *formulaIt );
2425  mLRA.add( res.first );
2426  ++formulaIt;
2427  }
2428  else
2429  {
2430  formulaIt = addedBoundaries.erase(formulaIt);
2431  }
2432  }
2433  mValidationFormula->updateProperties();
2434  Answer boxCheck = mLRA.check( false, true );
2435  #ifdef ICP_MODULE_DEBUG_1
2436  mLRA.print();
2437  std::cout << "Boxcheck: " << boxCheck << std::endl;
2438  #endif
2439  #ifdef SMTRAT_DEVOPTION_VALIDATION_ICP
2440  if ( boxCheck == UNSAT )
2441  {
2442  FormulaT actualAssumptions = FormulaT(*mValidationFormula);
2443  SMTRAT_VALIDATION_ADD("smtrat.modules.icp","ICP_BoxValidation",actualAssumptions,false);
2444  }
2445  #endif
2446  if( boxCheck != UNKNOWN )
2447  {
2448  if( boxCheck != SAT )
2449  {
2450  std::vector<FormulaSetT> tmpSet = mLRA.infeasibleSubsets();
2451  for ( auto infSetIt = tmpSet.begin(); infSetIt != tmpSet.end(); ++infSetIt )
2452  {
2453  for ( auto formulaIt = (*infSetIt).begin(); formulaIt != (*infSetIt).end(); ++formulaIt )
2454  {
2455  if( !carl::is_bound(formulaIt->constraint()) )
2456  {
2457  mHistoryActual->addInfeasibleConstraint(formulaIt->constraint());
2458  for( auto variable: formulaIt->variables() )
2459  {
2460  assert( mVariables.find(variable) != mVariables.end() );
2461  mHistoryActual->addInfeasibleVariable(mVariables.at(variable));
2462  }
2463  }
2464  else
2465  {
2466  assert( mVariables.find( *formulaIt->variables().begin() ) != mVariables.end() );
2467  mHistoryActual->addInfeasibleVariable( mVariables.at( *formulaIt->variables().begin() ) );
2468  }
2469  }
2470  }
2471  }
2472  else if( Settings::prolong_contraction )
2473  {
2474  EvalRationalIntervalMap bounds = mLRA.getVariableBounds();
2475  #ifdef ICP_MODULE_DEBUG_1
2476  std::cout << "Newly obtained Intervals: " << std::endl;
2477  #endif
2478  for ( auto boundIt = bounds.begin(); boundIt != bounds.end(); ++boundIt )
2479  {
2480  if( Settings::original_polynomial_contraction && mVariables.find((*boundIt).first) == mVariables.end() )
2481  continue;
2482  assert( mVariables.find((*boundIt).first) != mVariables.end() );
2483  icp::IcpVariable& icpVar = *mVariables.find((*boundIt).first)->second;
2484  RationalInterval tmp = (*boundIt).second;
2485  const DoubleInterval& icpVarInterval = icpVar.interval();
2486  // mHistoryRoot->addInterval((*boundIt).first, DoubleInterval(tmp.lower(), tmp.lower_bound_type(), tmp.upper(), tmp.upper_bound_type()) );
2487  DoubleInterval newInterval = DoubleInterval(tmp.lower(), tmp.lower_bound_type(), tmp.upper(), tmp.upper_bound_type() );
2488  if( !(icpVarInterval == newInterval) && icpVarInterval.contains(newInterval) )
2489  {
2490  #ifdef ICP_MODULE_DEBUG_1
2491  std::cout << (*boundIt).first << ": " << (*boundIt).second << std::endl;
2492  #endif
2493  updateRelativeContraction( icpVarInterval, newInterval );
2494  icpVar.setInterval( newInterval );
2495  updateRelevantCandidates((*boundIt).first);
2496  }
2497  }
2498 
2499  // get intervals for slackvariables
2500  const LRAModule<LRASettings1>::ExVariableMap slackVariables = mLRA.slackVariables();
2501  for ( auto slackIt = slackVariables.begin(); slackIt != slackVariables.end(); ++slackIt )
2502  {
2503  std::map<const icp::LRAVariable*, ContractionCandidates>::iterator linIt = mLinearConstraints.find((*slackIt).second);
2504  if ( linIt != mLinearConstraints.end() )
2505  {
2506  // dirty hack: expect lhs to be set and take first item of set of CCs --> Todo: Check if it is really set in the constructors of the CCs during inform and assert
2507  RationalInterval tmp = (*slackIt).second->getVariableBounds();
2508  // keep root updated about the initial box.
2509  // mHistoryRoot->rIntervals()[(*(*linIt).second.begin())->lhs()] = DoubleInterval(tmp.lower(), tmp.lower_bound_type(), tmp.upper(), tmp.upper_bound_type());
2510  DoubleInterval newInterval = DoubleInterval(tmp.lower(), tmp.lower_bound_type(), tmp.upper(), tmp.upper_bound_type() );
2511  carl::Variable var = (*(*linIt).second.begin())->lhs();
2512  icp::IcpVariable& icpVar = *mVariables.at(var);
2513  const DoubleInterval& icpVarInterval = icpVar.interval();
2514  if( !(icpVarInterval == newInterval) && icpVarInterval.contains(newInterval) )
2515  {
2516  updateRelativeContraction( icpVarInterval, newInterval );
2517  icpVar.setInterval( newInterval );
2518  updateRelevantCandidates(var);
2519  #ifdef ICP_MODULE_DEBUG_2
2520  std::cout << "Added interval (slackvariables): " << var << " " << tmp << std::endl;
2521  #endif
2522  }
2523  }
2524  }
2525  }
2526  }
2527  // remove boundaries from mLRA module after boxChecking.
2528  for( auto boundIt = addedBoundaries.begin(); boundIt != addedBoundaries.end(); )
2529  {
2530  auto pos = mValidationFormula->find( *boundIt );
2531  if( pos != mValidationFormula->end() )
2532  {
2533  mLRA.remove( pos );
2534  mValidationFormula->erase( pos );
2535  }
2536  boundIt = addedBoundaries.erase(boundIt);
2537  }
2538 
2539  mLRA.clearLemmas();
2540  assert(addedBoundaries.empty());
2541 
2542  if ( boxCheck == UNSAT )
2543  return false;
2544  return true;
2545  }
2546 
2547  template<class Settings>
2548  void ICPModule<Settings>::pushBoundsToPassedFormula()
2549  {
2550  carl::carlVariables originalRealVariables(carl::variable_type_filter::real());
2551  rReceivedFormula().gatherVariables(originalRealVariables);
2552  // TODO: store original variables as member, updating them efficiently with assert and remove
2553  auto varIntervalIter = mIntervals.begin();
2554  auto varInitialIntervalIter = mInitialIntervals.begin();
2555  for( std::map<carl::Variable, icp::IcpVariable*>::iterator iter = mVariables.begin(); iter != mVariables.end(); ++iter )
2556  {
2557  carl::Variable::Arg tmpSymbol = iter->first;
2558  icp::IcpVariable& icpVar = *iter->second;
2559  if( icpVar.isOriginal() && originalRealVariables.has( tmpSymbol ) )
2560  {
2561  if( icpVar.isExternalUpdated() != icp::Updated::NONE )
2562  {
2563  while( varIntervalIter->first < tmpSymbol )
2564  {
2565  assert( varIntervalIter != mIntervals.end() );
2566  ++varIntervalIter;
2567  }
2568  while( varInitialIntervalIter != mInitialIntervals.end() && varInitialIntervalIter->first < tmpSymbol )
2569  {
2570  ++varInitialIntervalIter;
2571  }
2572  const DoubleInterval& interval = varIntervalIter->second;
2573 
2574  icp::Updated icpVarExUpdated = icpVar.isExternalUpdated();
2575  // generate both bounds, left first
2576  if( icpVarExUpdated == icp::Updated::BOTH || icpVarExUpdated == icp::Updated::LEFT )
2577  {
2578  FormulaT leftTmp = intervalBoundToFormula( tmpSymbol, interval, varInitialIntervalIter, false );
2579  if( icpVar.externalLeftBound() != passedFormulaEnd() )
2580  {
2581  Module::eraseSubformulaFromPassedFormula( icpVar.externalLeftBound(), true );
2582  }
2583  if ( leftTmp.is_true() )
2584  {
2585  icpVar.setExternalLeftBound( passedFormulaEnd() );
2586  }
2587  else
2588  {
2589  addConstraintToInform( leftTmp );
2590  auto res = addSubformulaToPassedFormula( leftTmp );
2591  if( res.second )
2592  {
2593  icpVar.setExternalLeftBound( res.first );
2594  }
2595  }
2596  }
2597 
2598  if( icpVarExUpdated == icp::Updated::BOTH || icpVarExUpdated == icp::Updated::RIGHT )
2599  {
2600  // right:
2601  FormulaT rightTmp = intervalBoundToFormula( tmpSymbol, interval, varInitialIntervalIter, true );
2602  if( icpVar.externalRightBound() != passedFormulaEnd() )
2603  {
2604  Module::eraseSubformulaFromPassedFormula( icpVar.externalRightBound(), true );
2605  }
2606  if( rightTmp.is_true() )
2607  {
2608  icpVar.setExternalRightBound( passedFormulaEnd() );
2609  }
2610  else
2611  {
2612  addConstraintToInform( rightTmp );
2613  auto res = addSubformulaToPassedFormula( rightTmp );
2614  if( res.second )
2615  {
2616  icpVar.setExternalRightBound( res.first );
2617  }
2618  }
2619  }
2620  icpVar.setExternalUnmodified();
2621  }
2622  }
2623  }
2624  }
2625 
2626  template<class Settings>
2627  EvalRationalIntervalMap ICPModule<Settings>::getCurrentBoxAsIntervals() const
2628  {
2629  EvalRationalIntervalMap result;
2630  carl::carlVariables originalRealVariables(carl::variable_type_filter::real());
2631  rReceivedFormula().gatherVariables(originalRealVariables);
2632  // TODO: store original variables as member, updating them efficiently with assert and remove
2633  auto varIntervalIter = mIntervals.begin();
2634  auto varInitialIntervalIter = mInitialIntervals.begin();
2635  for( std::map<carl::Variable, icp::IcpVariable*>::const_iterator iter = mVariables.begin(); iter != mVariables.end(); ++iter )
2636  {
2637  carl::Variable::Arg tmpSymbol = iter->first;
2638  const icp::IcpVariable& icpVar = *iter->second;
2639  if( icpVar.isOriginal() && originalRealVariables.has( tmpSymbol ) )
2640  {
2641  while( varIntervalIter->first < tmpSymbol )
2642  {
2643  assert( varIntervalIter != mIntervals.end() );
2644  ++varIntervalIter;
2645  }
2646  while( varInitialIntervalIter != mInitialIntervals.end() && varInitialIntervalIter->first < tmpSymbol )
2647  {
2648  ++varInitialIntervalIter;
2649  }
2650  const DoubleInterval& interval = varIntervalIter->second;
2651  assert( result.find( tmpSymbol ) == result.end() );
2652  result.emplace( tmpSymbol, doubleToRationalInterval( tmpSymbol, interval, varInitialIntervalIter ) );
2653  }
2654  }
2655  return result;
2656  }
2657 
2658  template<class Settings>
2659  FormulasT ICPModule<Settings>::getCurrentBoxAsFormulas() const
2660  {
2661  FormulasT result;
2662  carl::carlVariables originalRealVariables(carl::variable_type_filter::real());
2663  rReceivedFormula().gatherVariables(originalRealVariables);
2664  // TODO: store original variables as member, updating them efficiently with assert and remove
2665  auto varIntervalIter = mIntervals.begin();
2666  auto varInitialIntervalIter = mInitialIntervals.begin();
2667  for( std::map<carl::Variable, icp::IcpVariable*>::const_iterator iter = mVariables.begin(); iter != mVariables.end(); ++iter )
2668  {
2669  carl::Variable::Arg tmpSymbol = iter->first;
2670  const icp::IcpVariable& icpVar = *iter->second;
2671  if( icpVar.isOriginal() && originalRealVariables.has( tmpSymbol ) )
2672  {
2673  while( varIntervalIter->first < tmpSymbol )
2674  {
2675  assert( varIntervalIter != mIntervals.end() );
2676  ++varIntervalIter;
2677  }
2678  while( varInitialIntervalIter != mInitialIntervals.end() && varInitialIntervalIter->first < tmpSymbol )
2679  {
2680  ++varInitialIntervalIter;
2681  }
2682  const DoubleInterval& interval = varIntervalIter->second;
2683  FormulaT leftTmp = intervalBoundToFormula( tmpSymbol, interval, varInitialIntervalIter, false );
2684  if( !leftTmp.is_true() )
2685  result.push_back( leftTmp );
2686  FormulaT rightTmp = intervalBoundToFormula( tmpSymbol, interval, varInitialIntervalIter, true );
2687  if( !rightTmp.is_true() )
2688  result.push_back( rightTmp );
2689  }
2690  }
2691  return result;
2692  }
2693 
2694  template<class Settings>
2695  RationalInterval ICPModule<Settings>::doubleToRationalInterval( carl::Variable::Arg _var, const DoubleInterval& _interval, EvalRationalIntervalMap::const_iterator _initialIntervalIter ) const
2696  {
2697  Rational lbound = carl::rationalize<Rational>( _interval.lower() );
2698  Rational ubound = carl::rationalize<Rational>( _interval.upper() );
2699  carl::BoundType lboundType = _interval.lower_bound_type();
2700  carl::BoundType uboundType = _interval.upper_bound_type();
2701  if( _initialIntervalIter != mInitialIntervals.end() && _initialIntervalIter->first == _var )
2702  {
2703  const RationalInterval& varBounds = _initialIntervalIter->second;
2704  if( varBounds.upper_bound_type() != carl::BoundType::INFTY && (uboundType == carl::BoundType::INFTY || ubound > varBounds.upper()) )
2705  {
2706  ubound = varBounds.upper();
2707  uboundType = varBounds.upper_bound_type();
2708  }
2709  if( varBounds.lower_bound_type() != carl::BoundType::INFTY && (lboundType == carl::BoundType::INFTY || lbound < varBounds.lower()) )
2710  {
2711  lbound = varBounds.lower();
2712  lboundType = varBounds.lower_bound_type();
2713  }
2714  }
2715  return RationalInterval( lbound, lboundType, ubound, uboundType );
2716  }
2717 
2718  template<class Settings>
2719  FormulaT ICPModule<Settings>::intervalBoundToFormula( carl::Variable::Arg _var, const DoubleInterval& _interval, EvalRationalIntervalMap::const_iterator _initialIntervalIter, bool _upper ) const
2720  {
2721  Rational bound = carl::rationalize<Rational>( _upper ? _interval.upper() : _interval.lower() );
2722  carl::BoundType boundType = _upper ? _interval.upper_bound_type() : _interval.lower_bound_type();
2723  if( _initialIntervalIter != mInitialIntervals.end() && _initialIntervalIter->first == _var )
2724  {
2725  const RationalInterval& varBounds = _initialIntervalIter->second;
2726  if( _upper )
2727  {
2728  if( varBounds.upper_bound_type() != carl::BoundType::INFTY && (boundType == carl::BoundType::INFTY || bound > varBounds.upper()) )
2729  {
2730  bound = varBounds.upper();
2731  boundType = varBounds.upper_bound_type();
2732  }
2733  }
2734  else
2735  {
2736  if( varBounds.lower_bound_type() != carl::BoundType::INFTY && (boundType == carl::BoundType::INFTY || bound < varBounds.lower()) )
2737  {
2738  bound = varBounds.lower();
2739  boundType = varBounds.lower_bound_type();
2740  }
2741 
2742  }
2743  }
2744  Poly p = Poly( _var ) - Poly(bound);
2745  FormulaT result( carl::FormulaType::TRUE );
2746  switch( boundType )
2747  {
2748  case carl::BoundType::STRICT:
2749  result = FormulaT( p, _upper ? carl::Relation::LESS : carl::Relation::GREATER );
2750  break;
2751  case carl::BoundType::WEAK:
2752  result = FormulaT( p, _upper ? carl::Relation::LEQ : carl::Relation::GEQ );
2753  break;
2754  default:
2755  break;
2756  }
2757  return result;
2758  }
2759 
2760  template<class Settings>
2761  FormulasT ICPModule<Settings>::variableReasonHull( icp::set_icpVariable& _reasons )
2762  {
2763  FormulasT reasons;
2764  for( auto variableIt = _reasons.begin(); variableIt != _reasons.end(); ++variableIt )
2765  {
2766  if ((*variableIt)->lraVar() != nullptr)
2767  {
2768  FormulasT definingOriginsTmp = (*variableIt)->lraVar()->getDefiningOrigins();
2769  FormulasT definingOrigins;
2770  for( auto& f : definingOriginsTmp )
2771  {
2772  if( rReceivedFormula().contains( f ) )
2773  collectOrigins( f, definingOrigins );
2774  }
2775  for( auto formulaIt = definingOrigins.begin(); formulaIt != definingOrigins.end(); ++formulaIt )
2776  {
2777  // std::cout << "Defining origin: " << **formulaIt << " FOR " << *(*variableIt) << std::endl;
2778  bool hasAdditionalVariables = false;
2779  carl::carlVariables realValuedVars(carl::variable_type_filter::real());
2780  rReceivedFormula().gatherVariables(realValuedVars);
2781  // TODO: store original variables as member, updating them efficiently with assert and remove
2782  for( auto varIt = realValuedVars.begin(); varIt != realValuedVars.end(); ++varIt )
2783  {
2784  if(*varIt != (*variableIt)->var() && formulaIt->constraint().variables().has(*varIt))
2785  {
2786  hasAdditionalVariables = true;
2787  break;
2788  }
2789  }
2790  if( hasAdditionalVariables)
2791  {
2792  // std::cout << "Addidional variables." << std::endl;
2793  for( auto receivedFormulaIt = rReceivedFormula().begin(); receivedFormulaIt != rReceivedFormula().end(); ++receivedFormulaIt )
2794  {
2795  if( receivedFormulaIt->formula().constraint().variables().has((*variableIt)->var()) && carl::is_bound(receivedFormulaIt->formula().constraint()) )
2796  {
2797  reasons.push_back( receivedFormulaIt->formula() );
2798  // std::cout << "Also add: " << **receivedFormulaIt << std::endl;
2799  }
2800  }
2801  }
2802  else
2803  {
2804  // std::cout << "No additional variables." << std::endl;
2805  auto replacementIt = mDeLinearizations.find( *formulaIt );
2806  assert( replacementIt != mDeLinearizations.end() ); // TODO (from Florian): Do we need this?
2807  reasons.push_back((*replacementIt).second);
2808  } // has no additional variables
2809  } // for all definingOrigins
2810  }
2811  }
2812  return reasons;
2813  }
2814 
2815  template<class Settings>
2816  FormulasT ICPModule<Settings>::createConstraintsFromBounds( const EvalDoubleIntervalMap& _map, bool _onlyOriginals )
2817  {
2818  FormulasT addedBoundaries;
2819  for ( auto variablesIt = mVariables.begin(); variablesIt != mVariables.end(); ++variablesIt )
2820  {
2821  if( (_onlyOriginals && !variablesIt->second->isOriginal()) || !variablesIt->second->isActive() )
2822  continue;
2823  carl::Variable tmpSymbol = variablesIt->first;
2824  if ( _map.find(tmpSymbol) != _map.end() )
2825  {
2826  if( variablesIt->second->lraVar() != nullptr )
2827  {
2828  std::pair<ConstraintT, ConstraintT> boundaries = icp::intervalToConstraint(Poly(variablesIt->second->lraVar()->expression()), _map.at(tmpSymbol));
2829  if( boundaries.second != ConstraintT() )
2830  {
2831  assert( boundaries.second.is_consistent() == 2 );
2832  FormulaT rightBound = FormulaT(boundaries.second);
2833  addedBoundaries.push_back(rightBound);
2834  #ifdef ICP_MODULE_DEBUG_2
2835  std::cout << "Created upper boundary constraint: " << rightBound << std::endl;
2836  #endif
2837  }
2838  if( boundaries.first != ConstraintT() )
2839  {
2840  assert( boundaries.first.is_consistent() == 2 );
2841  FormulaT leftBound = FormulaT(boundaries.first);
2842  addedBoundaries.push_back(leftBound);
2843  #ifdef ICP_MODULE_DEBUG_2
2844  std::cout << "Created lower boundary constraint: " << leftBound << std::endl;
2845  #endif
2846  }
2847  }
2848 // if( (*variablesIt).second->isInternalBoundsSet() == icp::Updated::BOTH && (*variablesIt).second->isInternalUpdated() == icp::Updated::NONE )
2849 // {
2850 // addedBoundaries.push_back((*variablesIt).second->internalLeftBound());
2851 // addedBoundaries.push_back((*variablesIt).second->internalRightBound());
2852 // }
2853 // else if( variablesIt->second->lraVar() != nullptr )
2854 // {
2855 // std::pair<ConstraintT, ConstraintT> boundaries = icp::intervalToConstraint(Poly(variablesIt->second->lraVar()->expression()), _map.at(tmpSymbol));
2856 // icp::Updated inBoundsSet = (*variablesIt).second->isInternalBoundsSet();
2857 // icp::Updated inBoundsUpdated = (*variablesIt).second->isInternalUpdated();
2858 // if( boundaries.second != ConstraintT() &&
2859 // (inBoundsUpdated == icp::Updated::BOTH || inBoundsUpdated == icp::Updated::RIGHT || inBoundsSet == icp::Updated::NONE || inBoundsSet == icp::Updated::LEFT) )
2860 // {
2861 // assert( boundaries.second.is_consistent() == 2 );
2862 // FormulaT rightBound = FormulaT(boundaries.second);
2863 // (*variablesIt).second->setInternalRightBound(rightBound);
2864 // addedBoundaries.push_back(rightBound);
2865 // #ifdef ICP_MODULE_DEBUG_2
2866 // std::cout << "Created upper boundary constraint: " << rightBound << std::endl;
2867 // #endif
2868 // }
2869 // if( boundaries.first != ConstraintT() &&
2870 // (inBoundsUpdated == icp::Updated::BOTH || inBoundsUpdated == icp::Updated::LEFT || inBoundsSet == icp::Updated::NONE || inBoundsSet == icp::Updated::RIGHT) )
2871 // {
2872 // assert( boundaries.first.is_consistent() == 2 );
2873 // FormulaT leftBound = FormulaT(boundaries.first);
2874 // (*variablesIt).second->setInternalLeftBound(leftBound);
2875 // addedBoundaries.push_back(leftBound);
2876 // #ifdef ICP_MODULE_DEBUG_2
2877 // std::cout << "Created lower boundary constraint: " << leftBound << std::endl;
2878 // #endif
2879 // }
2880 // }
2881  }
2882  }
2883  return addedBoundaries;
2884  }
2885 
2886  template<class Settings>
2887  FormulaT ICPModule<Settings>::getReceivedFormulas( const FormulaT& _deduction )
2888  {
2889  if( _deduction.type() == carl::FormulaType::CONSTRAINT )
2890  {
2891  auto iter = mDeLinearizations.find( _deduction );
2892  if( iter == mDeLinearizations.end() )
2893  {
2894  const ConstraintT& c = _deduction.constraint();
2895  return FormulaT( carl::substitute(c.lhs(), mSubstitutions), c.relation() );
2896  }
2897  else
2898  {
2899  return iter->second;
2900  }
2901  }
2902  else if( _deduction.type() == carl::FormulaType::NOT )
2903  {
2904  return FormulaT( carl::FormulaType::NOT, getReceivedFormulas( _deduction.subformula() ) );
2905  }
2906  else if( _deduction.is_boolean_combination() )
2907  {
2908  FormulasT subformulas;
2909  for( const FormulaT& subformula : _deduction.subformulas() )
2910  {
2911  subformulas.push_back( getReceivedFormulas( subformula ) );
2912  }
2913  return FormulaT( _deduction.type(), subformulas );
2914  }
2915  else if (_deduction.type() == carl::FormulaType::BOOL) {
2916  return _deduction;
2917  }
2918  else
2919  {
2920  //should not happen
2921  assert(false);
2922  return FormulaT( carl::FormulaType::TRUE );
2923  }
2924  }
2925 
2926  template<class Settings>
2927  void ICPModule<Settings>::remapAndSetLraInfeasibleSubsets()
2928  {
2929  const std::vector<FormulaSetT>& tmpSet = mLRA.infeasibleSubsets();
2930  for ( auto infSetIt = tmpSet.begin(); infSetIt != tmpSet.end(); ++infSetIt )
2931  {
2932  FormulaSetT newSet;
2933  for( auto formulaIt = (*infSetIt).begin(); formulaIt != (*infSetIt).end(); ++formulaIt )
2934  {
2935  auto delinIt = mDeLinearizations.find(*formulaIt);
2936  assert( delinIt != mDeLinearizations.end() );
2937  if( rReceivedFormula().contains( delinIt->second ) )
2938  {
2939  newSet.insert( delinIt->second );
2940  }
2941  }
2942  assert(newSet.size() == (*infSetIt).size());
2943  mInfeasibleSubsets.push_back(std::move(newSet));
2944  }
2945  }
2946 
2947  template<class Settings>
2948  double ICPModule<Settings>::calculateCurrentBoxSize()
2949  {
2950  if( mIntervals.empty() ) return 0.0;
2951  double result = 1.0;
2952  for( const auto& interv : mIntervals )
2953  {
2954  auto varIt = mVariables.find(interv.first);
2955  if( varIt != mVariables.end() && varIt->second->isOriginal() )
2956  {
2957  result *= interv.second.diameter();
2958  }
2959  }
2960  return result;
2961  }
2962 
2963  template<class Settings>
2964  void ICPModule<Settings>::addProgress( double _progress )
2965  {
2966  if( _progress > 0.0 )
2967  {
2968  mCovererdRegionSize += _progress;
2969  std::cout << "\r";
2970  std::cout << std::setprecision(10) << std::setw(20) << (mCovererdRegionSize > 0 ? ((mCovererdRegionSize/mGlobalBoxSize)*100.0) : 0.0) << " %";
2971  std::cout.flush();
2972  }
2973  }
2974 
2975  template<class Settings>
2976  void ICPModule<Settings>::setBox( icp::HistoryNode* _selection )
2977  {
2978  assert(_selection != nullptr);
2979  #ifdef ICP_MODULE_DEBUG_1
2980  std::cout << "Set box -> ";
2981  _selection->print(std::cout);
2982  std::cout << ", #intervals: " << mIntervals.size() << " -> " << _selection->intervals().size() << std::endl;
2983  #endif
2984  // set intervals - currently we don't change not contained intervals.
2985  for ( auto constraintIt = _selection->rIntervals().begin(); constraintIt != _selection->rIntervals().end(); ++constraintIt )
2986  {
2987  assert(mIntervals.find((*constraintIt).first) != mIntervals.end());
2988  // only update intervals which changed
2989  if ( !(mIntervals.at((*constraintIt).first)==(*constraintIt).second) )
2990  {
2991  std::map<carl::Variable, icp::IcpVariable*>::const_iterator icpVar = mVariables.find((*constraintIt).first);
2992  // std::cout << "Searching for " << (*intervalIt).first.get_name() << std::endl;
2993  assert(icpVar != mVariables.end());
2994  (*icpVar).second->setInterval( (*constraintIt).second );
2995  }
2996  }
2997  // set actual node as selection
2998  mHistoryActual = _selection;
2999  }
3000 
3001  template<class Settings>
3002  bool ICPModule<Settings>::intervalsEmpty( const EvalDoubleIntervalMap& _intervals ) const
3003  {
3004  for( const auto& interval : _intervals )
3005  {
3006  if( interval.second.is_empty() ) return true;
3007  }
3008  return false;
3009  }
3010 
3011  template<class Settings>
3012  bool ICPModule<Settings>::intervalsEmpty( bool _original ) const
3013  {
3014  for ( auto constraintIt = mIntervals.begin(); constraintIt != mIntervals.end(); ++constraintIt )
3015  {
3016  auto varIt = mVariables.find((*constraintIt).first);
3017  //assert( varIt != mVariables.end() );//TODO (from FLorian): can we assume this?
3018  if( !_original || (varIt != mVariables.end() && varIt->second->isOriginal()))
3019  {
3020  if( (*constraintIt).second.is_empty() ) return true;
3021  }
3022  }
3023  return false;
3024  }
3025 
3026  #ifdef ICP_MODULE_DEBUG_METHODS
3027  template<class Settings>
3028  void ICPModule<Settings>::debugPrint() const
3029  {
3030  std::cout << "********************* linear Constraints **********************" << std::endl;
3031  for( auto linearIt = mLinearConstraints.begin(); linearIt != mLinearConstraints.end(); ++linearIt){
3032  for ( auto candidateIt = (*linearIt).second.begin(); candidateIt != (*linearIt).second.end(); ++candidateIt )
3033  {
3034  std::cout << (*candidateIt)->id() << ": " << (*candidateIt)->constraint() << std::endl;
3035  }
3036  }
3037  std::cout << "****************** active linear constraints ******************" << std::endl;
3038  for(auto activeLinearIt = mActiveLinearConstraints.begin(); activeLinearIt != mActiveLinearConstraints.end(); ++activeLinearIt){
3039  std::cout << "Count: " << (*activeLinearIt)->activity() << " , ";
3040  (*activeLinearIt)->print();
3041  }
3042  std::cout << "******************* active linear variables *******************" << std::endl;
3043  for (auto variableIt = mVariables.begin(); variableIt != mVariables.end(); ++variableIt )
3044  {
3045  if ( (*variableIt).second->is_linear() )
3046  std::cout << (*variableIt).first << ", ";
3047  }
3048  std::cout << std::endl;
3049  std::cout << "******************** nonlinear constraints ********************" << std::endl;
3050  ContractionCandidates::iterator replacementsIt;
3051  for(auto nonlinearIt = mNonlinearConstraints.begin(); nonlinearIt != mNonlinearConstraints.end(); ++nonlinearIt){
3052  std::cout << (*nonlinearIt).first << std::endl;
3053  std::cout << "\t replacements: " << std::endl;
3054  for(replacementsIt = nonlinearIt->second.begin(); replacementsIt != nonlinearIt->second.end(); ++replacementsIt)
3055  {
3056  std::cout << " ";
3057  (*replacementsIt)->print();
3058  }
3059  }
3060  std::cout << "**************** active nonlinear constraints *****************" << std::endl;
3061  for( auto activeNonlinearIt = mActiveNonlinearConstraints.begin(); activeNonlinearIt != mActiveNonlinearConstraints.end(); ++activeNonlinearIt )
3062  {
3063  std::cout << "Count: " << (*activeNonlinearIt)->activity() << " , ";
3064  (*activeNonlinearIt)->print();
3065  }
3066  std::cout << "***************** active nonlinear variables ******************" << std::endl;
3067  for (auto variableIt = mVariables.begin(); variableIt != mVariables.end(); ++variableIt )
3068  {
3069  if ( (*variableIt).second->is_linear() )
3070  std::cout << (*variableIt).first << ", ";
3071  }
3072  std::cout << std::endl;
3073  std::cout << "************************** Intervals **************************" << std::endl;
3074  for ( auto constraintIt = mIntervals.begin(); constraintIt != mIntervals.end(); ++constraintIt )
3075  {
3076  std::cout << (*constraintIt).first << " \t -> \t" << (*constraintIt).second << std::endl;
3077  }
3078  std::cout << std::endl;
3079  std::cout << "************************* Linearizations ************************" << std::endl;
3080  for ( auto replacementIt = mLinearizations.begin(); replacementIt != mLinearizations.end(); ++replacementIt )
3081  {
3082  std::cout << (*replacementIt).first << " \t -> \t" << (*replacementIt).second << std::endl;
3083  }
3084  std::cout << std::endl;
3085  std::cout << "************************* Delinearizations ************************" << std::endl;
3086  for ( auto replacementIt = mDeLinearizations.begin(); replacementIt != mDeLinearizations.end(); ++replacementIt )
3087  {
3088  std::cout << (*replacementIt).first << " \t -> \t" << (*replacementIt).second << std::endl;
3089  }
3090  std::cout << std::endl;
3091  std::cout << "************************* ICP carl::Variables ***********************" << std::endl;
3092  for ( auto variablesIt = mVariables.begin(); variablesIt != mVariables.end(); ++variablesIt )
3093  (*variablesIt).second->print( std::cout, true );
3094 
3095  std::cout << std::endl;
3096  std::cout << "*********************** ValidationFormula *********************" << std::endl;
3097  std::cout << mValidationFormula << std::endl;
3098  std::cout << "***************************************************************" << std::endl;
3099 
3100  std::cout << "************************* Substitution ************************" << std::endl;
3101  for( auto subsIt = mSubstitutions.begin(); subsIt != mSubstitutions.end(); ++subsIt )
3102  std::cout << (*subsIt).first << " -> " << (*subsIt).second << std::endl;
3103 
3104  std::cout << "***************************************************************" << std::endl;
3105  }
3106 
3107  template<class Settings>
3108  void ICPModule<Settings>::printAffectedCandidates() const
3109  {
3110  for ( auto varIt = mVariables.begin(); varIt != mVariables.end(); ++varIt )
3111  {
3112  for ( auto candidateIt = (*varIt).second->candidates().begin(); candidateIt != (*varIt).second->candidates().end(); ++candidateIt)
3113  {
3114  std::cout << (*varIt).first << "\t -> ";
3115  (*candidateIt)->print();
3116  }
3117  }
3118  }
3119 
3120  template<class Settings>
3121  void ICPModule<Settings>::printIcpVariables() const
3122  {
3123  for ( auto varIt = mVariables.begin(); varIt != mVariables.end(); ++varIt )
3124  (*varIt).second->print( std::cout, true );
3125  }
3126 
3127  template<class Settings>
3128  void ICPModule<Settings>::printIcpRelevantCandidates() const
3129  {
3130  std::cout << "Size icpRelevantCandidates: " << mIcpRelevantCandidates.size() << std::endl;
3131  for ( auto candidateIt = mIcpRelevantCandidates.begin(); candidateIt != mIcpRelevantCandidates.end(); ++candidateIt )
3132  {
3133  std::cout << (*candidateIt).first << " \t " << (*candidateIt).second <<"\t Candidate: ";
3134  icp::ContractionCandidate* cc = mCandidateManager.getCandidate((*candidateIt).second);
3135  assert( cc != nullptr );
3136  cc->print();
3137  }
3138  }
3139 
3140  template<class Settings>
3141  void ICPModule<Settings>::printIntervals( bool _original ) const
3142  {
3143  for ( auto constraintIt = mIntervals.begin(); constraintIt != mIntervals.end(); ++constraintIt )
3144  {
3145  auto varIt = mVariables.find((*constraintIt).first);
3146  //assert( varIt != mVariables.end() );//TODO (from FLorian): can we assume this?
3147  if( !_original || (varIt != mVariables.end() && varIt->second->isOriginal()))
3148  {
3149  std::cout << std::setw(10) << (*constraintIt).first;
3150  std::stringstream s;
3151  s << (*constraintIt).second;
3152  std::cout << ":" << std::setw(30) << s.str();
3153  std::cout << std::endl;
3154  }
3155  }
3156  }
3157 
3158  template<class Settings>
3159  void ICPModule<Settings>::printPreprocessedInput( std::string _init ) const
3160  {
3161  ConstraintT last = ConstraintT();
3162  for(auto activeLinearIt = mActiveLinearConstraints.begin(); activeLinearIt != mActiveLinearConstraints.end(); ++activeLinearIt){
3163  if( (*activeLinearIt)->constraint() != last )
3164  {
3165  last = (*activeLinearIt)->constraint();
3166  std::cout << _init << last << std::endl;
3167  }
3168  }
3169  last = ConstraintT();
3170  for(auto activeNoninearIt = mActiveNonlinearConstraints.begin(); activeNoninearIt != mActiveNonlinearConstraints.end(); ++activeNoninearIt){
3171  if( (*activeNoninearIt)->constraint() != last )
3172  {
3173  last = (*activeNoninearIt)->constraint();
3174  std::cout << _init << last << std::endl;
3175  }
3176  }
3177  }
3178 
3179  template<class Settings>
3180  void ICPModule<Settings>::printContraction( const icp::ContractionCandidate& _cc, const DoubleInterval& _before, const DoubleInterval& _afterA, const DoubleInterval& _afterB, std::ostream& _out ) const
3181  {
3182  _out << ((mRelativeContraction > 0 || mAbsoluteContraction > 0) ? "#" : " ");
3183  _out << std::setw(10) << _cc.derivationVar();
3184  std::stringstream s;
3185  s << std::setprecision(20) << _before;
3186  _out << ":" << std::setw(50) << s.str();
3187  std::stringstream s2;
3188  if( _afterB.is_empty() )
3189  {
3190  s2 << std::setprecision(20) << _afterA;
3191  }
3192  else
3193  {
3194  s2 << std::setprecision(20) << _afterA << " or " << std::setprecision(20) << _afterB;
3195  }
3196  _out << " -> " << std::setw(50) << std::left << s2.str();
3197  _out << std::right << " with " << _cc.contractor().polynomial() << " (" << _cc.RWA() << ")" << std::endl;
3198  }
3199  #endif
3200 } // namespace smtrat
3201 
3202