3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-24 17:45:32 +00:00

fixes, tests

This commit is contained in:
Nikolaj Bjorner 2021-09-25 08:38:48 -07:00
parent e6c413b249
commit a574eebd05
9 changed files with 110 additions and 48 deletions

View file

@ -14,10 +14,6 @@ Notes:
TODO: try a final core reduction step or other core minimization
TODO: If we have e.g. 4x+y=2 and y=0, then we have a conflict no matter the value of x, so we should drop x=? from the core.
(works currently if x is unassigned; for other cases we would need extra info from constraint::is_currently_false)
note that we may have added too many variables: e.g., y disappears in x*y if x=0
TODO: revert(pvar v) is too weak.
It should apply saturation rules currently only available for propagated values.
@ -134,16 +130,22 @@ namespace polysat {
}
// NOTE: maybe we should skip intermediate steps and just collect the leaf premises for c?
// Ensure that c is assigned and justified
/**
* Premises can either be justified by a Clause or by a value assignment.
* Premises that are justified by value assignments are not assigned (the bvalue is l_undef)
* The justification for those premises are based on the free assigned variables.
*
* NOTE: maybe we should skip intermediate steps and just collect the leaf premises for c?
* Ensure that c is assigned and justified
*/
void conflict::insert(signed_constraint c, vector<signed_constraint> const& premises) {
insert(c);
keep(c);
clause_builder c_lemma(s);
for (auto premise : premises) {
LOG_H3("premise: " << premise);
keep(premise);
SASSERT(premise->has_bvar());
SASSERT(premise.bvalue(s) == l_true);
SASSERT(premise.bvalue(s) != l_false);
c_lemma.push(~premise.blit());
}
c_lemma.push(c.blit());
@ -278,15 +280,21 @@ namespace polysat {
return true;
}
std::cout << "vars " << m_vars << " contains: " << m_vars.contains(v) << "\n";
m_vars.remove(v);
for (auto c : cjust_v)
insert(c);
std::cout << "try explain v" << v << "\n";
for (auto* engine : ex_engines)
if (engine->try_explain(v, *this))
return true;
std::cout << "try elim v" << v << "\n";
// No value resolution method was successful => fall back to saturation and variable elimination
while (s.inc()) {
// TODO: as a last resort, substitute v by m_value[v]?
@ -296,7 +304,9 @@ namespace polysat {
break;
}
set_bailout();
m_vars.insert(v);
if (s.is_assigned(v))
m_vars.insert(v);
std::cout << "vars " << m_vars << "\n";
return false;
}

View file

@ -94,6 +94,8 @@ namespace polysat {
if (first)
m_bvars.watch(cl[0]).push_back(&cl);
m_bvars.watch(cl[1]).push_back(&cl);
if (m_bvars.is_true(cl[0]))
return;
if (first)
s.set_conflict(cl);
else
@ -283,6 +285,6 @@ namespace polysat {
}
lbool signed_constraint::bvalue(solver& s) const {
return s.m_bvars.value(blit());
return get()->has_bvar() ? s.m_bvars.value(blit()) : l_undef;
}
}

View file

@ -146,6 +146,7 @@ namespace polysat {
if (!c2->has_bvar() || l_undef == c2.bvalue(s))
core.keep(c2); // adds propagation of c to the search stack
core.reset();
LOG("reduced to " << c2);
if (c2.bvalue(s) == l_false) {
core.insert(eq);
core.insert(c);
@ -166,7 +167,7 @@ namespace polysat {
while (result == l_undef)
result = try_explain1(v, core);
LOG("success? " << result);
return result;
return result == l_true;
}
}

View file

@ -14,7 +14,10 @@ Author:
TODO:
move "forbidden interval method from constraints
compute forbidden interval coefficients a1, a2 modulo current assignment to handle pseudo-linear cases.
test_mont_bounds(8) produces constraint 13 <= v1*v2, where v2 = 1, then v1 is linear and is constrained above 13.
--*/
#include "math/polysat/forbidden_intervals.h"
@ -217,9 +220,15 @@ namespace polysat {
rhs.factor(v, 1, p2, e2);
// Interval extraction only works if v-coefficients are the same
// LOG("factored " << deg1 << " " << deg2 << " " << p1 << " " << p2);
if (deg1 != 0 && deg2 != 0 && p1 != p2)
return false;
// LOG("valued " << p1.is_val() << " " << p2.is_val());
// TODO: p1, p2 could be values under assignment.
// It could allow applying forbidden interval elimination under the assignment.
// test_monot_bounds(8)
//
// Currently only works if coefficient is a power of two
if (!p1.is_val())
return false;
@ -229,6 +238,7 @@ namespace polysat {
rational a2 = p2.val();
// TODO: to express the interval for coefficient 2^i symbolically, we need right-shift/upper-bits-extract in the language.
// So currently we can only do it if the coefficient is 1 or -1.
LOG("values " << a1 << " " << a2);
if (!a1.is_zero() && !a1.is_one() && a1 != minus_one)
return false;
if (!a2.is_zero() && !a2.is_one() && a2 != minus_one)

View file

@ -33,6 +33,8 @@ namespace polysat {
for (auto c1 : core) {
if (!c1->is_ule())
continue;
if (!c1.is_currently_false(s))
continue;
auto c = c1.as_inequality();
if (try_ugt_x(v, core, c))
return true;
@ -59,29 +61,27 @@ namespace polysat {
* Propagate c. It is added to reason and core all other literals in reason are false in current stack.
* The lemmas outlined in the rules are valid and therefore c is implied.
*/
bool inf_saturate::propagate(conflict& core, inequality const& crit1, inequality const& crit2, signed_constraint& c, vector<signed_constraint>& new_constraints) {
bool crit1_false = crit1.as_signed_constraint().is_currently_false(s);
bool crit2_false = crit2.as_signed_constraint().is_currently_false(s);
if (!crit1_false && !crit2_false)
return false;
bool is_bool_false = c.bvalue(s) == l_false;
bool is_model_false = c.is_currently_false(s);
if (!is_bool_false && !is_model_false)
bool inf_saturate::propagate(conflict& core, inequality const& _crit1, inequality const& _crit2, signed_constraint& c, vector<signed_constraint>& new_constraints) {
auto crit1 = _crit1.as_signed_constraint();
auto crit2 = _crit2.as_signed_constraint();
new_constraints.push_back(crit1);
new_constraints.push_back(crit2);
SASSERT(crit1.is_currently_false(s));
if (c.bvalue(s) == l_false) {
core.reset();
for (auto d : new_constraints)
core.insert(d);
core.insert(~c);
return true;
}
if (!c.is_currently_false(s))
return false;
// refresh dependencies for crit1, crit2
// this is called before core.set, which
// rehashes the variable dependencies
core.keep(crit1.as_signed_constraint());
core.keep(crit2.as_signed_constraint());
if (is_bool_false)
core.insert(~c);
else
core.set(c);
// add fresh constraints
for (auto d : new_constraints)
core.insert(d);
core.replace(crit1, c, new_constraints);
core.reset();
core.set(c);
return true;
}
@ -305,7 +305,10 @@ namespace polysat {
return false;
pdd x = s.var(v);
pdd z = x;
for (auto dd : core) {
for (auto si : s.m_search) {
if (!si.is_boolean())
continue;
auto dd = s.lit2cnstr(si.lit());
if (!dd->is_ule())
continue;
auto d = dd.as_inequality();
@ -323,7 +326,10 @@ namespace polysat {
return false;
pdd y = s.var(x);
pdd a = y;
for (auto dd : core) {
for (auto si : s.m_search) {
if (!si.is_boolean())
continue;
auto dd = s.lit2cnstr(si.lit());
if (!dd->is_ule())
continue;
auto d = dd.as_inequality();
@ -355,7 +361,10 @@ namespace polysat {
return false;
pdd y = s.var(z);
pdd x = y;
for (auto dd : core) {
for (auto si : s.m_search) {
if (!si.is_boolean())
continue;
auto dd = s.lit2cnstr(si.lit());
if (!dd->is_ule())
continue;
auto d = dd.as_inequality();

View file

@ -49,6 +49,11 @@ namespace polysat {
m_conflict.reset();
}
void solver::updt_params(params_ref const& p) {
m_params.append(p);
m_branch_bool = m_params.get_bool("branch_bool", false);
}
bool solver::should_search() {
return
m_lim.inc() &&
@ -347,7 +352,7 @@ namespace polysat {
void solver::decide() {
LOG_H2("Decide");
SASSERT(can_decide());
if (m_bvars.can_decide())
if (m_bvars.can_decide() && m_branch_bool)
bdecide(m_bvars.next_var());
else
pdecide(m_free_pvars.next_var());
@ -445,12 +450,12 @@ namespace polysat {
LOG("Justification: " << j);
if (j.level() <= base_level())
break;
if (j.is_decision()) {
if (!resolve_value(v) && j.is_decision()) {
revert_decision(v);
return;
}
SASSERT(j.is_propagation());
resolve_value(v);
//SASSERT(j.is_propagation());
//resolve_value(v);
}
else {
// Resolve over boolean literal
@ -475,8 +480,8 @@ namespace polysat {
}
/** Conflict resolution case where propagation 'v := ...' is on top of the stack */
void solver::resolve_value(pvar v) {
m_conflict.resolve_value(v, m_cjust[v]);
bool solver::resolve_value(pvar v) {
return m_conflict.resolve_value(v, m_cjust[v]);
}
/** Conflict resolution case where boolean literal 'lit' is on top of the stack */
@ -858,6 +863,8 @@ namespace polysat {
signed_constraint sc(c, is_positive);
for (auto const& wlist : m_pwatch) {
auto n = std::count(wlist.begin(), wlist.end(), sc);
if (n > 1)
std::cout << sc << "\n" << * this << "\n";
VERIFY(n <= 1); // no duplicates in the watchlist
num_watches += n;
}

View file

@ -77,6 +77,7 @@ namespace polysat {
uint64_t m_max_conflicts = std::numeric_limits<uint64_t>::max();
uint64_t m_max_decisions = std::numeric_limits<uint64_t>::max();
bool m_branch_bool = false;
@ -171,7 +172,7 @@ namespace polysat {
void set_conflict(clause& cl) { m_conflict.set(cl); }
void set_conflict(pvar v) { m_conflict.set(v); }
bool can_decide() const { return !m_free_pvars.empty() || m_bvars.can_decide(); }
bool can_decide() const { return !m_free_pvars.empty() || (m_branch_bool && m_bvars.can_decide()); }
void decide();
void pdecide(pvar v);
void bdecide(sat::bool_var b);
@ -187,7 +188,7 @@ namespace polysat {
unsigned base_level() const;
void resolve_conflict();
void resolve_value(pvar v);
bool resolve_value(pvar v);
void resolve_bool(sat::literal lit);
void revert_decision(pvar v);
void revert_bool_decision(sat::literal lit);
@ -313,7 +314,11 @@ namespace polysat {
void collect_statistics(statistics& st) const;
params_ref& params() { return m_params; }
params_ref const & params() const { return m_params; }
void updt_params(params_ref const& p);
void get_param_descrs(param_descrs& pd);
};

View file

@ -79,7 +79,7 @@ namespace polysat {
return;
}
// k <= p => p - k <= - k - 1
if (m_lhs.is_val()) {
if (m_lhs.is_val() && false) {
pdd k = m_lhs;
m_lhs = m_rhs - k;
m_rhs = - k - 1;

View file

@ -675,6 +675,17 @@ namespace polysat {
s.pop();
}
static void test_var_minimize(unsigned bw = 32) {
scoped_solver s(__func__);
auto x = s.var(s.add_var(bw));
auto y = s.var(s.add_var(bw));
auto z = s.var(s.add_var(bw));
s.add_eq(x);
s.add_eq(4 * y + 8 * z + x + 2); // should only depend on assignment to x
s.check();
s.expect_unsat();
}
/**
* x*x <= z
@ -1036,6 +1047,11 @@ namespace polysat {
void tst_polysat() {
polysat::test_p3();
polysat::test_var_minimize();
//return;
polysat::test_subst();
@ -1045,10 +1061,10 @@ void tst_polysat() {
// polysat::test_monot_bounds_simple(8);
// working
polysat::test_fixed_point_arith_mul_div_inverse();
// NOT: polysat::test_fixed_point_arith_mul_div_inverse();
polysat::test_monot_bounds(8);
// polysat::test_monot_bounds(8);
polysat::test_add_conflicts();
polysat::test_wlist();
@ -1070,6 +1086,8 @@ void tst_polysat() {
polysat::test_monot_bounds(2);
polysat::test_cjust();
return;
polysat::test_ineq_axiom1();
polysat::test_ineq_axiom2();
polysat::test_ineq_axiom3();