mirror of
https://github.com/Z3Prover/z3
synced 2025-07-01 02:18:46 +00:00
merge
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
4c4f916917
11 changed files with 1151 additions and 1095 deletions
|
@ -83,9 +83,9 @@ namespace polysat {
|
||||||
SASSERT(is_value_propagation(lit));
|
SASSERT(is_value_propagation(lit));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bool_var_manager::asserted(sat::literal lit, unsigned lvl, dependency dep) {
|
void bool_var_manager::assumption(sat::literal lit, unsigned lvl, dependency dep) {
|
||||||
LOG("Asserted " << lit << " @ " << lvl);
|
LOG("Asserted " << lit << " @ " << lvl);
|
||||||
assign(dep == null_dependency ? kind_t::decision : kind_t::assumption, lit, lvl, nullptr, dep);
|
assign(kind_t::assumption, lit, lvl, nullptr, dep);
|
||||||
SASSERT(is_decision(lit) || is_assumption(lit));
|
SASSERT(is_decision(lit) || is_assumption(lit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace polysat {
|
||||||
void decide(sat::literal lit, unsigned lvl, clause& lemma);
|
void decide(sat::literal lit, unsigned lvl, clause& lemma);
|
||||||
void decide(sat::literal lit, unsigned lvl);
|
void decide(sat::literal lit, unsigned lvl);
|
||||||
void eval(sat::literal lit, unsigned lvl);
|
void eval(sat::literal lit, unsigned lvl);
|
||||||
void asserted(sat::literal lit, unsigned lvl, dependency dep);
|
void assumption(sat::literal lit, unsigned lvl, dependency dep);
|
||||||
void unassign(sat::literal lit);
|
void unassign(sat::literal lit);
|
||||||
|
|
||||||
std::ostream& display(std::ostream& out) const;
|
std::ostream& display(std::ostream& out) const;
|
||||||
|
|
|
@ -50,8 +50,11 @@ namespace polysat {
|
||||||
if (!m_vars.empty())
|
if (!m_vars.empty())
|
||||||
out << " vars";
|
out << " vars";
|
||||||
for (auto v : m_vars)
|
for (auto v : m_vars)
|
||||||
if (is_pmarked(v))
|
out << " v" << v;
|
||||||
out << " v" << v;
|
if (!m_bail_vars.empty())
|
||||||
|
out << " bail vars";
|
||||||
|
for (auto v : m_bail_vars)
|
||||||
|
out << " v" << v;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +64,7 @@ namespace polysat {
|
||||||
m_constraints.reset();
|
m_constraints.reset();
|
||||||
m_literals.reset();
|
m_literals.reset();
|
||||||
m_vars.reset();
|
m_vars.reset();
|
||||||
|
m_bail_vars.reset();
|
||||||
m_conflict_var = null_var;
|
m_conflict_var = null_var;
|
||||||
m_bailout = false;
|
m_bailout = false;
|
||||||
SASSERT(empty());
|
SASSERT(empty());
|
||||||
|
@ -83,7 +87,7 @@ namespace polysat {
|
||||||
else {
|
else {
|
||||||
SASSERT(c.is_currently_false(s));
|
SASSERT(c.is_currently_false(s));
|
||||||
// TBD: fails with test_subst SASSERT(c.bvalue(s) == l_true);
|
// TBD: fails with test_subst SASSERT(c.bvalue(s) == l_true);
|
||||||
c->set_var_dependent();
|
insert_vars(c);
|
||||||
insert(c);
|
insert(c);
|
||||||
}
|
}
|
||||||
SASSERT(!empty());
|
SASSERT(!empty());
|
||||||
|
@ -140,6 +144,25 @@ namespace polysat {
|
||||||
m_constraints.push_back(c);
|
m_constraints.push_back(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void conflict::propagate(signed_constraint c) {
|
||||||
|
cm().ensure_bvar(c.get());
|
||||||
|
switch (c.bvalue(s)) {
|
||||||
|
case l_undef:
|
||||||
|
s.assign_eval(c.blit());
|
||||||
|
break;
|
||||||
|
case l_true:
|
||||||
|
break;
|
||||||
|
case l_false:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
insert(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void conflict::insert_vars(signed_constraint c) {
|
||||||
|
for (pvar v : c->vars())
|
||||||
|
if (s.is_assigned(v))
|
||||||
|
m_vars.insert(v);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Premises can either be justified by a Clause or by a value assignment.
|
* Premises can either be justified by a Clause or by a value assignment.
|
||||||
|
@ -210,7 +233,7 @@ namespace polysat {
|
||||||
SASSERT(std::count(cl.begin(), cl.end(), ~lit) == 0);
|
SASSERT(std::count(cl.begin(), cl.end(), ~lit) == 0);
|
||||||
|
|
||||||
remove_literal(lit);
|
remove_literal(lit);
|
||||||
unset_bmark(s.lit2cnstr(lit));
|
unset_mark(s.lit2cnstr(lit));
|
||||||
for (sat::literal lit2 : cl)
|
for (sat::literal lit2 : cl)
|
||||||
if (lit2 != lit)
|
if (lit2 != lit)
|
||||||
insert(s.lit2cnstr(~lit2));
|
insert(s.lit2cnstr(~lit2));
|
||||||
|
@ -226,14 +249,17 @@ namespace polysat {
|
||||||
SASSERT(contains_literal(lit));
|
SASSERT(contains_literal(lit));
|
||||||
SASSERT(!contains_literal(~lit));
|
SASSERT(!contains_literal(~lit));
|
||||||
|
|
||||||
remove_literal(lit);
|
|
||||||
signed_constraint c = s.lit2cnstr(lit);
|
signed_constraint c = s.lit2cnstr(lit);
|
||||||
unset_mark(c);
|
bool has_decision = false;
|
||||||
for (pvar v : c->vars()) {
|
for (pvar v : c->vars())
|
||||||
if (s.is_assigned(v) && s.get_level(v) <= lvl) {
|
if (s.is_assigned(v) && s.m_justification[v].is_decision())
|
||||||
m_vars.insert(v);
|
m_bail_vars.insert(v), has_decision = true;
|
||||||
inc_pref(v);
|
|
||||||
}
|
if (!has_decision) {
|
||||||
|
remove(c);
|
||||||
|
for (pvar v : c->vars())
|
||||||
|
if (s.is_assigned(v))
|
||||||
|
m_vars.insert(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,8 +294,6 @@ namespace polysat {
|
||||||
lemma.push(~c);
|
lemma.push(~c);
|
||||||
|
|
||||||
for (unsigned v : m_vars) {
|
for (unsigned v : m_vars) {
|
||||||
if (!is_pmarked(v))
|
|
||||||
continue;
|
|
||||||
auto eq = s.eq(s.var(v), s.get_value(v));
|
auto eq = s.eq(s.var(v), s.get_value(v));
|
||||||
cm().ensure_bvar(eq.get());
|
cm().ensure_bvar(eq.get());
|
||||||
if (eq.bvalue(s) == l_undef)
|
if (eq.bvalue(s) == l_undef)
|
||||||
|
@ -314,42 +338,24 @@ namespace polysat {
|
||||||
bool conflict::resolve_value(pvar v) {
|
bool conflict::resolve_value(pvar v) {
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// In the "standard" case where "v = val" is on the stack:
|
// In the "standard" case where "v = val" is on the stack:
|
||||||
// - core contains both false and true constraints
|
|
||||||
// (originally only false ones, but additional true ones may come from saturation)
|
|
||||||
|
|
||||||
// forbidden interval projection is performed at top level
|
// forbidden interval projection is performed at top level
|
||||||
SASSERT(v != conflict_var());
|
|
||||||
|
|
||||||
if (is_bailout()) {
|
SASSERT(v != conflict_var());
|
||||||
if (!s.m_justification[v].is_decision())
|
|
||||||
m_vars.remove(v);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const& j = s.m_justification[v];
|
auto const& j = s.m_justification[v];
|
||||||
|
|
||||||
s.inc_activity(v);
|
if (j.is_decision() && m_bail_vars.contains(v))
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (j.is_decision() && m_vars.contains(v)) {
|
|
||||||
set_bailout();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
#endif
|
s.inc_activity(v);
|
||||||
|
|
||||||
m_vars.remove(v);
|
m_vars.remove(v);
|
||||||
|
|
||||||
if (j.is_propagation()) {
|
if (is_bailout())
|
||||||
for (auto const& c : s.m_viable.get_constraints(v)) {
|
goto bailout;
|
||||||
if (!c->has_bvar()) {
|
|
||||||
// it is a side-condition that was not propagated already.
|
if (j.is_propagation())
|
||||||
// it is true in the current variable assignment.
|
for (auto const& c : s.m_viable.get_constraints(v))
|
||||||
cm().ensure_bvar(c.get());
|
propagate(c);
|
||||||
s.assign_eval(c.blit());
|
|
||||||
}
|
|
||||||
insert(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG("try-explain v" << v);
|
LOG("try-explain v" << v);
|
||||||
if (try_explain(v))
|
if (try_explain(v))
|
||||||
|
@ -366,6 +372,7 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
LOG("bailout v" << v);
|
LOG("bailout v" << v);
|
||||||
set_bailout();
|
set_bailout();
|
||||||
|
bailout:
|
||||||
if (s.is_assigned(v) && j.is_decision())
|
if (s.is_assigned(v) && j.is_decision())
|
||||||
m_vars.insert(v);
|
m_vars.insert(v);
|
||||||
return false;
|
return false;
|
||||||
|
@ -406,19 +413,12 @@ namespace polysat {
|
||||||
c->set_mark();
|
c->set_mark();
|
||||||
if (c->has_bvar())
|
if (c->has_bvar())
|
||||||
set_bmark(c->bvar());
|
set_bmark(c->bvar());
|
||||||
if (c->is_var_dependent()) {
|
|
||||||
for (auto v : c->vars()) {
|
|
||||||
if (s.is_assigned(v))
|
|
||||||
m_vars.insert(v);
|
|
||||||
inc_pref(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unset marking on the constraint, but keep variable dependencies.
|
* unset marking on the constraint, but keep variable dependencies.
|
||||||
*/
|
*/
|
||||||
void conflict::unset_bmark(signed_constraint c) {
|
void conflict::unset_mark(signed_constraint c) {
|
||||||
if (!c->is_marked())
|
if (!c->is_marked())
|
||||||
return;
|
return;
|
||||||
c->unset_mark();
|
c->unset_mark();
|
||||||
|
@ -426,32 +426,6 @@ namespace polysat {
|
||||||
unset_bmark(c->bvar());
|
unset_bmark(c->bvar());
|
||||||
}
|
}
|
||||||
|
|
||||||
void conflict::unset_mark(signed_constraint c) {
|
|
||||||
if (!c->is_marked())
|
|
||||||
return;
|
|
||||||
unset_bmark(c);
|
|
||||||
if (!c->is_var_dependent())
|
|
||||||
return;
|
|
||||||
c->unset_var_dependent();
|
|
||||||
for (auto v : c->vars())
|
|
||||||
dec_pref(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void conflict::inc_pref(pvar v) {
|
|
||||||
if (v >= m_pvar2count.size())
|
|
||||||
m_pvar2count.resize(v + 1);
|
|
||||||
m_pvar2count[v]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void conflict::dec_pref(pvar v) {
|
|
||||||
SASSERT(m_pvar2count[v] > 0);
|
|
||||||
m_pvar2count[v]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool conflict::is_pmarked(pvar v) const {
|
|
||||||
return m_pvar2count.get(v, 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void conflict::set_bmark(sat::bool_var b) {
|
void conflict::set_bmark(sat::bool_var b) {
|
||||||
if (b >= m_bvar2mark.size())
|
if (b >= m_bvar2mark.size())
|
||||||
m_bvar2mark.resize(b + 1);
|
m_bvar2mark.resize(b + 1);
|
||||||
|
|
|
@ -10,6 +10,64 @@ Author:
|
||||||
Nikolaj Bjorner (nbjorner) 2021-03-19
|
Nikolaj Bjorner (nbjorner) 2021-03-19
|
||||||
Jakob Rath 2021-04-6
|
Jakob Rath 2021-04-6
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
A conflict state is of the form <Vars, Constraints>
|
||||||
|
Where Vars are shorthand for the constraints v = value(v) for v in Vars and value(v) is the assignent.
|
||||||
|
|
||||||
|
The conflict state is unsatisfiable under background clauses F.
|
||||||
|
Dually, the negation is a consequence of F.
|
||||||
|
|
||||||
|
Conflict resolution resolves an assignment in the search stack against the conflict state.
|
||||||
|
|
||||||
|
Assignments are of the form:
|
||||||
|
|
||||||
|
lit <- D => lit - lit is propagated by the clause D => lit
|
||||||
|
lit <- ? - lit is a decision literal.
|
||||||
|
lit <- asserted - lit is asserted
|
||||||
|
lit <- Vars - lit is propagated from variable evaluation.
|
||||||
|
|
||||||
|
v = value <- D - v is assigned value by constraints D
|
||||||
|
v = value <- ? - v is a decision literal.
|
||||||
|
|
||||||
|
- All literals should be assigned in the stack prior to their use.
|
||||||
|
|
||||||
|
l <- D => l, < Vars, { l } u C > ===> < Vars, C u D >
|
||||||
|
l <- ?, < Vars, { l } u C > ===> ~l <- (C & Vars = value(Vars) => ~l)
|
||||||
|
l <- asserted, < Vars, { l } u C > ===> < Vars, { l } u C >
|
||||||
|
l <- Vars', < Vars, { l } u C > ===> < Vars u Vars', C > if all Vars' are propagated
|
||||||
|
l <- Vars', < Vars, { l } u C > ===> Mark < Vars, { l } u C > as bailout
|
||||||
|
|
||||||
|
v = value <- D, < Vars u { v }, C > ===> < Vars, D u C >
|
||||||
|
v = value <- ?, < Vars u { v }, C > ===> v != value <- (C & Vars = value(Vars) => v != value)
|
||||||
|
|
||||||
|
|
||||||
|
Example derivations:
|
||||||
|
|
||||||
|
Trail: z <= y <- asserted
|
||||||
|
xz > xy <- asserted
|
||||||
|
x = a <- ?
|
||||||
|
y = b <- ?
|
||||||
|
z = c <- ?
|
||||||
|
Conflict: < {x, y, z}, xz > xy > when ~O(a,b) and c <= b
|
||||||
|
Append x <= a <- { x }
|
||||||
|
Append y <= b <- { y }
|
||||||
|
Conflict: < {}, y >= z, xz > xy, x <= a, y <= b >
|
||||||
|
Based on: z <= y & x <= a & y <= b => xz <= xy
|
||||||
|
Resolve: y <= b <- { y }, y is a decision variable.
|
||||||
|
Bailout: lemma ~(y >= z & xz > xy & x <= a & y <= b) at decision level of lemma
|
||||||
|
|
||||||
|
With overflow predicate:
|
||||||
|
Append ~O(x, y) <- { x, y }
|
||||||
|
Conflict: < {}, y >= z, xz > xy, ~O(x,y) >
|
||||||
|
Based on z <= y & ~O(x,y) => xz <= xy
|
||||||
|
Resolve: ~O(x, y) <- { x, y } both x, y are decision variables
|
||||||
|
Lemma: y < z or xz <= xy or O(x,y)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--*/
|
--*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "math/polysat/constraint.h"
|
#include "math/polysat/constraint.h"
|
||||||
|
@ -30,15 +88,12 @@ namespace polysat {
|
||||||
signed_constraints m_constraints; // new constraints used as premises
|
signed_constraints m_constraints; // new constraints used as premises
|
||||||
indexed_uint_set m_literals; // set of boolean literals in the conflict
|
indexed_uint_set m_literals; // set of boolean literals in the conflict
|
||||||
uint_set m_vars; // variable assignments used as premises
|
uint_set m_vars; // variable assignments used as premises
|
||||||
|
uint_set m_bail_vars;
|
||||||
|
|
||||||
// If this is not null_var, the conflict was due to empty viable set for this variable.
|
// If this is not null_var, the conflict was due to empty viable set for this variable.
|
||||||
// Can be treated like "v = x" for any value x.
|
// Can be treated like "v = x" for any value x.
|
||||||
pvar m_conflict_var = null_var;
|
pvar m_conflict_var = null_var;
|
||||||
|
|
||||||
unsigned_vector m_pvar2count; // reference count of variables
|
|
||||||
void inc_pref(pvar v);
|
|
||||||
void dec_pref(pvar v);
|
|
||||||
|
|
||||||
bool_vector m_bvar2mark; // mark of Boolean variables
|
bool_vector m_bvar2mark; // mark of Boolean variables
|
||||||
void set_bmark(sat::bool_var b);
|
void set_bmark(sat::bool_var b);
|
||||||
void unset_bmark(sat::bool_var b);
|
void unset_bmark(sat::bool_var b);
|
||||||
|
@ -77,7 +132,7 @@ namespace polysat {
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
bool is_pmarked(pvar v) const;
|
bool contains_pvar(pvar v) const { return m_vars.contains(v) || m_bail_vars.contains(v); }
|
||||||
bool is_bmarked(sat::bool_var b) const;
|
bool is_bmarked(sat::bool_var b) const;
|
||||||
|
|
||||||
/** conflict because the constraint c is false under current variable assignment */
|
/** conflict because the constraint c is false under current variable assignment */
|
||||||
|
@ -87,7 +142,9 @@ namespace polysat {
|
||||||
/** all literals in clause are false */
|
/** all literals in clause are false */
|
||||||
void set(clause const& cl);
|
void set(clause const& cl);
|
||||||
|
|
||||||
|
void propagate(signed_constraint c);
|
||||||
void insert(signed_constraint c);
|
void insert(signed_constraint c);
|
||||||
|
void insert_vars(signed_constraint c);
|
||||||
void insert(signed_constraint c, vector<signed_constraint> const& premises);
|
void insert(signed_constraint c, vector<signed_constraint> const& premises);
|
||||||
void remove(signed_constraint c);
|
void remove(signed_constraint c);
|
||||||
void replace(signed_constraint c_old, signed_constraint c_new, vector<signed_constraint> const& c_new_premises);
|
void replace(signed_constraint c_old, signed_constraint c_new, vector<signed_constraint> const& c_new_premises);
|
||||||
|
|
|
@ -146,7 +146,6 @@ namespace polysat {
|
||||||
unsigned_vector m_vars;
|
unsigned_vector m_vars;
|
||||||
lbool m_external_sign = l_undef;
|
lbool m_external_sign = l_undef;
|
||||||
bool m_is_marked = false;
|
bool m_is_marked = false;
|
||||||
bool m_is_var_dependent = false;
|
|
||||||
bool m_is_active = false;
|
bool m_is_active = false;
|
||||||
/** The boolean variable associated to this constraint, if any.
|
/** The boolean variable associated to this constraint, if any.
|
||||||
* If this is not null_bool_var, then the constraint corresponds to a literal on the assignment stack.
|
* If this is not null_bool_var, then the constraint corresponds to a literal on the assignment stack.
|
||||||
|
@ -207,9 +206,6 @@ namespace polysat {
|
||||||
void unset_mark() { m_is_marked = false; }
|
void unset_mark() { m_is_marked = false; }
|
||||||
bool is_marked() const { return m_is_marked; }
|
bool is_marked() const { return m_is_marked; }
|
||||||
|
|
||||||
void set_var_dependent() { m_is_var_dependent = true; }
|
|
||||||
void unset_var_dependent() { m_is_var_dependent = false; }
|
|
||||||
bool is_var_dependent() const { return m_is_var_dependent; }
|
|
||||||
|
|
||||||
bool is_active() const { return m_is_active; }
|
bool is_active() const { return m_is_active; }
|
||||||
void set_active(bool f) { m_is_active = f; }
|
void set_active(bool f) { m_is_active = f; }
|
||||||
|
|
|
@ -165,10 +165,9 @@ namespace polysat {
|
||||||
auto c2 = s.ule(a, b);
|
auto c2 = s.ule(a, b);
|
||||||
if (!c.is_positive())
|
if (!c.is_positive())
|
||||||
c2 = ~c2;
|
c2 = ~c2;
|
||||||
LOG("try-reduce is false " << c2.is_currently_false(s));
|
|
||||||
if (!c2.is_currently_false(s))
|
if (!c2.is_currently_false(s))
|
||||||
continue;
|
continue;
|
||||||
if (c2.bvalue(s) == l_false)
|
if (c2.is_always_false() || c2.bvalue(s) == l_false)
|
||||||
return false;
|
return false;
|
||||||
if (!c2->has_bvar() || l_undef == c2.bvalue(s)) {
|
if (!c2->has_bvar() || l_undef == c2.bvalue(s)) {
|
||||||
vector<signed_constraint> premises;
|
vector<signed_constraint> premises;
|
||||||
|
|
|
@ -73,11 +73,9 @@ namespace polysat {
|
||||||
// a*v <= 0, a odd
|
// a*v <= 0, a odd
|
||||||
if (match_zero(c, a1, b1, e1, a2, b2, e2, fi))
|
if (match_zero(c, a1, b1, e1, a2, b2, e2, fi))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// a*v + b > 0, a odd
|
// a*v + b > 0, a odd
|
||||||
if (match_non_zero_linear(c, a1, b1, e1, a2, b2, e2, fi))
|
if (match_non_zero_linear(c, a1, b1, e1, a2, b2, e2, fi))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (match_linear1(c, a1, b1, e1, a2, b2, e2, fi))
|
if (match_linear1(c, a1, b1, e1, a2, b2, e2, fi))
|
||||||
return true;
|
return true;
|
||||||
if (match_linear2(c, a1, b1, e1, a2, b2, e2, fi))
|
if (match_linear2(c, a1, b1, e1, a2, b2, e2, fi))
|
||||||
|
@ -349,7 +347,7 @@ namespace polysat {
|
||||||
signed_constraint const& c,
|
signed_constraint const& c,
|
||||||
rational const & a1, pdd const& b1, pdd const& e1,
|
rational const & a1, pdd const& b1, pdd const& e1,
|
||||||
fi_record& fi) {
|
fi_record& fi) {
|
||||||
if (a1.is_odd() && b1.is_zero() && !c.is_positive()) {
|
if (a1.is_odd() && b1.is_zero() && c.is_negative()) {
|
||||||
auto& m = e1.manager();
|
auto& m = e1.manager();
|
||||||
rational lo_val(0);
|
rational lo_val(0);
|
||||||
auto lo = m.zero();
|
auto lo = m.zero();
|
||||||
|
@ -361,7 +359,7 @@ namespace polysat {
|
||||||
fi.side_cond.push_back(s.eq(b1, e1));
|
fi.side_cond.push_back(s.eq(b1, e1));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (a1.is_odd() && b1.is_val() && !c.is_positive()) {
|
if (a1.is_odd() && b1.is_val() && c.is_negative()) {
|
||||||
auto& m = e1.manager();
|
auto& m = e1.manager();
|
||||||
rational const& mod_value = m.two_to_N();
|
rational const& mod_value = m.two_to_N();
|
||||||
rational a1_inv;
|
rational a1_inv;
|
||||||
|
@ -389,7 +387,7 @@ namespace polysat {
|
||||||
signed_constraint const& c,
|
signed_constraint const& c,
|
||||||
rational const & a2, pdd const& b2, pdd const& e2,
|
rational const & a2, pdd const& b2, pdd const& e2,
|
||||||
fi_record& fi) {
|
fi_record& fi) {
|
||||||
if (a2.is_one() && b2.is_val() && !c.is_positive()) {
|
if (a2.is_one() && b2.is_val() && c.is_negative()) {
|
||||||
auto& m = e2.manager();
|
auto& m = e2.manager();
|
||||||
rational const& mod_value = m.two_to_N();
|
rational const& mod_value = m.two_to_N();
|
||||||
rational lo_val(mod(-b2.val() - 1, mod_value));
|
rational lo_val(mod(-b2.val() - 1, mod_value));
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace polysat {
|
||||||
for (auto d : m_new_constraints)
|
for (auto d : m_new_constraints)
|
||||||
core.insert(d);
|
core.insert(d);
|
||||||
if (c.bvalue(s) != l_false)
|
if (c.bvalue(s) != l_false)
|
||||||
c->set_var_dependent();
|
core.insert_vars(c);
|
||||||
core.insert(~c);
|
core.insert(~c);
|
||||||
LOG("Core " << core);
|
LOG("Core " << core);
|
||||||
return true;
|
return true;
|
||||||
|
@ -423,6 +423,22 @@ namespace polysat {
|
||||||
return false;
|
return false;
|
||||||
if (c.lhs.is_val() || c.rhs.is_val())
|
if (c.lhs.is_val() || c.rhs.is_val())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
pdd q_l(c.lhs), e_l(c.lhs), q_r(c.rhs), e_r(c.rhs);
|
||||||
|
bool is_linear = true;
|
||||||
|
is_linear &= c.lhs.degree(v) <= 1;
|
||||||
|
is_linear &= c.rhs.degree(v) <= 1;
|
||||||
|
if (c.lhs.degree(v) == 1) {
|
||||||
|
c.lhs.factor(v, 1, q_l, e_l);
|
||||||
|
is_linear &= q_l.is_val();
|
||||||
|
}
|
||||||
|
if (c.rhs.degree(v) == 1) {
|
||||||
|
c.rhs.factor(v, 1, q_r, e_r);
|
||||||
|
is_linear &= q_r.is_val();
|
||||||
|
}
|
||||||
|
if (is_linear)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!c.as_signed_constraint().is_currently_false(s))
|
if (!c.as_signed_constraint().is_currently_false(s))
|
||||||
return false;
|
return false;
|
||||||
rational l_val, r_val;
|
rational l_val, r_val;
|
||||||
|
|
|
@ -190,14 +190,14 @@ namespace polysat {
|
||||||
switch (m_bvars.value(lit)) {
|
switch (m_bvars.value(lit)) {
|
||||||
case l_false:
|
case l_false:
|
||||||
set_conflict(c);
|
set_conflict(c);
|
||||||
|
SASSERT(dep == null_dependency && "track dependencies is TODO");
|
||||||
break;
|
break;
|
||||||
case l_true:
|
case l_true:
|
||||||
// constraint c is already asserted
|
// constraint c is already asserted
|
||||||
SASSERT(m_bvars.level(lit) <= m_level);
|
SASSERT(m_bvars.level(lit) <= m_level);
|
||||||
// TODO: track additional dep?
|
|
||||||
break;
|
break;
|
||||||
case l_undef:
|
case l_undef:
|
||||||
m_bvars.asserted(lit, m_level, dep);
|
m_bvars.assumption(lit, m_level, dep);
|
||||||
m_trail.push_back(trail_instr_t::assign_bool_i);
|
m_trail.push_back(trail_instr_t::assign_bool_i);
|
||||||
m_search.push_boolean(lit);
|
m_search.push_boolean(lit);
|
||||||
if (c.is_currently_false(*this))
|
if (c.is_currently_false(*this))
|
||||||
|
@ -535,7 +535,7 @@ namespace polysat {
|
||||||
// Resolve over variable assignment
|
// Resolve over variable assignment
|
||||||
pvar v = item.var();
|
pvar v = item.var();
|
||||||
LOG(m_justification[v]);
|
LOG(m_justification[v]);
|
||||||
if (!m_conflict.is_pmarked(v) && !m_conflict.is_bailout()) {
|
if (!m_conflict.contains_pvar(v) && !m_conflict.is_bailout()) {
|
||||||
m_search.pop_assignment();
|
m_search.pop_assignment();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,11 @@ namespace polysat {
|
||||||
|
|
||||||
void viable::pop_viable() {
|
void viable::pop_viable() {
|
||||||
auto& [v, k, e] = m_trail.back();
|
auto& [v, k, e] = m_trail.back();
|
||||||
|
SASSERT(well_formed(m_units[v]));
|
||||||
switch (k) {
|
switch (k) {
|
||||||
case entry_kind::unit_e:
|
case entry_kind::unit_e:
|
||||||
e->remove_from(m_units[v], e);
|
e->remove_from(m_units[v], e);
|
||||||
|
SASSERT(well_formed(m_units[v]));
|
||||||
break;
|
break;
|
||||||
case entry_kind::equal_e:
|
case entry_kind::equal_e:
|
||||||
e->remove_from(m_equal_lin[v], e);
|
e->remove_from(m_equal_lin[v], e);
|
||||||
|
@ -67,13 +69,15 @@ namespace polysat {
|
||||||
SASSERT(e->prev() != e || e->next() == e);
|
SASSERT(e->prev() != e || e->next() == e);
|
||||||
SASSERT(k == entry_kind::unit_e);
|
SASSERT(k == entry_kind::unit_e);
|
||||||
(void)k;
|
(void)k;
|
||||||
|
SASSERT(well_formed(m_units[v]));
|
||||||
if (e->prev() != e) {
|
if (e->prev() != e) {
|
||||||
e->prev()->insert_after(e);
|
e->prev()->insert_after(e);
|
||||||
if (e->interval.lo_val() < e->next()->interval.lo_val())
|
if (e->interval.lo_val() < m_units[v]->interval.lo_val())
|
||||||
m_units[v] = e;
|
m_units[v] = e;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_units[v] = e;
|
m_units[v] = e;
|
||||||
|
SASSERT(well_formed(m_units[v]));
|
||||||
m_trail.pop_back();
|
m_trail.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +106,7 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void viable::insert(entry* e, pvar v, ptr_vector<entry>& entries, entry_kind k) {
|
void viable::insert(entry* e, pvar v, ptr_vector<entry>& entries, entry_kind k) {
|
||||||
|
SASSERT(well_formed(m_units[v]));
|
||||||
m_trail.push_back({ v, k, e });
|
m_trail.push_back({ v, k, e });
|
||||||
s.m_trail.push_back(trail_instr_t::viable_add_i);
|
s.m_trail.push_back(trail_instr_t::viable_add_i);
|
||||||
e->init(e);
|
e->init(e);
|
||||||
|
@ -109,6 +114,7 @@ namespace polysat {
|
||||||
entries[v] = e;
|
entries[v] = e;
|
||||||
else
|
else
|
||||||
e->insert_after(entries[v]);
|
e->insert_after(entries[v]);
|
||||||
|
SASSERT(well_formed(m_units[v]));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool viable::intersect(pvar v, entry* ne) {
|
bool viable::intersect(pvar v, entry* ne) {
|
||||||
|
@ -122,6 +128,7 @@ namespace polysat {
|
||||||
m_alloc.push_back(ne);
|
m_alloc.push_back(ne);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto create_entry = [&]() {
|
auto create_entry = [&]() {
|
||||||
m_trail.push_back({ v, entry_kind::unit_e, ne });
|
m_trail.push_back({ v, entry_kind::unit_e, ne });
|
||||||
|
@ -136,6 +143,13 @@ namespace polysat {
|
||||||
e->remove_from(m_units[v], e);
|
e->remove_from(m_units[v], e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ne->interval.is_full()) {
|
||||||
|
while (m_units[v])
|
||||||
|
remove_entry(m_units[v]);
|
||||||
|
m_units[v] = create_entry();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
m_units[v] = create_entry();
|
m_units[v] = create_entry();
|
||||||
else {
|
else {
|
||||||
|
@ -257,16 +271,21 @@ namespace polysat {
|
||||||
lo = val - lambda_l;
|
lo = val - lambda_l;
|
||||||
increase_hi(hi);
|
increase_hi(hi);
|
||||||
}
|
}
|
||||||
LOG("forbidden interval " << e->coeff << " * " << e->interval << " [" << lo << ", " << hi << "[");
|
LOG("forbidden interval v" << v << " " << val << " " << e->coeff << " * " << e->interval << " [" << lo << ", " << hi << "[");
|
||||||
SASSERT(hi <= mod_value);
|
SASSERT(hi <= mod_value);
|
||||||
if (hi == mod_value) hi = 0;
|
bool full = (lo == 0 && hi == mod_value);
|
||||||
|
if (hi == mod_value)
|
||||||
|
hi = 0;
|
||||||
pdd lop = s.var2pdd(v).mk_val(lo);
|
pdd lop = s.var2pdd(v).mk_val(lo);
|
||||||
pdd hip = s.var2pdd(v).mk_val(hi);
|
pdd hip = s.var2pdd(v).mk_val(hi);
|
||||||
entry* ne = alloc_entry();
|
entry* ne = alloc_entry();
|
||||||
ne->src = e->src;
|
ne->src = e->src;
|
||||||
ne->side_cond = e->side_cond;
|
ne->side_cond = e->side_cond;
|
||||||
ne->coeff = 1;
|
ne->coeff = 1;
|
||||||
ne->interval = eval_interval::proper(lop, lo, hip, hi);
|
if (full)
|
||||||
|
ne->interval = eval_interval::full();
|
||||||
|
else
|
||||||
|
ne->interval = eval_interval::proper(lop, lo, hip, hi);
|
||||||
intersect(v, ne);
|
intersect(v, ne);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -371,6 +390,8 @@ namespace polysat {
|
||||||
entry* first = e;
|
entry* first = e;
|
||||||
entry* last = e->prev();
|
entry* last = e->prev();
|
||||||
|
|
||||||
|
if (e->interval.is_full())
|
||||||
|
return false;
|
||||||
// quick check: last interval doesn't wrap around, so hi_val
|
// quick check: last interval doesn't wrap around, so hi_val
|
||||||
// has not been covered
|
// has not been covered
|
||||||
if (last->interval.lo_val() < last->interval.hi_val())
|
if (last->interval.lo_val() < last->interval.hi_val())
|
||||||
|
@ -413,6 +434,7 @@ namespace polysat {
|
||||||
return refine_viable(v, val);
|
return refine_viable(v, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rational viable::min_viable(pvar v) {
|
rational viable::min_viable(pvar v) {
|
||||||
refined:
|
refined:
|
||||||
rational lo(0);
|
rational lo(0);
|
||||||
|
@ -542,18 +564,15 @@ namespace polysat {
|
||||||
auto lhs = hi - next_lo;
|
auto lhs = hi - next_lo;
|
||||||
auto rhs = next_hi - next_lo;
|
auto rhs = next_hi - next_lo;
|
||||||
signed_constraint c = s.m_constraints.ult(lhs, rhs);
|
signed_constraint c = s.m_constraints.ult(lhs, rhs);
|
||||||
core.insert(c);
|
core.propagate(c);
|
||||||
}
|
}
|
||||||
for (auto sc : e->side_cond)
|
for (auto sc : e->side_cond)
|
||||||
core.insert(sc);
|
core.propagate(sc);
|
||||||
e->src->set_var_dependent();
|
|
||||||
core.insert(e->src);
|
core.insert(e->src);
|
||||||
e = n;
|
e = n;
|
||||||
}
|
}
|
||||||
while (e != first);
|
while (e != first);
|
||||||
|
|
||||||
// core.set_bailout();
|
|
||||||
// TODO - review this; c is true under current assignment?
|
|
||||||
for (auto c : core) {
|
for (auto c : core) {
|
||||||
if (c.bvalue(s) == l_false) {
|
if (c.bvalue(s) == l_false) {
|
||||||
core.reset();
|
core.reset();
|
||||||
|
@ -606,7 +625,7 @@ namespace polysat {
|
||||||
|
|
||||||
std::ostream& viable::display(std::ostream& out) const {
|
std::ostream& viable::display(std::ostream& out) const {
|
||||||
for (pvar v = 0; v < m_units.size(); ++v)
|
for (pvar v = 0; v < m_units.size(); ++v)
|
||||||
display(out << "v" << v << ": ", v);
|
display(out << "v" << v << ": ", v) << "\n";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1967
src/test/polysat.cpp
1967
src/test/polysat.cpp
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue