SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
CubeLIAModule.tpp
Go to the documentation of this file.
1 /**
2  * @file CubeLIA.cpp
3  * @author YOUR NAME <YOUR EMAIL ADDRESS>
4  *
5  * @version 2015-11-24
6  * Created on 2015-11-24.
7  */
8 
9 #include "CubeLIAModule.h"
10 //#define DEBUG_CUBELIAMODULE
11 
12 #include <carl-formula/model/Assignment.h>
13 
14 namespace smtrat
15 {
16  template<class Settings>
17  CubeLIAModule<Settings>::CubeLIAModule(const ModuleInput* _formula, Conditionals& _conditionals, Manager* _manager):
18  Module( _formula, _conditionals, _manager ),
19  mModelUpdated(false),
20  mIntToRealVarMap(),
21  mRealToIntVarMap(),
22  mCubifications(),
23  mLRAFormula( new ModuleInput() ),
24  mLRAFoundAnswer( std::vector< std::atomic_bool* >( 1, new std::atomic_bool( false ) ) ),
25  mLRA( mLRAFormula, mLRAFoundAnswer )
26  {}
27 
28  template<class Settings>
29  CubeLIAModule<Settings>::~CubeLIAModule()
30  {
31  while( !mLRAFoundAnswer.empty() )
32  {
33  std::atomic_bool* toDel = mLRAFoundAnswer.back();
34  mLRAFoundAnswer.pop_back();
35  delete toDel;
36  }
37  mLRAFoundAnswer.clear();
38  delete mLRAFormula;
39  }
40 
41  template<class Settings>
42  bool CubeLIAModule<Settings>::addCore( ModuleInput::const_iterator _subformula )
43  {
44  if( _subformula->formula().type() == carl::FormulaType::CONSTRAINT && !_subformula->formula().property_holds( carl::PROP_CONTAINS_REAL_VALUED_VARS ) )
45  {
46  const ConstraintT& constraint = _subformula->formula().constraint();
47  if( constraint.lhs().is_linear() && constraint.relation() != carl::Relation::NEQ && constraint.relation() != carl::Relation::EQ )
48  {
49  auto iter = mCubifications.find( _subformula->formula() );
50  if( iter == mCubifications.end() )
51  {
52  // For all variables in the constraint, which do not yet have a real relaxation, create one.
53  for( carl::Variable::Arg var : carl::variables(constraint.lhs()) )
54  {
55  if( var.type() == carl::VariableType::VT_INT || var.type() == carl::VariableType::VT_BOOL )
56  {
57  auto iter = mIntToRealVarMap.find( var );
58  if( iter == mIntToRealVarMap.end() )
59  {
60  carl::Variable realVar = carl::fresh_real_variable();
61  mIntToRealVarMap[var] = Poly(realVar);
62  mRealToIntVarMap[realVar] = var;
63  }
64  }
65  }
66  // Create the real relaxation of the constraint's left-hand side.
67  Poly realRelax = carl::substitute(constraint.lhs(), mIntToRealVarMap);
68  #ifdef DEBUG_CUBELIAMODULE
69  std::cout << "mIntToRealVarMap: " << mIntToRealVarMap << std::endl;
70  std::cout << "Real relaxation of " << constraint.lhs() << " is " << realRelax << std::endl;
71  #endif
72  // Find the 1-norm of the left-hand side's coefficients.
73  Rational norm = 0;
74  for( auto& term : realRelax.terms() )
75  {
76  if( !term.is_constant() )
77  {
78  norm += carl::abs( term.coeff() );
79  }
80  }
81  // Add half of the found 1-norm to the real relaxation of the constraint's left-hand side.
82  realRelax += norm/Rational(2);
83  // Store this "cubification".
84  FormulaT cubification( realRelax, constraint.relation() );
85  auto ret = mLRAFormula->add( cubification, false );
86  assert( ret.second );
87  #ifdef DEBUG_CUBELIAMODULE
88  std::cout << "Add to internal LRAModule: " << cubification << std::endl;
89  #endif
90  mLRA.inform( cubification );
91  mLRA.add( ret.first );
92  mCubifications.emplace( _subformula->formula(), Cubification( cubification, ret.first ) );
93  }
94  else
95  {
96  // If the cubification has already been created, update the usage counter.
97  if( iter->second.mUsages == 0 )
98  {
99  // If the cubification is now active again, add it to the internal LRAModule.
100  auto ret = mLRAFormula->add( iter->second.mCubification );
101  #ifdef DEBUG_CUBELIAMODULE
102  std::cout << "Add to internal LRAModule: " << iter->second.mCubification << std::endl;
103  #endif
104  assert( ret.second );
105  mLRA.add( ret.first );
106  assert( iter->second.mPosition == mLRAFormula->end() );
107  iter->second.mPosition = ret.first;
108  }
109  ++iter->second.mUsages;
110  }
111  }
112  }
113  addReceivedSubformulaToPassedFormula( _subformula );
114  return true;
115  }
116 
117  template<class Settings>
118  void CubeLIAModule<Settings>::removeCore( ModuleInput::const_iterator _subformula )
119  {
120  auto iter = mCubifications.find( _subformula->formula() );
121  if( iter != mCubifications.end() )
122  {
123  // If a cubification of this formula exists, update the usage counter.
124  assert( iter->second.mUsages > 0 );
125  --iter->second.mUsages;
126  if( iter->second.mUsages == 0 )
127  {
128  // If the cubification got deactivated, remove it from the internal LRAModule.
129  #ifdef DEBUG_CUBELIAMODULE
130  std::cout << "Remove from internal LRAModule: " << iter->second.mPosition->formula() << std::endl;
131  #endif
132  mLRA.remove( iter->second.mPosition );
133  mLRAFormula->erase( iter->second.mPosition );
134  iter->second.mPosition = mLRAFormula->end();
135  }
136  }
137  }
138 
139  template<class Settings>
140  void CubeLIAModule<Settings>::updateModel() const
141  {
142  if( !mModelComputed && !mModelUpdated )
143  {
144  clearModel();
145  if( solverState() != UNSAT )
146  {
147  getBackendsModel();
148  }
149  mModelUpdated = true;
150  }
151  }
152 
153  template<class Settings>
154  Answer CubeLIAModule<Settings>::checkCore()
155  {
156  #ifdef DEBUG_CUBELIAMODULE
157  print();
158  #endif
159  Answer ans;
160  if( !rReceivedFormula().is_real_constraint_conjunction() )
161  {
162  #ifdef DEBUG_CUBELIAMODULE
163  std::cout << "Call internal LRAModule:" << std::endl;
164  mLRA.print();
165  #endif
166  mLRA.clearLemmas();
167  mLRAFormula->updateProperties();
168  ans = mLRA.check( false, mFullCheck, objective() );
169  switch( ans )
170  {
171  case SAT:
172  {
173  clearModel();
174  // Get the model of mLRA
175  mLRA.updateModel();
176  const Model& relaxedModel = mLRA.model();
177  auto iter = mRealToIntVarMap.begin();
178  for( auto& ass : relaxedModel )
179  {
180  assert( iter != mRealToIntVarMap.end() );
181  // Round the result to the next integer
182  mModel.emplace_hint( mModel.end(), iter->second, carl::round( ass.second.asRational() ) );
183  ++iter;
184  }
185  // Check if the rounded model satisfies the received formula
186  bool receivedFormulaSatisfied = true;
187  for( const FormulaWithOrigins& fwo : rReceivedFormula() )
188  {
189  unsigned res = satisfies( mModel, fwo.formula() );
190  switch( res )
191  {
192  case 0:
193  case 2:
194  receivedFormulaSatisfied = false;
195  default:
196  break;
197  }
198  if( !receivedFormulaSatisfied )
199  break;
200  }
201  // If we found a model, we know that the formula is satisfiable, otherwise, we have to call the backends on the received formula
202  if( receivedFormulaSatisfied )
203  {
204  mModelUpdated = true;
205  return SAT;
206  }
207  clearModel();
208  break;
209  }
210  case UNSAT:
211  {
212  if( Settings::exclude_unsatisfiable_cube_space )
213  {
214  // Exclude the space for which mLRA has detected unsatisfiability
215  for( auto& infsubset : mLRA.infeasibleSubsets() )
216  {
217  FormulasT formulas;
218  for( auto& formula : infsubset )
219  formulas.push_back( formula.negated() );
220  addLemma( FormulaT( carl::FormulaType::OR, formulas ) );
221  }
222  }
223  break;
224  }
225  default:
226  assert( false );
227  }
228  }
229  #ifdef DEBUG_CUBELIAMODULE
230  std::cout << "Call Backends:" << std::endl;
231  #endif
232  // Run backends on received formula
233  ans = runBackends();
234  if( ans == UNSAT )
235  getInfeasibleSubsets();
236  else if( ans == SAT )
237  mModelUpdated = false;
238  return ans;
239  }
240 }
241 
242