mirror of
https://github.com/Z3Prover/z3
synced 2025-06-05 13:51:23 +00:00
Connect conflict2
This commit is contained in:
parent
a978604a7e
commit
b43971bb4a
9 changed files with 420 additions and 293 deletions
|
@ -4,10 +4,9 @@ z3_add_component(polysat
|
|||
clause.cpp
|
||||
clause_builder.cpp
|
||||
conflict.cpp
|
||||
conflict2.cpp
|
||||
constraint.cpp
|
||||
eq_explain.cpp
|
||||
explain.cpp
|
||||
# eq_explain.cpp
|
||||
# explain.cpp
|
||||
forbidden_intervals.cpp
|
||||
inference_logger.cpp
|
||||
justification.cpp
|
||||
|
@ -15,7 +14,7 @@ z3_add_component(polysat
|
|||
log.cpp
|
||||
op_constraint.cpp
|
||||
restart.cpp
|
||||
saturation.cpp
|
||||
# saturation.cpp
|
||||
search_state.cpp
|
||||
simplify.cpp
|
||||
simplify_clause.cpp
|
||||
|
@ -23,7 +22,7 @@ z3_add_component(polysat
|
|||
solver.cpp
|
||||
ule_constraint.cpp
|
||||
umul_ovfl_constraint.cpp
|
||||
variable_elimination.cpp
|
||||
# variable_elimination.cpp
|
||||
viable.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
util
|
||||
|
|
|
@ -14,7 +14,8 @@ Notes:
|
|||
|
||||
--*/
|
||||
|
||||
#include "math/polysat/conflict2.h"
|
||||
#include "math/polysat/conflict.h"
|
||||
#include "math/polysat/clause_builder.h"
|
||||
#include "math/polysat/solver.h"
|
||||
#include "math/polysat/inference_logger.h"
|
||||
#include "math/polysat/log.h"
|
||||
|
@ -25,10 +26,17 @@ Notes:
|
|||
#include "math/polysat/saturation.h"
|
||||
#include "math/polysat/variable_elimination.h"
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
namespace polysat {
|
||||
|
||||
class header_with_var : public displayable {
|
||||
char const* m_text;
|
||||
pvar m_var;
|
||||
public:
|
||||
header_with_var(char const* text, pvar var) : m_text(text), m_var(var) { SASSERT(text); }
|
||||
std::ostream& display(std::ostream& out) const override { return out << m_text << m_var; }
|
||||
};
|
||||
|
||||
struct inf_resolve_bool : public inference {
|
||||
sat::literal m_lit;
|
||||
clause const& m_clause;
|
||||
|
@ -61,7 +69,7 @@ namespace polysat {
|
|||
}
|
||||
};
|
||||
|
||||
conflict2::conflict2(solver& s) : s(s) {
|
||||
conflict::conflict(solver& s) : s(s) {
|
||||
// TODO: m_log_conflicts is always false even if "polysat.log_conflicts=true" is given on the command line
|
||||
if (true || s.get_config().m_log_conflicts)
|
||||
m_logger = alloc(file_inference_logger, s);
|
||||
|
@ -69,35 +77,73 @@ namespace polysat {
|
|||
m_logger = alloc(dummy_inference_logger);
|
||||
}
|
||||
|
||||
inference_logger& conflict2::logger() {
|
||||
inference_logger& conflict::logger() {
|
||||
return *m_logger;
|
||||
}
|
||||
|
||||
bool conflict2::empty() const {
|
||||
return m_literals.empty() && m_vars.empty() && m_lemmas.empty();
|
||||
conflict::const_iterator conflict::begin() const {
|
||||
return conflict_iterator::begin(s.m_constraints, m_literals);
|
||||
}
|
||||
|
||||
void conflict2::reset() {
|
||||
conflict::const_iterator conflict::end() const {
|
||||
return conflict_iterator::end(s.m_constraints, m_literals);
|
||||
}
|
||||
|
||||
bool conflict::empty() const {
|
||||
return m_literals.empty()
|
||||
&& m_vars.empty()
|
||||
&& m_bail_vars.empty()
|
||||
&& m_lemmas.empty();
|
||||
}
|
||||
|
||||
void conflict::reset() {
|
||||
m_literals.reset();
|
||||
m_vars.reset();
|
||||
m_bail_vars.reset();
|
||||
m_relevant_vars.reset();
|
||||
m_var_occurrences.reset();
|
||||
m_lemmas.reset();
|
||||
m_kind = conflict2_kind_t::ok;
|
||||
m_kind = conflict_kind_t::ok;
|
||||
SASSERT(empty());
|
||||
}
|
||||
|
||||
void conflict2::set_bailout() {
|
||||
SASSERT(m_kind == conflict2_kind_t::ok);
|
||||
m_kind = conflict2_kind_t::bailout;
|
||||
void conflict::set_bailout() {
|
||||
SASSERT(m_kind == conflict_kind_t::ok);
|
||||
m_kind = conflict_kind_t::bailout;
|
||||
s.m_stats.m_num_bailouts++;
|
||||
}
|
||||
|
||||
void conflict2::set_backjump() {
|
||||
SASSERT(m_kind == conflict2_kind_t::ok);
|
||||
m_kind = conflict2_kind_t::backjump;
|
||||
void conflict::set_backtrack() {
|
||||
SASSERT(m_kind == conflict_kind_t::ok);
|
||||
SASSERT(m_relevant_vars.empty());
|
||||
m_kind = conflict_kind_t::backtrack;
|
||||
|
||||
}
|
||||
void conflict::set_backjump() {
|
||||
SASSERT(m_kind == conflict_kind_t::ok);
|
||||
m_kind = conflict_kind_t::backjump;
|
||||
}
|
||||
|
||||
void conflict2::init(signed_constraint c) {
|
||||
bool conflict::is_relevant_pvar(pvar v) const {
|
||||
switch (m_kind) {
|
||||
case conflict_kind_t::ok:
|
||||
return contains_pvar(v);
|
||||
case conflict_kind_t::bailout:
|
||||
return true;
|
||||
case conflict_kind_t::backtrack:
|
||||
return pvar_occurs_in_constraints(v) || m_relevant_vars.contains(v);
|
||||
// return m_relevant_vars.contains(v);
|
||||
case conflict_kind_t::backjump:
|
||||
UNREACHABLE(); // we don't follow the regular loop when backjumping
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool conflict::is_relevant(sat::literal lit) const {
|
||||
return contains(lit) || contains(~lit);
|
||||
}
|
||||
|
||||
void conflict::init(signed_constraint c) {
|
||||
SASSERT(empty());
|
||||
if (c.bvalue(s) == l_false) {
|
||||
// boolean conflict
|
||||
|
@ -110,34 +156,48 @@ namespace polysat {
|
|||
insert_vars(c);
|
||||
}
|
||||
SASSERT(!empty());
|
||||
logger().begin_conflict(); // TODO: we often call reset/set so doing this here doesn't really work... make subsequent begins a no-op? or separate init and set? (set could then do reset() internally ... and we only need set() for signed_constraint, not all three variations)
|
||||
}
|
||||
|
||||
void conflict::init(clause const& cl) {
|
||||
// if (!empty())
|
||||
// return;
|
||||
// LOG("Conflict: " << cl);
|
||||
SASSERT(empty());
|
||||
for (auto lit : cl) {
|
||||
auto c = s.lit2cnstr(lit);
|
||||
SASSERT(c.bvalue(s) == l_false);
|
||||
insert(~c);
|
||||
}
|
||||
SASSERT(!empty());
|
||||
logger().begin_conflict();
|
||||
}
|
||||
|
||||
void conflict2::init(pvar v, bool by_viable_fallback) {
|
||||
void conflict::init(pvar v, bool by_viable_fallback) {
|
||||
if (by_viable_fallback) {
|
||||
logger().begin_conflict(header_with_var("unsat core from viable fallback for v", v));
|
||||
// Conflict detected by viable fallback:
|
||||
// initial conflict is the unsat core of the univariate solver
|
||||
signed_constraints unsat_core = s.m_viable_fallback.unsat_core(v);
|
||||
for (auto c : unsat_core)
|
||||
insert(c);
|
||||
logger().begin_conflict("unsat core from viable fallback");
|
||||
// TODO: apply conflict resolution plugins here too?
|
||||
} else {
|
||||
logger().begin_conflict(header_with_var("forbidden interval lemma for v", v));
|
||||
set_backtrack();
|
||||
VERIFY(s.m_viable.resolve(v, *this));
|
||||
// TODO: in general the forbidden interval lemma is not asserting.
|
||||
// but each branch exclude the current assignment.
|
||||
// in those cases we will (additionally?) need an abstraction that is asserting to make sure viable is updated properly.
|
||||
set_backjump();
|
||||
logger().begin_conflict("forbidden interval lemma");
|
||||
}
|
||||
}
|
||||
|
||||
bool conflict2::contains(sat::literal lit) const {
|
||||
bool conflict::contains(sat::literal lit) const {
|
||||
SASSERT(lit != sat::null_literal);
|
||||
return m_literals.contains(lit.index());
|
||||
}
|
||||
|
||||
void conflict2::insert(signed_constraint c) {
|
||||
void conflict::insert(signed_constraint c) {
|
||||
if (contains(c))
|
||||
return;
|
||||
if (c.is_always_true())
|
||||
|
@ -153,7 +213,7 @@ namespace polysat {
|
|||
}
|
||||
}
|
||||
|
||||
void conflict2::insert_eval(signed_constraint c) {
|
||||
void conflict::insert_eval(signed_constraint c) {
|
||||
switch (c.bvalue(s)) {
|
||||
case l_undef:
|
||||
s.assign_eval(c.blit());
|
||||
|
@ -166,20 +226,20 @@ namespace polysat {
|
|||
insert(c);
|
||||
}
|
||||
|
||||
void conflict2::insert_vars(signed_constraint c) {
|
||||
void conflict::insert_vars(signed_constraint c) {
|
||||
for (pvar v : c->vars())
|
||||
if (s.is_assigned(v))
|
||||
m_vars.insert(v);
|
||||
}
|
||||
|
||||
void conflict2::remove(signed_constraint c) {
|
||||
void conflict::remove(signed_constraint c) {
|
||||
SASSERT(contains(c));
|
||||
m_literals.remove(c.blit().index());
|
||||
for (pvar v : c->vars())
|
||||
m_var_occurrences[v]--;
|
||||
}
|
||||
|
||||
void conflict2::resolve_bool(sat::literal lit, clause const& cl) {
|
||||
void conflict::resolve_bool(sat::literal lit, clause const& cl) {
|
||||
// Note: core: x, y, z; corresponds to clause ~x \/ ~y \/ ~z
|
||||
// clause: x \/ u \/ v
|
||||
// resolvent: ~y \/ ~z \/ u \/ v; as core: y, z, ~u, ~v
|
||||
|
@ -197,7 +257,7 @@ namespace polysat {
|
|||
logger().log(inf_resolve_bool(lit, cl));
|
||||
}
|
||||
|
||||
void conflict2::resolve_with_assignment(sat::literal lit) {
|
||||
void conflict::resolve_with_assignment(sat::literal lit) {
|
||||
// The reason for lit is conceptually:
|
||||
// x1 = v1 /\ ... /\ xn = vn ==> lit
|
||||
|
||||
|
@ -227,19 +287,21 @@ namespace polysat {
|
|||
logger().log(inf_resolve_with_assignment(s, lit, c));
|
||||
}
|
||||
|
||||
bool conflict2::resolve_value(pvar v) {
|
||||
SASSERT(contains_pvar(v));
|
||||
|
||||
if (is_backjumping()) {
|
||||
for (auto const& c : s.m_viable.get_constraints(v))
|
||||
for (pvar v : c->vars())
|
||||
logger().log_var(v);
|
||||
return false;
|
||||
}
|
||||
bool conflict::resolve_value(pvar v) {
|
||||
|
||||
if (is_bailout())
|
||||
return false;
|
||||
|
||||
if (is_backtracking()) {
|
||||
for (auto const& c : s.m_viable.get_constraints(v))
|
||||
for (pvar v : c->vars()) {
|
||||
m_relevant_vars.insert(v);
|
||||
logger().log_var(v);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SASSERT(contains_pvar(v));
|
||||
auto const& j = s.m_justification[v];
|
||||
|
||||
if (j.is_decision() && m_bail_vars.contains(v)) // TODO: what if also m_vars.contains(v)? might have a chance at elimination
|
||||
|
@ -265,12 +327,79 @@ namespace polysat {
|
|||
// Need to keep the variable in case of decision
|
||||
if (s.is_assigned(v) && j.is_decision())
|
||||
m_vars.insert(v);
|
||||
logger().log("bailout");
|
||||
logger().log("Bailout");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostream& conflict2::display(std::ostream& out) const {
|
||||
out << "TODO\n";
|
||||
clause_ref conflict::build_lemma() {
|
||||
LOG_H3("Build lemma from core");
|
||||
LOG("core: " << *this);
|
||||
clause_builder lemma(s);
|
||||
|
||||
// TODO: is this sound, doing it for each constraint separately?
|
||||
// for (auto c : *this)
|
||||
// minimize_vars(c);
|
||||
|
||||
for (auto c : *this)
|
||||
lemma.push(~c);
|
||||
|
||||
for (unsigned v : m_vars) {
|
||||
auto eq = s.eq(s.var(v), s.get_value(v));
|
||||
if (eq.bvalue(s) == l_undef)
|
||||
s.assign_eval(eq.blit());
|
||||
lemma.push(~eq);
|
||||
}
|
||||
s.decay_activity();
|
||||
|
||||
logger().log_lemma(lemma);
|
||||
logger().end_conflict();
|
||||
|
||||
return lemma.build();
|
||||
}
|
||||
|
||||
bool conflict::minimize_vars(signed_constraint c) {
|
||||
if (m_vars.empty())
|
||||
return false;
|
||||
if (!c.is_currently_false(s))
|
||||
return false;
|
||||
|
||||
assignment_t a;
|
||||
for (auto v : m_vars)
|
||||
a.push_back(std::make_pair(v, s.get_value(v)));
|
||||
for (unsigned i = 0; i < a.size(); ++i) {
|
||||
std::pair<pvar, rational> save = a[i];
|
||||
std::pair<pvar, rational> last = a.back();
|
||||
a[i] = last;
|
||||
a.pop_back();
|
||||
if (c.is_currently_false(s, a))
|
||||
--i;
|
||||
else {
|
||||
a.push_back(last);
|
||||
a[i] = save;
|
||||
}
|
||||
}
|
||||
if (a.size() == m_vars.num_elems())
|
||||
return false;
|
||||
m_vars.reset();
|
||||
for (auto const& [v, val] : a)
|
||||
m_vars.insert(v);
|
||||
logger().log("minimize vars");
|
||||
LOG("reduced " << m_vars);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ostream& conflict::display(std::ostream& out) const {
|
||||
char const* sep = "";
|
||||
for (auto c : *this)
|
||||
out << sep << c->bvar2string() << " " << c, sep = " ; ";
|
||||
if (!m_vars.empty())
|
||||
out << " vars";
|
||||
for (auto v : m_vars)
|
||||
out << " v" << v;
|
||||
if (!m_bail_vars.empty())
|
||||
out << " bail vars";
|
||||
for (auto v : m_bail_vars)
|
||||
out << " v" << v;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,42 +77,54 @@ TODO:
|
|||
- bailout lemma if no method applies (log these cases in particular because it indicates where we are missing something)
|
||||
- force a restart if we get a bailout lemma or non-asserting conflict?
|
||||
- consider case if v is both in vars and bail_vars (do we need to keep it in bail_vars even if we can eliminate it from vars?)
|
||||
- Find a way to use resolve_value with forbidden interval lemmas.
|
||||
Then get rid of conflict_kind_t::backtrack and m_relevant_vars.
|
||||
Maybe:
|
||||
x := a, y := b, z has no viable value
|
||||
- assume y was propagated
|
||||
- FI-Lemma C1 \/ ... \/ Cn without z.
|
||||
- for each i, we should have x := a /\ Ci ==> y != b
|
||||
- can we choose one of the Ci to cover the domain of y and extract an FI-Lemma D1 \/ ... \/ Dk without y,z?
|
||||
- or try to find an L(x,y) such that C1 -> L, ..., Cn -> L, and L -> y != b (under x := a); worst case y != b can work as L
|
||||
- minimize_vars... is it sound to do for each constraint separately, like we are doing now?
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "math/polysat/constraint.h"
|
||||
#include "math/polysat/clause_builder.h"
|
||||
#include "math/polysat/inference_logger.h"
|
||||
#include <optional>
|
||||
|
||||
namespace polysat {
|
||||
|
||||
class solver;
|
||||
class explainer;
|
||||
class inference_engine;
|
||||
class variable_elimination_engine;
|
||||
class conflict_iterator;
|
||||
class inference_logger;
|
||||
|
||||
enum class conflict2_kind_t {
|
||||
enum class conflict_kind_t {
|
||||
// standard conflict resolution
|
||||
ok,
|
||||
// bailout lemma because no appropriate conflict resolution method applies
|
||||
bailout,
|
||||
// conflict contains the final lemma;
|
||||
// backtrack to and revert the last relevant decision
|
||||
// NOTE: this is currently used for the forbidden intervals lemmas.
|
||||
// we should find a way to use resolve_value with these lemmas,
|
||||
// to properly eliminate value propagations. (see todo notes above)
|
||||
backtrack,
|
||||
// conflict contains the final lemma;
|
||||
// force backjumping without further conflict resolution because a good lemma has been found
|
||||
// TODO: distinguish backtrack/revert of last decision from backjump to second-highest level in the lemma
|
||||
backjump,
|
||||
};
|
||||
|
||||
class conflict2 {
|
||||
class conflict {
|
||||
solver& s;
|
||||
scoped_ptr<inference_logger> m_logger;
|
||||
|
||||
// current conflict core consists of m_literals and m_vars
|
||||
indexed_uint_set m_literals; // set of boolean literals in the conflict
|
||||
uint_set m_vars; // variable assignments used as premises, shorthand for literals (x := v)
|
||||
uint_set m_bail_vars; // tracked for cone of influence but not directly involved in conflict resolution
|
||||
uint_set m_bail_vars; // decision variables that are only used to evaluate a constraint; see resolve_with_assignment.
|
||||
uint_set m_relevant_vars; // tracked for cone of influence but not directly involved in conflict resolution
|
||||
|
||||
unsigned_vector m_var_occurrences; // for each variable, the number of constraints in m_literals that contain it
|
||||
|
||||
|
@ -120,31 +132,47 @@ namespace polysat {
|
|||
// TODO: we might not need all of these in the end. add only the side lemmas which justify a constraint in the final lemma (recursively)?
|
||||
vector<clause_ref> m_lemmas;
|
||||
|
||||
conflict2_kind_t m_kind = conflict2_kind_t::ok;
|
||||
conflict_kind_t m_kind = conflict_kind_t::ok;
|
||||
|
||||
bool minimize_vars(signed_constraint c);
|
||||
|
||||
public:
|
||||
conflict2(solver& s);
|
||||
conflict(solver& s);
|
||||
|
||||
inference_logger& logger();
|
||||
|
||||
bool empty() const;
|
||||
void reset();
|
||||
|
||||
uint_set const& vars() const { return m_vars; }
|
||||
using const_iterator = conflict_iterator;
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
|
||||
bool is_bailout() const { return m_kind == conflict2_kind_t::bailout; }
|
||||
bool is_backjumping() const { return m_kind == conflict2_kind_t::backjump; }
|
||||
uint_set const& vars() const { return m_vars; }
|
||||
uint_set const& bail_vars() const { return m_bail_vars; }
|
||||
|
||||
conflict_kind_t kind() const { return m_kind; }
|
||||
bool is_bailout() const { return m_kind == conflict_kind_t::bailout; }
|
||||
bool is_backtracking() const { return m_kind == conflict_kind_t::backtrack; }
|
||||
bool is_backjumping() const { return m_kind == conflict_kind_t::backjump; }
|
||||
void set_bailout();
|
||||
void set_backtrack();
|
||||
void set_backjump();
|
||||
|
||||
bool is_relevant_pvar(pvar v) const;
|
||||
bool is_relevant(sat::literal lit) const;
|
||||
|
||||
/** conflict because the constraint c is false under current variable assignment */
|
||||
void init(signed_constraint c);
|
||||
/** boolean conflict with the given clause */
|
||||
void init(clause const& cl);
|
||||
/** conflict because there is no viable value for the variable v */
|
||||
void init(pvar v, bool by_viable_fallback = false);
|
||||
void init(pvar v, bool by_viable_fallback);
|
||||
|
||||
bool contains(signed_constraint c) const { SASSERT(c); return contains(c.blit()); }
|
||||
bool contains(sat::literal lit) const;
|
||||
bool contains_pvar(pvar v) const { return m_vars.contains(v) || m_bail_vars.contains(v); }
|
||||
bool pvar_occurs_in_constraints(pvar v) const { return v < m_var_occurrences.size() && m_var_occurrences[v] > 0; }
|
||||
|
||||
/**
|
||||
* Insert constraint c into conflict state.
|
||||
|
@ -172,9 +200,53 @@ namespace polysat {
|
|||
/** Perform resolution with "v = value <- ..." */
|
||||
bool resolve_value(pvar v);
|
||||
|
||||
/** Convert the core into a lemma to be learned. */
|
||||
clause_ref build_lemma();
|
||||
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, conflict2 const& c) { return c.display(out); }
|
||||
inline std::ostream& operator<<(std::ostream& out, conflict const& c) { return c.display(out); }
|
||||
|
||||
class conflict_iterator {
|
||||
friend class conflict;
|
||||
|
||||
using inner_t = indexed_uint_set::iterator;
|
||||
|
||||
constraint_manager* m_cm;
|
||||
inner_t m_inner;
|
||||
|
||||
conflict_iterator(constraint_manager& cm, inner_t inner):
|
||||
m_cm(&cm), m_inner(inner) {}
|
||||
|
||||
static conflict_iterator begin(constraint_manager& cm, indexed_uint_set const& lits) {
|
||||
return {cm, lits.begin()};
|
||||
}
|
||||
|
||||
static conflict_iterator end(constraint_manager& cm, indexed_uint_set const& lits) {
|
||||
return {cm, lits.end()};
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = signed_constraint;
|
||||
using difference_type = unsigned;
|
||||
using pointer = signed_constraint const*;
|
||||
using reference = signed_constraint const&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
conflict_iterator& operator++() {
|
||||
++m_inner;
|
||||
return *this;
|
||||
}
|
||||
|
||||
signed_constraint operator*() const {
|
||||
return m_cm->lookup(sat::to_literal(*m_inner));
|
||||
}
|
||||
|
||||
bool operator==(conflict_iterator const& other) const {
|
||||
return m_inner == other.m_inner;
|
||||
}
|
||||
|
||||
bool operator!=(conflict_iterator const& other) const { return !operator==(other); }
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,48 +40,53 @@ namespace polysat {
|
|||
return std::string(70, '-');
|
||||
}
|
||||
|
||||
void file_inference_logger::begin_conflict(char const* text) {
|
||||
void file_inference_logger::begin_conflict(displayable const& header) {
|
||||
++m_num_conflicts;
|
||||
if (text)
|
||||
LOG("Begin CONFLICT #" << m_num_conflicts << " (" << text << ")");
|
||||
else
|
||||
LOG("Begin CONFLICT #" << m_num_conflicts);
|
||||
LOG("Begin CONFLICT #" << m_num_conflicts << ": " << header);
|
||||
m_used_constraints.reset();
|
||||
m_used_vars.reset();
|
||||
if (!m_out)
|
||||
m_out = alloc(std::ofstream, "conflicts.txt");
|
||||
else
|
||||
out() << "\n\n\n\n\n\n\n\n\n\n\n\n";
|
||||
out() << "CONFLICT #" << m_num_conflicts;
|
||||
if (text)
|
||||
out() << " (" << text << ")";
|
||||
out() << "\n";
|
||||
out() << "CONFLICT #" << m_num_conflicts << ": " << header << "\n";
|
||||
// log initial conflict state
|
||||
out() << hline() << "\n";
|
||||
log_conflict_state();
|
||||
}
|
||||
|
||||
void file_inference_logger::log_conflict_state() {
|
||||
out() << "TODO";
|
||||
/* TODO: update for new conflict
|
||||
conflict2 const& core = s.m_conflict2;
|
||||
conflict const& core = s.m_conflict;
|
||||
for (auto const& c : core) {
|
||||
out_indent() << c.blit() << ": " << c << '\n';
|
||||
m_used_constraints.insert(c.blit().index());
|
||||
sat::literal const lit = c.blit();
|
||||
out_indent() << lit << ": " << c << '\n';
|
||||
// TODO: if justified by a side lemma, print it here
|
||||
// out_indent() << " justified by: " << lemma << '\n';
|
||||
m_used_constraints.insert(lit.index());
|
||||
for (pvar v : c->vars())
|
||||
m_used_vars.insert(v);
|
||||
}
|
||||
for (auto v : core.vars()) {
|
||||
out_indent() << assignment_pp(core.s, v, core.s.get_value(v)) << "\n";
|
||||
out_indent() << assignment_pp(s, v, s.get_value(v)) << "\n";
|
||||
m_used_vars.insert(v);
|
||||
}
|
||||
for (auto v : core.bail_vars()) {
|
||||
out_indent() << assignment_pp(core.s, v, core.s.get_value(v)) << " (bail)\n";
|
||||
out_indent() << assignment_pp(s, v, s.get_value(v)) << " (bail)\n";
|
||||
m_used_vars.insert(v);
|
||||
}
|
||||
if (core.is_bailout())
|
||||
switch (core.kind()) {
|
||||
case conflict_kind_t::ok:
|
||||
break;
|
||||
case conflict_kind_t::bailout:
|
||||
out_indent() << "(bailout)\n";
|
||||
*/
|
||||
break;
|
||||
case conflict_kind_t::backtrack:
|
||||
out_indent() << "(backtrack)\n";
|
||||
break;
|
||||
case conflict_kind_t::backjump:
|
||||
out_indent() << "(backjump)\n";
|
||||
break;
|
||||
}
|
||||
out().flush();
|
||||
}
|
||||
|
||||
|
@ -102,7 +107,6 @@ namespace polysat {
|
|||
out() << "\n";
|
||||
for (auto const& lit : cb)
|
||||
out_indent() << lit_pp(s, lit) << "\n";
|
||||
// out_indent() << lit << ": " << s.lit2cnstr(lit) << "\n";
|
||||
out().flush();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,13 +26,26 @@ namespace polysat {
|
|||
class search_item;
|
||||
class solver;
|
||||
|
||||
class inference {
|
||||
class displayable {
|
||||
public:
|
||||
virtual ~inference() {}
|
||||
virtual ~displayable() {}
|
||||
virtual std::ostream& display(std::ostream& out) const = 0;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, inference const& i) { return i.display(out); }
|
||||
inline std::ostream& operator<<(std::ostream& out, displayable const& d) { return d.display(out); }
|
||||
|
||||
class display_c_str : public displayable {
|
||||
char const* m_str;
|
||||
public:
|
||||
display_c_str(char const* str) : m_str(str) { }
|
||||
std::ostream& display(std::ostream& out) const override {
|
||||
if (m_str)
|
||||
out << m_str;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
class inference : public displayable { };
|
||||
|
||||
class inference_named : public inference {
|
||||
char const* m_name;
|
||||
|
@ -46,12 +59,14 @@ namespace polysat {
|
|||
virtual ~inference_logger() {}
|
||||
|
||||
/// Begin next conflict
|
||||
virtual void begin_conflict(char const* text = nullptr) = 0;
|
||||
void begin_conflict(char const* text = nullptr) { begin_conflict(display_c_str(text)); }
|
||||
virtual void begin_conflict(displayable const& header) = 0;
|
||||
/// Log inference and the current state.
|
||||
virtual void log(inference const& inf) = 0;
|
||||
virtual void log(char const* name) { log(inference_named(name)); }
|
||||
virtual void log_var(pvar v) = 0;
|
||||
/// Log relevant part of search state and viable.
|
||||
/// Call end_conflict before backjumping in the solver.
|
||||
virtual void end_conflict() = 0;
|
||||
|
||||
/// Log current conflict state (implicitly done by log_inference)
|
||||
|
@ -62,7 +77,7 @@ namespace polysat {
|
|||
|
||||
class dummy_inference_logger : public inference_logger {
|
||||
public:
|
||||
virtual void begin_conflict(char const* text) override {}
|
||||
virtual void begin_conflict(displayable const& header) override {}
|
||||
virtual void log(inference const& inf) override {}
|
||||
virtual void log_var(pvar v) override {}
|
||||
virtual void end_conflict() override {}
|
||||
|
@ -85,18 +100,11 @@ namespace polysat {
|
|||
|
||||
public:
|
||||
file_inference_logger(solver& s);
|
||||
|
||||
/// Begin next conflict
|
||||
void begin_conflict(char const* text) override;
|
||||
/// Log inference and the current state.
|
||||
void begin_conflict(displayable const& header) override;
|
||||
void log(inference const& inf) override;
|
||||
void log_var(pvar v) override;
|
||||
/// Log relevant part of search state and viable.
|
||||
void end_conflict() override;
|
||||
|
||||
/// Log current conflict state (implicitly done by log_inference)
|
||||
void log_conflict_state() override;
|
||||
|
||||
void log_lemma(clause_builder const& cb) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace polysat {
|
|||
m_viable_fallback(*this),
|
||||
m_linear_solver(*this),
|
||||
m_conflict(*this),
|
||||
m_conflict2(*this),
|
||||
m_simplify_clause(*this),
|
||||
m_simplify(*this),
|
||||
m_restart(*this),
|
||||
|
@ -545,7 +544,7 @@ namespace polysat {
|
|||
// (fail here in debug mode so we notice if we miss some)
|
||||
DEBUG_CODE( UNREACHABLE(); );
|
||||
m_free_pvars.unassign_var_eh(v);
|
||||
set_conflict(v);
|
||||
set_conflict(v, false);
|
||||
return;
|
||||
case dd::find_t::singleton:
|
||||
// NOTE: this case may happen legitimately if all other possibilities were excluded by brute force search
|
||||
|
@ -578,8 +577,7 @@ namespace polysat {
|
|||
case dd::find_t::empty:
|
||||
LOG("Fallback solver: unsat");
|
||||
m_free_pvars.unassign_var_eh(v);
|
||||
auto core = m_viable_fallback.unsat_core(v); // TODO: add constraints from unsat_core to conflict
|
||||
set_conflict(v);
|
||||
set_conflict(v, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -620,17 +618,6 @@ namespace polysat {
|
|||
|
||||
SASSERT(is_conflict());
|
||||
|
||||
if (m_conflict.conflict_var() != null_var) {
|
||||
m_conflict.begin_conflict("backtrack_fi");
|
||||
pvar v = m_conflict.conflict_var();
|
||||
// This case corresponds to a propagation of conflict_var, except it's not explicitly on the stack.
|
||||
// TODO: use unsat core from m_viable_fallback if the conflict is from there
|
||||
VERIFY(m_viable.resolve(v, m_conflict));
|
||||
backtrack_fi();
|
||||
return;
|
||||
}
|
||||
m_conflict.begin_conflict("resolve_conflict");
|
||||
|
||||
search_iterator search_it(m_search);
|
||||
while (search_it.next()) {
|
||||
auto& item = *search_it;
|
||||
|
@ -638,23 +625,21 @@ namespace polysat {
|
|||
if (item.is_assignment()) {
|
||||
// Resolve over variable assignment
|
||||
pvar v = item.var();
|
||||
if (!m_conflict.contains_pvar(v) && !m_conflict.is_bailout()) {
|
||||
// if (!m_conflict.contains_pvar(v) && !m_conflict.is_bailout()) {
|
||||
if (!m_conflict.is_relevant_pvar(v)) {
|
||||
m_search.pop_assignment();
|
||||
continue;
|
||||
}
|
||||
LOG_H2("Working on " << search_item_pp(m_search, item));
|
||||
LOG(m_justification[v]);
|
||||
LOG("Conflict: " << m_conflict);
|
||||
// inc_activity(v); // done in resolve_value
|
||||
justification& j = m_justification[v];
|
||||
if (j.level() > base_level() && !m_conflict.resolve_value(v) && j.is_decision()) {
|
||||
m_conflict.end_conflict();
|
||||
revert_decision(v);
|
||||
return;
|
||||
}
|
||||
if (m_conflict.is_bailout_lemma()) {
|
||||
m_conflict.end_conflict();
|
||||
backtrack_lemma();
|
||||
if (m_conflict.is_backjumping()) {
|
||||
backjump_lemma();
|
||||
return;
|
||||
}
|
||||
m_search.pop_assignment();
|
||||
|
@ -664,36 +649,37 @@ namespace polysat {
|
|||
SASSERT(item.is_boolean());
|
||||
sat::literal const lit = item.lit();
|
||||
sat::bool_var const var = lit.var();
|
||||
if (!m_conflict.is_marked(var))
|
||||
if (!m_conflict.is_relevant(lit))
|
||||
continue;
|
||||
|
||||
LOG_H2("Working on " << search_item_pp(m_search, item));
|
||||
LOG(bool_justification_pp(m_bvars, lit));
|
||||
LOG("Literal " << lit << " is " << lit2cnstr(lit));
|
||||
LOG("Conflict: " << m_conflict);
|
||||
if (m_bvars.is_assumption(var)) // TODO: wouldn't this mean we're already at the base level?
|
||||
continue;
|
||||
if (m_bvars.is_assumption(var)) {
|
||||
SASSERT(m_bvars.level(var) <= base_level());
|
||||
break;
|
||||
}
|
||||
else if (m_bvars.is_bool_propagation(var))
|
||||
m_conflict.resolve(lit, *m_bvars.reason(lit));
|
||||
m_conflict.resolve_bool(lit, *m_bvars.reason(lit));
|
||||
else {
|
||||
SASSERT(m_bvars.is_value_propagation(var));
|
||||
m_conflict.resolve_with_assignment(lit, m_bvars.level(lit));
|
||||
m_conflict.resolve_with_assignment(lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG("End of resolve_conflict loop");
|
||||
m_conflict.end_conflict();
|
||||
m_conflict.logger().end_conflict();
|
||||
report_unsat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple backtracking for lemmas:
|
||||
* Simple backjumping for lemmas:
|
||||
* jump to the level where the lemma can be (bool-)propagated,
|
||||
* even without reverting the last decision.
|
||||
*/
|
||||
void solver::backtrack_lemma() {
|
||||
clause_ref lemma = m_conflict.build_lemma().build();
|
||||
LOG_H2("backtrack_lemma: " << show_deref(lemma));
|
||||
void solver::backjump_lemma() {
|
||||
clause_ref lemma = m_conflict.build_lemma();
|
||||
LOG_H2("backjump_lemma: " << show_deref(lemma));
|
||||
SASSERT(lemma);
|
||||
LOG("Lemma: " << *lemma);
|
||||
for (sat::literal lit : *lemma) {
|
||||
|
@ -715,6 +701,7 @@ namespace polysat {
|
|||
jump_level = lit_level;
|
||||
}
|
||||
}
|
||||
SASSERT(max_level == m_level); // not required; see comment on max_level
|
||||
|
||||
jump_level = std::max(jump_level, base_level());
|
||||
|
||||
|
@ -728,69 +715,6 @@ namespace polysat {
|
|||
learn_lemma(*lemma);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simpler backtracking for forbidden interval lemmas:
|
||||
* since forbidden intervals already gives us a lemma where the conflict variable has been eliminated,
|
||||
* we can backtrack to the last relevant decision and learn this lemma.
|
||||
*/
|
||||
void solver::backtrack_fi() {
|
||||
uint_set relevant_vars;
|
||||
search_iterator search_it(m_search);
|
||||
while (search_it.next()) {
|
||||
auto& item = *search_it;
|
||||
search_it.set_resolved();
|
||||
if (item.is_assignment()) {
|
||||
// Resolve over variable assignment
|
||||
pvar v = item.var();
|
||||
if (!m_conflict.pvar_occurs_in_constraints(v) && !relevant_vars.contains(v)) {
|
||||
m_search.pop_assignment();
|
||||
continue;
|
||||
}
|
||||
LOG_H2("Working on " << search_item_pp(m_search, item));
|
||||
LOG(m_justification[v]);
|
||||
LOG("Conflict: " << m_conflict);
|
||||
inc_activity(v);
|
||||
justification& j = m_justification[v];
|
||||
if (j.level() > base_level() && j.is_decision()) {
|
||||
m_conflict.end_conflict();
|
||||
revert_decision(v);
|
||||
return;
|
||||
}
|
||||
SASSERT(j.is_propagation());
|
||||
// If a variable was propagated:
|
||||
// we don't really care about the constraints in this case, but just about the variables it depends on
|
||||
for (auto const& c : m_viable.get_constraints(v))
|
||||
for (pvar v : c->vars()) {
|
||||
relevant_vars.insert(v);
|
||||
m_conflict.log_var(v);
|
||||
}
|
||||
m_search.pop_assignment();
|
||||
}
|
||||
else {
|
||||
// Resolve over boolean literal
|
||||
SASSERT(item.is_boolean());
|
||||
sat::literal const lit = item.lit();
|
||||
sat::bool_var const var = lit.var();
|
||||
if (!m_conflict.is_marked(var))
|
||||
continue;
|
||||
LOG_H2("Working on " << search_item_pp(m_search, item));
|
||||
LOG(bool_justification_pp(m_bvars, lit));
|
||||
LOG("Literal " << lit << " is " << lit2cnstr(lit));
|
||||
LOG("Conflict: " << m_conflict);
|
||||
if (m_bvars.is_assumption(var)) // TODO: wouldn't this mean we're already at the base level?
|
||||
continue;
|
||||
else if (m_bvars.is_bool_propagation(var))
|
||||
m_conflict.resolve(lit, *m_bvars.reason(lit));
|
||||
else {
|
||||
SASSERT(m_bvars.is_value_propagation(var));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_conflict.end_conflict();
|
||||
report_unsat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable activity accounting.
|
||||
* As a placeholder we increment activity
|
||||
|
@ -839,6 +763,7 @@ namespace polysat {
|
|||
LOG("Learning: "<< lemma);
|
||||
SASSERT(!lemma.empty());
|
||||
m_simplify_clause.apply(lemma);
|
||||
// TODO: print warning if the lemma is non-asserting?
|
||||
add_clause(lemma);
|
||||
}
|
||||
|
||||
|
@ -858,7 +783,7 @@ namespace polysat {
|
|||
LOG_H3("Reverting decision: pvar " << v << " := " << val);
|
||||
SASSERT(m_justification[v].is_decision());
|
||||
|
||||
clause_ref lemma = m_conflict.build_lemma().build();
|
||||
clause_ref lemma = m_conflict.build_lemma();
|
||||
if (lemma->empty())
|
||||
report_unsat();
|
||||
else {
|
||||
|
@ -887,7 +812,7 @@ namespace polysat {
|
|||
}
|
||||
|
||||
void solver::assign_eval(sat::literal lit) {
|
||||
SASSERT(lit2cnstr(lit).is_currently_true(*this));
|
||||
// SASSERT(lit2cnstr(lit).is_currently_true(*this)); // "morally" this should hold, but currently fails because of pop_assignment during resolve_conflict
|
||||
unsigned level = 0;
|
||||
// NOTE: constraint may be evaluated even if some variables are still unassigned (e.g., 0*x doesn't depend on x).
|
||||
for (auto v : lit2cnstr(lit)->vars())
|
||||
|
@ -934,12 +859,13 @@ namespace polysat {
|
|||
void solver::add_clause(clause& clause) {
|
||||
LOG((clause.is_redundant() ? "Lemma: ": "Aux: ") << clause);
|
||||
for (sat::literal lit : clause) {
|
||||
LOG(" Literal " << lit << " is: " << lit_pp(*this, lit));
|
||||
LOG(" " << lit_pp(*this, lit));
|
||||
// SASSERT(m_bvars.value(lit) != l_true);
|
||||
// it could be that such a literal has been created previously but we don't detect it when e.g. narrowing a mul_ovfl_constraint
|
||||
if (m_bvars.value(lit) == l_true) {
|
||||
// in this case the clause is useless
|
||||
LOG(" Clause is already true, skipping...");
|
||||
// SASSERT(false); // should never happen (at least for redundant clauses)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1106,12 +1032,14 @@ namespace polysat {
|
|||
* Check that two variables of each constraint are watched.
|
||||
*/
|
||||
bool solver::wlist_invariant() {
|
||||
#if 0
|
||||
for (pvar v = 0; v < m_value.size(); ++v) {
|
||||
std::stringstream s;
|
||||
for (constraint* c : m_pwatch[v])
|
||||
s << " " << c->bvar();
|
||||
LOG("Watch for v" << v << ": " << s.str());
|
||||
}
|
||||
#endif
|
||||
// Skip boolean variables that aren't active yet
|
||||
uint_set skip;
|
||||
for (unsigned i = m_qhead; i < m_search.size(); ++i)
|
||||
|
|
|
@ -22,7 +22,6 @@ Author:
|
|||
#include "util/params.h"
|
||||
#include "math/polysat/boolean.h"
|
||||
#include "math/polysat/conflict.h"
|
||||
#include "math/polysat/conflict2.h"
|
||||
#include "math/polysat/constraint.h"
|
||||
#include "math/polysat/clause_builder.h"
|
||||
#include "math/polysat/simplify_clause.h"
|
||||
|
@ -37,8 +36,6 @@ Author:
|
|||
#include "math/polysat/viable.h"
|
||||
#include "math/polysat/log.h"
|
||||
|
||||
|
||||
|
||||
namespace polysat {
|
||||
|
||||
struct config {
|
||||
|
@ -70,14 +67,12 @@ namespace polysat {
|
|||
friend class clause;
|
||||
friend class clause_builder;
|
||||
friend class conflict;
|
||||
friend class conflict2;
|
||||
friend class conflict_explainer;
|
||||
friend class simplify_clause;
|
||||
friend class simplify;
|
||||
friend class restart;
|
||||
friend class explainer;
|
||||
friend class inference_engine;
|
||||
friend class old_inference_logger;
|
||||
friend class file_inference_logger;
|
||||
friend class forbidden_intervals;
|
||||
friend class linear_solver;
|
||||
|
@ -94,7 +89,6 @@ namespace polysat {
|
|||
friend class scoped_solverv;
|
||||
friend class test_polysat;
|
||||
friend class test_fi;
|
||||
friend struct inference_resolve_with_assignment;
|
||||
friend struct inf_resolve_with_assignment;
|
||||
|
||||
reslimit& m_lim;
|
||||
|
@ -105,7 +99,6 @@ namespace polysat {
|
|||
viable_fallback m_viable_fallback; // fallback for viable, using bitblasting over univariate constraints
|
||||
linear_solver m_linear_solver;
|
||||
conflict m_conflict;
|
||||
conflict2 m_conflict2;
|
||||
simplify_clause m_simplify_clause;
|
||||
simplify m_simplify;
|
||||
restart m_restart;
|
||||
|
@ -192,9 +185,9 @@ namespace polysat {
|
|||
void erase_pwatch(pvar v, constraint* c);
|
||||
void erase_pwatch(constraint* c);
|
||||
|
||||
void set_conflict(signed_constraint c) { m_conflict.set(c); }
|
||||
void set_conflict(clause& cl) { m_conflict.set(cl); }
|
||||
void set_conflict(pvar v) { m_conflict.set(v); }
|
||||
void set_conflict(signed_constraint c) { m_conflict.init(c); }
|
||||
void set_conflict(clause& cl) { m_conflict.init(cl); }
|
||||
void set_conflict(pvar v, bool by_viable_fallback) { m_conflict.init(v, by_viable_fallback); }
|
||||
|
||||
bool can_decide() const { return !m_free_pvars.empty(); }
|
||||
void decide();
|
||||
|
@ -202,14 +195,12 @@ namespace polysat {
|
|||
|
||||
void linear_propagate();
|
||||
|
||||
|
||||
bool is_conflict() const { return !m_conflict.empty(); }
|
||||
bool at_base_level() const;
|
||||
unsigned base_level() const;
|
||||
|
||||
void resolve_conflict();
|
||||
void backtrack_fi();
|
||||
void backtrack_lemma();
|
||||
void backjump_lemma();
|
||||
void revert_decision(pvar v);
|
||||
void revert_bool_decision(sat::literal lit);
|
||||
|
||||
|
@ -461,7 +452,4 @@ namespace polysat {
|
|||
|
||||
inline std::ostream& operator<<(std::ostream& out, assignments_pp const& a) { return a.display(out); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,9 +29,19 @@ TODO: improve management of the fallback univariate solvers:
|
|||
#include "util/debug.h"
|
||||
#include "math/polysat/viable.h"
|
||||
#include "math/polysat/solver.h"
|
||||
#include "math/polysat/univariate/univariate_solver.h"
|
||||
|
||||
namespace polysat {
|
||||
|
||||
struct inf_fi : public inference {
|
||||
viable& v;
|
||||
pvar var;
|
||||
inf_fi(viable& v, pvar var) : v(v), var(var) {}
|
||||
std::ostream& display(std::ostream& out) const override {
|
||||
return out << "Forbidden intervals for v" << var << ": " << viable::var_pp(v, var);
|
||||
}
|
||||
};
|
||||
|
||||
viable::viable(solver& s):
|
||||
s(s),
|
||||
m_forbidden_intervals(s) {
|
||||
|
@ -124,7 +134,7 @@ namespace polysat {
|
|||
prop = true;
|
||||
break;
|
||||
case dd::find_t::empty:
|
||||
s.set_conflict(v);
|
||||
s.set_conflict(v, false);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
|
@ -185,7 +195,6 @@ namespace polysat {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
auto create_entry = [&]() {
|
||||
m_trail.push_back({ v, entry_kind::unit_e, ne });
|
||||
s.m_trail.push_back(trail_instr_t::viable_add_i);
|
||||
|
@ -620,20 +629,6 @@ namespace polysat {
|
|||
return dd::find_t::multiple;
|
||||
}
|
||||
|
||||
struct inference_fi : public inference {
|
||||
viable& v;
|
||||
pvar var;
|
||||
inference_fi(viable& v, pvar var) : v(v), var(var) {}
|
||||
std::ostream& display(std::ostream& out) const override {
|
||||
return out << "Forbidden intervals for v" << var << ": " << viable::var_pp(v, var);
|
||||
}
|
||||
};
|
||||
|
||||
bool viable::resolve(pvar v, conflict2& core) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool viable::resolve(pvar v, conflict& core) {
|
||||
if (has_viable(v))
|
||||
return false;
|
||||
|
@ -652,7 +647,7 @@ namespace polysat {
|
|||
auto lhs = hi - next_lo;
|
||||
auto rhs = next_hi - next_lo;
|
||||
signed_constraint c = s.m_constraints.ult(lhs, rhs);
|
||||
core.propagate(c);
|
||||
core.insert_eval(c);
|
||||
#if 0
|
||||
if (n != first) {
|
||||
while {
|
||||
|
@ -667,20 +662,25 @@ namespace polysat {
|
|||
#endif
|
||||
}
|
||||
for (auto sc : e->side_cond)
|
||||
core.propagate(sc);
|
||||
core.insert_eval(sc);
|
||||
core.insert(e->src);
|
||||
e = n;
|
||||
}
|
||||
while (e != first);
|
||||
core.logger().log(inf_fi(*this, v));
|
||||
|
||||
// TODO: should not be here, too general
|
||||
/*
|
||||
for (auto c : core) {
|
||||
if (c.bvalue(s) == l_false) {
|
||||
core.reset();
|
||||
core.set(~c);
|
||||
core.logger().log("");
|
||||
break;
|
||||
}
|
||||
}
|
||||
core.log_inference(inference_fi(*this, v));
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,14 +23,14 @@ Author:
|
|||
#include "util/small_object_allocator.h"
|
||||
#include "math/polysat/types.h"
|
||||
#include "math/polysat/conflict.h"
|
||||
#include "math/polysat/conflict2.h"
|
||||
#include "math/polysat/constraint.h"
|
||||
#include "math/polysat/forbidden_intervals.h"
|
||||
#include "math/polysat/univariate/univariate_solver.h"
|
||||
|
||||
namespace polysat {
|
||||
|
||||
class solver;
|
||||
class univariate_solver;
|
||||
class univariate_solver_factory;
|
||||
|
||||
class viable {
|
||||
friend class test_fi;
|
||||
|
@ -112,7 +112,6 @@ namespace polysat {
|
|||
* \pre there are no viable values for v
|
||||
*/
|
||||
bool resolve(pvar v, conflict& core);
|
||||
bool resolve(pvar v, conflict2& core);
|
||||
|
||||
/** Log all viable values for the given variable.
|
||||
* (Inefficient, but useful for debugging small instances.)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue