SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
InequalitiesTable.tpp
Go to the documentation of this file.
1 #pragma once
2 
3 namespace smtrat
4 {
5  /**
6  * Initializes the inequalities table
7  * @param module
8  */
9  template<class Settings>
10  InequalitiesTable<Settings>::InequalitiesTable( GBModule<Settings>* module ) : mModule( module )
11  {
12  mBtnumber = 0;
13  mNewConstraints = mReducedInequalities.begin( );
14  }
15 
16  /**
17  * Adds the constraint as a row to the inequalities table.
18  * @param received A pointer from the receivedFormula to the inequality.
19  * @return The position in the inequalities table.
20  */
21 
22  template<class Settings>
23  typename InequalitiesTable<Settings>::Rows::iterator InequalitiesTable<Settings>::InsertReceivedFormula( ModuleInput::const_iterator received )
24  {
25  assert( received->formula().constraint().relation() != carl::Relation::EQ );
26  // We assume that the just added formula is the last one.
27  ModuleInput::iterator passedEntry = mModule->addReceivedSubformulaToPassedFormula(received).first;
28  // And we add a row to our table
29  return mReducedInequalities.insert( Row( received, RowEntry( passedEntry, received->formula().constraint( ).relation( ), std::list<CellEntry > (1, CellEntry( 0, Polynomial( (typename Poly::PolyType)received->formula().constraint( ).lhs( ) ) )) ) ) ).first;
30  }
31 
32  /**
33  * Informs the inequalities table that new reductions are with respect to the GB with the latest btpoint.
34  */
35 
36  template<class Settings>
37  void InequalitiesTable<Settings>::pushBacktrackPoint( )
38  {
39  ++mBtnumber;
40  if( Settings::setCheckInequalitiesToBeginAfter > 1 )
41  {
42  if( mLastRestart + Settings::setCheckInequalitiesToBeginAfter == mBtnumber )
43  {
44  mNewConstraints = mReducedInequalities.begin( );
45  }
46  }
47  }
48 
49  /**
50  * Clears cells from the inequalities table with backtrack points from the latest nrOfBacktracks many backtrackpoints.
51  * Also updates the new backtracknumber.
52  * @param nrOfBacktracks How many backtrack points are popped.
53  */
54 
55  template<class Settings>
56  void InequalitiesTable<Settings>::popBacktrackPoint( unsigned nrOfBacktracks )
57  {
58  assert( mBtnumber >= nrOfBacktracks );
59  mBtnumber -= nrOfBacktracks;
60  for( auto it = mReducedInequalities.begin( ); it != mReducedInequalities.end( ); ++it )
61  {
62  typename std::list<CellEntry>::iterator listEnd = std::get < 2 > (it->second).end( );
63  for( typename std::list<CellEntry>::iterator jt = std::get < 2 > (it->second).begin( ); jt != listEnd; ++jt )
64  {
65  if( jt->first > mBtnumber )
66  {
67  std::get < 2 > (it->second).erase( jt, listEnd );
68  bool pass;
69  if( Settings::passInequalities == FULL_REDUCED_IF )
70  {
71  pass = Settings::passPolynomial::evaluate( std::get < 2 > (it->second).front( ).second, std::get < 2 > (it->second).back( ).second );
72  }
73 
74  // what shall we pass
75  if( Settings::passInequalities == AS_RECEIVED )
76  {
77  if( std::get < 0 > (it->second) == mModule->rPassedFormula().end( ) )
78  {
79  // we had reduced it to true, therefore not passed it, but now we have to pass the original one again
80  std::get < 0 > (it->second) = mModule->addReceivedSubformulaToPassedFormula( it->first ).first;
81  }
82  }
83  else
84  {
85  if( std::get < 0 > (it->second) != mModule->rPassedFormula().end( ) )
86  {
87  // we can of course only remove something which is in the formula
88 
89  // TODO (from Florian): store the reasons formula somewhere, such that we only construct it if the reasons vector has been changed
90  FormulasT subformulas = mModule->generateReasons(std::get<2>(it->second).back( ).second.getReasons() );
91  subformulas.push_back( it->first->formula() );
92  FormulaT origin = FormulaT( carl::FormulaType::AND, subformulas );
93  mModule->removeOrigin( std::get < 0 > (it->second), origin );
94 // mModule->removeSubformulaFromPassedFormula( std::get < 0 > (it->second) );
95  }
96  if( Settings::passInequalities == FULL_REDUCED || (Settings::passInequalities == FULL_REDUCED_IF && pass) )
97  {
98  const carl::BitVector& reasons = std::get<2>(it->second).back( ).second.getReasons();
99  if( reasons.empty() )
100  {
101  std::get < 0 > (it->second) = mModule->addReceivedSubformulaToPassedFormula( it->first ).first;
102  }
103  else
104  {
105  FormulaT simplifiedConstraint = FormulaT( Poly(typename smtrat::Poly::PolyType(std::get<2>(it->second).back().second)), std::get<1>(it->second) );
106  assert( simplifiedConstraint.type() != carl::FormulaType::FALSE );
107  if( simplifiedConstraint.type() == carl::FormulaType::TRUE )
108  {
109  std::get < 0 > (it->second) = mModule->passedFormulaEnd();
110  }
111  else
112  {
113  FormulasT sformulas = mModule->generateReasons(reasons);
114  sformulas.push_back( it->first->formula() );
115  FormulaT originals = FormulaT( carl::FormulaType::AND, sformulas);
116  // we update the reference to the passed formula again
117  std::get < 0 > (it->second) = mModule->addSubformulaToPassedFormula( simplifiedConstraint, originals ).first;
118  }
119  }
120  }
121  else
122  {
123  assert( Settings::passInequalities == FULL_REDUCED_IF );
124  // we pass the original one and update the reference to the passed formula again
125  std::get < 0 > (it->second) = mModule->addReceivedSubformulaToPassedFormula( it->first ).first;
126  }
127  }
128  break;
129  }
130  }
131  }
132  }
133 
134  /**
135  * Reduce all rows with respect to the given Groebner basis.
136  * @param gb The groebner basis
137  * @return If one of the inequalities yields a contradiction, UNSAT, else Unknown.
138  */
139 
140  template<class Settings>
141  Answer InequalitiesTable<Settings>::reduceWRTGroebnerBasis( const Ideal& gb, const RewriteRules& rules )
142  {
143  for( auto it = mReducedInequalities.begin( ); it != mReducedInequalities.end( ); ++it )
144  {
145  // The formula is not passed because it is unsatisfiable.
146  if( !reduceWRTGroebnerBasis( it, gb, rules ) ) {
147  #ifdef SMTRAT_DEVOPTION_Statistics
148  mStats.infeasibleInequality();
149  #endif
150  if( Settings::withInfeasibleSubset == RETURN_DIRECTLY )
151  {
152  return UNSAT;
153  }
154  }
155  }
156  if( Settings::withInfeasibleSubset != RETURN_DIRECTLY )
157  {
158  if( mModule->mInfeasibleSubsets.empty( ) )
159  {
160  return UNKNOWN;
161  }
162  else
163  {
164  #ifdef SMTRAT_DEVOPTION_Statistics
165  mStats.infeasibleInequality();
166  #endif
167  return UNSAT;
168  }
169  }
170  else
171  {
172  return UNKNOWN;
173  }
174 
175  }
176 
177  /**
178  * Reduce the given rows with respect to the given Groebner basis.
179  * @param ineqToBeReduced A list of rows which should be updated.
180  * @param gb The Groebner basis.
181  * @return If one of the inequalities yields a contradiction, UNSAT, else Unknown.
182  */
183 
184  template<class Settings>
185  Answer InequalitiesTable<Settings>::reduceWRTGroebnerBasis( const std::list<typename Rows::iterator>& ineqToBeReduced, const Ideal& gb, const RewriteRules& rules )
186  {
187  for( auto it = ineqToBeReduced.begin( ); it != ineqToBeReduced.end( ); ++it )
188  {
189  assert( std::get < 1 > ((*it)->second) != carl::Relation::EQ );
190  if( !reduceWRTGroebnerBasis( *it, gb, rules ) ) {
191  #ifdef SMTRAT_DEVOPTION_Statistics
192  mStats.infeasibleInequality();
193  #endif
194  if( Settings::withInfeasibleSubset == RETURN_DIRECTLY )
195  {
196  return UNSAT;
197  }
198  }
199  }
200  if( Settings::withInfeasibleSubset != RETURN_DIRECTLY )
201  {
202  if( mModule->mInfeasibleSubsets.empty( ) )
203  {
204  return UNKNOWN;
205  }
206  else
207  {
208  #ifdef SMTRAT_DEVOPTION_Statistics
209  mStats.infeasibleInequality();
210  #endif
211  return UNSAT;
212  }
213  }
214  else
215  {
216  return UNKNOWN;
217  }
218  }
219 
220  /**
221  * Reduce the given row with respect to the given Groebner basis.
222  * @param ineqToBeReduced A pointer to the row which should be updated.
223  * @param gb The Groebner basis.
224  * @return If one of the inequalities yields a contradiction, false, else true.
225  */
226 
227  template<class Settings>
228  bool InequalitiesTable<Settings>::reduceWRTGroebnerBasis( typename Rows::iterator it, const Ideal& gb, const RewriteRules& rules )
229  {
230  assert( std::get < 1 > (it->second) != carl::Relation::EQ );
231  // Check if constraint has already been reduced to true (no further reduction possible).
232  if( std::get < 0 > (it->second) == mModule->passedFormulaEnd() ) return true;
233 
234  Polynomial& p = std::get<2>(it->second).back( ).second;
235  Polynomial reduced;
236 
237  bool reductionOccured = false;
238  bool rewriteOccured = false;
239  if( !carl::is_zero(p) && !p.is_constant( ) )
240  {
241  if(rules.size() == 0)
242  {
243  typename Settings::Reductor reductor( gb, p );
244  reduced = reductor.fullReduce( );
245  reductionOccured = reductor.reductionOccured( );
246  }
247  else
248  {
249  Polynomial ptemp = groebner::rewritePolynomial(p, rules);
250 
251  rewriteOccured = (ptemp != p);
252  if( !carl::is_zero(ptemp) && !ptemp.is_constant() )
253  {
254  typename Settings::Reductor reductor( gb, ptemp );
255  reduced = reductor.fullReduce( );
256  reductionOccured = reductor.reductionOccured( );
257  }
258  else
259  {
260  reduced = ptemp;
261  reduced.setReasons(ptemp.getReasons());
262  }
263  }
264  }
265 
266  carl::Relation relation = std::get < 1 > (it->second);
267  if( rewriteOccured || reductionOccured )
268  {
269  assert(std::get < 0 > (it->second) != mModule->passedFormulaEnd());
270  if( carl::is_zero(reduced) || reduced.is_constant( ) )
271  {
272  bool satisfied = false;
273  if( carl::is_zero(reduced) && is_weak( relation ) )
274  {
275  assert( is_weak( relation ) );
276  satisfied = true;
277  }
278  else if( !carl::is_zero(reduced) )
279  { // non zero
280  assert( reduced.nr_terms( ) > 0 );
281  assert( reduced.lcoeff( ) != 0 );
282 
283  smtrat::Rational reducedConstant = reduced.lcoeff( );
284  assert( reducedConstant != 0 );
285  if( reducedConstant < 0 )
286  {
287  if( relation == carl::Relation::LESS || relation == carl::Relation::LEQ || relation == carl::Relation::NEQ )
288  {
289  satisfied = true;
290  }
291  }
292  else
293  {
294  if( relation == carl::Relation::GREATER || relation == carl::Relation::GEQ || relation == carl::Relation::NEQ )
295  {
296  satisfied = true;
297  }
298  }
299  }
300 
301  if( satisfied )
302  {
303  // remove the last formula
304 
305  if( std::get < 0 > (it->second) != mModule->passedFormulaEnd( ) )
306  {
307  // TODO (from Florian): store the reasons formula somewhere, such that we only construct it if the reasons vector has been changed
308  FormulasT subformulas = mModule->generateReasons(std::get<2>(it->second).back( ).second.getReasons() );
309  subformulas.push_back( it->first->formula() );
310  FormulaT origin = FormulaT( carl::FormulaType::AND, subformulas );
311  mModule->removeOrigin( std::get < 0 > (it->second), origin );
312 // mModule->removeSubformulaFromPassedFormula( std::get < 0 > (it->second) );
313  std::get < 0 > (it->second) = mModule->passedFormulaEnd( );
314  }
315 
316  std::get < 2 > (it->second).push_back( CellEntry( mBtnumber, reduced ) ); // TODO: Is this necessary?
317  if( Settings::addTheoryDeductions != NO_CONSTRAINTS )
318  {
319  // TODO: Why is the following disabled?
320 // FormulasT originals = mModule->generateReasons( reduced.getReasons( ) );
321 // FormulasT subformulas;
322 // for( auto jt = originals.begin(); jt != originals.end(); ++jt )
323 // {
324 // subformulas.insert( FormulaT( carl::FormulaType::NOT, *jt ) );
325 // }
326 // subformulas.insert( it->first->formula() );
327 // mModule->print();
328 // std::cout << "Id="<<(*(it->first))->pConstraint()->id()<<std::endl;
329 // std::cout << "Gb learns: ";
330 // deduction->print();
331 // std::cout << std::endl;
332 // mModule->addLemma( FormulaT( carl::FormulaType::carl::FormulaType::OR, subformulas ) ); // TODO: Florian ask Sebastian, why he commented that line
333  #ifdef SMTRAT_DEVOPTION_Statistics
334  mStats.DeducedInequality();
335  #endif
336 
337  }
338  }
339  else // we have a conflict
340  {
341 
342  FormulaSetT infeasibleSubset( mModule->generateReasonSet( reduced.getReasons( ) ) );
343  infeasibleSubset.insert( it->first->formula() );
344  #ifdef SMTRAT_DEVOPTION_Statistics
345  mStats.EffectivenessOfConflicts(infeasibleSubset.size()/mModule->rReceivedFormula().size());
346  #endif //SMTRAT_DEVOPTION_Statistics
347  mModule->mInfeasibleSubsets.push_back( infeasibleSubset );
348  if( Settings::withInfeasibleSubset == RETURN_DIRECTLY )
349  {
350  return false;
351  }
352  }
353  }
354  else if( Settings::withInfeasibleSubset == PROCEED_ALLINEQUALITIES || mModule->mInfeasibleSubsets.empty( ) )
355  {
356  bool pass;
357  if( Settings::passInequalities == FULL_REDUCED_IF )
358  {
359  pass = Settings::passPolynomial::evaluate( std::get < 2 > (it->second).front( ).second, reduced );
360  }
361 
362  if( Settings::passInequalities == FULL_REDUCED || (Settings::passInequalities == FULL_REDUCED_IF && pass) )
363  {
364  //remove the last one
365 
366  // TODO (from Florian): store the reasons formula somewhere, such that we only construct it if the reasons vector has been changed
367  FormulasT subformulas = mModule->generateReasons(std::get<2>(it->second).back( ).second.getReasons() );
368  subformulas.push_back( it->first->formula() );
369  FormulaT origin = FormulaT( carl::FormulaType::AND, subformulas );
370  mModule->removeOrigin( std::get < 0 > (it->second), origin );
371 // mModule->removeSubformulaFromPassedFormula( std::get < 0 > (it->second) );
372  }
373  //add a new cell
374  std::get < 2 > (it->second).push_back( CellEntry( mBtnumber, reduced ) );
375  if( Settings::passInequalities == FULL_REDUCED || (Settings::passInequalities == FULL_REDUCED_IF && pass) )
376  {
377  FormulaT redResult = FormulaT( Poly(typename smtrat::Poly::PolyType(reduced)), relation );
378  switch( redResult.type() )
379  {
380  case carl::FormulaType::TRUE:
381  {
382  break;
383  }
384  case carl::FormulaType::FALSE:
385  {
386  FormulaSetT infeasibleSubset( mModule->generateReasonSet( reduced.getReasons( ) ) );
387  infeasibleSubset.insert( it->first->formula() );
388  #ifdef SMTRAT_DEVOPTION_Statistics
389  mStats.EffectivenessOfConflicts(infeasibleSubset.size()/mModule->rReceivedFormula().size());
390  #endif //SMTRAT_DEVOPTION_Statistics
391  mModule->mInfeasibleSubsets.push_back( infeasibleSubset );
392  if( Settings::withInfeasibleSubset == RETURN_DIRECTLY )
393  {
394  return false;
395  }
396  break;
397  }
398  default:
399  {
400  assert( redResult.type() == carl::FormulaType::CONSTRAINT );
401  // get the reason set for the reduced polynomial
402  FormulasT originals = mModule->generateReasons( reduced.getReasons( ) );
403  originals.push_back( it->first->formula() );
404 
405  //pass the result
406  //TODO: replace "Formula::constraintPool().variables()" by a smaller approximations of the variables contained in "reduced.toEx( )"
407  // and set the pointer to the passed formula accordingly.
408  std::get < 0 > (it->second) = mModule->addSubformulaToPassedFormula( redResult, FormulaT( carl::FormulaType::AND, originals ) ).first;
409  }
410  }
411  }
412  // new constraint learning
413  // If the original constraint is nonlinear
414  /*if( !((*(it->first))->pConstraint( ))->is_linear() )
415  {
416  // We only want to learn linear constraints.
417  if( reduced.is_linear() )
418  {
419  // get the reason set for the reduced polynomial
420  FormulasT subformulas;
421  std::vector<FormulasT > originals;
422  originals.push_back( mModule->generateReasons( reduced.getOrigins( ).getBitVector( ) ) );
423 
424  for( auto jt = originals.front().begin(); jt != originals.front().end(); ++jt )
425  {
426  subformulas.insert( FormulaT( carl::FormulaType::NOT, *it ) );
427  }
428  subformulas.insert( FormulaT( carl::FormulaType::NOT, *it->first ) );
429  subformulas.insert( FormulaT( reduced.toEx( ), relation ) );
430  //mModule->addLemma( FormulaT( carl::FormulaType::OR, subformulas ) );
431  }
432  }*/
433  }
434  }
435  return true;
436  }
437 
438  template<class Settings>
439  Answer InequalitiesTable<Settings>::reduceWRTVariableRewriteRules(const RewriteRules& rules)
440  {
441  for( auto it = mReducedInequalities.begin( ); it != mReducedInequalities.end( ); ++it )
442  {
443  assert( std::get < 1 > ((*it)->second) != carl::Relation::EQ );
444  if( !reduceWRTVariableRewriteRules( *it, rules ) ) {
445  #ifdef SMTRAT_DEVOPTION_Statistics
446  mStats.infeasibleInequality();
447  #endif
448  if( Settings::withInfeasibleSubset == RETURN_DIRECTLY )
449  {
450  return UNSAT;
451  }
452  }
453  }
454  if( Settings::withInfeasibleSubset != RETURN_DIRECTLY )
455  {
456  if( mModule->mInfeasibleSubsets.empty( ) )
457  {
458  return UNKNOWN;
459  }
460  else
461  {
462  #ifdef SMTRAT_DEVOPTION_Statistics
463  mStats.infeasibleInequality();
464  #endif
465  return UNSAT;
466  }
467  }
468  else
469  {
470  return UNKNOWN;
471  }
472  }
473 
474  template<class Settings>
475  Answer InequalitiesTable<Settings>::reduceWRTVariableRewriteRules(const std::list< typename Rows::iterator>& ineqToBeReduced, const RewriteRules& rules )
476  {
477  for( auto it = ineqToBeReduced.begin( ); it != ineqToBeReduced.end( ); ++it )
478  {
479  assert( std::get < 1 > ((*it)->second) != carl::Relation::EQ );
480  if( !reduceWRTVariableRewriteRules( *it, rules ) ) {
481  #ifdef SMTRAT_DEVOPTION_Statistics
482  mStats.infeasibleInequality();
483  #endif
484  if( Settings::withInfeasibleSubset == RETURN_DIRECTLY )
485  {
486  return UNSAT;
487  }
488  }
489  }
490  if( Settings::withInfeasibleSubset != RETURN_DIRECTLY )
491  {
492  if( mModule->mInfeasibleSubsets.empty( ) )
493  {
494  return UNKNOWN;
495  }
496  else
497  {
498  #ifdef SMTRAT_DEVOPTION_Statistics
499  mStats.infeasibleInequality();
500  #endif
501  return UNSAT;
502  }
503  }
504  else
505  {
506  return UNKNOWN;
507  }
508  }
509 
510  template<class Settings>
511  bool InequalitiesTable<Settings>::reduceWRTVariableRewriteRules( typename Rows::iterator , const RewriteRules& )
512  {
513  /// TODO implement or erase
514  assert(false);
515  return true;
516  }
517 
518 
519  /**
520  * Removes the row corresponding to this constraint from the inequalities table.
521  * @param _formula A pointer to the constraint in the receivedFormula which has to be removed.
522  */
523 
524  template<class Settings>
525  void InequalitiesTable<Settings>::removeInequality( ModuleInput::const_iterator _formula )
526  {
527  mReducedInequalities.erase( _formula );
528  if( mNewConstraints != mReducedInequalities.end( ) && _formula == mNewConstraints->first )
529  {
530  ++mNewConstraints;
531  }
532  }
533 
534  /**
535  * A print function for the inequalitiestable
536  * @param os
537  */
538 
539  template<class Settings>
540  void InequalitiesTable<Settings>::print( std::ostream& os ) const
541  {
542  os << "Bt: " << mBtnumber << std::endl;
543  for( auto it = mReducedInequalities.begin( ); it != mReducedInequalities.end( ); ++it )
544  {
545  typename std::list<CellEntry>::const_iterator listEnd = std::get < 2 > (it->second).end( );
546  os << it->first->formula() << " -> ";
547  if( std::get<0>(it->second) == mModule->passedFormulaEnd() )
548  os << "true" << std::endl;
549  else
550  os << std::get<0>(it->second)->formula() << std::endl;
551  for(typename std::list<CellEntry>::const_iterator jt = std::get < 2 > (it->second).begin( ); jt != listEnd; ++jt )
552  {
553  os << "\t(" << jt->first << ") " << jt->second << " [";
554  jt->second.getReasons().print();
555  os << "] " << std::endl;
556 
557  }
558  }
559  }
560 }