1 #include "MCSATMixin.h"
6 template<typename Settings>
7 void MCSATMixin<Settings>::pushTheoryDecision(const FormulaT& assignment, Minisat::Lit decisionLiteral) {
8 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Made theory decision for " << assignment.variable_assignment().var() << ": " << decisionLiteral);
9 assert(mInconsistentVariables.empty());
10 mBackend.pushAssignment( assignment.variable_assignment().var(), assignment.variable_assignment().value(), assignment);
11 mTheoryStack.emplace_back();
12 current().variable = assignment.variable_assignment().var();
13 current().decisionLiteral = decisionLiteral;
17 template<typename Settings>
18 void MCSATMixin<Settings>::popTheoryDecision() {
19 assert(!mTheoryStack.empty());
20 mUndecidedVariables.insert(
21 mUndecidedVariables.end(),
22 mTheoryStack.back().decidedVariables.begin(),
23 mTheoryStack.back().decidedVariables.end()
25 for (const auto var : mTheoryStack.back().decidedVariables) {
26 mTheoryLevels[varid(var)] = std::numeric_limits<std::size_t>::max();
27 mSemanticPropagations.erase(var);
29 mTheoryStack.pop_back();
30 mInconsistentVariables.clear();
31 // mModelAssignmentCache.clear();
34 template<typename Settings>
35 void MCSATMixin<Settings>::updateCurrentLevel() {
36 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Updating current level " << current().variable);
38 // Check undecided variables whether they became univariate
39 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Undecided Variables: " << mUndecidedVariables);
40 for (auto vit = mUndecidedVariables.begin(); vit != mUndecidedVariables.end();) {
41 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Looking at " << *vit);
42 if constexpr(!Settings::early_evaluation) {
43 if (computeTheoryLevel(*vit) != level()) {
48 if (mGetter.isTheoryAbstraction(*vit)) {
49 const auto& f = mGetter.reabstractVariable(*vit);
50 auto evalres = carl::evaluate(f, model());
51 if (!evalres.isBool()) {
54 } else if (mBackend.isActive(f) && mGetter.getBoolVarValue(*vit) != l_Undef && mGetter.getBoolVarValue(*vit) != Minisat::lbool(evalres.asBool())) {
55 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Found inconsistent variable " << *vit);
56 mInconsistentVariables.push_back(*vit);
60 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Associating " << *vit << " with " << current().variable << " at " << level());
61 current().decidedVariables.push_back(*vit);
62 mTheoryLevels[varid(*vit)] = level();
63 if (mGetter.getBoolVarValue(*vit) == l_Undef) {
64 mSemanticPropagations.insert(*vit);
66 vit = mUndecidedVariables.erase(vit);
68 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "-> " << mUndecidedVariables);
71 template<typename Settings>
72 bool MCSATMixin<Settings>::backtrackTo(Minisat::Lit literal) {
73 std::size_t lvl = level();
75 if (get(lvl).decisionLiteral == literal) break;
78 SMTRAT_LOG_TRACE("smtrat.sat.mcsat", "Backtracking until " << literal << " on level " << lvl);
80 SMTRAT_LOG_TRACE("smtrat.sat.mcsat", "Nothing to backtrack for " << literal);
84 while (level() >= lvl) {
85 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Backtracking theory assignment for " << current().variable);
87 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Model " << model());
89 if (current().decisionLiteral != Minisat::lit_Undef) {
90 mBackend.popAssignment(current().variable);
97 template<typename Settings>
98 Minisat::lbool MCSATMixin<Settings>::evaluateLiteral(Minisat::Lit lit) const {
99 SMTRAT_LOG_TRACE("smtrat.sat.mcsat", "Evaluate " << lit);
100 const FormulaT& f = mGetter.reabstractLiteral(lit);
101 SMTRAT_LOG_TRACE("smtrat.sat.mcsat", "Evaluate " << f << " on " << mBackend.getModel());
102 if (!Settings::early_evaluation && computeTheoryLevel(f) > level()) return l_Undef;
103 SMTRAT_LOG_TRACE("smtrat.sat.mcsat", "Evaluate " << f << " on " << mBackend.getModel());
104 auto res = carl::evaluate(f, mBackend.getModel());
106 return res.asBool() ? l_True : l_False;
108 assert(Settings::early_evaluation);
113 * Checks is given literal is feasible with the current trail.
115 template<typename Settings>
116 std::pair<bool, std::optional<Explanation>> MCSATMixin<Settings>::isBooleanDecisionFeasible(Minisat::Lit lit, bool always_explain) {
117 auto var = Minisat::var(lit);
118 if (!mGetter.isTheoryAbstraction(var)) return std::make_pair(true, std::nullopt);
119 const auto& f = mGetter.reabstractLiteral(lit);
121 // assert that literal is consistent with the trail
122 assert(evaluateLiteral(lit) != l_False);
124 auto vars = carl::arithmetic_variables(f);
125 for (const auto& v : mBackend.assignedVariables())
128 if (vars.size() > 0) {
129 carl::Variable tvar = *(vars.begin());
131 auto res = mBackend.isInfeasible(tvar, f);
132 if (std::holds_alternative<ModelValues>(res)) {
133 /* if (mModelAssignmentCache.empty()) {
134 mModelAssignmentCache.cache(std::get<ModelValues>(res));
136 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Decision " << lit << " (" << f << ") is feasible wrt " << tvar);
137 return std::make_pair(true, std::nullopt);
139 auto& confl = std::get<FormulasT>(res);
140 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Decision " << lit << " (" << f << ") is infeasible wrt " << tvar << " due to " << confl);
141 if (always_explain) {
142 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Explaining " << confl);
143 return std::make_pair(false, mBackend.explain(tvar, confl));
144 } else if (std::find(confl.begin(), confl.end(), f) == confl.end()) {
145 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Conflicting core " << confl << " is independent from decision " << f);
146 return std::make_pair(false, mBackend.explain(tvar, confl));
148 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Check if trail without " << f << " was feasible wrt " << tvar);
149 auto expl = isFeasible(tvar);
151 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Trail without " << f << " was infeasible wrt " << tvar);
152 return std::make_pair(false, std::move(*expl));
154 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Infeasibility wrt " << tvar << " depends truly on " << f);
155 return std::make_pair(false, std::nullopt);
160 return std::make_pair(true, std::nullopt);
164 template<typename Settings>
165 std::pair<boost::tribool, std::optional<Explanation>> MCSATMixin<Settings>::propagateBooleanDomain(Minisat::Lit lit) {
166 auto var = Minisat::var(lit);
167 if (!mGetter.isTheoryAbstraction(var)) return std::make_pair(boost::indeterminate, std::nullopt);
168 const auto& f = mGetter.reabstractLiteral(lit);
170 auto vars = carl::arithmetic_variables(f);
171 for (const auto& v : mBackend.assignedVariables())
174 assert(vars.size() > 0);
176 carl::Variable tvar = *(vars.begin());
178 auto res_pos = mBackend.isInfeasible(tvar, f);
179 auto res_neg = mBackend.isInfeasible(tvar, f.negated());
181 if (std::holds_alternative<ModelValues>(res_pos) && std::holds_alternative<ModelValues>(res_neg)) {
182 /* if (mModelAssignmentCache.empty()) {
183 mModelAssignmentCache.cache(std::get<ModelValues>(res));
185 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Decision: " << lit << " (" << f << ") and its negation are feasible wrt " << tvar);
186 return std::make_pair(boost::indeterminate, std::nullopt);
187 } else if (std::holds_alternative<ModelValues>(res_pos)) {
188 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Propagation: " << lit << " (" << f << ") is feasible wrt " << tvar);
189 return std::make_pair(true, std::nullopt);
190 } else if (std::holds_alternative<ModelValues>(res_neg)) {
191 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Propagation: negation of " << lit << " (" << f << ") is feasible wrt " << tvar);
192 return std::make_pair(false, std::nullopt);
194 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Conflict: " << lit << " (" << f << ") and its negation are infeasible wrt " << tvar << " due to " << std::get<FormulasT>(res_pos) << " resp. " << std::get<FormulasT>(res_neg));
196 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Check if trail without " << f << " was feasible wrt " << tvar);
197 auto expl = isFeasible(tvar);
199 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Trail without " << f << " was infeasible wrt " << tvar);
200 return std::make_pair(boost::indeterminate, std::move(*expl));
204 template<typename Settings>
205 std::size_t MCSATMixin<Settings>::addBooleanVariable(Minisat::Var variable) {
206 while (mVarPropertyCache.size() <= varid(variable)) {
207 mVarPropertyCache.emplace_back();
210 while (mTheoryLevels.size() <= varid(variable)) {
211 mTheoryLevels.emplace_back();
214 std::size_t level = computeTheoryLevel(variable);
215 if (!mGetter.isTheoryAbstraction(variable)) {
216 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Ignoring " << variable << " as it is not a theory abstraction");
219 assert(mGetter.reabstractVariable(variable).type() != carl::FormulaType::VARASSIGN);
220 if (level == std::numeric_limits<std::size_t>::max()) {
221 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Adding " << variable << " to undecided");
222 mUndecidedVariables.push_back(variable);
223 mTheoryLevels[varid(variable)] = std::numeric_limits<std::size_t>::max();
225 SMTRAT_LOG_DEBUG("smtrat.sat.mcsat", "Adding " << variable << " on level " << level);
226 mTheoryStack[level].decidedVariables.push_back(variable);
227 mTheoryLevels[varid(variable)] = level;
228 mSemanticPropagations.insert(variable);
233 template<typename Settings>
234 bool MCSATMixin<Settings>::isFormulaUnivariate(const FormulaT& formula, std::size_t level) const {
235 assert(level < mTheoryStack.size());
236 auto vars = carl::arithmetic_variables(formula);
237 for (std::size_t lvl = 1; lvl <= level; lvl++) {
238 vars.erase(variable(lvl));
240 SMTRAT_LOG_TRACE("smtrat.sat.mcsat", "Checking if " << formula << " is univariate on level " << level << ": " << vars.empty());
244 template<typename Settings>
245 void MCSATMixin<Settings>::printClause(std::ostream& os, Minisat::CRef clause) const {
246 const Minisat::Clause& c = mGetter.getClause(clause);
248 for (int i = 0; i < c.size(); i++) {
249 if (i > 0) os << " ";
250 if (mGetter.isTheoryAbstraction(var(c[i]))) {
251 os << mGetter.reabstractLiteral(c[i]);
259 template<typename Settings>
260 std::ostream& operator<<(std::ostream& os, const MCSATMixin<Settings>& mcm) {
261 os << "Theory Stack: " << mcm.level() << std::endl;
262 for (std::size_t lvl = 0; lvl < mcm.mTheoryStack.size(); lvl++) {
263 const auto& level = mcm.get(lvl);
264 os << lvl << " / " << level.variable << " (" << level.decisionLiteral << ")";
265 if (mcm.model().find(level.variable) != mcm.model().end()) {
266 os << " = " << mcm.model().at(level.variable);
268 // if (level.variable == mcm.current().variable) {
269 // os << " <<-- Current variable";
272 os << "\tVariables: " << level.decidedVariables << std::endl;
274 os << "Backend:" << std::endl;
275 os << mcm.mBackend << std::endl;
276 os << "Theory variable mapping:" << std::endl;
277 os << mcm.mTheoryVarMapping.minisatToCarl << std::endl;