mirror of
https://github.com/Z3Prover/z3
synced 2025-06-22 05:43:39 +00:00
n/a
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
2b49bd189a
commit
207735d55c
8 changed files with 273 additions and 58 deletions
|
@ -58,7 +58,7 @@ def init_project_def():
|
||||||
add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model')
|
add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model')
|
||||||
add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model', 'solver_assertions',
|
add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model', 'solver_assertions',
|
||||||
'substitution', 'grobner', 'simplex', 'proofs', 'pattern', 'parser_util', 'fpa', 'lp'])
|
'substitution', 'grobner', 'simplex', 'proofs', 'pattern', 'parser_util', 'fpa', 'lp'])
|
||||||
add_lib('polysat', ['util', 'dd'], 'sat/smt/polysat'),
|
add_lib('polysat', ['util', 'dd', 'sat'], 'sat/smt/polysat'),
|
||||||
add_lib('sat_smt', ['sat', 'euf', 'smt', 'tactic', 'solver', 'smt_params', 'bit_blaster', 'fpa', 'mbp', 'polysat', 'normal_forms', 'lp', 'pattern', 'qe_lite'], 'sat/smt')
|
add_lib('sat_smt', ['sat', 'euf', 'smt', 'tactic', 'solver', 'smt_params', 'bit_blaster', 'fpa', 'mbp', 'polysat', 'normal_forms', 'lp', 'pattern', 'qe_lite'], 'sat/smt')
|
||||||
add_lib('sat_tactic', ['tactic', 'sat', 'solver', 'sat_smt'], 'sat/tactic')
|
add_lib('sat_tactic', ['tactic', 'sat', 'solver', 'sat_smt'], 'sat/tactic')
|
||||||
add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic')
|
add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic')
|
||||||
|
|
|
@ -107,6 +107,7 @@ namespace polysat {
|
||||||
m_justification.push_back(null_dependency);
|
m_justification.push_back(null_dependency);
|
||||||
m_watch.push_back({});
|
m_watch.push_back({});
|
||||||
m_var_queue.mk_var_eh(v);
|
m_var_queue.mk_var_eh(v);
|
||||||
|
m_viable.ensure_var(v);
|
||||||
s.trail().push(mk_add_var(*this));
|
s.trail().push(mk_add_var(*this));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -147,8 +148,8 @@ namespace polysat {
|
||||||
s.trail().push(mk_dqueue_var(m_var, *this));
|
s.trail().push(mk_dqueue_var(m_var, *this));
|
||||||
switch (m_viable.find_viable(m_var, m_value)) {
|
switch (m_viable.find_viable(m_var, m_value)) {
|
||||||
case find_t::empty:
|
case find_t::empty:
|
||||||
m_unsat_core = m_viable.explain();
|
s.set_lemma(m_viable.get_core(), 0, m_viable.explain());
|
||||||
propagate_unsat_core();
|
// propagate_unsat_core();
|
||||||
return sat::check_result::CR_CONTINUE;
|
return sat::check_result::CR_CONTINUE;
|
||||||
case find_t::singleton:
|
case find_t::singleton:
|
||||||
s.propagate(m_constraints.eq(var2pdd(m_var), m_value), m_viable.explain());
|
s.propagate(m_constraints.eq(var2pdd(m_var), m_value), m_viable.explain());
|
||||||
|
|
|
@ -17,9 +17,10 @@ Author:
|
||||||
--*/
|
--*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/var_queue.h"
|
||||||
#include "util/dependency.h"
|
#include "util/dependency.h"
|
||||||
#include "math/dd/dd_pdd.h"
|
#include "math/dd/dd_pdd.h"
|
||||||
#include "sat/smt/sat_th.h"
|
#include "sat/sat_extension.h"
|
||||||
#include "sat/smt/polysat/polysat_types.h"
|
#include "sat/smt/polysat/polysat_types.h"
|
||||||
#include "sat/smt/polysat/polysat_constraints.h"
|
#include "sat/smt/polysat/polysat_constraints.h"
|
||||||
#include "sat/smt/polysat/polysat_viable.h"
|
#include "sat/smt/polysat/polysat_viable.h"
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace polysat {
|
||||||
using pvar_vector = unsigned_vector;
|
using pvar_vector = unsigned_vector;
|
||||||
inline const pvar null_var = UINT_MAX;
|
inline const pvar null_var = UINT_MAX;
|
||||||
|
|
||||||
|
class signed_constraint;
|
||||||
|
|
||||||
class dependency {
|
class dependency {
|
||||||
std::variant<sat::literal, std::pair<theory_var, theory_var>> m_data;
|
std::variant<sat::literal, std::pair<theory_var, theory_var>> m_data;
|
||||||
|
@ -87,7 +87,9 @@ namespace polysat {
|
||||||
|
|
||||||
using dependency_vector = vector<dependency>;
|
using dependency_vector = vector<dependency>;
|
||||||
|
|
||||||
class signed_constraint;
|
using core_vector = vector<std::variant<signed_constraint, dependency>>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// The interface that PolySAT uses to the SAT/SMT solver.
|
// The interface that PolySAT uses to the SAT/SMT solver.
|
||||||
|
@ -97,7 +99,7 @@ namespace polysat {
|
||||||
public:
|
public:
|
||||||
virtual void add_eq_literal(pvar v, rational const& val) = 0;
|
virtual void add_eq_literal(pvar v, rational const& val) = 0;
|
||||||
virtual void set_conflict(dependency_vector const& core) = 0;
|
virtual void set_conflict(dependency_vector const& core) = 0;
|
||||||
virtual void set_lemma(vector<signed_constraint> const& lemma, unsigned level, dependency_vector const& core) = 0;
|
virtual void set_lemma(core_vector const& aux_core, unsigned level, dependency_vector const& core) = 0;
|
||||||
virtual dependency propagate(signed_constraint sc, dependency_vector const& deps) = 0;
|
virtual dependency propagate(signed_constraint sc, dependency_vector const& deps) = 0;
|
||||||
virtual void propagate(dependency const& d, bool sign, dependency_vector const& deps) = 0;
|
virtual void propagate(dependency const& d, bool sign, dependency_vector const& deps) = 0;
|
||||||
virtual trail_stack& trail() = 0;
|
virtual trail_stack& trail() = 0;
|
||||||
|
|
|
@ -79,7 +79,6 @@ namespace polysat {
|
||||||
|
|
||||||
find_t viable::find_viable(pvar v, rational& lo) {
|
find_t viable::find_viable(pvar v, rational& lo) {
|
||||||
rational hi;
|
rational hi;
|
||||||
ensure_var(v);
|
|
||||||
switch (find_viable(v, lo, hi)) {
|
switch (find_viable(v, lo, hi)) {
|
||||||
case l_true:
|
case l_true:
|
||||||
return (lo == hi) ? find_t::singleton : find_t::multiple;
|
return (lo == hi) ? find_t::singleton : find_t::multiple;
|
||||||
|
@ -106,9 +105,6 @@ namespace polysat {
|
||||||
// max size should always be present, regardless of whether we have intervals there (to make sure all fixed bits are considered)
|
// max size should always be present, regardless of whether we have intervals there (to make sure all fixed bits are considered)
|
||||||
widths_set.insert(c.size(v));
|
widths_set.insert(c.size(v));
|
||||||
|
|
||||||
for (pvar v : overlaps)
|
|
||||||
ensure_var(v);
|
|
||||||
|
|
||||||
for (pvar v : overlaps)
|
for (pvar v : overlaps)
|
||||||
for (layer const& l : m_units[v].get_layers())
|
for (layer const& l : m_units[v].get_layers())
|
||||||
widths_set.insert(l.bit_width);
|
widths_set.insert(l.bit_width);
|
||||||
|
@ -121,6 +117,7 @@ namespace polysat {
|
||||||
|
|
||||||
rational const& max_value = c.var2pdd(v).max_value();
|
rational const& max_value = c.var2pdd(v).max_value();
|
||||||
|
|
||||||
|
m_explain.reset();
|
||||||
lbool result_lo = find_on_layers(v, widths, overlaps, fbi, rational::zero(), max_value, lo);
|
lbool result_lo = find_on_layers(v, widths, overlaps, fbi, rational::zero(), max_value, lo);
|
||||||
if (result_lo != l_true)
|
if (result_lo != l_true)
|
||||||
return result_lo;
|
return result_lo;
|
||||||
|
@ -132,15 +129,10 @@ namespace polysat {
|
||||||
|
|
||||||
lbool result_hi = find_on_layers(v, widths, overlaps, fbi, lo + 1, max_value, hi);
|
lbool result_hi = find_on_layers(v, widths, overlaps, fbi, lo + 1, max_value, hi);
|
||||||
|
|
||||||
switch (result_hi) {
|
if (result_hi != l_false)
|
||||||
case l_false:
|
return result_hi;
|
||||||
hi = lo;
|
hi = lo;
|
||||||
return l_true;
|
return l_true;
|
||||||
case l_undef:
|
|
||||||
return l_undef;
|
|
||||||
default:
|
|
||||||
return l_true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// l_true ... found viable value
|
// l_true ... found viable value
|
||||||
|
@ -153,18 +145,17 @@ namespace polysat {
|
||||||
fixed_bits_info const& fbi,
|
fixed_bits_info const& fbi,
|
||||||
rational const& to_cover_lo,
|
rational const& to_cover_lo,
|
||||||
rational const& to_cover_hi,
|
rational const& to_cover_hi,
|
||||||
rational& val
|
rational& val) {
|
||||||
) {
|
|
||||||
ptr_vector<entry> refine_todo;
|
ptr_vector<entry> refine_todo;
|
||||||
ptr_vector<entry> relevant_entries;
|
|
||||||
|
|
||||||
// max number of interval refinements before falling back to the univariate solver
|
// max number of interval refinements before falling back to the univariate solver
|
||||||
unsigned const refinement_budget = 100;
|
unsigned const refinement_budget = 100;
|
||||||
unsigned refinements = refinement_budget;
|
unsigned refinements = refinement_budget;
|
||||||
|
unsigned explain_size = m_explain.size();
|
||||||
|
|
||||||
while (refinements--) {
|
while (refinements--) {
|
||||||
relevant_entries.clear();
|
m_explain.shrink(explain_size);
|
||||||
lbool result = find_on_layer(v, widths.size() - 1, widths, overlaps, fbi, to_cover_lo, to_cover_hi, val, refine_todo, relevant_entries);
|
lbool result = find_on_layer(v, widths.size() - 1, widths, overlaps, fbi, to_cover_lo, to_cover_hi, val, refine_todo);
|
||||||
|
|
||||||
// store bit-intervals we have used
|
// store bit-intervals we have used
|
||||||
for (entry* e : refine_todo)
|
for (entry* e : refine_todo)
|
||||||
|
@ -191,8 +182,6 @@ namespace polysat {
|
||||||
if (!refined)
|
if (!refined)
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Refinement budget exhausted! Fall back to univariate solver.");
|
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,12 +200,10 @@ namespace polysat {
|
||||||
rational const& to_cover_lo,
|
rational const& to_cover_lo,
|
||||||
rational const& to_cover_hi,
|
rational const& to_cover_hi,
|
||||||
rational& val,
|
rational& val,
|
||||||
ptr_vector<entry>& refine_todo,
|
ptr_vector<entry>& refine_todo) {
|
||||||
ptr_vector<entry>& relevant_entries
|
|
||||||
) {
|
|
||||||
unsigned const w = widths[w_idx];
|
unsigned const w = widths[w_idx];
|
||||||
rational const& mod_value = rational::power_of_two(w);
|
rational const& mod_value = rational::power_of_two(w);
|
||||||
unsigned const first_relevant_for_conflict = relevant_entries.size();
|
unsigned const first_relevant_for_conflict = m_explain.size();
|
||||||
|
|
||||||
LOG("layer " << w << " bits, to_cover: [" << to_cover_lo << "; " << to_cover_hi << "[");
|
LOG("layer " << w << " bits, to_cover: [" << to_cover_lo << "; " << to_cover_hi << "[");
|
||||||
SASSERT(0 <= to_cover_lo);
|
SASSERT(0 <= to_cover_lo);
|
||||||
|
@ -295,12 +282,12 @@ namespace polysat {
|
||||||
if (!e)
|
if (!e)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
relevant_entries.push_back(e);
|
m_explain.push_back(e);
|
||||||
|
|
||||||
if (e->interval.is_full()) {
|
if (e->interval.is_full()) {
|
||||||
relevant_entries.clear();
|
m_explain.reset();
|
||||||
relevant_entries.push_back(e); // full interval e -> all other intervals are subsumed/irrelevant
|
m_explain.push_back(e); // full interval e -> all other intervals are subsumed/irrelevant
|
||||||
set_conflict_by_interval(v, w, relevant_entries, 0);
|
set_conflict_by_interval(v, w, m_explain, 0);
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +301,7 @@ namespace polysat {
|
||||||
|
|
||||||
if (progress >= mod_value) {
|
if (progress >= mod_value) {
|
||||||
// covered the whole domain => conflict
|
// covered the whole domain => conflict
|
||||||
set_conflict_by_interval(v, w, relevant_entries, first_relevant_for_conflict);
|
set_conflict_by_interval(v, w, m_explain, first_relevant_for_conflict);
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
}
|
||||||
if (progress >= to_cover_len) {
|
if (progress >= to_cover_len) {
|
||||||
|
@ -365,7 +352,7 @@ namespace polysat {
|
||||||
lower_cover_lo = 0;
|
lower_cover_lo = 0;
|
||||||
lower_cover_hi = lower_mod_value;
|
lower_cover_hi = lower_mod_value;
|
||||||
rational a;
|
rational a;
|
||||||
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, fbi, lower_cover_lo, lower_cover_hi, a, refine_todo, relevant_entries);
|
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, fbi, lower_cover_lo, lower_cover_hi, a, refine_todo);
|
||||||
VERIFY(result != l_undef);
|
VERIFY(result != l_undef);
|
||||||
if (result == l_false) {
|
if (result == l_false) {
|
||||||
SASSERT(c.inconsistent());
|
SASSERT(c.inconsistent());
|
||||||
|
@ -387,7 +374,7 @@ namespace polysat {
|
||||||
lower_cover_hi = mod(next_val, lower_mod_value);
|
lower_cover_hi = mod(next_val, lower_mod_value);
|
||||||
|
|
||||||
rational a;
|
rational a;
|
||||||
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, fbi, lower_cover_lo, lower_cover_hi, a, refine_todo, relevant_entries);
|
lbool result = find_on_layer(v, w_idx - 1, widths, overlaps, fbi, lower_cover_lo, lower_cover_hi, a, refine_todo);
|
||||||
if (result == l_false) {
|
if (result == l_false) {
|
||||||
SASSERT(c.inconsistent());
|
SASSERT(c.inconsistent());
|
||||||
return l_false; // conflict
|
return l_false; // conflict
|
||||||
|
@ -408,7 +395,7 @@ namespace polysat {
|
||||||
|
|
||||||
if (progress >= mod_value) {
|
if (progress >= mod_value) {
|
||||||
// covered the whole domain => conflict
|
// covered the whole domain => conflict
|
||||||
set_conflict_by_interval(v, w, relevant_entries, first_relevant_for_conflict);
|
set_conflict_by_interval(v, w, m_explain, first_relevant_for_conflict);
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,6 +408,197 @@ namespace polysat {
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void viable::set_conflict_by_interval(pvar v, unsigned w, ptr_vector<entry>& intervals, unsigned first_interval) {
|
||||||
|
SASSERT(!intervals.empty());
|
||||||
|
SASSERT(first_interval < intervals.size());
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
bool create_lemma = true;
|
||||||
|
uint_set vars_to_explain;
|
||||||
|
char const* lemma_name = nullptr;
|
||||||
|
|
||||||
|
// if there is a full interval, it should be the only one in the given vector
|
||||||
|
if (intervals.size() == 1 && intervals[0]->interval.is_full()) {
|
||||||
|
lemma_name = "viable (full interval)";
|
||||||
|
entry const* e = intervals[0];
|
||||||
|
for (auto sc : e->side_cond)
|
||||||
|
lemma.insert_eval(~sc);
|
||||||
|
for (const auto& src : e->src) {
|
||||||
|
lemma.insert(~src);
|
||||||
|
core.insert(src);
|
||||||
|
core.insert_vars(src);
|
||||||
|
}
|
||||||
|
if (v != e->var)
|
||||||
|
vars_to_explain.insert(e->var);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(all_of(intervals, [](entry* e) { return e->interval.is_proper(); }));
|
||||||
|
lemma_name = "viable (proper intervals)";
|
||||||
|
|
||||||
|
// allocate one dummy space in intervals storage to simplify recursive calls
|
||||||
|
intervals.push_back(nullptr);
|
||||||
|
entry** intervals_begin = intervals.data() + first_interval;
|
||||||
|
unsigned num_intervals = intervals.size() - first_interval - 1;
|
||||||
|
|
||||||
|
if (!set_conflict_by_interval_rec(v, w, intervals_begin, num_intervals, core, create_lemma, lemma, vars_to_explain))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pvar x : vars_to_explain) {
|
||||||
|
s.m_slicing.explain_simple_overlap(v, x, [this, &core, &lemma](sat::literal l) {
|
||||||
|
lemma.insert(~l);
|
||||||
|
core.insert(s.lit2cnstr(l));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_lemma)
|
||||||
|
core.add_lemma(lemma_name, lemma.build());
|
||||||
|
|
||||||
|
//core.logger().log(inf_fi(*this, v));
|
||||||
|
core.init_viable_end(v);
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool viable::set_conflict_by_interval_rec(pvar v, unsigned w, entry** intervals, unsigned num_intervals, bool& create_lemma, uint_set& vars_to_explain) {
|
||||||
|
SASSERT(std::all_of(intervals, intervals + num_intervals, [w](entry const* e) { return e->bit_width <= w; }));
|
||||||
|
// TODO: assert invariants on intervals list
|
||||||
|
rational const& mod_value = rational::power_of_two(w);
|
||||||
|
|
||||||
|
// heuristic: find longest interval as starting point
|
||||||
|
unsigned longest_idx = UINT_MAX;
|
||||||
|
rational longest_len;
|
||||||
|
for (unsigned i = 0; i < num_intervals; ++i) {
|
||||||
|
entry* e = intervals[i];
|
||||||
|
if (e->bit_width != w)
|
||||||
|
continue;
|
||||||
|
rational len = e->interval.current_len();
|
||||||
|
if (len > longest_len) {
|
||||||
|
longest_idx = i;
|
||||||
|
longest_len = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SASSERT(longest_idx < UINT_MAX);
|
||||||
|
entry* longest = intervals[longest_idx];
|
||||||
|
|
||||||
|
if (!longest->valid_for_lemma)
|
||||||
|
create_lemma = false;
|
||||||
|
|
||||||
|
unsigned i = longest_idx;
|
||||||
|
entry* e = longest; // e is the current baseline
|
||||||
|
|
||||||
|
entry* tmp = nullptr;
|
||||||
|
on_scope_exit dont_leak_entry = [this, &tmp]() {
|
||||||
|
if (tmp)
|
||||||
|
m_alloc.push_back(tmp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
while (!longest->interval.currently_contains(e->interval.hi_val())) {
|
||||||
|
unsigned j = (i + 1) % num_intervals;
|
||||||
|
entry* n = intervals[j];
|
||||||
|
|
||||||
|
if (n->bit_width != w) {
|
||||||
|
// we have a hole starting with 'n', to be filled with intervals at lower bit-width.
|
||||||
|
// note that the next lower bit-width is not necessarily n->bit_width (e.g., the next layer may start with a hole itself)
|
||||||
|
unsigned w2 = n->bit_width;
|
||||||
|
// first, find the next constraint after the hole
|
||||||
|
unsigned last_idx = j;
|
||||||
|
unsigned k = j;
|
||||||
|
while (intervals[k]->bit_width != w) {
|
||||||
|
if (intervals[k]->bit_width > w2)
|
||||||
|
w2 = intervals[k]->bit_width;
|
||||||
|
last_idx = k;
|
||||||
|
k = (k + 1) % num_intervals;
|
||||||
|
}
|
||||||
|
entry* after = intervals[k];
|
||||||
|
SASSERT(j < last_idx); // the hole cannot wrap around (but k may be 0)
|
||||||
|
|
||||||
|
rational const& lower_mod_value = rational::power_of_two(w2);
|
||||||
|
SASSERT(distance(e->interval.hi_val(), after->interval.lo_val(), mod_value) < lower_mod_value); // otherwise we would have started the conflict at w2 already
|
||||||
|
|
||||||
|
// create temporary entry that covers the hole-complement on the lower level
|
||||||
|
if (!tmp)
|
||||||
|
tmp = alloc_entry(v);
|
||||||
|
pdd dummy = s.var2pdd(v).mk_val(123); // we could create extract-terms for boundaries but let's skip that for now and just disable the lemma
|
||||||
|
create_lemma = false;
|
||||||
|
tmp->valid_for_lemma = false;
|
||||||
|
tmp->bit_width = w2;
|
||||||
|
tmp->interval = eval_interval::proper(dummy, mod(after->interval.lo_val(), lower_mod_value), dummy, mod(e->interval.hi_val(), lower_mod_value));
|
||||||
|
|
||||||
|
// the index "last_idx+1" is always valid because we allocate an extra dummy space at the end before starting the recursion.
|
||||||
|
// we only need a single dummy space because the temporary entry is always at bit-width w2.
|
||||||
|
entry* old = intervals[last_idx + 1];
|
||||||
|
intervals[last_idx + 1] = tmp;
|
||||||
|
|
||||||
|
bool result = set_conflict_by_interval_rec(v, w2, &intervals[j], last_idx - j + 2, create_lemma, vars_to_explain);
|
||||||
|
|
||||||
|
intervals[last_idx + 1] = old;
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (create_lemma) {
|
||||||
|
// hole_length < 2^w2
|
||||||
|
signed_constraint c = s.ult(after->interval.lo() - e->interval.hi(), lower_mod_value);
|
||||||
|
VERIFY(c.is_currently_true(s));
|
||||||
|
// this constraint may already exist on the stack with opposite bool value,
|
||||||
|
// in that case we have a different, earlier conflict
|
||||||
|
if (c.bvalue(s) == l_false) {
|
||||||
|
core.reset();
|
||||||
|
core.init(~c);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lemma.insert(~c);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp->bit_width = w;
|
||||||
|
tmp->interval = eval_interval::proper(dummy, e->interval.hi_val(), dummy, after->interval.lo_val());
|
||||||
|
e = tmp;
|
||||||
|
j = k;
|
||||||
|
n = after;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We may have a bunch of intervals that contain the current value.
|
||||||
|
// Choose the one making the most progress.
|
||||||
|
// TODO: it should be the last one, otherwise we wouldn't have added it to relevant_intervals? then we can skip the progress computation.
|
||||||
|
// (TODO: should note the relevant invariants of intervals list and assert them above.)
|
||||||
|
SASSERT(n->interval.currently_contains(e->interval.hi_val()));
|
||||||
|
unsigned best_j = j;
|
||||||
|
rational best_progress = distance(e->interval.hi_val(), n->interval.hi_val(), mod_value);
|
||||||
|
while (true) {
|
||||||
|
unsigned j1 = (j + 1) % num_intervals;
|
||||||
|
entry* n1 = intervals[j1];
|
||||||
|
if (n1->bit_width != w)
|
||||||
|
break;
|
||||||
|
if (!n1->interval.currently_contains(e->interval.hi_val()))
|
||||||
|
break;
|
||||||
|
j = j1;
|
||||||
|
n = n1;
|
||||||
|
SASSERT(n != longest); // because of loop condition on outer while loop
|
||||||
|
rational progress = distance(e->interval.hi_val(), n->interval.hi_val(), mod_value);
|
||||||
|
if (progress > best_progress) {
|
||||||
|
best_j = j;
|
||||||
|
best_progress = progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = best_j;
|
||||||
|
n = intervals[best_j];
|
||||||
|
|
||||||
|
if (!update_interval_conflict(v, e->interval.hi(), n, core, create_lemma, lemma, vars_to_explain))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
i = j;
|
||||||
|
e = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!update_interval_conflict(v, e->interval.hi(), longest, core, create_lemma, lemma, vars_to_explain))
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// returns true iff no conflict was encountered
|
// returns true iff no conflict was encountered
|
||||||
bool viable::collect_bit_information(pvar v, bool add_conflict, fixed_bits_info& out_fbi) {
|
bool viable::collect_bit_information(pvar v, bool add_conflict, fixed_bits_info& out_fbi) {
|
||||||
|
|
||||||
|
@ -625,15 +803,23 @@ namespace polysat {
|
||||||
/*
|
/*
|
||||||
* Explain why the current variable is not viable or signleton.
|
* Explain why the current variable is not viable or signleton.
|
||||||
*/
|
*/
|
||||||
dependency_vector viable::explain() { throw default_exception("nyi"); }
|
dependency_vector viable::explain() {
|
||||||
|
dependency_vector result;
|
||||||
|
for (auto e : m_explain) {
|
||||||
|
auto index = e->constraint_index;
|
||||||
|
auto const& [sc, d, value] = c.m_constraint_index[index];
|
||||||
|
result.push_back(d);
|
||||||
|
result.append(c.explain_eval(sc));
|
||||||
|
}
|
||||||
|
// TODO: explaination for fixed bits
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register constraint at index 'idx' as unitary in v.
|
* Register constraint at index 'idx' as unitary in v.
|
||||||
*/
|
*/
|
||||||
void viable::add_unitary(pvar v, unsigned idx) {
|
void viable::add_unitary(pvar v, unsigned idx) {
|
||||||
|
|
||||||
ensure_var(v);
|
|
||||||
|
|
||||||
if (c.is_assigned(v))
|
if (c.is_assigned(v))
|
||||||
return;
|
return;
|
||||||
auto [sc, d, value] = c.m_constraint_index[idx];
|
auto [sc, d, value] = c.m_constraint_index[idx];
|
||||||
|
|
|
@ -138,6 +138,9 @@ namespace polysat {
|
||||||
vector<layers> m_units; // set of viable values based on unit multipliers, layered by bit-width in descending order
|
vector<layers> m_units; // set of viable values based on unit multipliers, layered by bit-width in descending order
|
||||||
ptr_vector<entry> m_equal_lin; // entries that have non-unit multipliers, but are equal
|
ptr_vector<entry> m_equal_lin; // entries that have non-unit multipliers, but are equal
|
||||||
ptr_vector<entry> m_diseq_lin; // entries that have distinct non-zero multipliers
|
ptr_vector<entry> m_diseq_lin; // entries that have distinct non-zero multipliers
|
||||||
|
ptr_vector<entry> m_explain; // entries that explain the current propagation or conflict
|
||||||
|
core_vector m_core; // forbidden interval core
|
||||||
|
bool m_has_core = false;
|
||||||
|
|
||||||
bool well_formed(entry* e);
|
bool well_formed(entry* e);
|
||||||
bool well_formed(layers const& ls);
|
bool well_formed(layers const& ls);
|
||||||
|
@ -158,8 +161,6 @@ namespace polysat {
|
||||||
|
|
||||||
bool intersect(pvar v, entry* e);
|
bool intersect(pvar v, entry* e);
|
||||||
|
|
||||||
void ensure_var(pvar v);
|
|
||||||
|
|
||||||
lbool find_viable(pvar v, rational& lo, rational& hi);
|
lbool find_viable(pvar v, rational& lo, rational& hi);
|
||||||
|
|
||||||
lbool find_on_layers(
|
lbool find_on_layers(
|
||||||
|
@ -180,8 +181,7 @@ namespace polysat {
|
||||||
rational const& to_cover_lo,
|
rational const& to_cover_lo,
|
||||||
rational const& to_cover_hi,
|
rational const& to_cover_hi,
|
||||||
rational& out_val,
|
rational& out_val,
|
||||||
ptr_vector<entry>& refine_todo,
|
ptr_vector<entry>& refine_todo);
|
||||||
ptr_vector<entry>& relevant_entries);
|
|
||||||
|
|
||||||
|
|
||||||
template <bool FORWARD>
|
template <bool FORWARD>
|
||||||
|
@ -211,9 +211,8 @@ namespace polysat {
|
||||||
throw default_exception("nyi");
|
throw default_exception("nyi");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_conflict_by_interval(pvar v, unsigned w, ptr_vector<entry>& intervals, unsigned first_interval) {
|
void set_conflict_by_interval(pvar v, unsigned w, ptr_vector<entry>& intervals, unsigned first_interval);
|
||||||
throw default_exception("nyi");
|
bool set_conflict_by_interval_rec(pvar v, unsigned w, entry** intervals, unsigned num_intervals, bool& create_lemma, uint_set& vars_to_explain);
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<entry*, bool> find_value(rational const& val, entry* entries) {
|
std::pair<entry*, bool> find_value(rational const& val, entry* entries) {
|
||||||
throw default_exception("nyi");
|
throw default_exception("nyi");
|
||||||
|
@ -236,11 +235,26 @@ namespace polysat {
|
||||||
*/
|
*/
|
||||||
dependency_vector explain();
|
dependency_vector explain();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flag whether there is a forbidden interval core
|
||||||
|
*/
|
||||||
|
bool has_core() const { return m_has_core; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve lemma corresponding to forbidden interval constraints
|
||||||
|
*/
|
||||||
|
core_vector const& get_core() { SASSERT(m_has_core); return m_core; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register constraint at index 'idx' as unitary in v.
|
* Register constraint at index 'idx' as unitary in v.
|
||||||
*/
|
*/
|
||||||
void add_unitary(pvar v, unsigned idx);
|
void add_unitary(pvar v, unsigned idx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure data-structures tracking variable v.
|
||||||
|
*/
|
||||||
|
void ensure_var(pvar v);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,15 +104,26 @@ namespace polysat {
|
||||||
return { core, eqs };
|
return { core, eqs };
|
||||||
}
|
}
|
||||||
|
|
||||||
void solver::set_lemma(vector<signed_constraint> const& lemma, unsigned level, dependency_vector const& core) {
|
void solver::set_lemma(core_vector const& aux_core, unsigned level, dependency_vector const& core) {
|
||||||
auto [lits, eqs] = explain_deps(core);
|
auto [lits, eqs] = explain_deps(core);
|
||||||
auto ex = euf::th_explain::conflict(*this, lits, eqs, nullptr);
|
auto ex = euf::th_explain::conflict(*this, lits, eqs, nullptr);
|
||||||
ctx.push(value_trail<bool>(m_has_lemma));
|
ctx.push(value_trail<bool>(m_has_lemma));
|
||||||
m_has_lemma = true;
|
m_has_lemma = true;
|
||||||
m_lemma_level = level;
|
m_lemma_level = level;
|
||||||
m_lemma.reset();
|
m_lemma.reset();
|
||||||
for (auto sc : lemma)
|
for (auto sc : aux_core) {
|
||||||
m_lemma.push_back(constraint2expr(sc));
|
if (std::holds_alternative<dependency>(sc)) {
|
||||||
|
auto d = *std::get_if<dependency>(&sc);
|
||||||
|
if (d.is_literal())
|
||||||
|
m_lemma.push_back(ctx.literal2expr(d.literal()));
|
||||||
|
else {
|
||||||
|
auto [v1, v2] = d.eq();
|
||||||
|
m_lemma.push_back(ctx.mk_eq(var2enode(v1), var2enode(v2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<signed_constraint>(sc))
|
||||||
|
m_lemma.push_back(constraint2expr(*std::get_if<signed_constraint>(&sc)));
|
||||||
|
}
|
||||||
ctx.set_conflict(ex);
|
ctx.set_conflict(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +140,7 @@ namespace polysat {
|
||||||
|
|
||||||
sat::literal_vector lits;
|
sat::literal_vector lits;
|
||||||
for (auto* e : m_lemma)
|
for (auto* e : m_lemma)
|
||||||
lits.push_back(ctx.mk_literal(e));
|
lits.push_back(~ctx.mk_literal(e));
|
||||||
s().add_clause(lits.size(), lits.data(), sat::status::th(true, get_id(), nullptr));
|
s().add_clause(lits.size(), lits.data(), sat::status::th(true, get_id(), nullptr));
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ namespace polysat {
|
||||||
// callbacks from core
|
// callbacks from core
|
||||||
void add_eq_literal(pvar v, rational const& val) override;
|
void add_eq_literal(pvar v, rational const& val) override;
|
||||||
void set_conflict(dependency_vector const& core) override;
|
void set_conflict(dependency_vector const& core) override;
|
||||||
void set_lemma(vector<signed_constraint> const& lemma, unsigned level, dependency_vector const& core) override;
|
void set_lemma(core_vector const& aux_core, unsigned level, dependency_vector const& core) override;
|
||||||
dependency propagate(signed_constraint sc, dependency_vector const& deps) override;
|
dependency propagate(signed_constraint sc, dependency_vector const& deps) override;
|
||||||
void propagate(dependency const& d, bool sign, dependency_vector const& deps) override;
|
void propagate(dependency const& d, bool sign, dependency_vector const& deps) override;
|
||||||
trail_stack& trail() override;
|
trail_stack& trail() override;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue