SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
ExplanationGenerator.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "VSHelper.h"
4 #include <carl-formula/formula/functions/Substitution.h>
5 
7 
8 namespace smtrat {
9 namespace mcsat {
10 namespace vs {
11 
13  static const bool reduceConflictConstraints = true;
14  static const bool clause_chain_with_equivalences = false;
15 };
16 
17 template<class Settings>
19 private:
20  const std::vector<FormulaT>& mConstraints;
21  const std::vector<carl::Variable>& mVariableOrdering;
22  const carl::Variable& mTargetVar;
23  const Model& mModel;
24 
25 public:
26  ExplanationGenerator(const std::vector<FormulaT>& constraints, const std::vector<carl::Variable>& variableOrdering, const carl::Variable& targetVar, const Model& model):
27  mConstraints(constraints),
28  mVariableOrdering(variableOrdering),
29  mTargetVar(targetVar),
30  mModel(model)
31  {}
32 
33 private:
34 
35  std::pair<std::vector<carl::Variable>::const_iterator, std::vector<carl::Variable>::const_iterator> getUnassignedVariables() const {
36  std::unordered_set<carl::Variable> freeVariables;
37  for (const auto& constr : mConstraints) {
38  auto vars = carl::variables(constr);
39  freeVariables.insert(vars.begin(), vars.end());
40  }
41 
42  auto firstVar = std::find(mVariableOrdering.begin(), mVariableOrdering.end(), mTargetVar);
43  assert(firstVar != mVariableOrdering.end());
44  auto lastVar = firstVar;
45  for (auto iter = firstVar; iter != mVariableOrdering.end(); iter++) {
46  if (freeVariables.find(*iter) != freeVariables.end()) {
47  lastVar = iter;
48  }
49  }
50 
51  lastVar++;
52 
53  return std::make_pair(firstVar, lastVar);
54  }
55 
56  std::optional<FormulaT> eliminateVariable(const FormulaT& inputFormula, const carl::Variable& var) const {
57  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Eliminating variable " << var << " in " << inputFormula);
58 
59  // get formula atoms
60  FormulaSetT atoms;
61  helper::getFormulaAtoms(inputFormula, atoms);
62 
63  // generate test candidates
64  std::vector<helper::TestCandidate> testCandidates;
65  if (helper::generateTestCandidates(testCandidates, var, atoms)) {
66  FormulasT res;
67  res.reserve(testCandidates.size());
68  for (const auto& tc : testCandidates) {
69  FormulaT branchResult = inputFormula;
70 
71  // substitute tc into each input constraint
72  for (const auto& constr : atoms) {
73  // check if branchResult still contains constr
74  //if (branchResult.contains(constr)) {
75  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Substituting " << tc.term << " for " << var << " into " << constr);
76 
77  // calculate substitution
78  FormulaT substitutionResult; // TODO reduceConflictConstraints?
79  if (!helper::substitute(constr, var, tc.term, substitutionResult)) {
80  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Substitution failed");
81  return std::nullopt;
82  }
83 
84  // check if current constraint is part of the conflict
85  if (Settings::reduceConflictConstraints) {
86  carl::ModelValue<Rational,Poly> eval = carl::evaluate(substitutionResult, mModel);
87  // If constraint is not fully evaluated or evaluates to false, we take it in.
88  if (!eval.isBool() || !eval.asBool()) {
89  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Use constraint " << constr << " for explanation");
90  }
91  else {
92  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Ignore constraint " << constr << " because it is not part of the conflict");
93  substitutionResult = FormulaT(carl::FormulaType::TRUE);
94  }
95  }
96 
97  // substitute into formula
98  branchResult = carl::substitute(branchResult, constr, substitutionResult);
99  //}
100  }
101 
102  // add side condition
103  FormulasT branch;
104  branch.push_back(std::move(branchResult));
105  for (const auto& sc : tc.side_condition) {
106  branch.emplace_back(sc);
107  }
108 
109  res.emplace_back(carl::FormulaType::AND, std::move(branch));
110  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Substitution of " << tc.term << " into formula obtained " << res.back());
111  assert(res.back() != FormulaT(carl::FormulaType::TRUE));
112  }
113 
114  return FormulaT(carl::FormulaType::OR, std::move(res));
115  }
116  else {
117  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Could not generate test candidates");
118  return std::nullopt;
119  }
120  }
121 
122  std::optional<FormulaT> eliminateVariables() const {
123  // eliminate unassigned variables
124  std::optional<FormulaT> res = FormulaT(carl::FormulaType::AND, mConstraints);
125  auto unassignedVariables = getUnassignedVariables();
126  for (auto iter = unassignedVariables.first; iter != unassignedVariables.second; iter++) {
127  res = eliminateVariable(*res, *iter);
128  if (!res) {
129  return std::nullopt;
130  }
131  assert(res->variables().find(*iter) == res->variables().end());
132  }
133 
134  #ifndef NDEBUG
135  carl::ModelValue<Rational,Poly> evalRes = carl::evaluate(*res, mModel);
136  assert(evalRes.isBool());
137  assert(!evalRes.asBool());
138  #endif
139 
140  // collect input constraints
141  FormulasT expl;
142  expl.push_back(std::move(*res));
143  for (const auto& c: mConstraints) {
144  expl.emplace_back(c.negated());
145  }
146  return FormulaT(carl::FormulaType::OR, expl);
147  }
148 
149 public:
150  std::optional<mcsat::Explanation> getExplanation() const {
151  auto expl = eliminateVariables();
152 
153  if (expl) {
154  SMTRAT_LOG_DEBUG("smtrat.mcsat.vs", "Obtained explanation " << (*expl));
155  SMTRAT_VALIDATION_ADD("smtrat.mcsat.vs", "explanation", expl->negated(), false);
156  return mcsat::Explanation(ClauseChain::from_formula(*expl, mModel, Settings::clause_chain_with_equivalences));
157  } else {
158  return std::nullopt;
159  }
160  }
161 };
162 
163 }
164 }
165 }
#define SMTRAT_VALIDATION_ADD(channel, name, formula, consistent)
Definition: Validation.h:26
static ClauseChain from_formula(const FormulaT &f, const Model &model, bool with_equivalence)
Transforms a given Boolean conjunction over AND and OR to CNF via Tseitin-Transformation so that,...
std::optional< FormulaT > eliminateVariable(const FormulaT &inputFormula, const carl::Variable &var) const
std::pair< std::vector< carl::Variable >::const_iterator, std::vector< carl::Variable >::const_iterator > getUnassignedVariables() const
std::optional< FormulaT > eliminateVariables() const
const std::vector< carl::Variable > & mVariableOrdering
ExplanationGenerator(const std::vector< FormulaT > &constraints, const std::vector< carl::Variable > &variableOrdering, const carl::Variable &targetVar, const Model &model)
std::optional< mcsat::Explanation > getExplanation() const
const std::vector< FormulaT > & mConstraints
int var(Lit p)
Definition: SolverTypes.h:64
static bool find(V &ts, const T &t)
Definition: Alg.h:47
Rational evaluate(carl::Variable v, const Poly &p, const Rational &r)
Definition: utils.h:11
bool substitute(const FormulaT &constr, const carl::Variable var, const carl::vs::Term< Poly > &term, FormulaT &result)
Definition: VSHelper.h:138
static bool generateTestCandidates(std::vector< TestCandidate > &results, const carl::Variable &eliminationVar, const FormulaSetT &constraints)
Generate all test candidates according to "vanilla" virtual substitution.
Definition: VSHelper.h:105
void getFormulaAtoms(const FormulaT &f, FormulaSetT &result)
Definition: VSHelper.h:18
std::variant< FormulaT, ClauseChain > Explanation
Definition: smtrat-mcsat.h:14
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::FormulaSet< Poly > FormulaSetT
Definition: types.h:41
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_DEBUG(channel, msg)
Definition: logging.h:35