mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
bv and gc of literals (#4692)
* bv and gc of literals Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * overload Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * diseq Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * diseq Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
2d52367368
commit
549753845e
34 changed files with 1480 additions and 854 deletions
|
@ -5,6 +5,7 @@ z3_add_component(sat
|
|||
sat_aig_finder.cpp
|
||||
sat_anf_simplifier.cpp
|
||||
sat_asymm_branch.cpp
|
||||
sat_bcd.cpp
|
||||
sat_big.cpp
|
||||
sat_binspr.cpp
|
||||
sat_clause.cpp
|
||||
|
@ -18,7 +19,7 @@ z3_add_component(sat
|
|||
sat_drat.cpp
|
||||
sat_elim_eqs.cpp
|
||||
sat_elim_vars.cpp
|
||||
sat_bcd.cpp
|
||||
sat_gc.cpp
|
||||
sat_integrity_checker.cpp
|
||||
sat_local_search.cpp
|
||||
sat_lookahead.cpp
|
||||
|
|
|
@ -235,12 +235,15 @@ namespace dimacs {
|
|||
skip_whitespace(in);
|
||||
switch (*in) {
|
||||
case EOF:
|
||||
return false;
|
||||
return false;
|
||||
case 'c':
|
||||
// parse comment line
|
||||
case 'p':
|
||||
// parse meta-data information
|
||||
skip_line(in);
|
||||
goto loop;
|
||||
case 'i':
|
||||
// parse input clause
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
read_clause(in, err, m_record.m_lits);
|
||||
|
@ -248,6 +251,7 @@ namespace dimacs {
|
|||
m_record.m_status = sat::status::input();
|
||||
break;
|
||||
case 'a':
|
||||
// parse non-redundant theory clause
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
theory_id = read_theory_id();
|
||||
|
@ -256,16 +260,32 @@ namespace dimacs {
|
|||
m_record.m_tag = drat_record::tag_t::is_clause;
|
||||
m_record.m_status = sat::status::th(false, theory_id);
|
||||
break;
|
||||
case 'g':
|
||||
// parse garbage collected Boolean variable
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
b = parse_int(in, err);
|
||||
e = parse_int(in, err);
|
||||
if (e != 0 || b <= 0)
|
||||
throw lex_error();
|
||||
m_record.m_tag = drat_record::tag_t::is_var_gc;
|
||||
m_record.m_node_id = b;
|
||||
break;
|
||||
case 'e':
|
||||
// parse expression definition
|
||||
parse_ast(drat_record::tag_t::is_node);
|
||||
break;
|
||||
case 'f':
|
||||
// parse function declaration
|
||||
parse_ast(drat_record::tag_t::is_decl);
|
||||
break;
|
||||
case 's':
|
||||
// parse sort declaration (not used)
|
||||
parse_ast(drat_record::tag_t::is_sort);
|
||||
break;
|
||||
case 'b':
|
||||
// parse bridge between Boolean variable identifier b
|
||||
// and expression identifier e, which is of type Bool
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
b = parse_int(in, err);
|
||||
|
@ -279,6 +299,7 @@ namespace dimacs {
|
|||
m_record.m_args.push_back(n);
|
||||
break;
|
||||
case 'd':
|
||||
// parse clause deletion
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
read_clause(in, err, m_record.m_lits);
|
||||
|
@ -286,6 +307,8 @@ namespace dimacs {
|
|||
m_record.m_status = sat::status::deleted();
|
||||
break;
|
||||
case 'r':
|
||||
// parse redundant theory clause
|
||||
// the clause must be DRUP redundant modulo T
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
theory_id = read_theory_id();
|
||||
|
@ -294,6 +317,7 @@ namespace dimacs {
|
|||
m_record.m_status = sat::status::th(true, theory_id);
|
||||
break;
|
||||
default:
|
||||
// parse clause redundant modulo DRAT (or mostly just DRUP)
|
||||
read_clause(in, err, m_record.m_lits);
|
||||
m_record.m_tag = drat_record::tag_t::is_clause;
|
||||
m_record.m_status = sat::status::redundant();
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace dimacs {
|
|||
};
|
||||
|
||||
struct drat_record {
|
||||
enum class tag_t { is_clause, is_node, is_decl, is_sort, is_bool_def };
|
||||
enum class tag_t { is_clause, is_node, is_decl, is_sort, is_bool_def, is_var_gc };
|
||||
tag_t m_tag{ tag_t::is_clause };
|
||||
// a clause populates m_lits and m_status
|
||||
// a node populates m_node_id, m_name, m_args
|
||||
|
|
|
@ -165,6 +165,7 @@ namespace sat {
|
|||
explicit clause_wrapper(clause & c):m_cls(&c), m_l2_idx(null_literal.to_uint()) {}
|
||||
|
||||
bool is_binary() const { return m_l2_idx != null_literal.to_uint(); }
|
||||
bool is_ternary() const { return size() == 3; }
|
||||
unsigned size() const { return is_binary() ? 2 : m_cls->size(); }
|
||||
literal operator[](unsigned idx) const {
|
||||
SASSERT(idx < size());
|
||||
|
@ -178,6 +179,20 @@ namespace sat {
|
|||
bool contains(bool_var v) const;
|
||||
clause * get_clause() const { SASSERT(!is_binary()); return m_cls; }
|
||||
bool was_removed() const { return !is_binary() && get_clause()->was_removed(); }
|
||||
bool is_learned() const { return !is_binary() && get_clause()->is_learned(); }
|
||||
|
||||
class iterator {
|
||||
unsigned m_idx;
|
||||
clause_wrapper const& m_cw;
|
||||
public:
|
||||
iterator(clause_wrapper const& c, unsigned idx): m_idx(idx), m_cw(c) {}
|
||||
iterator& operator++() { ++m_idx; return *this; }
|
||||
literal operator*() { return m_cw[m_idx]; }
|
||||
bool operator==(iterator const& other) const { SASSERT(&m_cw == &other.m_cw); return m_idx == other.m_idx; }
|
||||
bool operator!=(iterator const& other) const { SASSERT(&m_cw == &other.m_cw); return m_idx != other.m_idx; }
|
||||
};
|
||||
iterator begin() const { return iterator(*this, 0); }
|
||||
iterator end() const { return iterator(*this, size()); }
|
||||
};
|
||||
|
||||
typedef svector<clause_wrapper> clause_wrapper_vector;
|
||||
|
|
|
@ -257,6 +257,22 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
void drat::gc_var(bool_var v) {
|
||||
sat::literal l(v, false);
|
||||
// TBD: we want to remove all clauses that mention v.
|
||||
std::cout << "GC " << v << "\n";
|
||||
m_watches[l.index()].reset();
|
||||
m_watches[(~l).index()].reset();
|
||||
if (m_assignment[l.var()] != l_undef) {
|
||||
unsigned j = 0;
|
||||
for (literal lit : m_units)
|
||||
if (lit.var() != v)
|
||||
m_units[j++] = lit;
|
||||
m_units.shrink(j);
|
||||
m_assignment[l.var()] = l_undef;
|
||||
}
|
||||
}
|
||||
|
||||
void drat::bool_def(bool_var v, unsigned n) {
|
||||
if (m_out)
|
||||
(*m_out) << "b " << v << " " << n << " 0\n";
|
||||
|
@ -277,6 +293,11 @@ namespace sat {
|
|||
(*m_out) << " 0\n";
|
||||
}
|
||||
|
||||
void drat::log_gc_var(bool_var v) {
|
||||
if (m_out)
|
||||
(*m_out) << "g " << v << " 0\n";
|
||||
}
|
||||
|
||||
void drat::log_adhoc(std::function<void(std::ostream&)>& fn) {
|
||||
if (m_out)
|
||||
fn(*m_out);
|
||||
|
|
|
@ -38,6 +38,12 @@ Notes:
|
|||
Redundant clause (theory lemma if theory id is given)
|
||||
[r [<theory-id>]] <literal>* 0
|
||||
|
||||
Declaration of an auxiliary function:
|
||||
f <smtlib2-function-declaration> 0
|
||||
|
||||
Garbage collection of a Boolean variable:
|
||||
g <bool-var-id> 0
|
||||
|
||||
Available theories are:
|
||||
- euf The theory lemma should be a consequence of congruence closure.
|
||||
- ba TBD (need to also log cardinality and pb constraints)
|
||||
|
@ -125,6 +131,8 @@ namespace sat {
|
|||
void add(literal_vector const& c); // add learned clause
|
||||
void add(unsigned sz, literal const* lits, status st);
|
||||
|
||||
void gc_var(bool_var v);
|
||||
|
||||
// support for SMT - connect Boolean variables with AST nodes
|
||||
// associate AST node id with Boolean variable v
|
||||
void bool_def(bool_var v, unsigned n);
|
||||
|
@ -134,6 +142,8 @@ namespace sat {
|
|||
void def_add_arg(unsigned arg);
|
||||
void def_end();
|
||||
|
||||
void log_gc_var(bool_var v);
|
||||
|
||||
// ad-hoc logging until a format is developed
|
||||
void log_adhoc(std::function<void(std::ostream&)>& fn);
|
||||
|
||||
|
|
562
src/sat/sat_gc.cpp
Normal file
562
src/sat/sat_gc.cpp
Normal file
|
@ -0,0 +1,562 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_solver.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
SAT solver main class.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-05-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "sat/sat_solver.h"
|
||||
|
||||
#define ENABLE_TERNARY true
|
||||
|
||||
namespace sat {
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// GC
|
||||
//
|
||||
// -----------------------
|
||||
|
||||
bool solver::should_gc() const {
|
||||
return
|
||||
m_conflicts_since_gc > m_gc_threshold &&
|
||||
(m_config.m_gc_strategy != GC_DYN_PSM || at_base_lvl());
|
||||
}
|
||||
|
||||
void solver::do_gc() {
|
||||
if (!should_gc()) return;
|
||||
TRACE("sat", tout << m_conflicts_since_gc << " " << m_gc_threshold << "\n";);
|
||||
unsigned gc = m_stats.m_gc_clause;
|
||||
m_conflicts_since_gc = 0;
|
||||
m_gc_threshold += m_config.m_gc_increment;
|
||||
IF_VERBOSE(10, verbose_stream() << "(sat.gc)\n";);
|
||||
CASSERT("sat_gc_bug", check_invariant());
|
||||
switch (m_config.m_gc_strategy) {
|
||||
case GC_GLUE:
|
||||
gc_glue();
|
||||
break;
|
||||
case GC_PSM:
|
||||
gc_psm();
|
||||
break;
|
||||
case GC_GLUE_PSM:
|
||||
gc_glue_psm();
|
||||
break;
|
||||
case GC_PSM_GLUE:
|
||||
gc_psm_glue();
|
||||
break;
|
||||
case GC_DYN_PSM:
|
||||
if (!m_assumptions.empty()) {
|
||||
gc_glue_psm();
|
||||
break;
|
||||
}
|
||||
if (!at_base_lvl())
|
||||
return;
|
||||
gc_dyn_psm();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
if (m_ext) m_ext->gc();
|
||||
if (gc > 0 && should_defrag()) {
|
||||
defrag_clauses();
|
||||
}
|
||||
CASSERT("sat_gc_bug", check_invariant());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Lex on (glue, size)
|
||||
*/
|
||||
struct glue_lt {
|
||||
bool operator()(clause const * c1, clause const * c2) const {
|
||||
if (c1->glue() < c2->glue()) return true;
|
||||
return c1->glue() == c2->glue() && c1->size() < c2->size();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Lex on (psm, size)
|
||||
*/
|
||||
struct psm_lt {
|
||||
bool operator()(clause const * c1, clause const * c2) const {
|
||||
if (c1->psm() < c2->psm()) return true;
|
||||
return c1->psm() == c2->psm() && c1->size() < c2->size();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Lex on (glue, psm, size)
|
||||
*/
|
||||
struct glue_psm_lt {
|
||||
bool operator()(clause const * c1, clause const * c2) const {
|
||||
if (c1->glue() < c2->glue()) return true;
|
||||
if (c1->glue() > c2->glue()) return false;
|
||||
if (c1->psm() < c2->psm()) return true;
|
||||
if (c1->psm() > c2->psm()) return false;
|
||||
return c1->size() < c2->size();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Lex on (psm, glue, size)
|
||||
*/
|
||||
struct psm_glue_lt {
|
||||
bool operator()(clause const * c1, clause const * c2) const {
|
||||
if (c1->psm() < c2->psm()) return true;
|
||||
if (c1->psm() > c2->psm()) return false;
|
||||
if (c1->glue() < c2->glue()) return true;
|
||||
if (c1->glue() > c2->glue()) return false;
|
||||
return c1->size() < c2->size();
|
||||
}
|
||||
};
|
||||
|
||||
void solver::gc_glue() {
|
||||
std::stable_sort(m_learned.begin(), m_learned.end(), glue_lt());
|
||||
gc_half("glue");
|
||||
}
|
||||
|
||||
void solver::gc_psm() {
|
||||
save_psm();
|
||||
std::stable_sort(m_learned.begin(), m_learned.end(), psm_lt());
|
||||
gc_half("psm");
|
||||
}
|
||||
|
||||
void solver::gc_glue_psm() {
|
||||
save_psm();
|
||||
std::stable_sort(m_learned.begin(), m_learned.end(), glue_psm_lt());
|
||||
gc_half("glue-psm");
|
||||
}
|
||||
|
||||
void solver::gc_psm_glue() {
|
||||
save_psm();
|
||||
std::stable_sort(m_learned.begin(), m_learned.end(), psm_glue_lt());
|
||||
gc_half("psm-glue");
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Compute the psm of all learned clauses.
|
||||
*/
|
||||
void solver::save_psm() {
|
||||
for (clause* cp : m_learned) {
|
||||
cp->set_psm(psm(*cp));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief GC (the second) half of the clauses in the database.
|
||||
*/
|
||||
void solver::gc_half(char const * st_name) {
|
||||
TRACE("sat", tout << "gc\n";);
|
||||
unsigned sz = m_learned.size();
|
||||
unsigned new_sz = sz/2; // std::min(sz/2, m_clauses.size()*2);
|
||||
unsigned j = new_sz;
|
||||
for (unsigned i = new_sz; i < sz; i++) {
|
||||
clause & c = *(m_learned[i]);
|
||||
if (can_delete(c)) {
|
||||
detach_clause(c);
|
||||
del_clause(c);
|
||||
}
|
||||
else {
|
||||
m_learned[j] = &c;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
new_sz = j;
|
||||
m_stats.m_gc_clause += sz - new_sz;
|
||||
m_learned.shrink(new_sz);
|
||||
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :strategy " << st_name << " :deleted " << (sz - new_sz) << ")\n";);
|
||||
}
|
||||
|
||||
bool solver::can_delete3(literal l1, literal l2, literal l3) const {
|
||||
if (value(l1) == l_true &&
|
||||
value(l2) == l_false &&
|
||||
value(l3) == l_false) {
|
||||
justification const& j = m_justification[l1.var()];
|
||||
if (j.is_ternary_clause()) {
|
||||
watched w1(l2, l3);
|
||||
watched w2(j.get_literal1(), j.get_literal2());
|
||||
return w1 != w2;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool solver::can_delete(clause const & c) const {
|
||||
if (c.on_reinit_stack())
|
||||
return false;
|
||||
if (ENABLE_TERNARY && c.size() == 3) {
|
||||
return
|
||||
can_delete3(c[0],c[1],c[2]) &&
|
||||
can_delete3(c[1],c[0],c[2]) &&
|
||||
can_delete3(c[2],c[0],c[1]);
|
||||
}
|
||||
literal l0 = c[0];
|
||||
if (value(l0) != l_true)
|
||||
return true;
|
||||
justification const & jst = m_justification[l0.var()];
|
||||
return !jst.is_clause() || cls_allocator().get_clause(jst.get_clause_offset()) != &c;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Use gc based on dynamic psm. Clauses are initially frozen.
|
||||
*/
|
||||
void solver::gc_dyn_psm() {
|
||||
TRACE("sat", tout << "gc\n";);
|
||||
// To do gc at scope_lvl() > 0, I will need to use the reinitialization stack, or live with the fact
|
||||
// that I may miss some propagations for reactivated clauses.
|
||||
SASSERT(at_base_lvl());
|
||||
// compute
|
||||
// d_tk
|
||||
unsigned h = 0;
|
||||
unsigned V_tk = 0;
|
||||
for (bool_var v = 0; v < num_vars(); v++) {
|
||||
if (m_assigned_since_gc[v]) {
|
||||
V_tk++;
|
||||
m_assigned_since_gc[v] = false;
|
||||
}
|
||||
if (m_phase[v] != m_prev_phase[v]) {
|
||||
h++;
|
||||
m_prev_phase[v] = m_phase[v];
|
||||
}
|
||||
}
|
||||
double d_tk = V_tk == 0 ? static_cast<double>(num_vars() + 1) : static_cast<double>(h)/static_cast<double>(V_tk);
|
||||
if (d_tk < m_min_d_tk)
|
||||
m_min_d_tk = d_tk;
|
||||
TRACE("sat_frozen", tout << "m_min_d_tk: " << m_min_d_tk << "\n";);
|
||||
unsigned frozen = 0;
|
||||
unsigned deleted = 0;
|
||||
unsigned activated = 0;
|
||||
clause_vector::iterator it = m_learned.begin();
|
||||
clause_vector::iterator it2 = it;
|
||||
clause_vector::iterator end = m_learned.end();
|
||||
for (; it != end; ++it) {
|
||||
clause & c = *(*it);
|
||||
if (!c.frozen()) {
|
||||
// Active clause
|
||||
if (c.glue() > m_config.m_gc_small_lbd) {
|
||||
// I never delete clauses with small lbd
|
||||
if (c.was_used()) {
|
||||
c.reset_inact_rounds();
|
||||
}
|
||||
else {
|
||||
c.inc_inact_rounds();
|
||||
if (c.inact_rounds() > m_config.m_gc_k) {
|
||||
detach_clause(c);
|
||||
del_clause(c);
|
||||
m_stats.m_gc_clause++;
|
||||
deleted++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
c.unmark_used();
|
||||
if (psm(c) > static_cast<unsigned>(c.size() * m_min_d_tk)) {
|
||||
// move to frozen;
|
||||
TRACE("sat_frozen", tout << "freezing size: " << c.size() << " psm: " << psm(c) << " " << c << "\n";);
|
||||
detach_clause(c);
|
||||
c.reset_inact_rounds();
|
||||
c.freeze();
|
||||
m_num_frozen++;
|
||||
frozen++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// frozen clause
|
||||
clause & c = *(*it);
|
||||
if (psm(c) <= static_cast<unsigned>(c.size() * m_min_d_tk)) {
|
||||
c.unfreeze();
|
||||
m_num_frozen--;
|
||||
activated++;
|
||||
if (!activate_frozen_clause(c)) {
|
||||
// clause was satisfied, reduced to a conflict, unit or binary clause.
|
||||
del_clause(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
c.inc_inact_rounds();
|
||||
if (c.inact_rounds() > m_config.m_gc_k) {
|
||||
del_clause(c);
|
||||
m_stats.m_gc_clause++;
|
||||
deleted++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
*it2 = *it;
|
||||
++it2;
|
||||
}
|
||||
m_learned.set_end(it2);
|
||||
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :d_tk " << d_tk << " :min-d_tk " << m_min_d_tk <<
|
||||
" :frozen " << frozen << " :activated " << activated << " :deleted " << deleted << ")\n";);
|
||||
}
|
||||
|
||||
// return true if should keep the clause, and false if we should delete it.
|
||||
bool solver::activate_frozen_clause(clause & c) {
|
||||
TRACE("sat_gc", tout << "reactivating:\n" << c << "\n";);
|
||||
SASSERT(at_base_lvl());
|
||||
// do some cleanup
|
||||
unsigned sz = c.size();
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
literal l = c[i];
|
||||
switch (value(l)) {
|
||||
case l_true:
|
||||
return false;
|
||||
case l_false:
|
||||
break;
|
||||
case l_undef:
|
||||
if (i != j) {
|
||||
std::swap(c[i], c[j]);
|
||||
}
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
TRACE("sat", tout << "after cleanup:\n" << mk_lits_pp(j, c.begin()) << "\n";);
|
||||
unsigned new_sz = j;
|
||||
switch (new_sz) {
|
||||
case 0:
|
||||
if (m_config.m_drat) m_drat.add();
|
||||
set_conflict();
|
||||
return false;
|
||||
case 1:
|
||||
assign_unit(c[0]);
|
||||
return false;
|
||||
case 2:
|
||||
mk_bin_clause(c[0], c[1], true);
|
||||
return false;
|
||||
default:
|
||||
shrink(c, sz, new_sz);
|
||||
attach_clause(c);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Compute phase saving measure for the given clause.
|
||||
*/
|
||||
unsigned solver::psm(clause const & c) const {
|
||||
unsigned r = 0;
|
||||
for (literal l : c) {
|
||||
if (l.sign() ^ m_phase[l.var()]) {
|
||||
r++;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Control the size of the reinit-stack.
|
||||
* by agressively garbage collecting lemmas that are not asserting.
|
||||
*/
|
||||
|
||||
void solver::gc_reinit_stack(unsigned num_scopes) {
|
||||
return;
|
||||
SASSERT (!at_base_lvl());
|
||||
unsigned new_lvl = scope_lvl() - num_scopes;
|
||||
ptr_vector<clause> to_gc;
|
||||
unsigned j = m_scopes[new_lvl].m_clauses_to_reinit_lim;
|
||||
unsigned sz = m_clauses_to_reinit.size();
|
||||
if (sz - j <= 2000)
|
||||
return;
|
||||
for (unsigned i = j; i < sz; ++i) {
|
||||
auto cw = m_clauses_to_reinit[i];
|
||||
if (cw.is_binary() || is_asserting(new_lvl, cw))
|
||||
m_clauses_to_reinit[j++] = cw;
|
||||
else
|
||||
to_gc.push_back(cw.get_clause());
|
||||
}
|
||||
m_clauses_to_reinit.shrink(j);
|
||||
if (to_gc.empty())
|
||||
return;
|
||||
for (clause* c : to_gc) {
|
||||
SASSERT(c->on_reinit_stack());
|
||||
c->set_removed(true);
|
||||
c->set_reinit_stack(false);
|
||||
}
|
||||
j = 0;
|
||||
for (unsigned i = 0; i < m_learned.size(); ++i) {
|
||||
clause & c = *(m_learned[i]);
|
||||
if (c.was_removed()) {
|
||||
detach_clause(c);
|
||||
del_clause(c);
|
||||
}
|
||||
else
|
||||
m_learned[j++] = &c;
|
||||
}
|
||||
std::cout << "gc: " << to_gc.size() << " " << m_learned.size() << " -> " << j << "\n";
|
||||
SASSERT(m_learned.size() - j == to_gc.size());
|
||||
m_learned.shrink(j);
|
||||
}
|
||||
|
||||
bool solver::is_asserting(unsigned new_lvl, clause_wrapper const& cw) const {
|
||||
if (!cw.is_learned())
|
||||
return true;
|
||||
bool seen_true = false;
|
||||
for (literal lit : cw) {
|
||||
switch (value(lit)) {
|
||||
case l_true:
|
||||
if (lvl(lit) > new_lvl || seen_true)
|
||||
return false;
|
||||
seen_true = true;
|
||||
continue;
|
||||
case l_false:
|
||||
continue;
|
||||
case l_undef:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void solver::gc_reinit_stack(unsigned num_scopes) {
|
||||
SASSERT (!at_base_lvl());
|
||||
collect_clauses_to_gc(num_scopes);
|
||||
for (literal lit : m_watch_literals_to_gc) {
|
||||
mark_members_of_watch_list(lit);
|
||||
shrink_watch_list(lit);
|
||||
}
|
||||
unsigned j = 0;
|
||||
for (clause* c : m_learned)
|
||||
if (!c->was_removed())
|
||||
m_learned[j++] = c;
|
||||
m_learned.shrink(j);
|
||||
for (clause* c : m_clauses_to_gc)
|
||||
del_clause(*c);
|
||||
m_clauses_to_gc.reset();
|
||||
}
|
||||
|
||||
void solver::add_to_gc(literal lit, clause_wrapper const& cw) {
|
||||
m_literal2gc_clause.reserve(lit.index()+1);
|
||||
m_literal2gc_clause[lit.index()].push_back(cw);
|
||||
if (!is_visited(lit)) {
|
||||
mark_visited(lit);
|
||||
m_watch_literals_to_gc.push_back(lit);
|
||||
}
|
||||
}
|
||||
|
||||
void solver::add_to_gc(clause_wrapper const& cw) {
|
||||
std::cout << "add-to-gc " << cw << "\n";
|
||||
if (cw.is_binary()) {
|
||||
add_to_gc(cw[0], cw);
|
||||
add_to_gc(cw[1], clause_wrapper(cw[1], cw[0]));
|
||||
}
|
||||
else if (ENABLE_TERNARY && cw.is_ternary()) {
|
||||
SASSERT(cw.is_learned());
|
||||
add_to_gc(cw[0], cw);
|
||||
add_to_gc(cw[1], cw);
|
||||
add_to_gc(cw[2], cw);
|
||||
cw.get_clause()->set_removed(true);
|
||||
}
|
||||
else {
|
||||
SASSERT(cw.is_learned());
|
||||
add_to_gc(cw[0], cw);
|
||||
add_to_gc(cw[1], cw);
|
||||
cw.get_clause()->set_removed(true);
|
||||
}
|
||||
}
|
||||
|
||||
void solver::insert_ternary_to_delete(literal lit, clause_wrapper const& cw) {
|
||||
SASSERT(cw.is_ternary());
|
||||
SASSERT(lit == cw[0] || lit == cw[1] || lit == cw[2]);
|
||||
literal lit1, lit2;
|
||||
if (cw[0] == lit)
|
||||
lit1 = cw[1], lit2 = cw[2];
|
||||
else if (cw[1] == lit)
|
||||
lit1 = cw[0], lit2 = cw[2];
|
||||
else
|
||||
lit1 = cw[0], lit2 = cw[1];
|
||||
insert_ternary_to_delete(lit1, lit2, true);
|
||||
}
|
||||
|
||||
void solver::insert_ternary_to_delete(literal lit1, literal lit2, bool should_delete) {
|
||||
if (lit1.index() > lit2.index())
|
||||
std::swap(lit1, lit2);
|
||||
m_ternary_to_delete.push_back(std::tuple(lit1, lit2, should_delete));
|
||||
}
|
||||
|
||||
bool solver::in_ternary_to_delete(literal lit1, literal lit2) {
|
||||
if (lit1.index() > lit2.index())
|
||||
std::swap(lit1, lit2);
|
||||
bool found = m_ternary_to_delete.contains(std::make_pair(lit1, lit2));
|
||||
if (found) std::cout << lit1 << " " << lit2 << "\n";
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
void solver::collect_clauses_to_gc(unsigned num_scopes) {
|
||||
unsigned new_lvl = scope_lvl() - num_scopes;
|
||||
init_visited();
|
||||
m_watch_literals_to_gc.reset();
|
||||
unsigned j = m_scopes[new_lvl].m_clauses_to_reinit_lim;
|
||||
for (unsigned i = j, sz = m_clauses_to_reinit.size(); i < sz; ++i) {
|
||||
auto cw = m_clauses_to_reinit[i];
|
||||
if (is_asserting(new_lvl, cw))
|
||||
m_clauses_to_reinit[j++] = cw;
|
||||
else
|
||||
add_to_gc(cw);
|
||||
}
|
||||
m_clauses_to_reinit.shrink(j);
|
||||
SASSERT(m_clauses_to_reinit.size() >= j);
|
||||
}
|
||||
|
||||
void solver::mark_members_of_watch_list(literal lit) {
|
||||
init_visited();
|
||||
m_ternary_to_delete.reset();
|
||||
for (auto const& cw : m_literal2gc_clause[lit.index()]) {
|
||||
SASSERT(!cw.is_binary() || lit == cw[0]);
|
||||
SASSERT(cw.is_binary() || cw.was_removed());
|
||||
if (cw.is_binary())
|
||||
mark_visited(cw[1]);
|
||||
else if (ENABLE_TERNARY && cw.is_ternary())
|
||||
insert_ternary_to_delete(lit, cw);
|
||||
}
|
||||
}
|
||||
|
||||
void solver::shrink_watch_list(literal lit) {
|
||||
auto& wl = get_wlist((~lit).index());
|
||||
unsigned j = 0, sz = wl.size(), end = sz;
|
||||
for (unsigned i = 0; i < end; ++i) {
|
||||
auto w = wl[i];
|
||||
if (w.is_binary_clause() && !is_visited(w.get_literal()))
|
||||
wl[j++] = w;
|
||||
else if (ENABLE_TERNARY && w.is_ternary_clause())
|
||||
insert_ternary_to_delete(w.literal1(), w.literal2(), false);
|
||||
else if (w.is_clause() && !get_clause(w).was_removed())
|
||||
wl[j++] = w;
|
||||
else if (w.is_ext_constraint())
|
||||
wl[j++] = w;
|
||||
}
|
||||
#if 0
|
||||
std::sort(m_ternary_to_delete.begin(), m_ternary_to_delete.end());
|
||||
int prev = -1;
|
||||
unsigned k = 0;
|
||||
std::tuple<literal, literal, bool> p = tuple(null_literal, null_literal, false);
|
||||
for (unsigned i = 0; i < m_ternary_to_delete.size(); ++i) {
|
||||
auto const& t = m_ternary_to_delete[i];
|
||||
}
|
||||
#endif
|
||||
std::cout << "gc-watch-list " << lit << " " << wl.size() << " -> " << j << "\n";
|
||||
wl.shrink(j);
|
||||
m_literal2gc_clause[lit.index()].reset();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
}
|
|
@ -202,6 +202,7 @@ namespace sat {
|
|||
|
||||
bool integrity_checker::check_reinit_stack() const {
|
||||
for (auto const& c : s.m_clauses_to_reinit) {
|
||||
SASSERT(c.is_binary() || c.get_clause()->on_reinit_stack());
|
||||
VERIFY(c.is_binary() || c.get_clause()->on_reinit_stack());
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -167,9 +167,11 @@ namespace sat {
|
|||
return;
|
||||
|
||||
if (m_probing_binary) {
|
||||
watch_list & wlist = s.get_wlist(~l);
|
||||
for (unsigned i = 0; i < wlist.size(); ++i) {
|
||||
unsigned sz = s.get_wlist(~l).size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
watch_list& wlist = s.get_wlist(~l);
|
||||
watched & w = wlist[i];
|
||||
sz = wlist.size();
|
||||
if (!w.is_binary_clause())
|
||||
continue;
|
||||
literal l2 = w.get_literal();
|
||||
|
@ -177,7 +179,8 @@ namespace sat {
|
|||
continue;
|
||||
if (s.value(l2) != l_undef)
|
||||
continue;
|
||||
// Note: that try_lit calls propagate, which may update the watch lists.
|
||||
// Note: that try_lit calls propagate, which may update the watch lists
|
||||
// and potentially change the set of variables.
|
||||
if (!try_lit(l2, false))
|
||||
return;
|
||||
if (s.inconsistent())
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -124,6 +124,7 @@ namespace sat {
|
|||
bool_vector m_lit_mark;
|
||||
bool_vector m_eliminated;
|
||||
bool_vector m_external;
|
||||
unsigned_vector m_var_scope;
|
||||
unsigned_vector m_touched;
|
||||
unsigned m_touch_index;
|
||||
literal_vector m_replay_assign;
|
||||
|
@ -286,6 +287,8 @@ namespace sat {
|
|||
clause * mk_ter_clause(literal * lits, status st);
|
||||
bool attach_ter_clause(clause & c, status st);
|
||||
clause * mk_nary_clause(unsigned num_lits, literal * lits, status st);
|
||||
bool has_variables_to_reinit(clause const& c) const;
|
||||
bool has_variables_to_reinit(literal l1, literal l2) const;
|
||||
bool attach_nary_clause(clause & c);
|
||||
void attach_clause(clause & c, bool & reinit);
|
||||
void attach_clause(clause & c) { bool reinit; attach_clause(c, reinit); }
|
||||
|
@ -320,6 +323,7 @@ namespace sat {
|
|||
void detach_nary_clause(clause & c);
|
||||
void detach_ter_clause(clause & c);
|
||||
void push_reinit_stack(clause & c);
|
||||
void push_reinit_stack(literal l1, literal l2);
|
||||
|
||||
void init_visited();
|
||||
void mark_visited(literal l) { m_visited[l.index()] = m_visited_ts; }
|
||||
|
@ -441,6 +445,7 @@ namespace sat {
|
|||
protected:
|
||||
bool should_propagate() const;
|
||||
bool propagate_core(bool update);
|
||||
bool propagate_literal(literal l, bool update);
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
|
@ -546,6 +551,10 @@ namespace sat {
|
|||
bool can_delete(clause const & c) const;
|
||||
bool can_delete3(literal l1, literal l2, literal l3) const;
|
||||
|
||||
// gc for lemmas in the reinit-stack
|
||||
void gc_reinit_stack(unsigned num_scopes);
|
||||
bool is_asserting(unsigned new_lvl, clause_wrapper const& cw) const;
|
||||
|
||||
clause& get_clause(watch_list::iterator it) const {
|
||||
SASSERT(it->get_kind() == watched::CLAUSE);
|
||||
return get_clause(it->get_clause_offset());
|
||||
|
|
|
@ -84,6 +84,7 @@ namespace array {
|
|||
}
|
||||
|
||||
sat::check_result solver::check() {
|
||||
force_push();
|
||||
// flet<bool> _is_redundant(m_is_redundant, true);
|
||||
bool turn[2] = { false, false };
|
||||
turn[s().rand()(2)] = true;
|
||||
|
@ -96,14 +97,8 @@ namespace array {
|
|||
return sat::check_result::CR_DONE;
|
||||
}
|
||||
|
||||
void solver::push() {
|
||||
th_euf_solver::lazy_push();
|
||||
}
|
||||
|
||||
void solver::pop(unsigned n) {
|
||||
n = lazy_pop(n);
|
||||
if (n == 0)
|
||||
return;
|
||||
void solver::pop_core(unsigned n) {
|
||||
th_euf_solver::pop_core(n);
|
||||
m_var_data.resize(get_num_vars());
|
||||
}
|
||||
|
||||
|
@ -111,9 +106,9 @@ namespace array {
|
|||
for (unsigned i = 0; i < get_num_vars(); ++i) {
|
||||
auto& d = get_var_data(i);
|
||||
out << var2enode(i)->get_expr_id() << " " << mk_bounded_pp(var2expr(i), m, 2) << "\n";
|
||||
display_info(out, "parent beta", d.m_parent_lambdas);
|
||||
display_info(out, "parent lambdas", d.m_parent_lambdas);
|
||||
display_info(out, "parent select", d.m_parent_selects);
|
||||
display_info(out, "beta ", d.m_lambdas);
|
||||
display_info(out, "b ", d.m_lambdas);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -159,12 +154,14 @@ namespace array {
|
|||
}
|
||||
|
||||
void solver::new_eq_eh(euf::th_eq const& eq) {
|
||||
m_find.merge(eq.m_v1, eq.m_v2);
|
||||
force_push();
|
||||
m_find.merge(eq.v1(), eq.v2());
|
||||
}
|
||||
|
||||
bool solver::unit_propagate() {
|
||||
if (m_qhead == m_axiom_trail.size())
|
||||
return false;
|
||||
force_push();
|
||||
bool prop = false;
|
||||
ctx.push(value_trail<euf::solver, unsigned>(m_qhead));
|
||||
for (; m_qhead < m_axiom_trail.size() && !s().inconsistent(); ++m_qhead)
|
||||
|
|
|
@ -175,6 +175,8 @@ namespace array {
|
|||
var_data& get_var_data(euf::enode* n) { return get_var_data(n->get_th_var(get_id())); }
|
||||
var_data& get_var_data(theory_var v) { return *m_var_data[v]; }
|
||||
var_data const& get_var_data(theory_var v) const { return *m_var_data[v]; }
|
||||
|
||||
void pop_core(unsigned n) override;
|
||||
|
||||
// models
|
||||
bool have_different_model_values(theory_var v1, theory_var v2);
|
||||
|
@ -191,8 +193,7 @@ namespace array {
|
|||
void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override {}
|
||||
void asserted(literal l) override {}
|
||||
sat::check_result check() override;
|
||||
void push() override;
|
||||
void pop(unsigned n) override;
|
||||
|
||||
std::ostream& display(std::ostream& out) const override;
|
||||
std::ostream& display_justification(std::ostream& out, sat::ext_justification_idx idx) const override;
|
||||
std::ostream& display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const override;
|
||||
|
|
|
@ -55,6 +55,25 @@ namespace bv {
|
|||
}
|
||||
}
|
||||
|
||||
void ackerman::used_diseq_eh(euf::theory_var v1, euf::theory_var v2) {
|
||||
if (v1 == v2)
|
||||
return;
|
||||
if (v1 > v2)
|
||||
std::swap(v1, v2);
|
||||
vv* n = m_tmp_vv;
|
||||
n->v1 = v1;
|
||||
n->v2 = v2;
|
||||
vv* other = m_table.insert_if_not_there(n);
|
||||
other->m_count++;
|
||||
if (other->m_count > m_propagate_high_watermark || other->m_glue == 0)
|
||||
s.s().set_should_simplify();
|
||||
vv::push_to_front(m_queue, other);
|
||||
if (other == n) {
|
||||
new_tmp();
|
||||
gc();
|
||||
}
|
||||
}
|
||||
|
||||
void ackerman::update_glue(vv& v) {
|
||||
unsigned sz = s.m_bits[v.v1].size();
|
||||
m_diff_levels.reserve(s.s().scope_lvl() + 1, false);
|
||||
|
|
|
@ -72,6 +72,8 @@ namespace bv {
|
|||
|
||||
void used_eq_eh(euf::theory_var v1, euf::theory_var v2);
|
||||
|
||||
void used_diseq_eh(euf::theory_var v1, euf::theory_var v2);
|
||||
|
||||
void propagate();
|
||||
};
|
||||
|
||||
|
|
|
@ -62,15 +62,17 @@ namespace bv {
|
|||
m_zero_one_bits.push_back(zero_one_bits());
|
||||
ctx.attach_th_var(n, this, r);
|
||||
|
||||
TRACE("bv", tout << "mk-var: " << r << " " << n->get_expr_id() << " " << mk_pp(n->get_expr(), m) << "\n";);
|
||||
TRACE("bv", tout << "mk-var: " << r << " " << n->get_expr_id() << " " << mk_bounded_pp(n->get_expr(), m) << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
void solver::apply_sort_cnstr(euf::enode * n, sort * s) {
|
||||
force_push();
|
||||
get_var(n);
|
||||
}
|
||||
|
||||
sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) {
|
||||
force_push();
|
||||
SASSERT(m.is_bool(e));
|
||||
if (!visit_rec(m, e, sign, root, redundant))
|
||||
return sat::null_literal;
|
||||
|
@ -81,6 +83,7 @@ namespace bv {
|
|||
}
|
||||
|
||||
void solver::internalize(expr* e, bool redundant) {
|
||||
force_push();
|
||||
visit_rec(m, e, false, false, redundant);
|
||||
}
|
||||
|
||||
|
@ -337,7 +340,7 @@ namespace bv {
|
|||
for (expr* b : k_bits)
|
||||
args.push_back(m.mk_ite(b, m_autil.mk_int(power2(i++)), zero));
|
||||
expr_ref sum(m_autil.mk_add(sz, args.c_ptr()), m);
|
||||
expr_ref eq(m.mk_eq(n, sum), m);
|
||||
expr_ref eq = mk_eq(n, sum);
|
||||
sat::literal lit = ctx.internalize(eq, false, false, m_is_redundant);
|
||||
add_unit(lit);
|
||||
}
|
||||
|
@ -367,7 +370,7 @@ namespace bv {
|
|||
unsigned sz = bv.get_bv_size(n);
|
||||
numeral mod = power(numeral(2), sz);
|
||||
rhs = m_autil.mk_mod(e, m_autil.mk_int(mod));
|
||||
expr_ref eq(m.mk_eq(lhs, rhs), m);
|
||||
expr_ref eq = mk_eq(lhs, rhs);
|
||||
TRACE("bv", tout << eq << "\n";);
|
||||
add_unit(ctx.internalize(eq, false, false, m_is_redundant));
|
||||
|
||||
|
@ -378,9 +381,9 @@ namespace bv {
|
|||
numeral div = power2(i);
|
||||
rhs = m_autil.mk_idiv(e, m_autil.mk_int(div));
|
||||
rhs = m_autil.mk_mod(rhs, m_autil.mk_int(2));
|
||||
rhs = m.mk_eq(rhs, m_autil.mk_int(1));
|
||||
rhs = mk_eq(rhs, m_autil.mk_int(1));
|
||||
lhs = n_bits.get(i);
|
||||
expr_ref eq(m.mk_eq(lhs, rhs), m);
|
||||
expr_ref eq = mk_eq(lhs, rhs);
|
||||
TRACE("bv", tout << eq << "\n";);
|
||||
add_unit(ctx.internalize(eq, false, false, m_is_redundant));
|
||||
}
|
||||
|
@ -403,10 +406,10 @@ namespace bv {
|
|||
|
||||
void solver::internalize_carry(app* n) {
|
||||
SASSERT(n->get_num_args() == 3);
|
||||
literal r = ctx.get_literal(n);
|
||||
literal l1 = ctx.get_literal(n->get_arg(0));
|
||||
literal l2 = ctx.get_literal(n->get_arg(1));
|
||||
literal l3 = ctx.get_literal(n->get_arg(2));
|
||||
literal r = expr2literal(n);
|
||||
literal l1 = expr2literal(n->get_arg(0));
|
||||
literal l2 = expr2literal(n->get_arg(1));
|
||||
literal l3 = expr2literal(n->get_arg(2));
|
||||
add_clause(~r, l1, l2);
|
||||
add_clause(~r, l1, l3);
|
||||
add_clause(~r, l2, l3);
|
||||
|
@ -417,7 +420,7 @@ namespace bv {
|
|||
|
||||
void solver::internalize_xor3(app* n) {
|
||||
SASSERT(n->get_num_args() == 3);
|
||||
literal r = ctx.get_literal(n);
|
||||
literal r = expr2literal(n);
|
||||
literal l1 = expr2literal(n->get_arg(0));
|
||||
literal l2 = expr2literal(n->get_arg(1));
|
||||
literal l3 = expr2literal(n->get_arg(2));
|
||||
|
@ -483,7 +486,7 @@ namespace bv {
|
|||
expr_ref out(m);
|
||||
fn(arg1_bits.size(), arg1_bits.c_ptr(), arg2_bits.c_ptr(), out);
|
||||
sat::literal def = ctx.internalize(out, false, false, m_is_redundant);
|
||||
add_def(def, ctx.get_literal(n));
|
||||
add_def(def, expr2literal(n));
|
||||
}
|
||||
|
||||
void solver::add_def(sat::literal def, sat::literal l) {
|
||||
|
@ -568,14 +571,18 @@ namespace bv {
|
|||
}
|
||||
|
||||
void solver::assert_ackerman(theory_var v1, theory_var v2) {
|
||||
flet<bool> _red(m_is_redundant, true);
|
||||
if (v1 == v2)
|
||||
return;
|
||||
if (v1 > v2)
|
||||
std::swap(v1, v2);
|
||||
flet<bool> _red(m_is_redundant, true);
|
||||
++m_stats.m_ackerman;
|
||||
expr* o1 = var2expr(v1);
|
||||
expr* o2 = var2expr(v2);
|
||||
expr_ref oe(m.mk_eq(o1, o2), m);
|
||||
expr_ref oe = mk_var_eq(v1, v2);
|
||||
literal oeq = ctx.internalize(oe, false, false, m_is_redundant);
|
||||
unsigned sz = get_bv_size(v1);
|
||||
TRACE("bv", tout << oe << "\n";);
|
||||
unsigned sz = m_bits[v1].size();
|
||||
TRACE("bv", tout << "ackerman-eq: " << s().scope_lvl() << " " << oe << "\n";);
|
||||
literal_vector eqs;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
literal l1 = m_bits[v1][i];
|
||||
|
@ -583,7 +590,7 @@ namespace bv {
|
|||
expr_ref e1(m), e2(m);
|
||||
e1 = bv.mk_bit2bool(o1, i);
|
||||
e2 = bv.mk_bit2bool(o2, i);
|
||||
expr_ref e(m.mk_eq(e1, e2), m);
|
||||
expr_ref e = mk_eq(e1, e2);
|
||||
literal eq = ctx.internalize(e, false, false, m_is_redundant);
|
||||
add_clause(l1, ~l2, ~eq);
|
||||
add_clause(~l1, l2, ~eq);
|
||||
|
|
|
@ -37,15 +37,14 @@ namespace bv {
|
|||
};
|
||||
|
||||
class solver::bit_occs_trail : public trail<euf::solver> {
|
||||
solver& s;
|
||||
bit_atom& a;
|
||||
var_pos_occ* m_occs;
|
||||
|
||||
public:
|
||||
bit_occs_trail(solver& s, bit_atom& a):s(s), a(a), m_occs(a.m_occs) {}
|
||||
bit_occs_trail(solver& s, bit_atom& a): a(a), m_occs(a.m_occs) {}
|
||||
|
||||
virtual void undo(euf::solver& euf) {
|
||||
std::cout << "add back occurrences " << & a << "\n";
|
||||
IF_VERBOSE(1, verbose_stream() << "add back occurrences " << & a << "\n");
|
||||
a.m_occs = m_occs;
|
||||
}
|
||||
};
|
||||
|
@ -57,6 +56,7 @@ namespace bv {
|
|||
m_ackerman(*this),
|
||||
m_bb(m, get_config()),
|
||||
m_find(*this) {
|
||||
ctx.get_egraph().set_th_propagates_diseqs(id);
|
||||
}
|
||||
|
||||
void solver::fixed_var_eh(theory_var v1) {
|
||||
|
@ -194,9 +194,37 @@ namespace bv {
|
|||
}
|
||||
|
||||
void solver::new_eq_eh(euf::th_eq const& eq) {
|
||||
TRACE("bv", tout << "new eq " << eq.m_v1 << " == " << eq.m_v2 << "\n";);
|
||||
if (is_bv(eq.m_v1))
|
||||
m_find.merge(eq.m_v1, eq.m_v2);
|
||||
force_push();
|
||||
TRACE("bv", tout << "new eq " << eq.v1() << " == " << eq.v2() << "\n";);
|
||||
if (is_bv(eq.v1()))
|
||||
m_find.merge(eq.v1(), eq.v2());
|
||||
}
|
||||
|
||||
void solver::new_diseq_eh(euf::th_eq const& ne) {
|
||||
theory_var v1 = ne.v1(), v2 = ne.v2();
|
||||
if (!is_bv(v1))
|
||||
return;
|
||||
if (!get_config().m_bv_eq_axioms)
|
||||
return;
|
||||
|
||||
TRACE("bv", tout << "diff: " << v1 << " != " << v2 << "\n";);
|
||||
unsigned sz = m_bits[v1].size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
sat::literal a = m_bits[v1][i];
|
||||
sat::literal b = m_bits[v2][i];
|
||||
if (a == ~b)
|
||||
return;
|
||||
auto va = s().value(a);
|
||||
auto vb = s().value(b);
|
||||
if (va != l_undef && vb != l_undef && va != vb)
|
||||
return;
|
||||
}
|
||||
if (s().at_search_lvl()) {
|
||||
force_push();
|
||||
assert_ackerman(v1, v2);
|
||||
}
|
||||
else
|
||||
m_ackerman.used_diseq_eh(v1, v2);
|
||||
}
|
||||
|
||||
double solver::get_reward(literal l, sat::ext_constraint_idx idx, sat::literal_occs_fun& occs) const { return 0; }
|
||||
|
@ -209,6 +237,7 @@ namespace bv {
|
|||
TRACE("bv", display_constraint(tout, idx););
|
||||
switch (c.m_kind) {
|
||||
case bv_justification::kind_t::bv2bit:
|
||||
SASSERT(s().value(c.m_antecedent) == l_true);
|
||||
r.push_back(c.m_antecedent);
|
||||
ctx.add_antecedent(var2enode(c.m_v1), var2enode(c.m_v2));
|
||||
break;
|
||||
|
@ -235,9 +264,16 @@ namespace bv {
|
|||
}
|
||||
|
||||
void solver::log_drat(bv_justification const& c) {
|
||||
// this has a side-effect so changes provability:
|
||||
expr_ref eq(m.mk_eq(var2expr(c.m_v1), var2expr(c.m_v2)), m);
|
||||
sat::literal leq = ctx.internalize(eq, false, false, false);
|
||||
// introduce dummy literal for equality.
|
||||
sat::literal leq(s().num_vars() + 1, false);
|
||||
expr* e1 = var2expr(c.m_v1);
|
||||
expr* e2 = var2expr(c.m_v2);
|
||||
expr_ref eq(m.mk_eq(e1, e2), m);
|
||||
ctx.get_drat().def_begin('e', eq->get_id(), std::string("="));
|
||||
ctx.get_drat().def_add_arg(e1->get_id());
|
||||
ctx.get_drat().def_add_arg(e2->get_id());
|
||||
ctx.get_drat().def_end();
|
||||
ctx.get_drat().bool_def(leq.var(), eq->get_id());
|
||||
sat::literal_vector lits;
|
||||
auto add_bit = [&](sat::literal lit) {
|
||||
if (s().value(lit) == l_true)
|
||||
|
@ -263,19 +299,24 @@ namespace bv {
|
|||
break;
|
||||
}
|
||||
ctx.get_drat().add(lits, status());
|
||||
ctx.get_drat().log_gc_var(leq.var());
|
||||
}
|
||||
|
||||
void solver::asserted(literal l) {
|
||||
|
||||
atom* a = get_bv2a(l.var());
|
||||
TRACE("bv", tout << "asserted: " << l << "\n";);
|
||||
if (a && a->is_bit())
|
||||
if (a && a->is_bit()) {
|
||||
force_push();
|
||||
for (auto vp : a->to_bit())
|
||||
m_prop_queue.push_back(vp);
|
||||
}
|
||||
}
|
||||
|
||||
bool solver::unit_propagate() {
|
||||
if (m_prop_queue_head == m_prop_queue.size())
|
||||
return false;
|
||||
force_push();
|
||||
ctx.push(value_trail<euf::solver, unsigned>(m_prop_queue_head));
|
||||
for (; m_prop_queue_head < m_prop_queue.size() && !s().inconsistent(); ++m_prop_queue_head)
|
||||
propagate_bits(m_prop_queue[m_prop_queue_head]);
|
||||
|
@ -311,26 +352,26 @@ namespace bv {
|
|||
}
|
||||
|
||||
sat::check_result solver::check() {
|
||||
force_push();
|
||||
SASSERT(m_prop_queue.size() == m_prop_queue_head);
|
||||
return sat::check_result::CR_DONE;
|
||||
}
|
||||
|
||||
void solver::push() {
|
||||
th_euf_solver::lazy_push();
|
||||
void solver::push_core() {
|
||||
th_euf_solver::push_core();
|
||||
m_prop_queue_lim.push_back(m_prop_queue.size());
|
||||
}
|
||||
|
||||
void solver::pop(unsigned n) {
|
||||
void solver::pop_core(unsigned n) {
|
||||
SASSERT(m_num_scopes == 0);
|
||||
unsigned old_sz = m_prop_queue_lim.size() - n;
|
||||
m_prop_queue.shrink(m_prop_queue_lim[old_sz]);
|
||||
m_prop_queue_lim.shrink(old_sz);
|
||||
n = lazy_pop(n);
|
||||
if (n > 0) {
|
||||
old_sz = get_num_vars();
|
||||
m_bits.shrink(old_sz);
|
||||
m_wpos.shrink(old_sz);
|
||||
m_zero_one_bits.shrink(old_sz);
|
||||
}
|
||||
th_euf_solver::pop_core(n);
|
||||
old_sz = get_num_vars();
|
||||
m_bits.shrink(old_sz);
|
||||
m_wpos.shrink(old_sz);
|
||||
m_zero_one_bits.shrink(old_sz);
|
||||
}
|
||||
|
||||
void solver::pre_simplify() {}
|
||||
|
@ -559,8 +600,7 @@ namespace bv {
|
|||
SASSERT(s().inconsistent());
|
||||
}
|
||||
else {
|
||||
if (get_config().m_bv_eq_axioms && false) {
|
||||
// TODO - enable when pop_reinit is available
|
||||
if (false && get_config().m_bv_eq_axioms) {
|
||||
expr_ref eq(m.mk_eq(var2expr(v1), var2expr(v2)), m);
|
||||
flet<bool> _is_redundant(m_is_redundant, true);
|
||||
literal eq_lit = ctx.internalize(eq, false, false, m_is_redundant);
|
||||
|
|
|
@ -246,8 +246,8 @@ namespace bv {
|
|||
void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) override;
|
||||
void asserted(literal l) override;
|
||||
sat::check_result check() override;
|
||||
void push() override;
|
||||
void pop(unsigned n) override;
|
||||
void push_core() override;
|
||||
void pop_core(unsigned n) override;
|
||||
void pre_simplify() override;
|
||||
void simplify() override;
|
||||
bool set_root(literal l, literal r) override;
|
||||
|
@ -270,6 +270,8 @@ namespace bv {
|
|||
unsigned max_var(unsigned w) const override;
|
||||
|
||||
void new_eq_eh(euf::th_eq const& eq) override;
|
||||
void new_diseq_eh(euf::th_eq const& ne) override;
|
||||
bool use_diseqs() const override { return true; }
|
||||
bool unit_propagate() override;
|
||||
|
||||
void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override;
|
||||
|
|
|
@ -54,9 +54,11 @@ namespace euf {
|
|||
if (is_app(e) && to_app(e)->get_num_args() > 0) {
|
||||
m_stack.push_back(sat::eframe(e));
|
||||
return false;
|
||||
}
|
||||
n = m_egraph.mk(e, 0, nullptr);
|
||||
attach_node(n);
|
||||
}
|
||||
if (auto* s = expr2solver(e))
|
||||
s->internalize(e, m_is_redundant);
|
||||
else
|
||||
attach_node(m_egraph.mk(e, 0, nullptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -67,12 +69,10 @@ namespace euf {
|
|||
m_args.push_back(m_egraph.find(to_app(e)->get_arg(i)));
|
||||
if (root && internalize_root(to_app(e), sign, m_args))
|
||||
return false;
|
||||
if (auto* s = expr2solver(e)) {
|
||||
s->internalize(e, m_is_redundant);
|
||||
return true;
|
||||
}
|
||||
enode* n = m_egraph.mk(e, num, m_args.c_ptr());
|
||||
attach_node(n);
|
||||
if (auto* s = expr2solver(e))
|
||||
s->internalize(e, m_is_redundant);
|
||||
else
|
||||
attach_node(m_egraph.mk(e, num, m_args.c_ptr()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ namespace euf {
|
|||
sat::literal_vector lits;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
for (unsigned j = i + 1; j < sz; ++j) {
|
||||
expr_ref eq(m.mk_eq(args[i]->get_expr(), args[j]->get_expr()), m);
|
||||
expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr());
|
||||
sat::literal lit = internalize(eq, false, false, m_is_redundant);
|
||||
lits.push_back(lit);
|
||||
}
|
||||
|
@ -167,10 +167,10 @@ namespace euf {
|
|||
for (expr* arg : *e) {
|
||||
expr_ref fapp(m.mk_app(f, arg), m);
|
||||
expr_ref gapp(m.mk_app(g, fapp.get()), m);
|
||||
expr_ref eq(m.mk_eq(gapp, arg), m);
|
||||
expr_ref eq = mk_eq(gapp, arg);
|
||||
sat::literal lit = internalize(eq, false, false, m_is_redundant);
|
||||
s().add_clause(1, &lit, st);
|
||||
eqs.push_back(m.mk_eq(fapp, a));
|
||||
eqs.push_back(mk_eq(fapp, a));
|
||||
}
|
||||
pb_util pb(m);
|
||||
expr_ref at_least2(pb.mk_at_least_k(eqs.size(), eqs.c_ptr(), 2), m);
|
||||
|
@ -191,7 +191,7 @@ namespace euf {
|
|||
if (sz <= distinct_max_args) {
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
for (unsigned j = i + 1; j < sz; ++j) {
|
||||
expr_ref eq(m.mk_eq(args[i]->get_expr(), args[j]->get_expr()), m);
|
||||
expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr());
|
||||
sat::literal lit = internalize(eq, true, false, m_is_redundant);
|
||||
s().add_clause(1, &lit, st);
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ namespace euf {
|
|||
expr_ref fresh(m.mk_fresh_const("dist-value", u), m);
|
||||
enode* n = m_egraph.mk(fresh, 0, nullptr);
|
||||
n->mark_interpreted();
|
||||
expr_ref eq(m.mk_eq(fapp, fresh), m);
|
||||
expr_ref eq = mk_eq(fapp, fresh);
|
||||
sat::literal lit = internalize(eq, false, false, m_is_redundant);
|
||||
s().add_clause(1, &lit, st);
|
||||
}
|
||||
|
@ -221,23 +221,30 @@ namespace euf {
|
|||
expr* c = nullptr, * th = nullptr, * el = nullptr;
|
||||
if (!m.is_bool(e) && m.is_ite(e, c, th, el)) {
|
||||
app* a = to_app(e);
|
||||
sat::bool_var v = si.to_bool_var(c);
|
||||
SASSERT(v != sat::null_bool_var);
|
||||
expr_ref eq_th(m.mk_eq(a, th), m);
|
||||
expr_ref eq_el(m.mk_eq(a, el), m);
|
||||
expr_ref eq_th = mk_eq(a, th);
|
||||
sat::literal lit_th = internalize(eq_th, false, false, m_is_redundant);
|
||||
sat::literal lit_el = internalize(eq_el, false, false, m_is_redundant);
|
||||
literal lits1[2] = { literal(v, true), lit_th };
|
||||
literal lits2[2] = { literal(v, false), lit_el };
|
||||
s().add_clause(2, lits1, st);
|
||||
s().add_clause(2, lits2, st);
|
||||
if (th == el) {
|
||||
s().add_clause(1, &lit_th, st);
|
||||
}
|
||||
else {
|
||||
sat::bool_var v = si.to_bool_var(c);
|
||||
SASSERT(v != sat::null_bool_var);
|
||||
|
||||
expr_ref eq_el = mk_eq(a, el);
|
||||
|
||||
sat::literal lit_el = internalize(eq_el, false, false, m_is_redundant);
|
||||
literal lits1[2] = { literal(v, true), lit_th };
|
||||
literal lits2[2] = { literal(v, false), lit_el };
|
||||
s().add_clause(2, lits1, st);
|
||||
s().add_clause(2, lits2, st);
|
||||
}
|
||||
}
|
||||
else if (m.is_distinct(e)) {
|
||||
expr_ref_vector eqs(m);
|
||||
unsigned sz = n->num_args();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
for (unsigned j = i + 1; j < sz; ++j) {
|
||||
expr_ref eq(m.mk_eq(n->get_arg(i)->get_expr(), n->get_arg(j)->get_expr()), m);
|
||||
expr_ref eq = mk_eq(n->get_arg(i)->get_expr(), n->get_arg(j)->get_expr());
|
||||
eqs.push_back(eq);
|
||||
}
|
||||
}
|
||||
|
@ -308,4 +315,13 @@ namespace euf {
|
|||
// TODO
|
||||
// return get_theory(th_id)->is_shared(l->get_var());
|
||||
}
|
||||
|
||||
expr_ref solver::mk_eq(expr* e1, expr* e2) {
|
||||
if (e1 == e2)
|
||||
return expr_ref(m.mk_true(), m);
|
||||
expr_ref r(m.mk_eq(e2, e1), m);
|
||||
if (!m_egraph.find(r))
|
||||
r = m.mk_eq(e1, e2);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,19 +27,19 @@ namespace euf {
|
|||
void solver::check_eqc_bool_assignment() const {
|
||||
for (enode* n : m_egraph.nodes()) {
|
||||
VERIFY(!m.is_bool(n->get_expr()) ||
|
||||
s().value(get_literal(n)) == s().value(get_literal(n->get_root())));
|
||||
s().value(enode2literal(n)) == s().value(enode2literal(n->get_root())));
|
||||
}
|
||||
}
|
||||
|
||||
void solver::check_missing_bool_enode_propagation() const {
|
||||
for (enode* n : m_egraph.nodes())
|
||||
if (m.is_bool(n->get_expr()) && l_undef == s().value(get_literal(n))) {
|
||||
if (m.is_bool(n->get_expr()) && l_undef == s().value(enode2literal(n))) {
|
||||
if (!n->is_root()) {
|
||||
VERIFY(l_undef == s().value(get_literal(n->get_root())));
|
||||
VERIFY(l_undef == s().value(enode2literal(n->get_root())));
|
||||
}
|
||||
else
|
||||
for (enode* o : enode_class(n)) {
|
||||
VERIFY(l_undef == s().value(get_literal(o)));
|
||||
VERIFY(l_undef == s().value(enode2literal(o)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,8 +42,15 @@ namespace euf {
|
|||
updt_params(p);
|
||||
|
||||
std::function<void(std::ostream&, void*)> disp =
|
||||
[&](std::ostream& out, void* j) { display_justification_ptr(out, reinterpret_cast<size_t*>(j)); };
|
||||
[&](std::ostream& out, void* j) {
|
||||
display_justification_ptr(out, reinterpret_cast<size_t*>(j));
|
||||
};
|
||||
std::function<lbool(enode* n)> eval = [&](enode* n) {
|
||||
sat::literal lit = expr2literal(n->get_expr());
|
||||
return (lit == sat::null_literal) ? l_undef : s().value(lit);
|
||||
};
|
||||
m_egraph.set_display_justification(disp);
|
||||
m_egraph.set_eval(eval);
|
||||
}
|
||||
|
||||
void solver::updt_params(params_ref const& p) {
|
||||
|
@ -140,8 +147,8 @@ namespace euf {
|
|||
ext->get_antecedents(l, idx, r, probing);
|
||||
for (unsigned qhead = 0; qhead < m_explain.size(); ++qhead) {
|
||||
size_t* e = m_explain[qhead];
|
||||
if (is_literal(e))
|
||||
r.push_back(get_literal(e));
|
||||
if (is_literal(e))
|
||||
r.push_back(get_literal(e));
|
||||
else {
|
||||
size_t idx = get_justification(e);
|
||||
auto* ext = sat::constraint_base::to_extension(idx);
|
||||
|
@ -150,9 +157,14 @@ namespace euf {
|
|||
ext->get_antecedents(lit, idx, r, probing);
|
||||
}
|
||||
}
|
||||
m_egraph.end_explain();
|
||||
m_egraph.end_explain();
|
||||
unsigned j = 0;
|
||||
for (sat::literal lit : r)
|
||||
if (s().lvl(lit) > 0) r[j++] = lit;
|
||||
r.shrink(j);
|
||||
TRACE("euf", tout << "eplain " << l << " <- " << r << " " << probing << "\n";);
|
||||
DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true););
|
||||
|
||||
if (!probing)
|
||||
log_antecedents(l, r);
|
||||
}
|
||||
|
@ -204,13 +216,13 @@ namespace euf {
|
|||
|
||||
void solver::asserted(literal l) {
|
||||
expr* e = m_var2expr.get(l.var(), nullptr);
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
if (!e)
|
||||
return;
|
||||
|
||||
bool sign = l.sign();
|
||||
TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << "\n";);
|
||||
|
||||
euf::enode* n = m_egraph.find(e);
|
||||
TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << "\n";);
|
||||
if (!n)
|
||||
return;
|
||||
for (auto th : enode_th_vars(n))
|
||||
|
@ -220,32 +232,17 @@ namespace euf {
|
|||
size_t* c = to_ptr(l);
|
||||
SASSERT(is_literal(c));
|
||||
SASSERT(l == get_literal(c));
|
||||
if (m.is_eq(e) && n->num_args() == 2) {
|
||||
if (m.is_eq(e) && n->num_args() == 2 && !sign) {
|
||||
euf::enode* na = n->get_arg(0);
|
||||
euf::enode* nb = n->get_arg(1);
|
||||
if (!sign) {
|
||||
m_egraph.merge(na, nb, c);
|
||||
return;
|
||||
}
|
||||
else
|
||||
new_diseq(na, nb, l);
|
||||
m_egraph.merge(na, nb, c);
|
||||
}
|
||||
else {
|
||||
euf::enode* nb = sign ? mk_false() : mk_true();
|
||||
m_egraph.merge(n, nb, c);
|
||||
}
|
||||
euf::enode* nb = sign ? mk_false() : mk_true();
|
||||
m_egraph.merge(n, nb, c);
|
||||
}
|
||||
|
||||
void solver::new_diseq(enode* n1, enode* n2, literal lit) {
|
||||
enode * r1 = n1->get_root();
|
||||
enode * r2 = n2->get_root();
|
||||
if (r1 == r2)
|
||||
return;
|
||||
if (r1->has_one_th_var() && r2->has_one_th_var() && r1->get_first_th_id() == r2->get_first_th_id()) {
|
||||
theory_id id = r1->get_first_th_id();
|
||||
theory_var v1 = r1->get_th_var(id);
|
||||
theory_var v2 = r2->get_th_var(id);
|
||||
fid2solver(id)->new_diseq_eh(r1, r2);
|
||||
}
|
||||
}
|
||||
|
||||
bool solver::unit_propagate() {
|
||||
bool propagated = false;
|
||||
|
@ -284,7 +281,7 @@ namespace euf {
|
|||
bool_var v = si.to_bool_var(e);
|
||||
SASSERT(m.is_bool(e));
|
||||
size_t cnstr;
|
||||
literal lit;
|
||||
literal lit;
|
||||
if (is_eq) {
|
||||
VERIFY(m.is_eq(e, a, b));
|
||||
cnstr = eq_constraint().to_index();
|
||||
|
@ -315,7 +312,10 @@ namespace euf {
|
|||
void solver::propagate_th_eqs() {
|
||||
for (; m_egraph.has_th_eq() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_th_eq()) {
|
||||
th_eq eq = m_egraph.get_th_eq();
|
||||
m_id2solver[eq.m_id]->new_eq_eh(eq);
|
||||
if (eq.is_eq())
|
||||
m_id2solver[eq.id()]->new_eq_eh(eq);
|
||||
else
|
||||
m_id2solver[eq.id()]->new_diseq_eh(eq);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,6 +379,7 @@ namespace euf {
|
|||
m_scopes.shrink(m_scopes.size() - n);
|
||||
si.pop(n);
|
||||
SASSERT(m_egraph.num_scopes() == m_scopes.size());
|
||||
TRACE("euf", tout << "pop to: " << m_scopes.size() << "\n";);
|
||||
}
|
||||
|
||||
void solver::start_reinit(unsigned n) {
|
||||
|
@ -405,9 +406,19 @@ namespace euf {
|
|||
if (expr2var_replay.empty())
|
||||
return;
|
||||
si.set_expr2var_replay(&expr2var_replay);
|
||||
for (auto const& kv : expr2var_replay)
|
||||
attach_lit(si.internalize(kv.m_key, true), kv.m_key);
|
||||
si.set_expr2var_replay(nullptr);
|
||||
TRACE("euf", for (auto const& kv : expr2var_replay) tout << "replay: " << kv.m_value << " " << mk_bounded_pp(kv.m_key, m) << "\n";);
|
||||
for (auto const& kv : expr2var_replay) {
|
||||
sat::literal lit;
|
||||
expr* e = kv.m_key;
|
||||
if (si.is_bool_op(e))
|
||||
lit = literal(expr2var_replay[e], false);
|
||||
else
|
||||
lit = si.internalize(kv.m_key, true);
|
||||
VERIFY(lit.var() == kv.m_value);
|
||||
attach_lit(lit, kv.m_key);
|
||||
}
|
||||
si.set_expr2var_replay(nullptr);
|
||||
TRACE("euf", tout << "replay done\n";);
|
||||
}
|
||||
|
||||
void solver::pre_simplify() {
|
||||
|
|
|
@ -49,8 +49,6 @@ namespace euf {
|
|||
size_t to_index() const { return sat::constraint_base::mem2base(this); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class solver : public sat::extension, public th_internalizer, public th_decompile {
|
||||
typedef top_sort<euf::enode> deps_t;
|
||||
friend class ackerman;
|
||||
|
@ -194,10 +192,11 @@ namespace euf {
|
|||
sat::sat_internalizer& get_si() { return si; }
|
||||
ast_manager& get_manager() { return m; }
|
||||
enode* get_enode(expr* e) { return m_egraph.find(e); }
|
||||
sat::literal get_literal(expr* e) const { return literal(si.to_bool_var(e), false); }
|
||||
sat::literal get_literal(enode* e) const { return get_literal(e->get_expr()); }
|
||||
sat::literal expr2literal(expr* e) const { return literal(si.to_bool_var(e), false); }
|
||||
sat::literal enode2literal(enode* e) const { return expr2literal(e->get_expr()); }
|
||||
smt_params const& get_config() { return m_config; }
|
||||
region& get_region() { return m_trail.get_region(); }
|
||||
egraph& get_egraph() { return m_egraph; }
|
||||
template <typename C>
|
||||
void push(C const& c) { m_trail.push(c); }
|
||||
euf_trail_stack& get_trail_stack() { return m_trail; }
|
||||
|
@ -254,6 +253,8 @@ namespace euf {
|
|||
void internalize(expr* e, bool learned) override;
|
||||
void attach_th_var(enode* n, th_solver* th, theory_var v) { m_egraph.add_th_var(n, v, th->get_id()); }
|
||||
void attach_node(euf::enode* n);
|
||||
expr_ref mk_eq(expr* e1, expr* e2);
|
||||
expr_ref mk_eq(euf::enode* n1, euf::enode* n2) { return mk_eq(n1->get_expr(), n2->get_expr()); }
|
||||
euf::enode* mk_enode(expr* e, unsigned n, enode* const* args) { return m_egraph.mk(e, n, args); }
|
||||
expr* bool_var2expr(sat::bool_var v) { return m_var2expr.get(v, nullptr); }
|
||||
void unhandled_function(func_decl* f);
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace euf {
|
|||
}
|
||||
|
||||
sat::literal th_euf_solver::expr2literal(expr* e) const {
|
||||
return ctx.get_literal(e);
|
||||
return ctx.expr2literal(e);
|
||||
}
|
||||
|
||||
expr* th_euf_solver::bool_var2expr(sat::bool_var v) const {
|
||||
|
@ -98,26 +98,23 @@ namespace euf {
|
|||
return get_th_var(ctx.get_enode(e));
|
||||
}
|
||||
|
||||
void th_euf_solver::push() {
|
||||
void th_euf_solver::push_core() {
|
||||
TRACE("euf", tout << "push-core\n";);
|
||||
m_var2enode_lim.push_back(m_var2enode.size());
|
||||
}
|
||||
|
||||
void th_euf_solver::pop(unsigned num_scopes) {
|
||||
void th_euf_solver::pop_core(unsigned num_scopes) {
|
||||
unsigned new_lvl = m_var2enode_lim.size() - num_scopes;
|
||||
m_var2enode.shrink(m_var2enode_lim[new_lvl]);
|
||||
m_var2enode_lim.shrink(new_lvl);
|
||||
}
|
||||
|
||||
unsigned th_euf_solver::lazy_pop(unsigned n) {
|
||||
if (n <= m_num_scopes) {
|
||||
m_num_scopes -= n;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
n -= m_num_scopes;
|
||||
pop(n);
|
||||
return n;
|
||||
}
|
||||
void th_euf_solver::pop(unsigned n) {
|
||||
unsigned k = std::min(m_num_scopes, n);
|
||||
m_num_scopes -= k;
|
||||
n -= k;
|
||||
if (n > 0)
|
||||
pop_core(n);
|
||||
}
|
||||
|
||||
bool th_euf_solver::add_unit(sat::literal lit) {
|
||||
|
@ -154,4 +151,9 @@ namespace euf {
|
|||
void th_euf_solver::rewrite(expr_ref& a) {
|
||||
ctx.get_rewriter()(a);
|
||||
}
|
||||
|
||||
expr_ref th_euf_solver::mk_eq(expr* e1, expr* e2) {
|
||||
return ctx.mk_eq(e1, e2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -95,13 +95,15 @@ namespace euf {
|
|||
|
||||
virtual bool use_diseqs() const { return false; }
|
||||
|
||||
virtual void new_diseq_eh(euf::enode* a, euf::enode* b) {}
|
||||
virtual void new_diseq_eh(euf::th_eq const& eq) {}
|
||||
|
||||
/**
|
||||
\brief Parametric theories (e.g. Arrays) should implement this method.
|
||||
*/
|
||||
virtual bool is_shared(theory_var v) const { return false; }
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
class th_euf_solver : public th_solver {
|
||||
|
@ -129,9 +131,15 @@ namespace euf {
|
|||
|
||||
euf::enode* e_internalize(expr* e) { internalize(e, m_is_redundant); return expr2enode(e); }
|
||||
euf::enode* mk_enode(expr* e, bool suppress_args);
|
||||
expr_ref mk_eq(expr* e1, expr* e2);
|
||||
expr_ref mk_var_eq(theory_var v1, theory_var v2) { return mk_eq(var2expr(v1), var2expr(v2)); }
|
||||
|
||||
void rewrite(expr_ref& a);
|
||||
|
||||
virtual void push_core();
|
||||
virtual void pop_core(unsigned n);
|
||||
void force_push() { for (; m_num_scopes > 0; --m_num_scopes) push_core(); }
|
||||
|
||||
public:
|
||||
th_euf_solver(euf::solver& ctx, euf::theory_id id);
|
||||
virtual ~th_euf_solver() {}
|
||||
|
@ -147,12 +155,9 @@ namespace euf {
|
|||
trail_stack<euf::solver> & get_trail_stack();
|
||||
bool is_attached_to_var(enode* n) const;
|
||||
bool is_root(theory_var v) const { return var2enode(v)->is_root(); }
|
||||
void push() override;
|
||||
void pop(unsigned n) override;
|
||||
void push() override { m_num_scopes++; }
|
||||
void pop(unsigned n) override;
|
||||
|
||||
void lazy_push() { ++m_num_scopes; }
|
||||
void force_push() { for (; m_num_scopes > 0; --m_num_scopes) push(); }
|
||||
unsigned lazy_pop(unsigned n);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -155,7 +155,10 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
}
|
||||
|
||||
sat::bool_var add_var(bool is_ext, expr* n) {
|
||||
auto v = m_solver.add_var(is_ext);
|
||||
sat::bool_var v;
|
||||
if (m_expr2var_replay && m_expr2var_replay->find(n, v))
|
||||
return v;
|
||||
v = m_solver.add_var(is_ext);
|
||||
log_node(n);
|
||||
log_def(v, n);
|
||||
return v;
|
||||
|
@ -298,18 +301,17 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
}
|
||||
}
|
||||
|
||||
bool process_cached(app * t, bool root, bool sign) {
|
||||
sat::literal l;
|
||||
if (m_cache.find(t, l)) {
|
||||
if (sign)
|
||||
l.neg();
|
||||
if (root)
|
||||
mk_root_clause(l);
|
||||
else
|
||||
m_result_stack.push_back(l);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
bool process_cached(app* t, bool root, bool sign) {
|
||||
sat::literal l = sat::null_literal;
|
||||
if (!m_cache.find(t, l))
|
||||
return false;
|
||||
if (sign)
|
||||
l.neg();
|
||||
if (root)
|
||||
mk_root_clause(l);
|
||||
else
|
||||
m_result_stack.push_back(l);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(expr * t, bool root, bool sign) {
|
||||
|
@ -321,7 +323,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
if (process_cached(to_app(t), root, sign))
|
||||
return true;
|
||||
if (to_app(t)->get_family_id() != m.get_basic_family_id())
|
||||
return convert_app(to_app(t), root, sign);
|
||||
return convert_app(to_app(t), root, sign);
|
||||
switch (to_app(t)->get_decl_kind()) {
|
||||
case OP_NOT:
|
||||
case OP_OR:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue