dlinear  0.0.1
Delta-complete SMT solver for linear programming
Loading...
Searching...
No Matches
DeltaSoplexTheorySolver.cpp
1
6#include "DeltaSoplexTheorySolver.h"
7
8#include <algorithm>
9#include <cstddef>
10#include <map>
11
12#include "dlinear/libs/libsoplex.h"
13#include "dlinear/solver/LpRowSense.h"
14#include "dlinear/symbolic/symbolic.h"
15#include "dlinear/util/exception.h"
16#include "dlinear/util/logging.h"
17
18namespace dlinear {
19
20using SoplexStatus = soplex::SPxSolver::Status;
21using soplex::Rational;
22
23DeltaSoplexTheorySolver::DeltaSoplexTheorySolver(PredicateAbstractor &predicate_abstractor,
24 const std::string &class_name)
25 : SoplexTheorySolver(predicate_abstractor, class_name) {
26 DLINEAR_ASSERT(config_.simplex_sat_phase() == 1, "DeltaSoplexTheorySolver must use phase 1");
27}
28
29void DeltaSoplexTheorySolver::AddLiteral(const Variable &formula_var, const Formula &formula) {
30 DLINEAR_ASSERT(!is_consolidated_, "Cannot add literals after consolidation");
31 // Literal is already present
32 if (lit_to_theory_row_.contains(formula_var.get_id())) return;
33
34 DLINEAR_TRACE_FMT("DeltaSoplexTheorySolver::AddLiteral({})", formula);
35
36 // Create the LP solver variables
37 for (const Variable &var : formula.GetFreeVariables()) AddVariable(var);
38 if (BoundPreprocessor::IsSimpleBound(formula)) return;
39
40 const int spx_row{spx_rows_.num()};
41 soplex::DSVectorRational coeffs{ParseRowCoeff(formula)};
42 spx_rows_.add(soplex::LPRowRational(-soplex::infinity, coeffs, soplex::infinity));
43 spx_sense_.emplace_back(~parseLpSense(formula));
44
45 // Update indexes
46 lit_to_theory_row_.emplace(formula_var.get_id(), spx_row);
47 theory_row_to_lit_.emplace_back(formula_var, true);
48
49 DLINEAR_ASSERT(static_cast<std::size_t>(spx_row) == theory_row_to_lit_.size() - 1,
50 "incorrect theory_row_to_lit_.size()");
51 DLINEAR_ASSERT(static_cast<std::size_t>(spx_row) == spx_sense_.size() - 1, "incorrect spx_sense_.size()");
52 DLINEAR_ASSERT(static_cast<std::size_t>(spx_row) == spx_rhs_.size() - 1, "incorrect spx_rhs_.size()");
53 DLINEAR_DEBUG_FMT("DeltaSoplexTheorySolver::AddLiteral: {} ↦ {}", formula, spx_row);
54}
55
56DeltaSoplexTheorySolver::Explanations DeltaSoplexTheorySolver::EnableLiteral(const Literal &lit) {
57 DLINEAR_ASSERT(is_consolidated_, "The solver must be consolidate before enabling a literal");
58 DLINEAR_ASSERT(predicate_abstractor_.var_to_formula_map().contains(lit.var), "var must map to a theory literal");
59
60 Explanations explanations{preprocessor_.EnableLiteral(lit)};
61 if (!explanations.empty()) return explanations;
62
63 const auto &[var, truth] = lit;
64 const auto it = lit_to_theory_row_.find(var.get_id());
65 // If the literal was not already among the constraints (rows) of the LP, it must be a learned literal.
66 if (it == lit_to_theory_row_.end()) {
67 DLINEAR_TRACE_FMT("DeltaSoplexTheorySolver::EnableLinearLiteral: ignoring ({})", lit);
68 return {};
69 }
70
71 // A non-trivial linear literal from the input problem
72 const int spx_row = it->second;
73 // Update the truth value for the current iteration with the last SAT solver assignment
74 theory_row_to_lit_[spx_row].truth = truth;
75
76 DLINEAR_TRACE_FMT("DeltaSoplexTheorySolver::EnableLinearLiteral({})", lit);
77
78 EnableSpxRow(spx_row, truth);
79 return explanations;
80}
81
82SatResult DeltaSoplexTheorySolver::CheckSatCore(mpq_class *actual_precision, Explanations &explanations) {
83 DLINEAR_ASSERT(is_consolidated_, "The solver must be consolidate before checking for sat");
84
85 // Set the bounds for the variables
86 EnableSpxVarBound();
87 // Remove all the disabled rows from the LP solver
88 DisableSpxRows();
89
90 // Now we call the solver
91 DLINEAR_DEBUG_FMT("DeltaSoplexTheorySolver::CheckSat: calling SoPlex (phase {})", config_.simplex_sat_phase());
92 Rational max_violation, sum_violation;
93 SoplexStatus status = spx_.optimize();
94
95 // The status must be OPTIMAL, UNBOUNDED, or INFEASIBLE. Anything else is an error
96 if (status != SoplexStatus::OPTIMAL && status != SoplexStatus::UNBOUNDED && status != SoplexStatus::INFEASIBLE) {
97 DLINEAR_RUNTIME_ERROR_FMT("SoPlex returned {}. That's not allowed here", status);
98 } else if (spx_.getRowViolationRational(max_violation, sum_violation)) {
99 *actual_precision = gmp::ToMpqClass(max_violation.backend().data());
100 DLINEAR_DEBUG_FMT("DeltaSoplexTheorySolver::CheckSat: SoPlex returned {}, precision = {}", status,
101 *actual_precision);
102 } else {
103 DLINEAR_DEBUG_FMT("DeltaSoplexTheorySolver::CheckSat: SoPlex has returned {}, but no precision", status);
104 }
105
106 switch (status) {
107 case SoplexStatus::OPTIMAL:
108 UpdateModelSolution();
109 DLINEAR_DEBUG("DeltaSoplexTheorySolver::CheckSat: returning SAT_DELTA_SATISFIABLE");
110 return SatResult::SAT_DELTA_SATISFIABLE;
111 case SoplexStatus::INFEASIBLE:
112 UpdateExplanations(explanations);
113 DLINEAR_DEBUG("DeltaSoplexTheorySolver::CheckSat: returning SAT_UNSATISFIABLE");
114 return SatResult::SAT_UNSATISFIABLE;
115 default:
116 DLINEAR_UNREACHABLE();
117 }
118}
119
120void DeltaSoplexTheorySolver::EnableSpxRow(int spx_row, bool truth) {
121 const LpRowSense sense = spx_sense_[spx_row];
122 const mpq_class &rhs{spx_rhs_[spx_row]};
123 if (truth) {
124 if (sense == LpRowSense::NQ) return;
125 spx_.changeRangeRational(
126 spx_row,
127 sense == LpRowSense::GE || sense == LpRowSense::EQ ? Rational(gmp::ToMpq(rhs)) : Rational(-soplex::infinity),
128 sense == LpRowSense::LE || sense == LpRowSense::EQ ? Rational(gmp::ToMpq(rhs)) : Rational(soplex::infinity));
129 } else {
130 if (sense == LpRowSense::EQ) return;
131 spx_.changeRangeRational(
132 spx_row,
133 sense == LpRowSense::LE || sense == LpRowSense::NQ ? Rational(gmp::ToMpq(rhs)) : Rational(-soplex::infinity),
134 sense == LpRowSense::GE || sense == LpRowSense::NQ ? Rational(gmp::ToMpq(rhs)) : Rational(soplex::infinity));
135 }
136 theory_rows_state_.at(spx_row) = true;
137 DLINEAR_TRACE_FMT("DeltaSoplexTheorySolver::EnableLinearLiteral({}{})", truth ? "" : "¬", spx_row);
138}
139
140} // namespace dlinear
std::set< LiteralSet > Explanations
Set of explanations of the conflict.
Represents a symbolic form of a first-order logic formula.
const Variables & GetFreeVariables() const
Gets free variables (unquantified variables).
Represents a symbolic variable.
Global namespace for the dlinear library.
SatResult
Result of running the theory solver over the literals decided by the SAT solver.
Definition SatResult.h:17
LpRowSense parseLpSense(const Formula &f)
Parse the sense from a formula.
LpRowSense
Sense of a linear programming row describing a constraint.
Definition LpRowSense.h:23
A literal is a variable with an associated truth value, indicating whether it is true or false.
Definition literal.h:24
Variable var
Variable.
Definition literal.h:25