SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
AssignmentFinder_ctx.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 #include <carl-arith/ran/Conversion.h>
11 #include <carl-arith/extended/Conversion.h>
12 #include <carl-arith/constraint/Conversion.h>
13 
14 
15 
16 #include <algorithm>
17 
18 namespace smtrat {
19 namespace mcsat {
20 namespace arithmetic {
21 
22 using carl::operator<<;
23 
25 #ifdef USE_LIBPOLY
26 using Polynomial = carl::LPPolynomial;
27 #else
28 using Polynomial = carl::ContextPolynomial<Rational>;
29 #endif
30 
31 private:
32  typename Polynomial::ContextType m_context;
33  carl::Variable m_var;
34  carl::Assignment<typename Polynomial::RootType> m_assignment;
36  /**
37  * Maps the input formula to the list of real roots and the simplified formula where m_assignment was substituted.
38  */
39  std::map<FormulaT, std::pair<std::vector<typename Polynomial::RootType>, std::variant<carl::BasicConstraint<Polynomial>, carl::VariableComparison<Polynomial>>>> m_root_map;
40 
41  bool satisfies(const std::variant<carl::BasicConstraint<Polynomial>, carl::VariableComparison<Polynomial>>& f, const typename Polynomial::RootType& r) const {
42  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", f << ", " << m_assignment << ", " << m_var << ", " << r);
43  auto m = m_assignment;
44  m.emplace(m_var, r);
45  auto res = std::visit([&](auto&& arg) { return carl::evaluate(arg, m); }, f);
46  assert(!indeterminate(res));
47  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Evaluating " << f << " on " << m << " -> " << res);
48  return (bool)res;
49  }
50 
51  bool compare_assignments(std::size_t lhs, std::size_t rhs) const {
52  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", lhs << " < " << rhs << "?");
53  const auto& l = m_ri.sampleFrom(lhs);
54  const auto& r = m_ri.sampleFrom(rhs);
55  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", l << " (" << m_ri.is_root(lhs) << ") < " << r << " (" << m_ri.is_root(rhs) << ") ?");
56  // this is more like z3, but performs worse:
57  // if ((l.is_integer() || l.is_numeric()) && (r.is_integer() || r.is_numeric()) && (m_ri.is_root(lhs) != m_ri.is_root(rhs))) return !m_ri.is_root(lhs);
58  // even the opposite performs better (but not better than not respecting samples being a root):
59  // if ((l.is_integer() || l.is_numeric()) && (r.is_integer() || r.is_numeric()) && (m_ri.is_root(lhs) != m_ri.is_root(rhs))) return m_ri.is_root(lhs);
60  if (carl::is_integer(l) != carl::is_integer(r)) return carl::is_integer(l);
61  if (l.is_numeric() != r.is_numeric()) return l.is_numeric();
62  if (carl::bitsize(l) != carl::bitsize(r)) return carl::bitsize(l) < carl::bitsize(r);
63  if (carl::abs(l) != carl::abs(r)) return carl::abs(l) < carl::abs(r);
64  return l < r;
65  }
66 
67  auto select_assignment(const Covering& cover) const {
68  std::vector<std::size_t> samples;
69  for (auto b: cover.satisfyingSamples()) {
70  samples.push_back(b);
71  }
72  assert(samples.size() > 0);
73  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Finding minimum from " << samples);
74  auto min = std::min_element(samples.begin(), samples.end(), [this](auto lhs, auto rhs){ return this->compare_assignments(lhs, rhs); });
75  return m_ri.sampleFrom(*min);
76  }
77 
78  bool fits_context(const FormulaT& f) {
79  for (const auto& v : f.variables()) {
80  if (std::find(m_context.variable_ordering().begin(), m_context.variable_ordering().end(), v) == m_context.variable_ordering().end()) {
81  return false;
82  }
83  }
84  return true;
85  }
86 
87 public:
88  AssignmentFinder_ctx(const std::vector<carl::Variable>& var_order, carl::Variable var, const Model& model): m_context(var_order), m_var(var) {
89  for (const auto& e : get_ran_assignment(model)) {
90  m_assignment.emplace(e.first, carl::convert<typename Polynomial::RootType>(e.second));
91  }
92  }
93 
94  bool addConstraint(const FormulaT& f1) {
95  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Adding " << f1);
96  if (!fits_context(f1)) {
97  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f1 << " contains too many variables for context " << m_context);
98  return true;
99  }
100  auto f = carl::convert<Polynomial>(m_context, f1.constraint().constr());
101  if (f.is_trivial_true() || f.is_trivial_false()) {
102  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f << " is constant " << f.is_trivial_true());
103  return f.is_trivial_true();
104  } else if (f.lhs().main_var() == m_var) {
105  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Considering univariate constraint " << f << " under " << m_assignment);
106  std::vector<typename Polynomial::RootType> list;
107  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Real roots of " << f.lhs() << " in " << m_var << " w.r.t. " << m_assignment);
108  auto roots = carl::real_roots(f.lhs(), m_assignment);
109  if (roots.is_univariate()) {
110  list = roots.roots();
111  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Adding " << list);
112  m_ri.add(list);
113  m_root_map.emplace(f1, std::move(std::make_pair(list, f)));
114  return true;
115  } else {
116  assert(roots.is_nullified());
117  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Failed to compute roots because polynomial is nullified.");
118  if (carl::evaluate(carl::Sign::ZERO, f.relation())) {
119  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f << " simplified to true.");
120  return true;
121  } else {
122  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
123  return false;
124  }
125  }
126  } else if (m_assignment.find(f.lhs().main_var()) != m_assignment.end()) {
127  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f << " evaluates under " << m_assignment);
128  auto res = carl::evaluate(f, m_assignment);
129  assert(!indeterminate(res));
130  if (res) {
131  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Ignoring " << f << " which simplified to true.");
132  return true;
133  } else {
134  assert(!res);
135  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
136  return false;
137  }
138  } else {
139  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Ignoring unassigned constraint " << f << " under " << m_assignment);
140  return true;
141  }
142  }
143 
144  bool addMVBound(const FormulaT& f1) {
145  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Adding " << f1);
146  if (!fits_context(f1)) {
147  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f1 << " contains too many variables for context " << m_context);
148  return true;
149  }
150  auto f = carl::convert<Polynomial>(m_context, f1.variable_comparison());
151  assert(std::get<carl::MultivariateRoot<Polynomial>>(f.value()).var() == f.var());
152  if (f.var() == m_var) {
153  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f << " is univariate under " << m_assignment);
154  auto value = carl::evaluate(std::get<carl::MultivariateRoot<Polynomial>>(f.value()), m_assignment);
155  if (!value) {
156  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " is not well-defined.");
157  return f.negated();
158  } else {
159  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Evaluated to " << *value);
160  std::vector<typename Polynomial::RootType> list;
161  list.push_back(*value);
162  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Adding " << list << " with " << f);
163  m_ri.add(list);
164  m_root_map.emplace(f1, std::make_pair(std::move(list), f));
165  return true;
166  }
167  } else if (m_assignment.find(f.var()) != m_assignment.end()) {
168  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", f << " evaluates under " << m_assignment);
169  auto res = carl::evaluate(f, m_assignment);
170  if (indeterminate(res)) {
171  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " is not well-defined.");
172  return f.negated();
173  } else if (res) {
174  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", "Ignoring " << f << " which simplified to true.");
175  return true;
176  } else {
177  assert(!res);
178  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Conflict: " << f << " simplified to false.");
179  return false;
180  }
181  } else {
182  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Ignoring unassigned bound " << f << " under " << m_assignment);
183  return true;
184  }
185  }
186 
188  m_ri.process();
189  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", m_ri);
190  Covering cover(m_ri.size() * 2 + 1);
191  for (const auto& c: m_root_map) {
192  carl::Bitset b;
193  const auto& roots = c.second.first; // sorted
194  const auto& constraint = c.second.second;
195  std::size_t last = 0;
196  for (const auto& r: roots) {
197  std::size_t cur = m_ri[r];
198  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", constraint << " vs " << m_ri.sampleFrom(2*cur));
199  if (!satisfies(constraint, m_ri.sampleFrom(2*cur))) {
200  // Refutes interval left of this root
201  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << m_ri.sampleFrom(2*cur) << " -> " << last << ".." << (2*cur));
202  b.set_interval(last, 2*cur);
203  }
204  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", constraint << " vs " << m_ri.sampleFrom(2*cur+1));
205  if (!satisfies(constraint, r)) {
206  // Refutes root
207  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << r << " -> " << 2*cur+1);
208  b.set(2*cur+1, 2*cur+1);
209  }
210  last = 2*cur + 2;
211  }
212  SMTRAT_LOG_TRACE("smtrat.mcsat.assignmentfinder", constraint << " vs " << m_ri.sampleFrom(last));
213  if (!satisfies(constraint, m_ri.sampleFrom(last))) {
214  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << m_ri.sampleFrom(last) << " which is " << m_ri.sampleFrom(roots.size()*2));
215  // Refutes interval right of largest root
216  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", constraint << " refutes " << m_ri.sampleFrom(roots.size()*2) << " -> " << last << ".." << (m_ri.size()*2));
217  b.set_interval(last, m_ri.size()*2);
218  }
219  if (b.any()) {
220  cover.add(c.first, b);
221  }
222  }
223  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", cover);
224  return cover;
225  }
226 
228  Covering cover = computeCover();
229  if (cover.conflicts()) {
230  FormulasT conflict;
231  cover.buildConflictingCore(conflict);
232  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "No Assignment, built conflicting core " << conflict << " under model " << m_assignment);
233  return conflict;
234  } else {
235  ModelValue assignment = carl::convert<RAN>(select_assignment(cover));
236  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Assignment: " << m_var << " = " << assignment << " from interval " << cover.satisfyingInterval());
237  assert(assignment.isRAN());
238  if (assignment.asRAN().is_numeric()) {
239  assignment = assignment.asRAN().value();
240  }
241  SMTRAT_LOG_DEBUG("smtrat.mcsat.assignmentfinder", "Assignment: " << m_var << " = " << assignment);
242  ModelValues res;
243  res.push_back(std::make_pair(m_var,assignment));
244  return res;
245  }
246  }
247 
248 };
249 
250 }
251 }
252 }
RootIndexer< typename Polynomial::RootType > m_ri
std::map< FormulaT, std::pair< std::vector< typename Polynomial::RootType >, std::variant< carl::BasicConstraint< Polynomial >, carl::VariableComparison< Polynomial > > > > m_root_map
Maps the input formula to the list of real roots and the simplified formula where m_assignment was su...
bool compare_assignments(std::size_t lhs, std::size_t rhs) const
auto select_assignment(const Covering &cover) const
AssignmentFinder_ctx(const std::vector< carl::Variable > &var_order, carl::Variable var, const Model &model)
carl::ContextPolynomial< Rational > Polynomial
bool satisfies(const std::variant< carl::BasicConstraint< Polynomial >, carl::VariableComparison< Polynomial >> &f, const typename Polynomial::RootType &r) const
carl::Assignment< typename Polynomial::RootType > m_assignment
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
static bool find(V &ts, const T &t)
Definition: Alg.h:47
auto get(const It &it, level)
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
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::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