SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
AssignmentFinder_SMT.cpp
Go to the documentation of this file.
1 #include "AssignmentFinder_SMT.h"
2 
5 
6 namespace smtrat {
7 namespace mcsat {
8 namespace smtaf {
9 
10 struct SMTModule : public Manager
11 {
13  {
14  setStrategy({
15  addBackend<LRAModule<LRASettings1>>()
16  });
17  }
18 };
19 
20 inline bool includes(const VariableRange& superset, const carl::Variables& subset) {
21  for (const auto& var : subset) {
22  if (std::find(superset.first, superset.second, var) == superset.second) {
23  return false;
24  }
25  }
26  return true;
27 }
28 
30  ModelValues values;
31  for (auto varIter = mVariables.first; varIter != mVariables.second; varIter++) {
32  if (model.find(*varIter) != model.end()) {
33  values.push_back(std::make_pair(*varIter, model.at(*varIter)));
34  }
35  }
36  return values;
37 }
38 
39 std::variant<VariablePos,bool> AssignmentFinder_SMT::level(const FormulaT& constraint) const {
40  bool lowerLevelFound = false;
41  auto highestLevel = mVariables.first;
42  for (const auto& var : constraint.variables()) {
43  auto currentVarInOrdering = std::find(mVariables.first, mVariables.second, var);
44  if (currentVarInOrdering == mVariables.second) { // variable not found
45  if (mModel.find(var) != mModel.end()) { // level is lower than current range
46  lowerLevelFound = true;
47  } else { // level is higher
48  return true;
49  }
50  }
51  else if (highestLevel < currentVarInOrdering) {
52  highestLevel = currentVarInOrdering;
53  }
54  }
55  if (lowerLevelFound) return false;
56  return highestLevel;
57 }
58 
60  assert(f.type() == carl::FormulaType::CONSTRAINT);
61 
63  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Constraint " << f << " evaluated to " << fnew);
64  if (fnew.type() == carl::FormulaType::CONSTRAINT) {
65  assert(fnew.variables().size() > 0);
66  auto lvl = level(fnew);
67  if (std::holds_alternative<VariablePos>(lvl)) {
68  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Considering constraint " << f << " for level " << *std::get<VariablePos>(lvl) << ".");
69  mConstraints[std::get<VariablePos>(lvl)].push_back(fnew);
70  mEvaluatedConstraints[fnew] = f;
71  mFreeConstraintVars[std::get<VariablePos>(lvl)].insert(fnew.variables().begin(), fnew.variables().end());
72  return true;
73  } else if (std::get<bool>(lvl) == true) {
74  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Ignoring constraint " << f << " because it has more unassigned variables than in the current range.");
75  return true;
76  } else {
77  assert(std::get<bool>(lvl) == false);
78  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Constraint " << f << " did not fully evaluate under the current model");
79  return boost::indeterminate;
80  }
81  } else if (fnew.is_true()) {
82  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Ignoring " << f << " which simplified to true.");
83  return true;
84  } else {
85  assert(fnew.is_false());
86  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Conflict: " << f << " simplified to false.");
87  return false;
88  }
89  assert(false);
90 }
91 
92 boost::tribool AssignmentFinder_SMT::addMVBound(const FormulaT& f) {
93  assert(f.type() == carl::FormulaType::VARCOMPARE);
94 
95  // A VariableComparison is of the form y ~ RAN or y ~ MVRoot(i,p) where p is in variables x_1,...,x_n
96  // and x_1,...,x_n are of lower level according to the current variable ordering.
97  // Thus, if y is not in the variable range, then:
98  // * If y is of lower level (according to the variable ordering): Then, we can evaluate it and it
99  // evaluates either to true (and can be ignored) or false (conflict found).
100  // * If y is of higher level: Then, the bound can be ignored.
101  // If y is in the variable range, then:
102  // * If the MVRoot or RAN evaluates to a Rational, we can simplify it to a Constraint y ~ Rational,
103  // * otherwise, this method fails.
104 
105  VariablePos lvl = std::find(mVariables.first, mVariables.second, f.variable_comparison().var());
106  if (lvl == mVariables.second) {
107  if (mModel.find(f.variable_comparison().var()) != mModel.end()) {
108  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Evaluating " << f);
109  FormulaT fnew(carl::substitute(f, mModel));
110  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "-> " << fnew);
111  if (fnew.is_true()) {
112  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Bound evaluated to true, we can ignore it.");
113  return true;
114  } else if (fnew.is_false()) {
115  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
116  return false;
117  } else { // not fully evaluated => not possible, as all variables are assigned
118  assert(false);
119  }
120  } else {
121  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Ignoring bound " << f << " of higher level");
122  return true;
123  }
124  } else { // the bound's level is potentially in the range to be checked
125  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Evaluating " << f);
126  FormulaT fnew(carl::substitute(f, mModel));
127  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "-> " << fnew);
128  if (fnew.is_true()) {
129  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Bound evaluated to true, we can ignore it.");
130  return true;
131  } else if (fnew.is_false()) {
132  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
133  return false;
134  } else {
135  assert(fnew.type() == carl::FormulaType::VARCOMPARE);
136 
137  ModelValue value = fnew.variable_comparison().value();
138  if (value.isSubstitution()) {
139  auto res = value.asSubstitution()->evaluate(mModel);
140  value = res;
141  }
142  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Evaluated to " << value);
143 
144  if (value.isRational()) {
145  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Value is Rational, can convert to Constraint");
146  auto rel = fnew.variable_comparison().negated() ? carl::inverse(fnew.variable_comparison().relation()) : fnew.variable_comparison().relation();
147  ConstraintT constr(Poly(fnew.variable_comparison().var()) - value.asRational(), rel);
148  FormulaT fnewnew = FormulaT(constr);
149  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Considering constraint " << fnewnew);
150  mConstraints[lvl].push_back(fnewnew);
151  mEvaluatedConstraints[fnewnew] = f;
152  mFreeConstraintVars[lvl].insert(fnew.variable_comparison().var());
153  return true;
154  } else {
155  return boost::indeterminate;
156  }
157  }
158  }
159  assert(false);
160  return boost::indeterminate;
161 }
162 
163 std::optional<AssignmentOrConflict> AssignmentFinder_SMT::findAssignment(const VariablePos excludeVar) const {
164  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Look for assignment on level " << *(excludeVar-1));
165 
166  // set all variables to zero that do not occur in the given constraints
167  Model model;
168  bool freeVariables = false;
169  for (auto varIter = mVariables.first; varIter != excludeVar; varIter++) {
170  bool found = false;
171  for (auto iter = mVariables.first; iter != excludeVar; iter++) {
172  if (mFreeConstraintVars.at(iter).find(*varIter) != mFreeConstraintVars.at(iter).end()) {
173  found = true;
174  break;
175  }
176  }
177  if (!found) {
178  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Variable " << *varIter << " does not occur in constraint set, assigning to 0");
179  model.assign(*varIter, Rational(0));
180  } else {
181  freeVariables = true;
182  }
183  }
184 
185  if (!freeVariables) {
186  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "No free variables left, returning " << model);
188  } else {
189  SMTModule smtModule;
190  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Calling SMT backend");
191  smtModule.push();
192  for (auto iter = mVariables.first; iter != excludeVar; iter++) {
193  for (const auto& constraint : mConstraints.at(iter)) {
194  smtModule.add(constraint);
195  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "-> Consider " << constraint);
196  }
197  }
198  Answer answer = smtModule.check();
199  if (answer == UNKNOWN || answer == ABORTED) {
200  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Backend could not solve instance");
201  return std::nullopt;
202  } else if (answer == SAT) {
203  assert(smtModule.model().size() > 0);
204  model.update(smtModule.model());
205  // assign all remaining vars to 0, if any
206  for (auto iter = mVariables.first; iter != excludeVar; iter++) {
207  if (model.find(*iter) == model.end()) {
208  model.assign(*iter, Rational(0));
209  }
210  }
211  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Found assignment " << model);
213  } else if (answer == UNSAT) {
214  assert(smtModule.infeasibleSubsets().size() > 0);
215  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "No assignment found, conflicting core (after evaluation under current model) is " << smtModule.infeasibleSubsets()[0]);
216  const auto& infSubset = smtModule.infeasibleSubsets()[0];
217  FormulasT infCore;
218  for (const auto& feval : infSubset) {
219  infCore.push_back(mEvaluatedConstraints.at(feval));
220  }
221  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Conflicting core is " << infCore);
222  return AssignmentOrConflict(std::move(infCore));
223  } else {
224  assert(false);
225  }
226  }
227  assert(false);
228  return std::nullopt;
229 }
230 
231 std::optional<AssignmentOrConflict> AssignmentFinder_SMT::findAssignment() const {
232  for (auto curVar = mVariables.first; curVar != mVariables.second; curVar++) {
233  auto res = findAssignment(curVar+1);
234  if (res) {
235  // if a conflict has been found OR we looked at the last variable, we return the result
236  if (std::holds_alternative<FormulasT>(*res) || curVar == mVariables.second - 1) {
237  SMTRAT_LOG_DEBUG("smtrat.mcsat.smtaf", "Found result");
238  return res;
239  }
240  } else {
241  return std::nullopt;
242  }
243  }
244  assert(false);
245  return std::nullopt;
246 }
247 
248 }
249 }
250 }
Base class for solvers.
Definition: Manager.h:34
void push()
Pushes a backtrack point to the stack of backtrack points.
Definition: Manager.h:142
const std::vector< FormulaSetT > & infeasibleSubsets() const
Definition: Manager.cpp:122
void setStrategy(const std::initializer_list< BackendLink > &backends)
Definition: Manager.h:385
bool add(const FormulaT &_subformula, bool _containsUnknownConstraints=true)
Adds the given formula to the conjunction of formulas, which will be considered for the next satisfia...
Definition: Manager.cpp:86
Answer check(bool _full=true)
Checks the so far added formulas for satisfiability.
Definition: Manager.cpp:115
const Model & model() const
Definition: Manager.cpp:132
boost::tribool addConstraint(const FormulaT &f)
std::optional< AssignmentOrConflict > findAssignment() const
std::variant< VariablePos, bool > level(const FormulaT &constraint) const
std::map< VariablePos, FormulasT > mConstraints
std::unordered_map< FormulaT, FormulaT > mEvaluatedConstraints
boost::tribool addMVBound(const FormulaT &f)
std::map< VariablePos, carl::Variables > mFreeConstraintVars
ModelValues modelToAssignment(const Model &model) const
int var(Lit p)
Definition: SolverTypes.h:64
static bool find(V &ts, const T &t)
Definition: Alg.h:47
std::vector< carl::Variable >::const_iterator VariablePos
bool includes(const VariableRange &superset, const carl::Variables &subset)
std::pair< VariablePos, VariablePos > VariableRange
bool substitute(const FormulaT &constr, const carl::Variable var, const carl::vs::Term< Poly > &term, FormulaT &result)
Definition: VSHelper.h:138
std::vector< std::pair< carl::Variable, ModelValue > > ModelValues
Definition: smtrat-mcsat.h:12
std::variant< ModelValues, FormulasT > AssignmentOrConflict
Definition: smtrat-mcsat.h:13
Class to create the formulas for axioms.
carl::ModelValue< Rational, Poly > ModelValue
Definition: model.h:12
carl::Formula< Poly > FormulaT
Definition: types.h:37
carl::Model< Rational, Poly > Model
Definition: model.h:13
carl::MultivariatePolynomial< Rational > Poly
Definition: types.h:25
Answer
An enum with the possible answers a Module can give.
Definition: types.h:57
@ UNKNOWN
Definition: types.h:57
@ ABORTED
Definition: types.h:57
carl::Constraint< Poly > ConstraintT
Definition: types.h:29
carl::Formulas< Poly > FormulasT
Definition: types.h:39
mpq_class Rational
Definition: types.h:19
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35