SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
AssignmentFinder_arithmetic.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "Covering.h"
4 #include "RootIndexer.h"
5 
8 #include <carl-formula/model/Assignment.h>
9 
10 
11 #include <algorithm>
12 
13 namespace smtrat {
14 namespace mcsat {
15 namespace arithmetic {
16 
17 using carl::operator<<;
18 
20 private:
21  carl::Variable mVar;
22  const Model& mModel;
24  /**
25  * Maps the input formula to the list of real roots and the simplified formula where mModel was substituted.
26  */
27  std::map<FormulaT, std::pair<std::vector<RAN>, FormulaT>> mRootMap;
28  std::vector<FormulaT> mMVBounds;
29 
30  /// Checks whether a formula is univariate, meaning it contains mVar and only variables from mModel otherwise.
31  bool is_univariate(const FormulaT& f) const {
33  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "is " << f << " univariate in " << mVar << "?");
34  carl::Variables vars = carl::arithmetic_variables(f).as_set();
35  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Collected " << vars);
36  auto it = vars.find(mVar);
37  if (it == vars.end()) return false;
38  vars.erase(it);
39  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Checking whether " << mModel << " covers " << vars);
40  return mModel.contains(vars);
41  }
42  bool satisfies(const FormulaT& f, const RAN& r) const {
43  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", f << ", " << mModel << ", " << mVar << ", " << r);
44  Model m = mModel;
45  m.assign(mVar, r);
46  auto res = carl::evaluate(f, m);
47  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Evaluating " << f << " on " << m << " -> " << res);
48  if (!res.isBool()) return true;
49  assert(res.isBool());
50  return res.asBool();
51  }
52 
53  bool compare_assignments(std::size_t lhs, std::size_t rhs) const {
54  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", lhs << " < " << rhs << "?");
55  const auto& l = mRI.sampleFrom(lhs);
56  const auto& r = mRI.sampleFrom(rhs);
57  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", l << " (" << mRI.is_root(lhs) << ") < " << r << " (" << mRI.is_root(rhs) << ") ?");
58  // this is more like z3, but performs worse:
59  // if ((l.is_integer() || l.is_numeric()) && (r.is_integer() || r.is_numeric()) && (mRI.is_root(lhs) != mRI.is_root(rhs))) return !mRI.is_root(lhs);
60  // even the opposite performs better (but not better than not respecting samples being a root):
61  // if ((l.is_integer() || l.is_numeric()) && (r.is_integer() || r.is_numeric()) && (mRI.is_root(lhs) != mRI.is_root(rhs))) return mRI.is_root(lhs);
62  if (carl::is_integer(l) != carl::is_integer(r)) return carl::is_integer(l);
63  if (l.is_numeric() != r.is_numeric()) return l.is_numeric();
64  if (carl::bitsize(l) != carl::bitsize(r)) return carl::bitsize(l) < carl::bitsize(r);
65  if (carl::abs(l) != carl::abs(r)) return carl::abs(l) < carl::abs(r);
66  return l < r;
67  }
68 
69  ModelValue selectAssignment(const Covering& cover) const {
70  std::vector<std::size_t> samples;
71  for (auto b: cover.satisfyingSamples()) {
72  samples.push_back(b);
73  }
74  assert(samples.size() > 0);
75  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Finding minimum from " << samples);
76  auto min = std::min_element(samples.begin(), samples.end(), [this](auto lhs, auto rhs){ return this->compare_assignments(lhs, rhs); });
77  return mRI.sampleFrom(*min);
78  }
79 
80 public:
81  AssignmentFinder_detail(carl::Variable var, const Model& model): mVar(var), mModel(model) {}
82 
83  bool addConstraint(const FormulaT& f) {
84  assert(f.type() == carl::FormulaType::CONSTRAINT);
85  auto category = mcsat::constraint_type::categorize(f, mModel, mVar);
86  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f << " is " << category << " under " << mModel << " w.r.t. " << mVar);
87  switch (category) {
89  assert(f.is_true() || f.is_false());
90  if (f.is_false()) return false;
91  break;
93  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Checking fully assigned " << f);
94  FormulaT fnew = carl::substitute(f, mModel);
95  if (fnew.is_true()) {
96  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Ignoring " << f << " which simplified to true.");
97  return true;
98  } else {
99  assert(fnew.is_false());
100  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
101  return false;
102  }
103  break;
104  }
106  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Considering univariate constraint " << f);
107  break;
109  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Considering unassigned constraint " << f << " (which may still become univariate)");
110  return true;
111  break;
112  }
113  FormulaT fnew(carl::substitute(f, mModel));
114  std::vector<RAN> list;
115  if (fnew.type() == carl::FormulaType::CONSTRAINT) {
116  const auto& poly = fnew.constraint().lhs();
117  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Real roots of " << poly << " in " << mVar << " w.r.t. " << mModel);
118  auto upoly = carl::to_univariate_polynomial(poly, mVar);
119  auto polyvars = carl::variables(upoly);
120  polyvars.erase(mVar);
121  auto roots = carl::real_roots(upoly, *carl::get_ran_assignment(polyvars, mModel));
122  if (roots.is_univariate()) {
123  list = roots.roots();
124  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "-> " << list);
125  } else {
126  assert(roots.is_nullified());
127  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Failed to compute roots because polynomial is nullified.");
128  if (carl::evaluate(carl::Sign::ZERO, fnew.constraint().relation())) {
129  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f << " simplified to true.");
130  return true;
131  } else {
132  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
133  return false;
134  }
135  }
136  } else if (fnew.is_true()) {
137  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Ignoring " << f << " which simplified to true.");
138  return true;
139  } else {
140  assert(fnew.is_false());
141  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
142  return false;
143  }
144 
145  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Adding " << list << " with " << fnew);
146  mRI.add(list);
147  mRootMap.emplace(f, std::make_pair(std::move(list), fnew));
148  return true;
149  }
150 
151  bool addMVBound(const FormulaT& f) {
152  assert(f.type() == carl::FormulaType::VARCOMPARE);
153  if (!is_univariate(f)) {
154  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Ignoring non-univariate bound " << f);
155  return true;
156  }
157  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Adding univariate bound " << f);
158  FormulaT fnew(carl::substitute(f, mModel));
159  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "-> " << fnew);
160  if (fnew.is_true()) {
161  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Bound evaluated to true, we can ignore it.");
162  return true;
163  } else if (fnew.is_false()) {
164  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
165  return false;
166  }
167  assert(fnew.type() == carl::FormulaType::VARCOMPARE);
168  ModelValue value = fnew.variable_comparison().value();
169  if (value.isSubstitution()) {
170  // Prevent memory error due to deallocation of shared_ptr before copying value from shared_ptr.
171  auto res = value.asSubstitution()->evaluate(mModel);
172  value = res;
173  }
174  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Evaluated to " << value);
175  if (!value.isRational() && !value.isRAN()) {
176  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Value is neither rational nor RAN, cannot generate roots from it");
177  if (value.isBool()) {
178  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "But it is bool");
179  assert(false);
180  }
181  mMVBounds.emplace_back(fnew);
182  return true;
183  }
184  std::vector<RAN> list;
185  if (value.isRational()) list.emplace_back(value.asRational());
186  else list.push_back(value.asRAN());
187  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Adding " << list << " with " << fnew);
188  mRI.add(list);
189  mRootMap.emplace(f, std::make_pair(std::move(list), fnew));
190  return true;
191  }
192 
194  mRI.process();
195  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", mRI);
196  Covering cover(mRI.size() * 2 + 1);
197  for (const auto& c: mRootMap) {
198  carl::Bitset b;
199  const auto& roots = c.second.first; // sorted
200  const auto& constraint = c.second.second;
201  std::size_t last = 0;
202  for (const auto& r: roots) {
203  std::size_t cur = mRI[r];
204  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", constraint << " vs " << mRI.sampleFrom(2*cur));
205  if (!satisfies(constraint, mRI.sampleFrom(2*cur))) {
206  // Refutes interval left of this root
207  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << mRI.sampleFrom(2*cur) << " -> " << last << ".." << (2*cur));
208  b.set_interval(last, 2*cur);
209  }
210  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", constraint << " vs " << mRI.sampleFrom(2*cur+1));
211  if (!satisfies(constraint, r)) {
212  // Refutes root
213  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << r << " -> " << 2*cur+1);
214  b.set(2*cur+1, 2*cur+1);
215  }
216  last = 2*cur + 2;
217  }
218  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", constraint << " vs " << mRI.sampleFrom(last));
219  if (!satisfies(constraint, mRI.sampleFrom(last))) {
220  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << mRI.sampleFrom(last) << " which is " << mRI.sampleFrom(roots.size()*2));
221  // Refutes interval right of largest root
222  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << mRI.sampleFrom(roots.size()*2) << " -> " << last << ".." << (mRI.size()*2));
223  b.set_interval(last, mRI.size()*2);
224  }
225  if (b.any()) {
226  cover.add(c.first, b);
227  }
228  }
229  // Handling multivariate bounds this way is unsoud: A consistent assignment may exist for these bounds,
230  // but cannot be found by the assignment finder. Thus, satisfying cells may be excluded.
231  // Currently, these bounds are disabled in the BaseBackend/Bookkeeping, but they may be handled using
232  // the CAD.
233  assert(mMVBounds.empty());
234  /*
235  for (const auto& c: mMVBounds) {
236  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Computing cover for " << c);
237  carl::Bitset b;
238  for (std::size_t i = 0; i < mRI.size() * 2 + 1; ++i) {
239  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", c << " vs " << mRI.sampleFrom(i));
240 
241  Model m = mModel;
242  m.assign(mVar, mRI.sampleFrom(i));
243  auto res = carl::evaluate(c, m);
244  if (!res.isBool()) {
245  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", c << " is inconclusive on " << mRI.sampleFrom(i));
246  } else if (!res.asBool()) {
247  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", c << " refutes " << mRI.sampleFrom(i));
248  b.set(i);
249  }
250  }
251  if (b.any()) {
252  cover.add(c, b);
253  }
254  }
255  */
256  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", cover);
257  return cover;
258  }
259 
261  Covering cover = computeCover();
262  if (cover.conflicts()) {
263  FormulasT conflict;
264  cover.buildConflictingCore(conflict);
265  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "No Assignment, built conflicting core " << conflict << " under model " << mModel);
266  return conflict;
267  } else {
268  ModelValue assignment = selectAssignment(cover);
269  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Assignment: " << mVar << " = " << assignment << " from interval " << cover.satisfyingInterval());
270  assert(assignment.isRAN());
271  if (assignment.asRAN().is_numeric()) {
272  assignment = assignment.asRAN().value();
273  }
274  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Assignment: " << mVar << " = " << assignment);
275  ModelValues res;
276  res.push_back(std::make_pair(mVar,assignment));
277  return res;
278  }
279  }
280 
281 };
282 
283 }
284 }
285 }
AssignmentFinder_detail(carl::Variable var, const Model &model)
std::map< FormulaT, std::pair< std::vector< RAN >, FormulaT > > mRootMap
Maps the input formula to the list of real roots and the simplified formula where mModel was substitu...
bool compare_assignments(std::size_t lhs, std::size_t rhs) const
bool is_univariate(const FormulaT &f) const
Checks whether a formula is univariate, meaning it contains mVar and only variables from mModel other...
bool satisfies(const FormulaT &f, const RAN &r) const
ModelValue selectAssignment(const Covering &cover) const
Semantics: The space is divided into a number of intervals: (-oo,a)[a,a](a,b)[b,b](b,...
Definition: Covering.h:19
void buildConflictingCore(std::vector< FormulaT > &core) const
Definition: Covering.h:41
const auto & satisfyingSamples() const
Definition: Covering.h:38
void add(const FormulaT &c, const carl::Bitset &b)
Definition: Covering.h:28
std::size_t satisfyingInterval() const
Definition: Covering.h:35
void add(const std::vector< RANT > &list)
Definition: RootIndexer.h:21
bool is_root(std::size_t n) const
Definition: RootIndexer.h:56
const RANT & sampleFrom(std::size_t n) const
Definition: RootIndexer.h:53
int var(Lit p)
Definition: SolverTypes.h:64
Polynomial::RootType RAN
Definition: common.h:24
Numeric abs(const Numeric &_value)
Calculates the absolute value of the given Numeric.
Definition: Numeric.cpp:276
Rational evaluate(carl::Variable v, const Poly &p, const Rational &r)
Definition: utils.h:11
bool is_univariate(const T &t, const Model &model, carl::Variable next)
Checks whether the constraint contains only a single unassigned variable, and this is the next one.
ConstraintType categorize(const T &t, const Model &model, carl::Variable next)
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
@ Unassigned
The constraint has a single unassigned variable being the next one.
@ Univariate
The constraint is fully assigned.
@ Assigned
The constraint contains no variables.
std::variant< ModelValues, FormulasT > AssignmentOrConflict
Definition: smtrat-mcsat.h:13
std::vector< carl::Variable > vars(const std::pair< QuantifierType, std::vector< carl::Variable >> &p)
Definition: QEQuery.h:43
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::Formulas< Poly > FormulasT
Definition: types.h:39
#define SMTRAT_LOG_TRACE(channel, msg)
Definition: logging.h:36
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35