6#include "DeltaSoplexTheorySolver.h"
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"
20using SoplexStatus = soplex::SPxSolver::Status;
21using soplex::Rational;
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");
29void DeltaSoplexTheorySolver::AddLiteral(
const Variable &formula_var,
const Formula &formula) {
30 DLINEAR_ASSERT(!is_consolidated_,
"Cannot add literals after consolidation");
32 if (lit_to_theory_row_.contains(formula_var.get_id()))
return;
34 DLINEAR_TRACE_FMT(
"DeltaSoplexTheorySolver::AddLiteral({})", formula);
38 if (BoundPreprocessor::IsSimpleBound(formula))
return;
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));
46 lit_to_theory_row_.emplace(formula_var.get_id(), spx_row);
47 theory_row_to_lit_.emplace_back(formula_var,
true);
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);
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");
60 Explanations explanations{preprocessor_.EnableLiteral(lit)};
61 if (!explanations.empty())
return explanations;
63 const auto &[var, truth] = lit;
64 const auto it = lit_to_theory_row_.find(var.get_id());
66 if (it == lit_to_theory_row_.end()) {
67 DLINEAR_TRACE_FMT(
"DeltaSoplexTheorySolver::EnableLinearLiteral: ignoring ({})", lit);
72 const int spx_row = it->second;
74 theory_row_to_lit_[spx_row].truth = truth;
76 DLINEAR_TRACE_FMT(
"DeltaSoplexTheorySolver::EnableLinearLiteral({})", lit);
78 EnableSpxRow(spx_row, truth);
82SatResult DeltaSoplexTheorySolver::CheckSatCore(mpq_class *actual_precision, Explanations &explanations) {
83 DLINEAR_ASSERT(is_consolidated_,
"The solver must be consolidate before checking for sat");
91 DLINEAR_DEBUG_FMT(
"DeltaSoplexTheorySolver::CheckSat: calling SoPlex (phase {})", config_.simplex_sat_phase());
92 Rational max_violation, sum_violation;
93 SoplexStatus status = spx_.optimize();
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,
103 DLINEAR_DEBUG_FMT(
"DeltaSoplexTheorySolver::CheckSat: SoPlex has returned {}, but no precision", 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;
116 DLINEAR_UNREACHABLE();
120void DeltaSoplexTheorySolver::EnableSpxRow(
int spx_row,
bool truth) {
122 const mpq_class &rhs{spx_rhs_[spx_row]};
124 if (sense == LpRowSense::NQ)
return;
125 spx_.changeRangeRational(
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));
130 if (sense == LpRowSense::EQ)
return;
131 spx_.changeRangeRational(
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));
136 theory_rows_state_.at(spx_row) =
true;
137 DLINEAR_TRACE_FMT(
"DeltaSoplexTheorySolver::EnableLinearLiteral({}{})", truth ?
"" :
"¬", spx_row);
std::set< LiteralSet > Explanations
Set of explanations of the conflict.
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.
LpRowSense parseLpSense(const Formula &f)
Parse the sense from a formula.
LpRowSense
Sense of a linear programming row describing a constraint.
A literal is a variable with an associated truth value, indicating whether it is true or false.