SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
FormulaEvaluationGraph.cpp
Go to the documentation of this file.
2 
3 #include <carl-arith/constraint/Conversion.h>
4 #include <carl-arith/ran/Conversion.h>
5 
6 #include <carl-common/util/streamingOperators.h>
7 
8 #include "CoveringNGStatistics.h"
9 
11 using carl::operator<<;
12 
13 namespace formula_ds {
14 
15 // helper type for the visitor
16 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
17 // explicit deduction guide (not needed as of C++20)
18 template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
19 
20 void print(std::ostream& stream, const FormulaDB& db, const FormulaID id, const std::size_t level) {
21  std::visit(overloaded{
22  [&](const TRUE&) {
23  stream << std::string(level, ' ') << "TRUE";
24  },
25  [&](const FALSE&) {
26  stream << std::string(level, ' ') << "FALSE";
27  },
28  [&](const NOT& c) {
29  stream << std::string(level, ' ') << "NOT(" << std::endl;
30  print(stream, db, c.subformula, level+1);
31  stream << std::endl << std::string(level, ' ') << ")";
32  },
33  [&](const AND& c) {
34  stream << std::string(level, ' ') << "AND(" << std::endl;
35  for (const auto subformula : c.subformulas) {
36  print(stream, db, subformula, level+1);
37  stream << std::endl;
38  }
39  stream << std::string(level, ' ') << ")";
40  },
41  [&](const OR& c) {
42  stream << std::string(level, ' ') << "OR(" << std::endl;
43  for (const auto subformula : c.subformulas) {
44  print(stream, db, subformula, level+1);
45  stream << std::endl;
46  }
47  stream << std::string(level, ' ') << ")";
48  },
49  [&](const IFF& c) {
50  stream << std::string(level, ' ') << "IFF(" << std::endl;
51  for (const auto subformula : c.subformulas) {
52  print(stream, db, subformula, level+1);
53  stream << std::endl;
54  }
55  stream << std::string(level, ' ') << ")";
56  },
57  [&](const XOR& c) {
58  stream << std::string(level, ' ') << "XOR(" << std::endl;
59  for (const auto subformula : c.subformulas) {
60  print(stream, db, subformula, level+1);
61  stream << std::endl;
62  }
63  stream << std::string(level, ' ') << ")";
64  },
65  [&](const BOOL& c) {
66  stream << std::string(level, ' ') << c.variable;
67  },
68  [&](const CONSTRAINT& c) {
69  stream << std::string(level, ' ') << c.constraint;
70  },
71  }, db[id].content);
72 
73  std::size_t spacing = 50 - level;
74  if (level > 50) spacing = 4;
75 
76  stream << std::string(spacing, ' ') << "id: " << id << " T: " << db[id].reasons_true << " F: " << db[id].reasons_false;
77 }
78 
79 void log(const FormulaDB& db, const FormulaID id) {
80  std::stringstream ss;
81  ss << std::endl;
82  print(ss, db, id, 0);
83  ss << std::endl;
84  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", ss.str());
85 }
86 
87 
88 FormulaID to_formula_db(cadcells::datastructures::Projections& c, const FormulaT& f, FormulaDB& db, VariableToFormula& vartof, std::map<std::size_t,FormulaID>& cache) {
89  {
90  auto cache_it = cache.find(f.id());
91  if (cache_it != cache.end()) return cache_it->second;
92  }
93 
94  assert(db.size() < std::numeric_limits<FormulaID>::max());
95 
96  if (f.id() > f.negated().id()) {
97  auto child = to_formula_db(c,f.negated(),db,vartof, cache);
98  db.emplace_back(NOT{ child });
99  db[child].parents.insert((FormulaID)(db.size()-1));
100  cache.emplace(f.id(), (FormulaID)(db.size()-1));
101  return (FormulaID)(db.size()-1);
102  }
103 
104  switch(f.type()) {
105  case carl::FormulaType::ITE: {
106  auto id = to_formula_db(c, FormulaT(carl::FormulaType::OR, FormulaT(carl::FormulaType::AND, f.condition(), f.first_case()), FormulaT(carl::FormulaType::AND, f.condition().negated(), f.second_case())), db, vartof, cache);
107  cache.emplace(f.id(), id);
108  return id;
109  }
110  case carl::FormulaType::TRUE: {
111  db.emplace_back(TRUE{ });
112  cache.emplace(f.id(), (FormulaID)(db.size()-1));
113  return (FormulaID)(db.size()-1);
114  }
115  case carl::FormulaType::FALSE: {
116  db.emplace_back(FALSE{ });
117  cache.emplace(f.id(), (FormulaID)(db.size()-1));
118  return (FormulaID)(db.size()-1);
119  }
120  case carl::FormulaType::NOT: {
121  auto child = to_formula_db(c,f.subformula(),db,vartof, cache);
122  db.emplace_back(NOT{ child });
123  db[child].parents.insert((FormulaID)(db.size()-1));
124  cache.emplace(f.id(), (FormulaID)(db.size()-1));
125  return (FormulaID)(db.size()-1);
126  }
127  case carl::FormulaType::IMPLIES: {
128  auto id = to_formula_db(c, FormulaT(carl::FormulaType::OR, f.premise().negated(), f.conclusion()), db, vartof, cache);
129  cache.emplace(f.id(), id);
130  return id;
131  }
132  case carl::FormulaType::AND: {
133  std::vector<FormulaID> subformulas;
134  for (const auto& sf : f.subformulas()) {
135  subformulas.emplace_back(to_formula_db(c,sf, db, vartof, cache));
136  }
137  db.emplace_back(AND{ subformulas });
138  for (const auto child : subformulas) {
139  db[child].parents.insert((FormulaID)(db.size()-1));
140  }
141  cache.emplace(f.id(), (FormulaID)(db.size()-1));
142  return (FormulaID)(db.size()-1);
143  }
144  case carl::FormulaType::OR: {
145  std::vector<FormulaID> subformulas;
146  for (const auto& sf : f.subformulas()) {
147  subformulas.emplace_back(to_formula_db(c,sf, db, vartof, cache));
148  }
149  db.emplace_back(OR{ subformulas });
150  for (const auto child : subformulas) {
151  db[child].parents.insert((FormulaID)(db.size()-1));
152  }
153  cache.emplace(f.id(), (FormulaID)(db.size()-1));
154  return (FormulaID)(db.size()-1);
155  }
156  case carl::FormulaType::XOR: {
157  std::vector<FormulaID> subformulas;
158  for (const auto& sf : f.subformulas()) {
159  subformulas.emplace_back(to_formula_db(c,sf, db, vartof, cache));
160  }
161  db.emplace_back(XOR{ subformulas });
162  for (const auto child : subformulas) {
163  db[child].parents.insert((FormulaID)(db.size()-1));
164  }
165  cache.emplace(f.id(), (FormulaID)(db.size()-1));
166  return (FormulaID)(db.size()-1);
167  }
168  case carl::FormulaType::IFF: {
169  std::vector<FormulaID> subformulas;
170  for (const auto& sf : f.subformulas()) {
171  subformulas.emplace_back(to_formula_db(c,sf, db, vartof, cache));
172  }
173  db.emplace_back(IFF{ subformulas });
174  for (const auto child : subformulas) {
175  db[child].parents.insert((FormulaID)(db.size()-1));
176  }
177  cache.emplace(f.id(), (FormulaID)(db.size()-1));
178  return (FormulaID)(db.size()-1);
179  }
180  case carl::FormulaType::CONSTRAINT: {
181  auto bc = carl::convert<cadcells::Polynomial>(c.polys().context(), f.constraint().constr());
182  db.emplace_back(CONSTRAINT{ c.polys()(bc) });
183  auto var = bc.lhs().main_var();
184  vartof.try_emplace(var).first->second.push_back((FormulaID)(db.size()-1));
185  cache.emplace(f.id(), (FormulaID)(db.size()-1));
186  return (FormulaID)(db.size()-1);
187  }
188  case carl::FormulaType::BOOL: {
189  db.emplace_back(BOOL{ f.boolean() });
190  vartof.try_emplace(f.boolean()).first->second.push_back((FormulaID)(db.size()-1));
191  cache.emplace(f.id(), (FormulaID)(db.size()-1));
192  return (FormulaID)(db.size()-1);
193  }
194  default: {
195  assert(false);
196  db.emplace_back(FALSE{});
197  cache.emplace(f.id(), (FormulaID)(db.size()-1));
198  return (FormulaID)(db.size()-1);
199  }
200  }
201 }
202 
204 
206  if (a.size() == b.size()) {
207  auto it_a = a.begin();
208  auto it_b = b.begin();
209  while (it_a != a.end() && *it_a == *it_b) {
210  assert(it_b != b.end());
211  it_a++;
212  it_b++;
213  }
214  return (it_a == a.end()) ? EQ : NONE;
215  } else if (a.size() < b.size()) {
216  return std::includes(b.begin(), b.end(), a.begin(), a.end()) ? SUBSET : NONE;
217  } else /* a.size() > b.size() */ {
218  return std::includes(a.begin(), a.end(), b.begin(), b.end()) ? SUPSET : NONE;
219  }
220 }
221 
223  for (auto s = set.begin(); s != set.end(); ) {
224  switch(compare(*s,add)) {
225  case SUBSET:
226  case EQ:
227  return false;
228  case SUPSET:
229  s = set.erase(s);
230  break;
231  case NONE:
232  default:
233  s++;
234  }
235  }
236  set.push_back(add);
237  return true;
238 }
239 
241  Formula::Reasons to_add;
242  for (const auto& add : adds) {
243  bool redundant = false;
244  for (auto s = set.begin(); s != set.end(); ) {
245  switch(compare(*s,add)) {
246  case SUBSET:
247  case EQ:
248  s = set.end();
249  redundant = true;
250  break;
251  case SUPSET:
252  s = set.erase(s);
253  break;
254  case NONE:
255  default:
256  s++;
257  }
258  }
259  if (!redundant) to_add.push_back(add);
260  }
261  if (to_add.empty()) return false;
262  else {
263  set.insert(set.end(), to_add.begin(), to_add.end());
264  return true;
265  }
266 }
267 
270  result.reserve(a.size()+b.size());
271  auto first1 = a.begin();
272  auto last1 = a.end();
273  auto first2 = b.begin();
274  auto last2 = b.end();
275  auto d_first = std::back_inserter(result);
276  for (; first1 != last1; ++d_first) {
277  if (first2 == last2) {
278  std::copy(first1, last1, d_first);
279  return result;
280  }
281  if (*first2 < *first1) {
282  *d_first = *first2;
283  ++first2;
284  } else if (*first2 > *first1) {
285  *d_first = *first1;
286  ++first1;
287  } else {
288  *d_first = *first1;
289  ++first1;
290  ++first2;
291  }
292  }
293  std::copy(first2, last2, d_first);
294  result.shrink_to_fit();
295  return result;
296 }
297 
299  Formula::Reasons results;
300  for (const auto& ar : a) {
301  for (const auto& br : b) {
302  merge_reason(results, merge(ar, br));
303  }
304  }
305  return results;
306 }
307 
309  std::vector<FormulaID> tru;
310  std::vector<FormulaID> fals;
311  std::vector<FormulaID> multi;
312  std::vector<FormulaID> confl;
313 };
314 
315 FormulaClassification classify_formulas(const FormulaDB& db, const std::vector<FormulaID>& formulas) {
317  for (const auto f : formulas) {
318  auto sub_val = db[f].valuation();
319  if (sub_val == Valuation::FALSE) {
320  subs.fals.push_back(f);
321  } else if (sub_val == Valuation::TRUE) {
322  subs.tru.push_back(f);
323  } else if (sub_val == Valuation::MULTIVARIATE) {
324  subs.multi.push_back(f);
325  } else {
326  assert(sub_val == Valuation::UNKNOWN);
327  subs.confl.push_back(f);
328  }
329  }
330  return subs;
331 }
332 
333 
334 
336  if (db[id].valuation() == Valuation::UNKNOWN) {
337  return;
338  }
339 
340  SMTRAT_LOG_FUNC("smtrat.covering_ng.evaluation", id);
341  #ifdef SMTRAT_DEVOPTION_Expensive
342  log(db, root);
343  #endif
344 
345  return std::visit(overloaded{
346  [&](TRUE&) {},
347  [&](FALSE&) {},
348  [&](NOT& c) {
349  auto val = db[id].valuation();
350  auto sub_val = db[c.subformula].valuation();
351 
352  // upwards propagation
353  if (sub_val == Valuation::TRUE) add_reasons_false(id, db[c.subformula].reasons_true);
354  else if (sub_val == Valuation::FALSE) add_reasons_true(id, db[c.subformula].reasons_false);
355 
356  // downwards propagation
357  if (downwards_propagation) {
358  if (val == Valuation::TRUE && sub_val == Valuation::MULTIVARIATE) { // sub_val == Valuation::MULTIVARIATE to avoid redundancies // TODO geht hierdurch was verloren?
359  add_reasons_false(c.subformula, db[id].reasons_true);
360  } else if (val == Valuation::FALSE && sub_val == Valuation::MULTIVARIATE) {
361  add_reasons_true(c.subformula, db[id].reasons_false);
362  }
363  }
364  },
365  [&](AND& c) {
366  auto val = db[id].valuation();
367  auto subs = classify_formulas(db, c.subformulas);
368 
369  // upwards propagation
370  {
371  if (!subs.fals.empty()) {
372  for (const auto& subformula : subs.fals) {
373  add_reasons_false(id, db[subformula].reasons_false);
374  }
375  } else if (subs.confl.empty() && subs.multi.empty() && subs.fals.empty()) {
376  Formula::Reasons reasons;
377  reasons.emplace_back();
378  for (const auto& subformula : subs.tru) {
379  reasons = combine_reasons(reasons, db[subformula].reasons_true);
380  }
381  add_reasons_true(id, reasons);
382  }
383  }
384 
385  // downwards propagation
386  if (downwards_propagation) {
387  if (val == Valuation::TRUE) {
388  for (const auto subformula : subs.multi) { // avoids redundancy
389  add_reasons_true(subformula, db[id].reasons_true);
390  }
391  } else if (val == Valuation::FALSE) {
392  if (subs.multi.size() == 1 && subs.confl.empty() && subs.fals.empty()) {
393  Formula::Reasons reasons = db[id].reasons_false;
394  for (const auto& subformula : subs.tru) {
395  reasons = combine_reasons(reasons, db[subformula].reasons_true);
396  }
397  add_reasons_false(*subs.multi.begin(), reasons);
398  }
399  }
400  }
401  },
402  [&](OR& c) {
403  auto val = db[id].valuation();
404  auto subs = classify_formulas(db, c.subformulas);
405 
406  // upwards propagation
407  {
408  if (!subs.tru.empty()) {
409  for (const auto& subformula : subs.tru) {
410  add_reasons_true(id, db[subformula].reasons_true);
411  }
412  } else if (subs.confl.empty() && subs.multi.empty() && subs.tru.empty()) {
413  Formula::Reasons reasons;
414  reasons.emplace_back();
415  for (const auto& subformula : subs.fals) {
416  reasons = combine_reasons(reasons, db[subformula].reasons_false);
417  }
418  add_reasons_false(id, reasons);
419  }
420  }
421 
422  // downwards propagation
423  if (downwards_propagation) {
424  if (val == Valuation::TRUE) {
425  if (subs.multi.size() == 1 && subs.confl.empty() && subs.tru.empty()) {
426  Formula::Reasons reasons = db[id].reasons_true;
427  for (const auto& subformula : subs.fals) {
428  reasons = combine_reasons(reasons, db[subformula].reasons_false);
429  }
430  add_reasons_true(*subs.multi.begin(), reasons);
431  }
432  } else if (val == Valuation::FALSE) {
433  for (const auto subformula : subs.multi) { // avoids redundancy
434  add_reasons_false(subformula, db[id].reasons_false);
435  }
436  }
437  }
438  },
439  [&](IFF& c) {
440  auto subs = classify_formulas(db, c.subformulas);
441  auto val = db[id].valuation();
442 
443  // upwards propagation
444  {
445  if (!subs.tru.empty() && !subs.fals.empty()) {
446  Formula::Reasons reasons;
447  for (const auto t : subs.tru) {
448  for (const auto f : subs.fals) {
449  auto tmp = combine_reasons(db[t].reasons_true,db[f].reasons_false);
450  merge_reasons(reasons, tmp);
451  }
452  }
453  add_reasons_false(id, reasons);
454  } else if (subs.multi.empty() && !subs.tru.empty()) {
455  Formula::Reasons reasons;
456  reasons.emplace_back();
457  for (const auto t : subs.tru) {
458  reasons = combine_reasons(reasons, db[t].reasons_true);
459  }
460  add_reasons_true(id, reasons);
461  } else if (subs.multi.empty() && !subs.fals.empty()) {
462  Formula::Reasons reasons;
463  reasons.emplace_back();
464  for (const auto f : subs.fals) {
465  reasons = combine_reasons(reasons, db[f].reasons_false);
466  }
467  add_reasons_true(id, reasons);
468  }
469  }
470 
471  // downwards propagation
472  if (downwards_propagation) {
473  if (val == Valuation::TRUE) {
474  for (const auto t : subs.tru) {
475  for (const auto sub : c.subformulas) {
476  auto sub_val = db[sub].valuation();
477  if (sub_val == Valuation::MULTIVARIATE) { // avoids redundancy
478  add_reasons_true(sub, combine_reasons(db[id].reasons_true, db[t].reasons_true));
479  }
480  }
481  }
482  for (const auto f : subs.fals) {
483  for (const auto sub : c.subformulas) {
484  auto sub_val = db[sub].valuation();
485  if (sub_val == Valuation::MULTIVARIATE) { // avoids redundancy
486  add_reasons_false(sub, combine_reasons(db[id].reasons_true, db[f].reasons_false));
487  }
488  }
489  }
490  } else if (val == Valuation::FALSE) {
491  if (subs.multi.size() == 1 && (subs.tru.empty() || subs.fals.empty())) {
492  if (subs.tru.empty()) {
493  Formula::Reasons reasons = db[id].reasons_false;
494  for (const auto f : subs.fals) {
495  reasons = combine_reasons(reasons, db[f].reasons_false);
496  }
497  add_reasons_true(*subs.multi.begin(), reasons);
498  } else {
499  assert(subs.fals.empty());
500  Formula::Reasons reasons = db[id].reasons_false;
501  for (const auto t : subs.tru) {
502  reasons = combine_reasons(reasons, db[t].reasons_true);
503  }
504  add_reasons_false(*subs.multi.begin(), reasons);
505  }
506  }
507  }
508  }
509  },
510  [&](XOR& c) {
511  auto val = db[id].valuation();
512  auto subs = classify_formulas(db, c.subformulas);
513 
514  if (subs.confl.empty() && (subs.multi.empty() || subs.multi.size() == 1)) {
515  Formula::Reasons reasons;
516  reasons.emplace_back();
517  for (const auto subformula : subs.tru) {
518  reasons = combine_reasons(reasons, db[subformula].reasons_true);
519  }
520  for (const auto subformula : subs.fals) {
521  reasons = combine_reasons(reasons, db[subformula].reasons_false);
522  }
523 
524  // upwards propagation
525  if (subs.multi.empty() && subs.confl.empty()) {
526  if (subs.tru.size() % 2 != 0) {
527  add_reasons_true(id, reasons);
528  } else {
529  add_reasons_false(id, reasons);
530  }
531  }
532 
533  // downwards propagation
534  if (downwards_propagation) {
535  if (subs.multi.size() == 1 && subs.confl.empty()) {
536  bool value = (subs.tru.size() % 2 != 0);
537  if (val == Valuation::TRUE) {
538  reasons = combine_reasons(reasons, db[id].reasons_true);
539  value = !value;
540  } else if (val == Valuation::FALSE) {
541  reasons = combine_reasons(reasons, db[id].reasons_false);
542  }
543 
544  if (value) {
545  add_reasons_true(*subs.multi.begin(), reasons);
546  } else {
547  add_reasons_false(*subs.multi.begin(), reasons);
548  }
549  }
550  }
551  }
552  },
553  [&](BOOL&) {},
554  [&](CONSTRAINT&) {},
555  }, db[id].content);
556 
557 }
558 
559 void FormulaGraph::propagate_root(FormulaID id, bool is_true) {
560  SMTRAT_LOG_FUNC("smtrat.covering_ng.evaluation", id << ", " << is_true);
561  #ifdef SMTRAT_DEVOPTION_Expensive
562  log(db, root);
563  #endif
564  if (is_true) {
565  // assert(db[id].reasons_true.empty());
566  db[id].reasons_true.emplace_back();
567  } else {
568  // assert(db[id].reasons_false.empty());
569  db[id].reasons_false.emplace_back();
570  }
572 }
573 
575  SMTRAT_LOG_FUNC("smtrat.covering_ng.evaluation", id << ", " << is_true);
576  #ifdef SMTRAT_DEVOPTION_Expensive
577  log(db, root);
578  #endif
579  Formula::Reasons reasons;
580  reasons.emplace_back(Formula::Reason({std::make_pair(id, is_true)}));
581  if (is_true) {
582  add_reasons_true(id, reasons);
583  } else {
584  add_reasons_false(id, reasons);
585  }
586 }
587 
589  if (merge_reasons(db[id].reasons_true, reasons)) {
590  if (db[id].valuation() != Valuation::UNKNOWN) {
591  for (const auto parent : db[id].parents) {
592  propagate_consistency(parent);
593  }
595  } else {
596  conflicts.insert(id);
597  }
598  }
599 }
600 
602  if (merge_reasons(db[id].reasons_false, reasons)) {
603  if (db[id].valuation() != Valuation::UNKNOWN) {
604  for (const auto parent : db[id].parents) {
605  propagate_consistency(parent);
606  }
608  } else {
609  conflicts.insert(id);
610  }
611  }
612 }
613 
615  Formula::Reasons reasons;
616  for (const auto c : conflicts) {
617  merge_reasons(reasons,combine_reasons(db[c].reasons_false, db[c].reasons_true));
618  }
619  return reasons;
620 }
621 
622 void FormulaGraph::backtrack(FormulaID id, bool is_true) {
623  for (formula_ds::FormulaID idx = 0; idx < db.size(); ++idx) {
624  auto& f = db[idx];
625  for (auto reason = f.reasons_true.begin(); reason != f.reasons_true.end(); ) {
626  if (std::binary_search(reason->begin(), reason->end(), std::make_pair(id, is_true))) {
627  reason = f.reasons_true.erase(reason);
628  } else {
629  reason++;
630  }
631  }
632  for (auto reason = f.reasons_false.begin(); reason != f.reasons_false.end(); ) {
633  if (std::binary_search(reason->begin(), reason->end(), std::make_pair(id, is_true))) {
634  reason = f.reasons_false.erase(reason);
635  } else {
636  reason++;
637  }
638  }
639 
640  if (f.reasons_true.empty() || f.reasons_false.empty()) {
641  conflicts.erase(idx);
642  }
643  }
644 }
645 
646 }
647 
648 carl::Variable new_var(const cadcells::Assignment& old_ass, const cadcells::Assignment& new_ass) {
649  for (const auto& [k,v] : new_ass) {
650  if (old_ass.find(k) == old_ass.end()) return k;
651  }
652  return carl::Variable::NO_VARIABLE;
653 }
654 
655 namespace pp {
656 
657 inline carl::BasicConstraint<Poly> normalize(const carl::BasicConstraint<Poly>& c) {
658  assert(c.relation() == carl::Relation::LESS || c.relation() == carl::Relation::LEQ || c.relation() == carl::Relation::EQ || c.relation() == carl::Relation::NEQ);
659  return carl::BasicConstraint<Poly>(c.lhs().normalize(), carl::is_negative(c.lhs().lcoeff()) ? carl::turn_around(c.relation()) : c.relation());
660 }
661 
662 struct PolyInfo {
663  bool EQ = false;
664  bool NEQ = false;
665  bool LESS = false;
666  bool LEQ = false;
667  bool GREATER = false;
668  bool GEQ = false;
669  void set(carl::Relation rel) {
670  if (rel == carl::Relation::EQ) EQ = true;
671  else if (rel == carl::Relation::NEQ) NEQ = true;
672  else if (rel == carl::Relation::LESS) LESS = true;
673  else if (rel == carl::Relation::LEQ) LEQ = true;
674  else if (rel == carl::Relation::GREATER) GREATER = true;
675  else if (rel == carl::Relation::GEQ) GEQ = true;
676  }
677 };
678 
680  std::vector<ConstraintT> constraints;
681  carl::arithmetic_constraints(f, constraints);
682  boost::container::flat_map<Poly,PolyInfo> info;
683  for (const auto& c : constraints) {
684  auto constr = normalize(c.constr());
685  info.try_emplace(constr.lhs()).first->second.set(constr.relation());
686  }
687 
688  std::vector<FormulaT> lemmas;
689  for (const auto& [poly,rels] : info) {
690  if ((rels.LESS || rels.GEQ) && (rels.GREATER || rels.LEQ)) {
691  lemmas.emplace_back(carl::FormulaType::OR, FormulaT(ConstraintT(poly,carl::Relation::GEQ)), FormulaT(ConstraintT(poly,carl::Relation::LEQ)));
692  }
693  if ((rels.LESS || rels.GEQ) && (rels.EQ || rels.NEQ)) {
694  lemmas.emplace_back(carl::FormulaType::OR, FormulaT(ConstraintT(poly,carl::Relation::NEQ)), FormulaT(ConstraintT(poly,carl::Relation::GEQ)));
695  }
696  if ((rels.GREATER || rels.LEQ) && (rels.EQ || rels.NEQ)) {
697  lemmas.emplace_back(carl::FormulaType::OR, FormulaT(ConstraintT(poly,carl::Relation::NEQ)), FormulaT(ConstraintT(poly,carl::Relation::LEQ)));
698  }
699  if ((rels.LESS || rels.GEQ) && (rels.GREATER || rels.LEQ) && (rels.EQ || rels.NEQ)) {
700  lemmas.emplace_back(carl::FormulaType::OR, FormulaT(ConstraintT(poly,carl::Relation::EQ)), FormulaT(ConstraintT(poly,carl::Relation::LESS)), FormulaT(ConstraintT(poly,carl::Relation::GREATER)));
701  }
702  }
703 
704  lemmas.push_back(f);
705  return FormulaT(carl::FormulaType::AND, std::move(lemmas));
706 }
707 
708 }
709 
710 
712  auto input = f;
713  if (m_preprocess) {
714  input = pp::preprocess(input);
715  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Got " << input);
716  }
717 
718  std::map<std::size_t,formula_ds::FormulaID> cache;
722 
723  for (auto& [var, atoms] : vartof) {
724  if (var.type() == carl::VariableType::VT_REAL) {
725  std::sort(atoms.begin(), atoms.end(), [&](const formula_ds::FormulaID a, const formula_ds::FormulaID b) {
726  const auto& constr_a = std::get<formula_ds::CONSTRAINT>(true_graph.db[a].content).constraint;
727  const auto& constr_b = std::get<formula_ds::CONSTRAINT>(true_graph.db[b].content).constraint;
728  return m_constraint_complexity_ordering(m_proj, constr_a, constr_b);
729  });
730  }
731  }
732 
733  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Initial formula:");
735  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Polynomials:" << m_proj.polys());
736 
737  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Update true_graph");
738  for (formula_ds::FormulaID i = 0; i < true_graph.db.size(); i++) {
739  if (std::holds_alternative<formula_ds::TRUE>(true_graph.db[i].content)) {
740  true_graph.propagate_root(i, true);
741  }
742  if (std::holds_alternative<formula_ds::FALSE>(true_graph.db[i].content)) {
743  true_graph.propagate_root(i, false);
744  }
745  }
747  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Update false_graph");
748  for (formula_ds::FormulaID i = 0; i < false_graph.db.size(); i++) {
749  if (std::holds_alternative<formula_ds::TRUE>(false_graph.db[i].content)) {
750  false_graph.propagate_root(i, true);
751  }
752  if (std::holds_alternative<formula_ds::FALSE>(false_graph.db[i].content)) {
753  false_graph.propagate_root(i, false);
754  }
755  }
757 }
758 
760  // this is a quick and dirty implementation of a SAT solver
761  std::optional<formula_ds::FormulaID> next_dec_id;
762  for (const auto& [k,vs] : vartof) {
763  if (m_boolean_exploration == EXPLORATION_ONLY_BOOL && k.type() != carl::VariableType::VT_BOOL) continue;
764  for (const auto& v : vs) {
765  if (graph.db[v].reasons_true.empty() && graph.db[v].reasons_false.empty()) {
766  next_dec_id = v;
767  break;
768  }
769  }
770  if (next_dec_id) break;
771  }
772  if (!next_dec_id) return formula_ds::Formula::Reasons();
773 
774  graph.propagate_decision(*next_dec_id, true);
775  auto true_conflicts = graph.conflict_reasons();
776  if (true_conflicts.empty()) {
777  true_conflicts = explore(graph);
778  }
779  graph.backtrack(*next_dec_id, true);
780  if (true_conflicts.empty()) {
782  }
783 
784  graph.propagate_decision(*next_dec_id, false);
785  auto false_conflicts = graph.conflict_reasons();
786  if (false_conflicts.empty()) {
787  false_conflicts = explore(graph);
788  }
789  graph.backtrack(*next_dec_id, false);
790  if (false_conflicts.empty()) {
792  }
793 
795  for (auto conflict : formula_ds::combine_reasons(true_conflicts, false_conflicts)) {
796  std::erase(conflict, std::make_pair(*next_dec_id, true));
797  std::erase(conflict, std::make_pair(*next_dec_id, false));
798  formula_ds::merge_reason(conflicts, conflict);
799  }
800  return conflicts;
801 }
802 
804  auto var = new_var(assignment, ass);
805  assignment = ass;
806  if (var == carl::Variable::NO_VARIABLE) return;
807  if(root_valuation() != Valuation::MULTIVARIATE) return;
808  auto atoms = vartof.find(var);
809  if (atoms == vartof.end()) return;
810 
811  for (const auto id : atoms->second) {
812  const auto& constr = std::get<formula_ds::CONSTRAINT>(true_graph.db[id].content).constraint;
813  assert (m_proj.main_var(constr.lhs) == var);
814 
815  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Evaluate constraint " << constr);
816  auto res = m_proj.evaluate(ass, constr);
817  if (!boost::indeterminate(res)) {
818  m_decisions.emplace(id, (bool)res);
819  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Update true_graph");
820  true_graph.propagate_decision(id, (bool)res);
821  SMTRAT_LOG_TRACE("smtrat.covering_ng.evaluation", "Update false_graph");
822  false_graph.propagate_decision(id, (bool)res);
823  }
824 
826  break;
827  }
828  }
829 
830  if (!true_graph.conflicts.empty()) {
831  assert(m_true_conflict_reasons.empty());
833  }
834  if (!false_graph.conflicts.empty()) {
835  assert(m_false_conflict_reasons.empty());
837  }
838 
840  if (m_true_conflict_reasons.empty()) {
842  }
843  if (m_false_conflict_reasons.empty()) {
845  }
846  assert(m_true_conflict_reasons.empty() || m_false_conflict_reasons.empty());
847  }
848 
849  // TODO gröbner propagation
850 }
851 
853  auto var = new_var(ass, assignment);
854  assignment = ass;
855  if (var == carl::Variable::NO_VARIABLE) return;
856  auto atomset = vartof.find(var);
857  if (atomset == vartof.end()) return;
858 
859  for (const auto id : atomset->second) {
862 
863  for (auto iter = m_true_conflict_reasons.begin(); iter != m_true_conflict_reasons.end(); ) {
864  if (std::binary_search(iter->begin(), iter->end(), std::make_pair(id, m_decisions[id]))) {
865  iter = m_true_conflict_reasons.erase(iter);
866  } else {
867  iter++;
868  }
869  }
870 
871  for (auto iter = m_false_conflict_reasons.begin(); iter != m_false_conflict_reasons.end(); ) {
872  if (std::binary_search(iter->begin(), iter->end(), std::make_pair(id, m_decisions[id]))) {
873  iter = m_false_conflict_reasons.erase(iter);
874  } else {
875  iter++;
876  }
877  }
878 
879  m_decisions.erase(id);
880  }
881 }
882 
883 void postprocess(cadcells::datastructures::Projections& proj, boost::container::flat_set<cadcells::datastructures::PolyConstraint>& i) {
884  // Replace equations by their Gröbner basis if possible
885  // TODO reduce other constraints using the gröbner basis?
886 
887  boost::container::flat_set<cadcells::Constraint> implicant;
888  for (const auto& e : i) {
889  implicant.insert(proj.polys()(e));
890  }
891  std::vector<cadcells::Polynomial> equations;
892  for (const auto& c : implicant) {
893  if (c.relation() == carl::Relation::EQ) {
894  equations.emplace_back(c.lhs());
895  }
896  }
897  if (equations.size()>1) {
898  equations = carl::groebner_basis(equations);
899  for (auto it = implicant.begin(); it != implicant.end(); ) {
900  if (it->relation() == carl::Relation::EQ) {
901  it = implicant.erase(it);
902  } else {
903  it++;
904  }
905  }
906  for (const auto& poly : equations) {
907  implicant.emplace(poly, carl::Relation::EQ);
908  }
909  }
910  i.clear();
911  for (const auto& e : implicant) {
912  i.insert(proj.polys()(e));
913  }
914 }
915 
916 std::vector<boost::container::flat_set<cadcells::datastructures::PolyConstraint>> GraphEvaluation::compute_implicants() {
918 
919  std::vector<boost::container::flat_set<cadcells::datastructures::PolyConstraint>> implicants;
920  for (const auto& r : reasons) {
921  implicants.emplace_back();
922  for (const auto& c : r) {
923  if (c.second) {
924  implicants.back().insert(std::get<formula_ds::CONSTRAINT>(true_graph.db[c.first].content).constraint);
925  } else {
926  implicants.back().insert(m_proj.negation(std::get<formula_ds::CONSTRAINT>(true_graph.db[c.first].content).constraint));
927  }
928  }
929  }
930 
931  SMTRAT_STATISTICS_CALL(statistics().implicants_found(implicants.size()));
932 
933  // TODO pre-compute features and sort then?
934  if (m_results == 1) {
935  *implicants.begin() = *std::min_element(implicants.begin(), implicants.end(), std::bind_front(m_implicant_complexity_ordering, m_proj));
936  implicants.erase(implicants.begin() + 1, implicants.end());
937  } else if (m_results > 1) {
938  std::sort(implicants.begin(), implicants.end(), std::bind_front(m_implicant_complexity_ordering, m_proj));
939  if (m_results < implicants.size())
940  implicants.erase(implicants.begin() + m_results, implicants.end());
941  }
942 
943  if (m_postprocess) {
944  for (auto& implicant : implicants) {
945  postprocess(m_proj, implicant);
946  }
947  }
948 
949  return implicants;
950 }
951 
953  assert(m_true_conflict_reasons.empty() || m_false_conflict_reasons.empty());
954  if (!m_true_conflict_reasons.empty()) return Valuation::FALSE;
955  else if (!m_false_conflict_reasons.empty()) return Valuation::TRUE;
956  else return Valuation::MULTIVARIATE;
957 }
958 
959 }
Encapsulates all computations on polynomials.
Definition: projections.h:46
RAN evaluate(const Assignment &sample, IndexedRoot r)
Definition: projections.h:429
PolyConstraint negation(const PolyConstraint &constraint) const
Definition: projections.h:506
std::vector< boost::container::flat_set< cadcells::datastructures::PolyConstraint > > compute_implicants()
boost::container::flat_map< formula_ds::FormulaID, bool > m_decisions
formula_ds::Formula::Reasons explore(formula_ds::FormulaGraph &graph)
cadcells::datastructures::Projections m_proj
void revert_valuation(const cadcells::Assignment &ass)
void extend_valuation(const cadcells::Assignment &ass)
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:67
int var(Lit p)
Definition: SolverTypes.h:64
static void copy(const T &from, T &to)
Definition: Alg.h:60
carl::Assignment< RAN > Assignment
Definition: common.h:25
FormulaClassification classify_formulas(const FormulaDB &db, const std::vector< FormulaID > &formulas)
Formula::Reason merge(const Formula::Reason &a, const Formula::Reason &b)
void log(const FormulaDB &db, const FormulaID id)
FormulaID to_formula_db(cadcells::datastructures::Projections &c, const FormulaT &f, FormulaDB &db, VariableToFormula &vartof, std::map< std::size_t, FormulaID > &cache)
bool merge_reasons(Formula::Reasons &set, const Formula::Reasons &adds)
bool merge_reason(Formula::Reasons &set, const Formula::Reason &add)
boost::container::flat_map< carl::Variable, std::vector< FormulaID > > VariableToFormula
void print(std::ostream &stream, const FormulaDB &db, const FormulaID id, const std::size_t level)
overloaded(Ts...) -> overloaded< Ts... >
CompareResult compare(const Formula::Reason &a, const Formula::Reason &b)
Formula::Reasons combine_reasons(const Formula::Reasons &a, const Formula::Reasons &b)
carl::BasicConstraint< Poly > normalize(const carl::BasicConstraint< Poly > &c)
FormulaT preprocess(const FormulaT &f)
carl::Variable new_var(const cadcells::Assignment &old_ass, const cadcells::Assignment &new_ass)
void postprocess(cadcells::datastructures::Projections &proj, boost::container::flat_set< cadcells::datastructures::PolyConstraint > &i)
bool includes(const VariableRange &superset, const carl::Variables &subset)
carl::Formula< Poly > FormulaT
Definition: types.h:37
carl::Constraint< Poly > ConstraintT
Definition: types.h:29
#define SMTRAT_LOG_TRACE(channel, msg)
Definition: logging.h:36
#define SMTRAT_LOG_FUNC(channel, args)
Definition: logging.h:38
#define SMTRAT_STATISTICS_CALL(function)
Definition: Statistics.h:23
void add_reasons_false(FormulaID id, const Formula::Reasons &reasons)
void add_reasons_true(FormulaID id, const Formula::Reasons &reasons)
std::vector< std::pair< FormulaID, bool > > Reason