mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 09:35:32 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
1df749ad33
368 changed files with 12363 additions and 6152 deletions
|
@ -39,6 +39,7 @@ z3_add_component(sat
|
|||
util
|
||||
dd
|
||||
grobner
|
||||
params
|
||||
PYG_FILES
|
||||
sat_asymm_branch_params.pyg
|
||||
sat_params.pyg
|
||||
|
|
|
@ -112,27 +112,6 @@ static void read_clause(Buffer & in, std::ostream& err, sat::literal_vector & li
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Buffer>
|
||||
static void read_pragma(Buffer & in, std::ostream& err, std::string& p, sat::proof_hint& h) {
|
||||
skip_whitespace(in);
|
||||
if (*in != 'p')
|
||||
return;
|
||||
++in;
|
||||
while (*in == ' ')
|
||||
++in;
|
||||
while (true) {
|
||||
if (*in == EOF)
|
||||
break;
|
||||
if (*in == '\n') {
|
||||
++in;
|
||||
break;
|
||||
}
|
||||
p.push_back(*in);
|
||||
++in;
|
||||
}
|
||||
if (!p.empty())
|
||||
h.from_string(p);
|
||||
}
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
|
@ -177,25 +156,7 @@ namespace dimacs {
|
|||
std::ostream& operator<<(std::ostream& out, drat_pp const& p) {
|
||||
auto const& r = p.r;
|
||||
sat::status_pp pp(r.m_status, p.th);
|
||||
switch (r.m_tag) {
|
||||
case drat_record::tag_t::is_clause:
|
||||
if (!r.m_pragma.empty())
|
||||
return out << pp << " " << r.m_lits << " 0 p " << r.m_pragma << "\n";
|
||||
return out << pp << " " << r.m_lits << " 0\n";
|
||||
case drat_record::tag_t::is_node:
|
||||
return out << "e " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n";
|
||||
case drat_record::tag_t::is_sort:
|
||||
return out << "s " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n";
|
||||
case drat_record::tag_t::is_decl:
|
||||
return out << "f " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n";
|
||||
case drat_record::tag_t::is_bool_def:
|
||||
return out << "b " << r.m_node_id << " " << r.m_args << "0\n";
|
||||
case drat_record::tag_t::is_var:
|
||||
return out << "v " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n";
|
||||
case drat_record::tag_t::is_quantifier:
|
||||
return out << "q " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n";
|
||||
}
|
||||
return out;
|
||||
return out << pp << " " << r.m_lits << " 0\n";
|
||||
}
|
||||
|
||||
char const* drat_parser::parse_identifier() {
|
||||
|
@ -266,47 +227,10 @@ namespace dimacs {
|
|||
}
|
||||
|
||||
bool drat_parser::next() {
|
||||
int n, b, e, theory_id;
|
||||
auto parse_ast = [&](drat_record::tag_t tag) {
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
n = parse_int(in, err);
|
||||
skip_whitespace(in);
|
||||
m_record.m_name = parse_sexpr();
|
||||
m_record.m_tag = tag;
|
||||
m_record.m_node_id = n;
|
||||
m_record.m_args.reset();
|
||||
while (true) {
|
||||
n = parse_int(in, err);
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n < 0)
|
||||
throw lex_error();
|
||||
m_record.m_args.push_back(n);
|
||||
}
|
||||
};
|
||||
auto parse_var = [&]() {
|
||||
++in;
|
||||
skip_whitespace(in);
|
||||
n = parse_int(in, err);
|
||||
skip_whitespace(in);
|
||||
m_record.m_name = parse_sexpr();
|
||||
m_record.m_tag = drat_record::tag_t::is_var;
|
||||
m_record.m_node_id = n;
|
||||
m_record.m_args.reset();
|
||||
n = parse_int(in, err);
|
||||
if (n < 0)
|
||||
throw lex_error();
|
||||
m_record.m_args.push_back(n);
|
||||
n = parse_int(in, err);
|
||||
if (n != 0)
|
||||
throw lex_error();
|
||||
};
|
||||
int theory_id;
|
||||
try {
|
||||
loop:
|
||||
skip_whitespace(in);
|
||||
m_record.m_pragma.clear();
|
||||
m_record.m_hint.reset();
|
||||
switch (*in) {
|
||||
case EOF:
|
||||
return false;
|
||||
|
@ -321,7 +245,6 @@ namespace dimacs {
|
|||
++in;
|
||||
skip_whitespace(in);
|
||||
read_clause(in, err, m_record.m_lits);
|
||||
m_record.m_tag = drat_record::tag_t::is_clause;
|
||||
m_record.m_status = sat::status::input();
|
||||
break;
|
||||
case 'a':
|
||||
|
@ -331,49 +254,13 @@ namespace dimacs {
|
|||
theory_id = read_theory_id();
|
||||
skip_whitespace(in);
|
||||
read_clause(in, err, m_record.m_lits);
|
||||
read_pragma(in, err, m_record.m_pragma, m_record.m_hint);
|
||||
m_record.m_tag = drat_record::tag_t::is_clause;
|
||||
m_record.m_status = sat::status::th(false, theory_id);
|
||||
break;
|
||||
case 'e':
|
||||
// parse expression definition
|
||||
parse_ast(drat_record::tag_t::is_node);
|
||||
break;
|
||||
case 'v':
|
||||
parse_var();
|
||||
break;
|
||||
case 'q':
|
||||
parse_ast(drat_record::tag_t::is_quantifier);
|
||||
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);
|
||||
n = parse_int(in, err);
|
||||
e = parse_int(in, err);
|
||||
if (e != 0)
|
||||
throw lex_error();
|
||||
m_record.m_tag = drat_record::tag_t::is_bool_def;
|
||||
m_record.m_node_id = b;
|
||||
m_record.m_args.reset();
|
||||
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);
|
||||
m_record.m_tag = drat_record::tag_t::is_clause;
|
||||
m_record.m_status = sat::status::deleted();
|
||||
break;
|
||||
case 'r':
|
||||
|
@ -383,13 +270,11 @@ namespace dimacs {
|
|||
skip_whitespace(in);
|
||||
theory_id = read_theory_id();
|
||||
read_clause(in, err, m_record.m_lits);
|
||||
m_record.m_tag = drat_record::tag_t::is_clause;
|
||||
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();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -53,18 +53,11 @@ namespace dimacs {
|
|||
};
|
||||
|
||||
struct drat_record {
|
||||
enum class tag_t { is_clause, is_node, is_decl, is_sort, is_bool_def, is_var, is_quantifier };
|
||||
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
|
||||
// a bool def populates m_node_id and one element in m_args
|
||||
sat::literal_vector m_lits;
|
||||
sat::status m_status = sat::status::redundant();
|
||||
unsigned m_node_id = 0;
|
||||
std::string m_name;
|
||||
unsigned_vector m_args;
|
||||
std::string m_pragma;
|
||||
sat::proof_hint m_hint;
|
||||
};
|
||||
|
||||
struct drat_pp {
|
||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
|||
#include "sat/sat_types.h"
|
||||
#include "sat/sat_params.hpp"
|
||||
#include "sat/sat_simplifier_params.hpp"
|
||||
#include "params/solver_params.hpp"
|
||||
|
||||
|
||||
namespace sat {
|
||||
|
@ -31,6 +32,8 @@ namespace sat {
|
|||
|
||||
void config::updt_params(params_ref const & _p) {
|
||||
sat_params p(_p);
|
||||
solver_params sp(_p);
|
||||
|
||||
m_max_memory = megabytes_to_bytes(p.max_memory());
|
||||
|
||||
symbol s = p.restart();
|
||||
|
@ -194,10 +197,10 @@ namespace sat {
|
|||
m_drat_check_unsat = p.drat_check_unsat();
|
||||
m_drat_check_sat = p.drat_check_sat();
|
||||
m_drat_file = p.drat_file();
|
||||
m_drat = (m_drat_check_unsat || m_drat_file.is_non_empty_string() || m_drat_check_sat) && p.threads() == 1;
|
||||
m_smt_proof = p.smt_proof();
|
||||
m_drat = !p.drat_disable() && (sp.lemmas2console() || m_drat_check_unsat || m_drat_file.is_non_empty_string() || m_smt_proof.is_non_empty_string() || m_drat_check_sat) && p.threads() == 1;
|
||||
m_drat_binary = p.drat_binary();
|
||||
m_drat_activity = p.drat_activity();
|
||||
m_drup_trim = p.drup_trim();
|
||||
m_dyn_sub_res = p.dyn_sub_res();
|
||||
|
||||
// Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016.
|
||||
|
@ -248,13 +251,9 @@ namespace sat {
|
|||
m_card_solver = p.cardinality_solver();
|
||||
m_xor_solver = false; // prevent users from playing with this option
|
||||
|
||||
sat_simplifier_params sp(_p);
|
||||
m_elim_vars = sp.elim_vars();
|
||||
sat_simplifier_params ssp(_p);
|
||||
m_elim_vars = ssp.elim_vars();
|
||||
|
||||
#if 0
|
||||
if (m_drat && (m_xor_solver || m_card_solver))
|
||||
throw sat_param_exception("DRAT checking only works for pure CNF");
|
||||
#endif
|
||||
}
|
||||
|
||||
void config::collect_param_descrs(param_descrs & r) {
|
||||
|
|
|
@ -177,9 +177,9 @@ namespace sat {
|
|||
bool m_drat;
|
||||
bool m_drat_binary;
|
||||
symbol m_drat_file;
|
||||
symbol m_smt_proof;
|
||||
bool m_drat_check_unsat;
|
||||
bool m_drat_check_sat;
|
||||
bool m_drup_trim;
|
||||
bool m_drat_activity;
|
||||
|
||||
bool m_card_solver;
|
||||
|
|
|
@ -52,8 +52,7 @@ namespace sat {
|
|||
void drat::updt_config() {
|
||||
m_check_unsat = s.get_config().m_drat_check_unsat;
|
||||
m_check_sat = s.get_config().m_drat_check_sat;
|
||||
m_trim = s.get_config().m_drup_trim;
|
||||
m_check = m_check_unsat || m_check_sat || m_trim;
|
||||
m_check = m_check_unsat || m_check_sat;
|
||||
m_activity = s.get_config().m_drat_activity;
|
||||
}
|
||||
|
||||
|
@ -130,14 +129,6 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
buffer[len++] = '0';
|
||||
if (st.get_hint()) {
|
||||
buffer[len++] = ' ';
|
||||
buffer[len++] = 'p';
|
||||
buffer[len++] = ' ';
|
||||
auto* ps = st.get_hint();
|
||||
for (auto ch : ps->to_string())
|
||||
buffer[len++] = ch;
|
||||
}
|
||||
buffer[len++] = '\n';
|
||||
m_out->write(buffer, len);
|
||||
}
|
||||
|
@ -210,8 +201,6 @@ namespace sat {
|
|||
if (st.is_redundant() && st.is_sat())
|
||||
verify(1, &l);
|
||||
|
||||
if (m_trim)
|
||||
m_proof.push_back({mk_clause(1, &l, st.is_redundant()), st});
|
||||
|
||||
if (st.is_deleted())
|
||||
return;
|
||||
|
@ -230,8 +219,7 @@ namespace sat {
|
|||
|
||||
IF_VERBOSE(20, trace(verbose_stream(), 2, lits, st););
|
||||
if (st.is_deleted()) {
|
||||
if (m_trim)
|
||||
m_proof.push_back({mk_clause(2, lits, true), st});
|
||||
;
|
||||
}
|
||||
else {
|
||||
if (st.is_redundant() && st.is_sat())
|
||||
|
@ -255,31 +243,6 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
void drat::bool_def(bool_var v, unsigned n) {
|
||||
if (m_out)
|
||||
(*m_out) << "b " << v << " " << n << " 0\n";
|
||||
}
|
||||
|
||||
void drat::def_begin(char id, unsigned n, std::string const& name) {
|
||||
if (m_out)
|
||||
(*m_out) << id << " " << n << " " << name;
|
||||
}
|
||||
|
||||
void drat::def_add_arg(unsigned arg) {
|
||||
if (m_out)
|
||||
(*m_out) << " " << arg;
|
||||
}
|
||||
|
||||
void drat::def_end() {
|
||||
if (m_out)
|
||||
(*m_out) << " 0\n";
|
||||
}
|
||||
|
||||
void drat::log_adhoc(std::function<void(std::ostream&)>& fn) {
|
||||
if (m_out)
|
||||
fn(*m_out);
|
||||
}
|
||||
|
||||
void drat::append(clause& c, status st) {
|
||||
TRACE("sat_drat", pp(tout, st) << " " << c << "\n";);
|
||||
for (literal lit : c) declare(lit);
|
||||
|
@ -453,6 +416,8 @@ namespace sat {
|
|||
void drat::verify(unsigned n, literal const* c) {
|
||||
if (!m_check_unsat)
|
||||
return;
|
||||
if (m_inconsistent)
|
||||
return;
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
declare(c[i]);
|
||||
if (is_drup(n, c)) {
|
||||
|
@ -683,6 +648,7 @@ namespace sat {
|
|||
verify(0, nullptr);
|
||||
SASSERT(m_inconsistent);
|
||||
}
|
||||
if (m_clause_eh) m_clause_eh->on_clause(0, nullptr, status::redundant());
|
||||
}
|
||||
void drat::add(literal l, bool learned) {
|
||||
++m_stats.m_num_add;
|
||||
|
@ -690,6 +656,8 @@ namespace sat {
|
|||
if (m_out) dump(1, &l, st);
|
||||
if (m_bout) bdump(1, &l, st);
|
||||
if (m_check) append(l, st);
|
||||
TRACE("sat", tout << "add " << m_clause_eh << "\n");
|
||||
if (m_clause_eh) m_clause_eh->on_clause(1, &l, st);
|
||||
}
|
||||
void drat::add(literal l1, literal l2, status st) {
|
||||
if (st.is_deleted())
|
||||
|
@ -700,6 +668,7 @@ namespace sat {
|
|||
if (m_out) dump(2, ls, st);
|
||||
if (m_bout) bdump(2, ls, st);
|
||||
if (m_check) append(l1, l2, st);
|
||||
if (m_clause_eh) m_clause_eh->on_clause(2, ls, st);
|
||||
}
|
||||
void drat::add(clause& c, status st) {
|
||||
if (st.is_deleted())
|
||||
|
@ -709,6 +678,7 @@ namespace sat {
|
|||
if (m_out) dump(c.size(), c.begin(), st);
|
||||
if (m_bout) bdump(c.size(), c.begin(), st);
|
||||
if (m_check) append(mk_clause(c), st);
|
||||
if (m_clause_eh) m_clause_eh->on_clause(c.size(), c.begin(), st);
|
||||
}
|
||||
|
||||
void drat::add(literal_vector const& lits, status st) {
|
||||
|
@ -722,13 +692,16 @@ namespace sat {
|
|||
++m_stats.m_num_add;
|
||||
if (m_check) {
|
||||
switch (sz) {
|
||||
case 0: add(); break;
|
||||
case 0: if (st.is_input()) m_inconsistent = true; else add(); break;
|
||||
case 1: append(lits[0], st); break;
|
||||
default: append(mk_clause(sz, lits, st.is_redundant()), st); break;
|
||||
}
|
||||
}
|
||||
if (m_out)
|
||||
dump(sz, lits, st);
|
||||
|
||||
if (m_clause_eh)
|
||||
m_clause_eh->on_clause(sz, lits, st);
|
||||
}
|
||||
|
||||
void drat::add(literal_vector const& c) {
|
||||
|
@ -748,6 +721,8 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (m_clause_eh)
|
||||
m_clause_eh->on_clause(c.size(), c.data(), status::redundant());
|
||||
}
|
||||
|
||||
void drat::del(literal l) {
|
||||
|
@ -755,6 +730,7 @@ namespace sat {
|
|||
if (m_out) dump(1, &l, status::deleted());
|
||||
if (m_bout) bdump(1, &l, status::deleted());
|
||||
if (m_check) append(l, status::deleted());
|
||||
if (m_clause_eh) m_clause_eh->on_clause(1, &l, status::deleted());
|
||||
}
|
||||
|
||||
void drat::del(literal l1, literal l2) {
|
||||
|
@ -763,6 +739,7 @@ namespace sat {
|
|||
if (m_out) dump(2, ls, status::deleted());
|
||||
if (m_bout) bdump(2, ls, status::deleted());
|
||||
if (m_check) append(l1, l2, status::deleted());
|
||||
if (m_clause_eh) m_clause_eh->on_clause(2, ls, status::deleted());
|
||||
}
|
||||
|
||||
void drat::del(clause& c) {
|
||||
|
@ -780,7 +757,8 @@ namespace sat {
|
|||
++m_stats.m_num_del;
|
||||
if (m_out) dump(c.size(), c.begin(), status::deleted());
|
||||
if (m_bout) bdump(c.size(), c.begin(), status::deleted());
|
||||
if (m_check) append(mk_clause(c), status::deleted());
|
||||
if (m_check) append(mk_clause(c), status::deleted());
|
||||
if (m_clause_eh) m_clause_eh->on_clause(c.size(), c.begin(), status::deleted());
|
||||
}
|
||||
|
||||
clause& drat::mk_clause(clause& c) {
|
||||
|
@ -796,23 +774,9 @@ namespace sat {
|
|||
if (m_out) dump(c.size(), c.begin(), status::deleted());
|
||||
if (m_bout) bdump(c.size(), c.begin(), status::deleted());
|
||||
if (m_check) append(mk_clause(c.size(), c.begin(), true), status::deleted());
|
||||
if (m_clause_eh) m_clause_eh->on_clause(c.size(), c.begin(), status::deleted());
|
||||
}
|
||||
|
||||
//
|
||||
// placeholder for trim function.
|
||||
// 1. trail contains justification for the empty clause.
|
||||
// 2. backward pass to prune.
|
||||
//
|
||||
svector<std::pair<clause&, status>> drat::trim() {
|
||||
SASSERT(m_units.empty());
|
||||
svector<std::pair<clause&, status>> proof;
|
||||
for (auto const& [c, st] : m_proof)
|
||||
if (!st.is_deleted())
|
||||
proof.push_back({c,st});
|
||||
return proof;
|
||||
}
|
||||
|
||||
|
||||
void drat::check_model(model const& m) {
|
||||
}
|
||||
|
||||
|
@ -844,196 +808,4 @@ namespace sat {
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
std::string proof_hint::to_string() const {
|
||||
std::ostringstream ous;
|
||||
switch (m_ty) {
|
||||
case hint_type::null_h:
|
||||
return std::string();
|
||||
case hint_type::farkas_h:
|
||||
ous << "farkas ";
|
||||
break;
|
||||
case hint_type::bound_h:
|
||||
ous << "bound ";
|
||||
break;
|
||||
case hint_type::implied_eq_h:
|
||||
ous << "implied_eq ";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
for (auto const& [q, l] : m_literals)
|
||||
ous << rational(q) << " * " << l << " ";
|
||||
for (auto const& [a, b] : m_eqs)
|
||||
ous << " = " << a << " " << b << " ";
|
||||
for (auto const& [a, b] : m_diseqs)
|
||||
ous << " != " << a << " " << b << " ";
|
||||
return ous.str();
|
||||
}
|
||||
|
||||
void proof_hint::from_string(char const* s) {
|
||||
proof_hint& h = *this;
|
||||
h.reset();
|
||||
h.m_ty = hint_type::null_h;
|
||||
if (!s)
|
||||
return;
|
||||
auto ws = [&]() {
|
||||
while (*s == ' ' || *s == '\n' || *s == '\t')
|
||||
++s;
|
||||
};
|
||||
|
||||
auto parse_type = [&]() {
|
||||
if (0 == strncmp(s, "farkas", 6)) {
|
||||
h.m_ty = hint_type::farkas_h;
|
||||
s += 6;
|
||||
return true;
|
||||
}
|
||||
if (0 == strncmp(s, "bound", 5)) {
|
||||
h.m_ty = hint_type::bound_h;
|
||||
s += 5;
|
||||
return true;
|
||||
}
|
||||
if (0 == strncmp(s, "implied_eq", 10)) {
|
||||
h.m_ty = hint_type::implied_eq_h;
|
||||
s += 10;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
sbuffer<char> buff;
|
||||
auto parse_coeff = [&]() {
|
||||
buff.reset();
|
||||
while (*s && *s != ' ') {
|
||||
buff.push_back(*s);
|
||||
++s;
|
||||
}
|
||||
buff.push_back(0);
|
||||
return rational(buff.data());
|
||||
};
|
||||
|
||||
auto parse_literal = [&]() {
|
||||
rational r = parse_coeff();
|
||||
if (!r.is_int())
|
||||
return sat::null_literal;
|
||||
if (r < 0)
|
||||
return sat::literal((-r).get_unsigned(), true);
|
||||
return sat::literal(r.get_unsigned(), false);
|
||||
};
|
||||
auto parse_coeff_literal = [&]() {
|
||||
if (*s == '=') {
|
||||
++s;
|
||||
ws();
|
||||
unsigned a = parse_coeff().get_unsigned();
|
||||
ws();
|
||||
unsigned b = parse_coeff().get_unsigned();
|
||||
h.m_eqs.push_back(std::make_pair(a, b));
|
||||
return true;
|
||||
}
|
||||
if (*s == '!' && *(s + 1) == '=') {
|
||||
s += 2;
|
||||
ws();
|
||||
unsigned a = parse_coeff().get_unsigned();
|
||||
ws();
|
||||
unsigned b = parse_coeff().get_unsigned();
|
||||
h.m_diseqs.push_back(std::make_pair(a, b));
|
||||
return true;
|
||||
}
|
||||
rational coeff = parse_coeff();
|
||||
ws();
|
||||
if (*s == '*') {
|
||||
++s;
|
||||
ws();
|
||||
sat::literal lit = parse_literal();
|
||||
h.m_literals.push_back(std::make_pair(coeff, lit));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
ws();
|
||||
if (!parse_type())
|
||||
return;
|
||||
ws();
|
||||
while (*s) {
|
||||
if (!parse_coeff_literal())
|
||||
return;
|
||||
ws();
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// debugging code
|
||||
bool drat::is_clause(clause& c, literal l1, literal l2, literal l3, drat::status st1, drat::status st2) {
|
||||
//if (st1 != st2) return false;
|
||||
if (c.size() != 3) return false;
|
||||
if (l1 == c[0]) {
|
||||
if (l2 == c[1] && l3 == c[2]) return true;
|
||||
if (l2 == c[2] && l3 == c[1]) return true;
|
||||
}
|
||||
if (l2 == c[0]) {
|
||||
if (l1 == c[1] && l3 == c[2]) return true;
|
||||
if (l1 == c[2] && l3 == c[1]) return true;
|
||||
}
|
||||
if (l3 == c[0]) {
|
||||
if (l1 == c[1] && l2 == c[2]) return true;
|
||||
if (l1 == c[2] && l2 == c[1]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
if (!m_inconsistent) {
|
||||
literal_vector lits(n, c);
|
||||
IF_VERBOSE(0, verbose_stream() << "not drup " << lits << "\n");
|
||||
for (unsigned v = 0; v < m_assignment.size(); ++v) {
|
||||
lbool val = m_assignment[v];
|
||||
if (val != l_undef) {
|
||||
IF_VERBOSE(0, verbose_stream() << literal(v, false) << " |-> " << val << "\n");
|
||||
}
|
||||
}
|
||||
for (clause* cp : s.m_clauses) {
|
||||
clause& cl = *cp;
|
||||
bool found = false;
|
||||
for (literal l : cl) {
|
||||
if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n");
|
||||
}
|
||||
}
|
||||
for (clause* cp : s.m_learned) {
|
||||
clause& cl = *cp;
|
||||
bool found = false;
|
||||
for (literal l : cl) {
|
||||
if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n");
|
||||
}
|
||||
}
|
||||
svector<sat::solver::bin_clause> bin;
|
||||
s.collect_bin_clauses(bin, true);
|
||||
for (auto& b : bin) {
|
||||
bool found = false;
|
||||
if (m_assignment[b.first.var()] != (b.first.sign() ? l_true : l_false)) found = true;
|
||||
if (m_assignment[b.second.var()] != (b.second.sign() ? l_true : l_false)) found = true;
|
||||
if (!found) {
|
||||
IF_VERBOSE(0, verbose_stream() << "Bin clause is false under assignment: " << b.first << " " << b.second << "\n");
|
||||
}
|
||||
}
|
||||
IF_VERBOSE(0, s.display(verbose_stream()));
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -60,6 +60,11 @@ namespace sat {
|
|||
class justification;
|
||||
class clause;
|
||||
|
||||
struct clause_eh {
|
||||
virtual ~clause_eh() {}
|
||||
virtual void on_clause(unsigned, literal const*, status) = 0;
|
||||
};
|
||||
|
||||
class drat {
|
||||
struct stats {
|
||||
unsigned m_num_drup = 0;
|
||||
|
@ -73,6 +78,7 @@ namespace sat {
|
|||
watched_clause(clause* c, literal l1, literal l2):
|
||||
m_clause(c), m_l1(l1), m_l2(l2) {}
|
||||
};
|
||||
clause_eh* m_clause_eh = nullptr;
|
||||
svector<watched_clause> m_watched_clauses;
|
||||
typedef svector<unsigned> watch;
|
||||
solver& s;
|
||||
|
@ -89,9 +95,9 @@ namespace sat {
|
|||
bool m_check_sat = false;
|
||||
bool m_check = false;
|
||||
bool m_activity = false;
|
||||
bool m_trim = false;
|
||||
stats m_stats;
|
||||
|
||||
|
||||
void dump_activity();
|
||||
void dump(unsigned n, literal const* c, status st);
|
||||
void bdump(unsigned n, literal const* c, status st);
|
||||
|
@ -138,17 +144,9 @@ namespace sat {
|
|||
void add(literal_vector const& c); // add learned clause
|
||||
void add(unsigned sz, literal const* lits, status st);
|
||||
|
||||
// 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);
|
||||
void set_clause_eh(clause_eh& clause_eh) { m_clause_eh = &clause_eh; }
|
||||
|
||||
// declare AST node n with 'name' and arguments arg
|
||||
void def_begin(char id, unsigned n, std::string const& name);
|
||||
void def_add_arg(unsigned arg);
|
||||
void def_end();
|
||||
|
||||
// ad-hoc logging until a format is developed
|
||||
void log_adhoc(std::function<void(std::ostream&)>& fn);
|
||||
std::ostream* out() { return m_out; }
|
||||
|
||||
bool is_cleaned(clause& c) const;
|
||||
void del(literal l);
|
||||
|
@ -175,8 +173,6 @@ namespace sat {
|
|||
svector<std::pair<literal, clause*>> const& units() { return m_units; }
|
||||
bool is_drup(unsigned n, literal const* c, literal_vector& units);
|
||||
solver& get_solver() { return s; }
|
||||
|
||||
svector<std::pair<clause&, status>> trim();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace sat {
|
|||
solver* m_solver { nullptr };
|
||||
public:
|
||||
extension(symbol const& name, int id): m_id(id), m_name(name) { }
|
||||
virtual ~extension() {}
|
||||
virtual ~extension() = default;
|
||||
int get_id() const { return m_id; }
|
||||
void set_solver(solver* s) { m_solver = s; }
|
||||
solver& s() { return *m_solver; }
|
||||
|
|
|
@ -353,7 +353,7 @@ namespace sat {
|
|||
candidate(bool_var v, double r): m_var(v), m_rating(r) {}
|
||||
};
|
||||
svector<candidate> m_candidates;
|
||||
uint_set m_select_lookahead_vars;
|
||||
tracked_uint_set m_select_lookahead_vars;
|
||||
|
||||
double get_rating(bool_var v) const { return m_rating[v]; }
|
||||
double get_rating(literal l) const { return get_rating(l.var()); }
|
||||
|
|
|
@ -46,11 +46,12 @@ def_module_params('sat',
|
|||
('backtrack.conflicts', UINT, 4000, 'number of conflicts before enabling chronological backtracking'),
|
||||
('threads', UINT, 1, 'number of parallel threads to use'),
|
||||
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'),
|
||||
('drat.disable', BOOL, False, 'override anything that enables DRAT'),
|
||||
('smt.proof', SYMBOL, '', 'add SMT proof to file'),
|
||||
('drat.file', SYMBOL, '', 'file to dump DRAT proofs'),
|
||||
('drat.binary', BOOL, False, 'use Binary DRAT output format'),
|
||||
('drat.check_unsat', BOOL, False, 'build up internal proof and check'),
|
||||
('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'),
|
||||
('drup.trim', BOOL, False, 'build and trim drup proof'),
|
||||
('drat.activity', BOOL, False, 'dump variable activities'),
|
||||
('cardinality.solver', BOOL, True, 'use cardinality solver'),
|
||||
('pb.solver', SYMBOL, 'solver', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), binary_merge, segmented, solver (use native solver)'),
|
||||
|
|
|
@ -403,6 +403,7 @@ namespace sat {
|
|||
extension::scoped_drating _sd(*m_ext.get());
|
||||
if (j.get_kind() == justification::EXT_JUSTIFICATION)
|
||||
fill_ext_antecedents(lit, j, false);
|
||||
TRACE("sat", tout << "drat-unit\n");
|
||||
m_drat.add(lit, m_searching);
|
||||
}
|
||||
|
||||
|
@ -413,6 +414,7 @@ namespace sat {
|
|||
clause * solver::mk_clause_core(unsigned num_lits, literal * lits, sat::status st) {
|
||||
bool redundant = st.is_redundant();
|
||||
TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << (redundant?" learned":" aux") << "\n";);
|
||||
bool logged = false;
|
||||
if (!redundant || !st.is_sat()) {
|
||||
unsigned old_sz = num_lits;
|
||||
bool keep = simplify_clause(num_lits, lits);
|
||||
|
@ -421,13 +423,14 @@ namespace sat {
|
|||
return nullptr; // clause is equivalent to true.
|
||||
}
|
||||
// if an input clause is simplified, then log the simplified version as learned
|
||||
if (m_config.m_drat && old_sz > num_lits)
|
||||
if (m_config.m_drat && old_sz > num_lits) {
|
||||
drat_log_clause(num_lits, lits, st);
|
||||
logged = true;
|
||||
}
|
||||
|
||||
++m_stats.m_non_learned_generation;
|
||||
if (!m_searching) {
|
||||
m_mc.add_clause(num_lits, lits);
|
||||
}
|
||||
if (!m_searching)
|
||||
m_mc.add_clause(num_lits, lits);
|
||||
}
|
||||
|
||||
|
||||
|
@ -436,7 +439,7 @@ namespace sat {
|
|||
set_conflict();
|
||||
return nullptr;
|
||||
case 1:
|
||||
if (m_config.m_drat && (!st.is_sat() || st.is_input()))
|
||||
if (!logged && m_config.m_drat && (!st.is_sat() || st.is_input()))
|
||||
drat_log_clause(num_lits, lits, st);
|
||||
assign_unit(lits[0]);
|
||||
return nullptr;
|
||||
|
@ -938,16 +941,17 @@ namespace sat {
|
|||
m_inconsistent = true;
|
||||
m_conflict = c;
|
||||
m_not_l = not_l;
|
||||
TRACE("sat", display(display_justification(tout << "conflict " << not_l << " ", c) << "\n"));
|
||||
}
|
||||
|
||||
void solver::assign_core(literal l, justification j) {
|
||||
SASSERT(value(l) == l_undef);
|
||||
SASSERT(!m_trail.contains(l) && !m_trail.contains(~l));
|
||||
TRACE("sat_assign_core", tout << l << " " << j << "\n";);
|
||||
if (j.level() == 0) {
|
||||
if (m_config.m_drat)
|
||||
drat_log_unit(l, j);
|
||||
if (!m_config.m_drup_trim)
|
||||
j = justification(0); // erase justification for level 0
|
||||
j = justification(0); // erase justification for level 0
|
||||
}
|
||||
else {
|
||||
VERIFY(!at_base_lvl());
|
||||
|
@ -1801,24 +1805,21 @@ namespace sat {
|
|||
|
||||
|
||||
void solver::init_assumptions(unsigned num_lits, literal const* lits) {
|
||||
if (num_lits == 0 && m_user_scope_literals.empty()) {
|
||||
return;
|
||||
}
|
||||
if (num_lits == 0 && m_user_scope_literals.empty())
|
||||
return;
|
||||
|
||||
SASSERT(at_base_lvl());
|
||||
reset_assumptions();
|
||||
push();
|
||||
|
||||
propagate(false);
|
||||
if (inconsistent()) {
|
||||
return;
|
||||
}
|
||||
if (inconsistent())
|
||||
return;
|
||||
|
||||
TRACE("sat",
|
||||
tout << literal_vector(num_lits, lits) << "\n";
|
||||
if (!m_user_scope_literals.empty()) {
|
||||
tout << "user literals: " << m_user_scope_literals << "\n";
|
||||
}
|
||||
if (!m_user_scope_literals.empty())
|
||||
tout << "user literals: " << m_user_scope_literals << "\n";
|
||||
m_mc.display(tout);
|
||||
);
|
||||
|
||||
|
@ -1895,13 +1896,11 @@ namespace sat {
|
|||
tout << "consistent: " << !inconsistent() << "\n";
|
||||
for (literal a : m_assumptions) {
|
||||
index_set s;
|
||||
if (m_antecedents.find(a.var(), s)) {
|
||||
tout << a << ": "; display_index_set(tout, s) << "\n";
|
||||
}
|
||||
}
|
||||
for (literal lit : m_user_scope_literals) {
|
||||
tout << "user " << lit << "\n";
|
||||
if (m_antecedents.find(a.var(), s))
|
||||
tout << a << ": "; display_index_set(tout, s) << "\n";
|
||||
}
|
||||
for (literal lit : m_user_scope_literals)
|
||||
tout << "user " << lit << "\n";
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2417,7 +2416,9 @@ namespace sat {
|
|||
m_conflict_lvl = get_max_lvl(m_not_l, m_conflict, unique_max);
|
||||
justification js = m_conflict;
|
||||
|
||||
if (m_conflict_lvl <= 1 && tracking_assumptions()) {
|
||||
if (m_conflict_lvl <= 1 && (!m_assumptions.empty() ||
|
||||
!m_ext_assumption_set.empty() ||
|
||||
!m_user_scope_literals.empty())) {
|
||||
TRACE("sat", tout << "unsat core\n";);
|
||||
resolve_conflict_for_unsat_core();
|
||||
return l_false;
|
||||
|
@ -3652,11 +3653,14 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
m_trail.shrink(old_sz);
|
||||
DEBUG_CODE(for (literal l : m_trail) SASSERT(lvl(l.var()) <= new_lvl););
|
||||
m_qhead = m_trail.size();
|
||||
if (!m_replay_assign.empty()) IF_VERBOSE(20, verbose_stream() << "replay assign: " << m_replay_assign.size() << "\n");
|
||||
CTRACE("sat", !m_replay_assign.empty(), tout << "replay-assign: " << m_replay_assign << "\n";);
|
||||
for (unsigned i = m_replay_assign.size(); i-- > 0; ) {
|
||||
literal lit = m_replay_assign[i];
|
||||
SASSERT(value(lit) == l_true);
|
||||
SASSERT(!m_trail.contains(lit) && !m_trail.contains(~lit));
|
||||
m_trail.push_back(lit);
|
||||
}
|
||||
|
||||
|
@ -3707,11 +3711,11 @@ namespace sat {
|
|||
//
|
||||
|
||||
void solver::user_push() {
|
||||
|
||||
pop_to_base_level();
|
||||
m_free_var_freeze.push_back(m_free_vars);
|
||||
m_free_vars.reset(); // resetting free_vars forces new variables to be assigned above new_v
|
||||
bool_var new_v = mk_var(true, false);
|
||||
SASSERT(new_v + 1 == m_justification.size()); // there are no active variables that have higher values
|
||||
literal lit = literal(new_v, false);
|
||||
m_user_scope_literals.push_back(lit);
|
||||
m_cut_simplifier = nullptr; // for simplicity, wipe it out
|
||||
|
@ -3722,13 +3726,13 @@ namespace sat {
|
|||
|
||||
void solver::user_pop(unsigned num_scopes) {
|
||||
unsigned old_sz = m_user_scope_literals.size() - num_scopes;
|
||||
bool_var max_var = m_user_scope_literals[old_sz].var();
|
||||
bool_var max_var = m_user_scope_literals[old_sz].var();
|
||||
m_user_scope_literals.shrink(old_sz);
|
||||
|
||||
pop_to_base_level();
|
||||
if (m_ext)
|
||||
m_ext->user_pop(num_scopes);
|
||||
|
||||
|
||||
gc_vars(max_var);
|
||||
TRACE("sat", display(tout););
|
||||
|
||||
|
@ -3741,7 +3745,7 @@ namespace sat {
|
|||
m_free_vars.append(m_free_var_freeze[old_sz]);
|
||||
m_free_var_freeze.shrink(old_sz);
|
||||
scoped_suspend_rlimit _sp(m_rlimit);
|
||||
propagate(false);
|
||||
propagate(false);
|
||||
}
|
||||
|
||||
void solver::pop_to_base_level() {
|
||||
|
@ -4832,20 +4836,22 @@ namespace sat {
|
|||
return true;
|
||||
}
|
||||
|
||||
void solver::init_ts(unsigned n, svector<unsigned>& v, unsigned& ts) {
|
||||
if (v.empty())
|
||||
ts = 0;
|
||||
|
||||
ts++;
|
||||
if (ts == 0) {
|
||||
ts = 1;
|
||||
v.reset();
|
||||
}
|
||||
while (v.size() < n)
|
||||
v.push_back(0);
|
||||
}
|
||||
|
||||
void solver::init_visited() {
|
||||
if (m_visited.empty()) {
|
||||
m_visited_ts = 0;
|
||||
}
|
||||
m_visited_ts++;
|
||||
if (m_visited_ts == 0) {
|
||||
m_visited_ts = 1;
|
||||
m_visited.reset();
|
||||
}
|
||||
while (m_visited.size() < 2*num_vars()) {
|
||||
m_visited.push_back(0);
|
||||
}
|
||||
init_ts(2 * num_vars(), m_visited, m_visited_ts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace sat {
|
|||
};
|
||||
|
||||
struct no_drat_params : public params_ref {
|
||||
no_drat_params() { set_sym("drat.file", symbol()); }
|
||||
no_drat_params() { set_bool("drat.disable", true); }
|
||||
};
|
||||
|
||||
class solver : public solver_core {
|
||||
|
@ -343,6 +343,7 @@ namespace sat {
|
|||
void push_reinit_stack(clause & c);
|
||||
void push_reinit_stack(literal l1, literal l2);
|
||||
|
||||
void init_ts(unsigned n, svector<unsigned>& v, unsigned& ts);
|
||||
void init_visited();
|
||||
void mark_visited(literal l) { m_visited[l.index()] = m_visited_ts; }
|
||||
void mark_visited(bool_var v) { mark_visited(literal(v, false)); }
|
||||
|
@ -527,20 +528,21 @@ namespace sat {
|
|||
|
||||
unsigned m_conflicts_since_init { 0 };
|
||||
unsigned m_restarts { 0 };
|
||||
unsigned m_restart_next_out { 0 };
|
||||
unsigned m_conflicts_since_restart { 0 };
|
||||
bool m_force_conflict_analysis { false };
|
||||
unsigned m_simplifications { 0 };
|
||||
unsigned m_restart_threshold { 0 };
|
||||
unsigned m_luby_idx { 0 };
|
||||
unsigned m_conflicts_since_gc { 0 };
|
||||
unsigned m_gc_threshold { 0 };
|
||||
unsigned m_defrag_threshold { 0 };
|
||||
unsigned m_num_checkpoints { 0 };
|
||||
double m_min_d_tk { 0 } ;
|
||||
unsigned m_next_simplify { 0 };
|
||||
bool m_simplify_enabled { true };
|
||||
bool m_restart_enabled { true };
|
||||
unsigned m_restart_next_out = 0;
|
||||
unsigned m_conflicts_since_restart = 0;
|
||||
bool m_force_conflict_analysis = false;
|
||||
unsigned m_simplifications = 0;
|
||||
unsigned m_restart_threshold = 0;
|
||||
unsigned m_luby_idx = 0;
|
||||
unsigned m_conflicts_since_gc = 0;
|
||||
unsigned m_gc_threshold = 0;
|
||||
unsigned m_defrag_threshold = 0;
|
||||
unsigned m_num_checkpoints = 0;
|
||||
double m_min_d_tk = 0.0 ;
|
||||
unsigned m_next_simplify = 0;
|
||||
double m_simplify_mult = 1.5;
|
||||
bool m_simplify_enabled = true;
|
||||
bool m_restart_enabled = true;
|
||||
bool guess(bool_var next);
|
||||
bool decide();
|
||||
bool_var next_var();
|
||||
|
@ -713,7 +715,6 @@ namespace sat {
|
|||
//
|
||||
// -----------------------
|
||||
public:
|
||||
void set_should_simplify() { m_next_simplify = m_conflicts_since_init; }
|
||||
bool_var_vector const& get_vars_to_reinit() const { return m_vars_to_reinit; }
|
||||
bool is_probing() const { return m_is_probing; }
|
||||
bool is_free(bool_var v) const { return m_free_vars.contains(v); }
|
||||
|
|
|
@ -596,10 +596,10 @@ public:
|
|||
|
||||
void convert_internalized() {
|
||||
m_solver.pop_to_base_level();
|
||||
if (!is_internalized() && m_fmls_head > 0) {
|
||||
internalize_formulas();
|
||||
}
|
||||
if (!is_internalized() || m_internalized_converted) return;
|
||||
if (!is_internalized() && m_fmls_head > 0)
|
||||
internalize_formulas();
|
||||
if (!is_internalized() || m_internalized_converted)
|
||||
return;
|
||||
sat2goal s2g;
|
||||
m_cached_mc = nullptr;
|
||||
goal g(m, false, true, false);
|
||||
|
@ -657,7 +657,8 @@ public:
|
|||
}
|
||||
|
||||
euf::solver* ensure_euf() {
|
||||
auto* ext = dynamic_cast<euf::solver*>(m_solver.get_extension());
|
||||
m_goal2sat.init(m, m_params, m_solver, m_map, m_dep2asm, is_incremental());
|
||||
auto* ext = m_goal2sat.ensure_euf();
|
||||
return ext;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace sat {
|
|||
reslimit& m_rlimit;
|
||||
public:
|
||||
solver_core(reslimit& l) : m_rlimit(l) {}
|
||||
virtual ~solver_core() {}
|
||||
virtual ~solver_core() = default;
|
||||
|
||||
// add clauses
|
||||
virtual void add_clause(unsigned n, literal* lits, status st) = 0;
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace sat {
|
|||
|
||||
class i_local_search {
|
||||
public:
|
||||
virtual ~i_local_search() {}
|
||||
virtual ~i_local_search() = default;
|
||||
virtual void add(solver const& s) = 0;
|
||||
virtual void updt_params(params_ref const& p) = 0;
|
||||
virtual void set_seed(unsigned s) = 0;
|
||||
|
@ -94,22 +94,9 @@ namespace sat {
|
|||
|
||||
};
|
||||
|
||||
enum class hint_type {
|
||||
null_h,
|
||||
farkas_h,
|
||||
bound_h,
|
||||
implied_eq_h,
|
||||
};
|
||||
|
||||
struct proof_hint {
|
||||
hint_type m_ty = hint_type::null_h;
|
||||
vector<std::pair<rational, literal>> m_literals;
|
||||
vector<std::pair<unsigned, unsigned>> m_eqs;
|
||||
vector<std::pair<unsigned, unsigned>> m_diseqs;
|
||||
void reset() { m_ty = hint_type::null_h; m_literals.reset(); m_eqs.reset(); m_diseqs.reset(); }
|
||||
std::string to_string() const;
|
||||
void from_string(char const* s);
|
||||
void from_string(std::string const& s) { from_string(s.c_str()); }
|
||||
class proof_hint {
|
||||
public:
|
||||
virtual ~proof_hint() {}
|
||||
};
|
||||
|
||||
class status {
|
||||
|
|
|
@ -22,6 +22,7 @@ z3_add_component(sat_smt
|
|||
euf_invariant.cpp
|
||||
euf_model.cpp
|
||||
euf_proof.cpp
|
||||
euf_proof_checker.cpp
|
||||
euf_relevancy.cpp
|
||||
euf_solver.cpp
|
||||
fpa_solver.cpp
|
||||
|
|
|
@ -264,11 +264,12 @@ namespace arith {
|
|||
SASSERT(k1 != k2 || kind1 != kind2);
|
||||
|
||||
auto bin_clause = [&](sat::literal l1, sat::literal l2) {
|
||||
sat::proof_hint* bound_params = nullptr;
|
||||
arith_proof_hint* bound_params = nullptr;
|
||||
if (ctx.use_drat()) {
|
||||
bound_params = &m_farkas2;
|
||||
m_farkas2.m_literals[0] = std::make_pair(rational(1), ~l1);
|
||||
m_farkas2.m_literals[1] = std::make_pair(rational(1), ~l2);
|
||||
m_arith_hint.set_type(ctx, hint_type::farkas_h);
|
||||
m_arith_hint.add_lit(rational(1), ~l1);
|
||||
m_arith_hint.add_lit(rational(1), ~l2);
|
||||
bound_params = m_arith_hint.mk(ctx);
|
||||
}
|
||||
add_clause(l1, l2, bound_params);
|
||||
};
|
||||
|
|
|
@ -15,6 +15,8 @@ Author:
|
|||
|
||||
--*/
|
||||
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/scoped_proof.h"
|
||||
#include "sat/smt/euf_solver.h"
|
||||
#include "sat/smt/arith_solver.h"
|
||||
|
||||
|
@ -81,7 +83,6 @@ namespace arith {
|
|||
}
|
||||
|
||||
void solver::explain_assumptions() {
|
||||
m_arith_hint.reset();
|
||||
unsigned i = 0;
|
||||
for (auto const & ev : m_explanation) {
|
||||
++i;
|
||||
|
@ -91,14 +92,12 @@ namespace arith {
|
|||
switch (m_constraint_sources[idx]) {
|
||||
case inequality_source: {
|
||||
literal lit = m_inequalities[idx];
|
||||
m_arith_hint.m_literals.push_back({ev.coeff(), lit});
|
||||
m_arith_hint.add_lit(ev.coeff(), lit);
|
||||
break;
|
||||
}
|
||||
case equality_source: {
|
||||
auto [u, v] = m_equalities[idx];
|
||||
ctx.drat_log_expr(u->get_expr());
|
||||
ctx.drat_log_expr(v->get_expr());
|
||||
m_arith_hint.m_eqs.push_back({u->get_expr_id(), v->get_expr_id()});
|
||||
m_arith_hint.add_eq(u, v);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -115,22 +114,65 @@ namespace arith {
|
|||
* such that there is a r >= 1
|
||||
* (r1*a1+..+r_k*a_k) = r*a, (r1*b1+..+r_k*b_k) <= r*b
|
||||
*/
|
||||
sat::proof_hint const* solver::explain(sat::hint_type ty, sat::literal lit) {
|
||||
arith_proof_hint const* solver::explain(hint_type ty, sat::literal lit) {
|
||||
if (!ctx.use_drat())
|
||||
return nullptr;
|
||||
m_arith_hint.m_ty = ty;
|
||||
m_arith_hint.set_type(ctx, ty);
|
||||
explain_assumptions();
|
||||
if (lit != sat::null_literal)
|
||||
m_arith_hint.m_literals.push_back({rational(1), ~lit});
|
||||
return &m_arith_hint;
|
||||
m_arith_hint.add_lit(rational(1), ~lit);
|
||||
return m_arith_hint.mk(ctx);
|
||||
}
|
||||
|
||||
sat::proof_hint const* solver::explain_implied_eq(euf::enode* a, euf::enode* b) {
|
||||
arith_proof_hint const* solver::explain_implied_eq(euf::enode* a, euf::enode* b) {
|
||||
if (!ctx.use_drat())
|
||||
return nullptr;
|
||||
m_arith_hint.m_ty = sat::hint_type::implied_eq_h;
|
||||
m_arith_hint.set_type(ctx, hint_type::implied_eq_h);
|
||||
explain_assumptions();
|
||||
m_arith_hint.m_diseqs.push_back({a->get_expr_id(), b->get_expr_id()});
|
||||
return &m_arith_hint;
|
||||
m_arith_hint.add_diseq(a, b);
|
||||
return m_arith_hint.mk(ctx);
|
||||
}
|
||||
|
||||
expr* arith_proof_hint::get_hint(euf::solver& s) const {
|
||||
ast_manager& m = s.get_manager();
|
||||
family_id fid = m.get_family_id("arith");
|
||||
arith_util arith(m);
|
||||
solver& a = dynamic_cast<solver&>(*s.fid2solver(fid));
|
||||
char const* name;
|
||||
switch (m_ty) {
|
||||
case hint_type::farkas_h:
|
||||
name = "farkas";
|
||||
break;
|
||||
case hint_type::bound_h:
|
||||
name = "bound";
|
||||
break;
|
||||
case hint_type::implied_eq_h:
|
||||
name = "implied-eq";
|
||||
break;
|
||||
}
|
||||
rational lc(1);
|
||||
for (unsigned i = m_lit_head; i < m_lit_tail; ++i)
|
||||
lc = lcm(lc, denominator(a.m_arith_hint.lit(i).first));
|
||||
|
||||
expr_ref_vector args(m);
|
||||
sort_ref_vector sorts(m);
|
||||
for (unsigned i = m_lit_head; i < m_lit_tail; ++i) {
|
||||
auto const& [coeff, lit] = a.m_arith_hint.lit(i);
|
||||
args.push_back(arith.mk_int(abs(coeff*lc)));
|
||||
args.push_back(s.literal2expr(lit));
|
||||
}
|
||||
for (unsigned i = m_eq_head; i < m_eq_tail; ++i) {
|
||||
auto const& [x, y, is_eq] = a.m_arith_hint.eq(i);
|
||||
expr_ref eq(m.mk_eq(x->get_expr(), y->get_expr()), m);
|
||||
if (!is_eq) eq = m.mk_not(eq);
|
||||
args.push_back(arith.mk_int(1));
|
||||
args.push_back(eq);
|
||||
}
|
||||
for (expr* arg : args)
|
||||
sorts.push_back(arg->get_sort());
|
||||
sort* range = m.mk_proof_sort();
|
||||
func_decl* d = m.mk_func_decl(symbol(name), args.size(), sorts.data(), range);
|
||||
expr* r = m.mk_app(d, args);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
|
@ -11,7 +11,15 @@ Abstract:
|
|||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2020-09-08
|
||||
Nikolaj Bjorner (nbjorner) 2022-08-28
|
||||
|
||||
Notes:
|
||||
|
||||
The module assumes a limited repertoire of arithmetic proof rules.
|
||||
|
||||
- farkas - inequalities, equalities and disequalities with coefficients
|
||||
- implied-eq - last literal is a disequality. The literals before imply the corresponding equality.
|
||||
- bound - last literal is a bound. It is implied by prior literals.
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
@ -19,11 +27,12 @@ Author:
|
|||
#include "util/obj_pair_set.h"
|
||||
#include "ast/ast_trail.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "sat/smt/euf_proof_checker.h"
|
||||
|
||||
|
||||
namespace arith {
|
||||
|
||||
class proof_checker {
|
||||
class proof_checker : public euf::proof_checker_plugin {
|
||||
struct row {
|
||||
obj_map<expr, rational> m_coeffs;
|
||||
rational m_coeff;
|
||||
|
@ -32,16 +41,19 @@ namespace arith {
|
|||
m_coeff = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
arith_util a;
|
||||
vector<std::pair<rational, expr*>> m_todo;
|
||||
bool m_strict = false;
|
||||
row m_ineq;
|
||||
row m_conseq;
|
||||
vector<row> m_eqs;
|
||||
vector<row> m_ineqs;
|
||||
vector<row> m_diseqs;
|
||||
bool m_strict = false;
|
||||
row m_ineq;
|
||||
row m_conseq;
|
||||
vector<row> m_eqs;
|
||||
vector<row> m_ineqs;
|
||||
vector<row> m_diseqs;
|
||||
symbol m_farkas;
|
||||
symbol m_implied_eq;
|
||||
symbol m_bound;
|
||||
|
||||
void add(row& r, expr* v, rational const& coeff) {
|
||||
rational coeff1;
|
||||
|
@ -131,11 +143,15 @@ namespace arith {
|
|||
SASSERT(m_todo.empty());
|
||||
m_todo.push_back({ mul, e });
|
||||
rational coeff1;
|
||||
expr* e1, *e2;
|
||||
expr* e1, *e2, *e3;
|
||||
for (unsigned i = 0; i < m_todo.size(); ++i) {
|
||||
auto [coeff, e] = m_todo[i];
|
||||
if (a.is_mul(e, e1, e2) && a.is_numeral(e1, coeff1))
|
||||
m_todo.push_back({coeff*coeff1, e2});
|
||||
else if (a.is_mul(e, e1, e2) && a.is_uminus(e1, e3) && a.is_numeral(e3, coeff1))
|
||||
m_todo.push_back({-coeff*coeff1, e2});
|
||||
else if (a.is_mul(e, e1, e2) && a.is_uminus(e2, e3) && a.is_numeral(e3, coeff1))
|
||||
m_todo.push_back({ -coeff * coeff1, e1 });
|
||||
else if (a.is_mul(e, e1, e2) && a.is_numeral(e2, coeff1))
|
||||
m_todo.push_back({coeff*coeff1, e1});
|
||||
else if (a.is_add(e))
|
||||
|
@ -149,6 +165,8 @@ namespace arith {
|
|||
}
|
||||
else if (a.is_numeral(e, coeff1))
|
||||
r.m_coeff += coeff*coeff1;
|
||||
else if (a.is_uminus(e, e1) && a.is_numeral(e1, coeff1))
|
||||
r.m_coeff -= coeff*coeff1;
|
||||
else
|
||||
add(r, e, coeff);
|
||||
}
|
||||
|
@ -296,10 +314,16 @@ namespace arith {
|
|||
rows.push_back(row());
|
||||
return rows.back();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
proof_checker(ast_manager& m): m(m), a(m) {}
|
||||
proof_checker(ast_manager& m):
|
||||
m(m),
|
||||
a(m),
|
||||
m_farkas("farkas"),
|
||||
m_implied_eq("implied-eq"),
|
||||
m_bound("bound") {}
|
||||
|
||||
~proof_checker() override {}
|
||||
|
||||
void reset() {
|
||||
m_ineq.reset();
|
||||
|
@ -313,7 +337,8 @@ namespace arith {
|
|||
bool add_ineq(rational const& coeff, expr* e, bool sign) {
|
||||
if (!m_diseqs.empty())
|
||||
return add_literal(fresh(m_ineqs), abs(coeff), e, sign);
|
||||
return add_literal(m_ineq, abs(coeff), e, sign);
|
||||
else
|
||||
return add_literal(m_ineq, abs(coeff), e, sign);
|
||||
}
|
||||
|
||||
bool add_conseq(rational const& coeff, expr* e, bool sign) {
|
||||
|
@ -350,6 +375,76 @@ namespace arith {
|
|||
return out;
|
||||
}
|
||||
|
||||
bool check(expr_ref_vector const& clause, app* jst, expr_ref_vector& units) override {
|
||||
reset();
|
||||
expr_mark pos, neg;
|
||||
for (expr* e : clause)
|
||||
if (m.is_not(e, e))
|
||||
neg.mark(e, true);
|
||||
else
|
||||
pos.mark(e, true);
|
||||
|
||||
if (jst->get_name() != m_farkas &&
|
||||
jst->get_name() != m_bound &&
|
||||
jst->get_name() != m_implied_eq) {
|
||||
IF_VERBOSE(0, verbose_stream() << "unhandled inference " << mk_pp(jst, m) << "\n");
|
||||
return false;
|
||||
}
|
||||
bool is_bound = jst->get_name() == m_bound;
|
||||
bool even = true;
|
||||
rational coeff;
|
||||
expr* x, * y;
|
||||
unsigned j = 0;
|
||||
for (expr* arg : *jst) {
|
||||
if (even) {
|
||||
if (!a.is_numeral(arg, coeff)) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not numeral " << mk_pp(jst, m) << "\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool sign = m.is_not(arg, arg);
|
||||
if (a.is_le(arg) || a.is_lt(arg) || a.is_ge(arg) || a.is_gt(arg)) {
|
||||
if (is_bound && j + 1 == jst->get_num_args())
|
||||
add_conseq(coeff, arg, sign);
|
||||
else
|
||||
add_ineq(coeff, arg, sign);
|
||||
}
|
||||
else if (m.is_eq(arg, x, y)) {
|
||||
if (sign)
|
||||
add_diseq(x, y);
|
||||
else
|
||||
add_eq(x, y);
|
||||
}
|
||||
else {
|
||||
IF_VERBOSE(0, verbose_stream() << "not a recognized arithmetical relation " << mk_pp(arg, m) << "\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sign && !pos.is_marked(arg)) {
|
||||
units.push_back(m.mk_not(arg));
|
||||
pos.mark(arg, false);
|
||||
}
|
||||
else if (!sign && !neg.is_marked(arg)) {
|
||||
units.push_back(arg);
|
||||
neg.mark(arg, false);
|
||||
}
|
||||
}
|
||||
even = !even;
|
||||
++j;
|
||||
}
|
||||
if (check())
|
||||
return true;
|
||||
|
||||
IF_VERBOSE(0, verbose_stream() << "did not check condition\n" << mk_pp(jst, m) << "\n"; display(verbose_stream()); );
|
||||
return false;
|
||||
}
|
||||
|
||||
void register_plugins(euf::proof_checker& pc) override {
|
||||
pc.register_plugin(m_farkas, this);
|
||||
pc.register_plugin(m_bound, this);
|
||||
pc.register_plugin(m_implied_eq, this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -39,8 +39,6 @@ namespace arith {
|
|||
lp().settings().set_random_seed(get_config().m_random_seed);
|
||||
|
||||
m_lia = alloc(lp::int_solver, *m_solver.get());
|
||||
m_farkas2.m_ty = sat::hint_type::farkas_h;
|
||||
m_farkas2.m_literals.resize(2);
|
||||
}
|
||||
|
||||
solver::~solver() {
|
||||
|
@ -197,11 +195,12 @@ namespace arith {
|
|||
reset_evidence();
|
||||
m_core.push_back(lit1);
|
||||
TRACE("arith", tout << lit2 << " <- " << m_core << "\n";);
|
||||
sat::proof_hint* ph = nullptr;
|
||||
arith_proof_hint* ph = nullptr;
|
||||
if (ctx.use_drat()) {
|
||||
ph = &m_farkas2;
|
||||
m_farkas2.m_literals[0] = std::make_pair(rational(1), lit1);
|
||||
m_farkas2.m_literals[1] = std::make_pair(rational(1), ~lit2);
|
||||
m_arith_hint.set_type(ctx, hint_type::farkas_h);
|
||||
m_arith_hint.add_lit(rational(1), lit1);
|
||||
m_arith_hint.add_lit(rational(1), ~lit2);
|
||||
ph = m_arith_hint.mk(ctx);
|
||||
}
|
||||
assign(lit2, m_core, m_eqs, ph);
|
||||
++m_stats.m_bounds_propagations;
|
||||
|
@ -262,7 +261,7 @@ namespace arith {
|
|||
TRACE("arith", for (auto lit : m_core) tout << lit << ": " << s().value(lit) << "\n";);
|
||||
DEBUG_CODE(for (auto lit : m_core) { VERIFY(s().value(lit) == l_true); });
|
||||
++m_stats.m_bound_propagations1;
|
||||
assign(lit, m_core, m_eqs, explain(sat::hint_type::bound_h, lit));
|
||||
assign(lit, m_core, m_eqs, explain(hint_type::bound_h, lit));
|
||||
}
|
||||
|
||||
if (should_refine_bounds() && first)
|
||||
|
@ -378,7 +377,7 @@ namespace arith {
|
|||
reset_evidence();
|
||||
m_explanation.clear();
|
||||
lp().explain_implied_bound(be, m_bp);
|
||||
assign(bound, m_core, m_eqs, explain(sat::hint_type::farkas_h, bound));
|
||||
assign(bound, m_core, m_eqs, explain(hint_type::farkas_h, bound));
|
||||
}
|
||||
|
||||
|
||||
|
@ -386,20 +385,16 @@ namespace arith {
|
|||
TRACE("arith", tout << b << "\n";);
|
||||
lp::constraint_index ci = b.get_constraint(is_true);
|
||||
lp().activate(ci);
|
||||
if (is_infeasible()) {
|
||||
if (is_infeasible())
|
||||
return;
|
||||
}
|
||||
lp::lconstraint_kind k = bound2constraint_kind(b.is_int(), b.get_bound_kind(), is_true);
|
||||
if (k == lp::LT || k == lp::LE) {
|
||||
if (k == lp::LT || k == lp::LE)
|
||||
++m_stats.m_assert_lower;
|
||||
}
|
||||
else {
|
||||
else
|
||||
++m_stats.m_assert_upper;
|
||||
}
|
||||
inf_rational value = b.get_value(is_true);
|
||||
if (propagate_eqs() && value.is_rational()) {
|
||||
if (propagate_eqs() && value.is_rational())
|
||||
propagate_eqs(b.tv(), ci, k, b, value.get_rational());
|
||||
}
|
||||
#if 0
|
||||
if (propagation_mode() != BP_NONE)
|
||||
lp().mark_rows_for_bound_prop(b.tv().id());
|
||||
|
@ -617,8 +612,7 @@ namespace arith {
|
|||
verbose_stream() << eval << " " << value << " " << ctx.bpp(n) << "\n";
|
||||
verbose_stream() << n->bool_var() << " " << n->value() << " " << get_phase(n->bool_var()) << " " << ctx.bpp(n) << "\n";
|
||||
verbose_stream() << *b << "\n";);
|
||||
IF_VERBOSE(0, ctx.display(verbose_stream()));
|
||||
IF_VERBOSE(0, verbose_stream() << mdl << "\n");
|
||||
IF_VERBOSE(0, ctx.display_validation_failure(verbose_stream(), mdl, n));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
@ -1119,16 +1113,23 @@ namespace arith {
|
|||
}
|
||||
|
||||
bool solver::check_delayed_eqs() {
|
||||
for (auto p : m_delayed_eqs) {
|
||||
bool found_diseq = false;
|
||||
if (m_delayed_eqs_qhead == m_delayed_eqs.size())
|
||||
return true;
|
||||
force_push();
|
||||
ctx.push(value_trail<unsigned>(m_delayed_eqs_qhead));
|
||||
for (; m_delayed_eqs_qhead < m_delayed_eqs.size(); ++ m_delayed_eqs_qhead) {
|
||||
auto p = m_delayed_eqs[m_delayed_eqs_qhead];
|
||||
auto const& e = p.first;
|
||||
if (p.second)
|
||||
new_eq_eh(e);
|
||||
else if (is_eq(e.v1(), e.v2())) {
|
||||
mk_diseq_axiom(e);
|
||||
return false;
|
||||
found_diseq = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return !found_diseq;
|
||||
}
|
||||
|
||||
lbool solver::check_lia() {
|
||||
|
@ -1178,7 +1179,7 @@ namespace arith {
|
|||
app_ref b = mk_bound(m_lia->get_term(), m_lia->get_offset(), !m_lia->is_upper());
|
||||
IF_VERBOSE(4, verbose_stream() << "cut " << b << "\n");
|
||||
literal lit = expr2literal(b);
|
||||
assign(lit, m_core, m_eqs, explain(sat::hint_type::bound_h, lit));
|
||||
assign(lit, m_core, m_eqs, explain(hint_type::bound_h, lit));
|
||||
lia_check = l_false;
|
||||
break;
|
||||
}
|
||||
|
@ -1200,7 +1201,7 @@ namespace arith {
|
|||
return lia_check;
|
||||
}
|
||||
|
||||
void solver::assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs, sat::proof_hint const* pma) {
|
||||
void solver::assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs, euf::th_proof_hint const* pma) {
|
||||
if (core.size() < small_lemma_size() && eqs.empty()) {
|
||||
m_core2.reset();
|
||||
for (auto const& c : core)
|
||||
|
@ -1247,7 +1248,7 @@ namespace arith {
|
|||
for (literal& c : m_core)
|
||||
c.neg();
|
||||
|
||||
add_clause(m_core, explain(sat::hint_type::farkas_h));
|
||||
add_clause(m_core, explain(hint_type::farkas_h));
|
||||
}
|
||||
|
||||
bool solver::is_infeasible() const {
|
||||
|
|
|
@ -48,8 +48,61 @@ namespace arith {
|
|||
typedef sat::literal_vector literal_vector;
|
||||
typedef lp_api::bound<sat::literal> api_bound;
|
||||
|
||||
enum class hint_type {
|
||||
farkas_h,
|
||||
bound_h,
|
||||
implied_eq_h
|
||||
};
|
||||
|
||||
struct arith_proof_hint : public euf::th_proof_hint {
|
||||
hint_type m_ty;
|
||||
unsigned m_lit_head, m_lit_tail, m_eq_head, m_eq_tail;
|
||||
arith_proof_hint(hint_type t, unsigned lh, unsigned lt, unsigned eh, unsigned et):
|
||||
m_ty(t), m_lit_head(lh), m_lit_tail(lt), m_eq_head(eh), m_eq_tail(et) {}
|
||||
expr* get_hint(euf::solver& s) const override;
|
||||
};
|
||||
|
||||
class arith_proof_hint_builder {
|
||||
vector<std::pair<rational, literal>> m_literals;
|
||||
svector<std::tuple<euf::enode*,euf::enode*,bool>> m_eqs;
|
||||
hint_type m_ty;
|
||||
unsigned m_lit_head = 0, m_lit_tail = 0, m_eq_head = 0, m_eq_tail = 0;
|
||||
void reset() { m_lit_head = m_lit_tail; m_eq_head = m_eq_tail; }
|
||||
void add(euf::enode* a, euf::enode* b, bool is_eq) {
|
||||
if (m_eq_tail < m_eqs.size())
|
||||
m_eqs[m_eq_tail] = std::tuple(a, b, is_eq);
|
||||
else
|
||||
m_eqs.push_back(std::tuple(a, b, is_eq));
|
||||
m_eq_tail++;
|
||||
}
|
||||
public:
|
||||
void set_type(euf::solver& ctx, hint_type ty) {
|
||||
ctx.push(value_trail<unsigned>(m_eq_tail));
|
||||
ctx.push(value_trail<unsigned>(m_lit_tail));
|
||||
m_ty = ty;
|
||||
reset();
|
||||
}
|
||||
void add_eq(euf::enode* a, euf::enode* b) { add(a, b, true); }
|
||||
void add_diseq(euf::enode* a, euf::enode* b) { add(a, b, false); }
|
||||
void add_lit(rational const& coeff, literal lit) {
|
||||
if (m_lit_tail < m_literals.size())
|
||||
m_literals[m_lit_tail] = {coeff, lit};
|
||||
else
|
||||
m_literals.push_back({coeff, lit});
|
||||
m_lit_tail++;
|
||||
}
|
||||
std::pair<rational, literal> const& lit(unsigned i) const { return m_literals[i]; }
|
||||
std::tuple<enode*, enode*, bool> const& eq(unsigned i) const { return m_eqs[i]; }
|
||||
arith_proof_hint* mk(euf::solver& s) {
|
||||
return new (s.get_region()) arith_proof_hint(m_ty, m_lit_head, m_lit_tail, m_eq_head, m_eq_tail);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class solver : public euf::th_euf_solver {
|
||||
|
||||
friend struct arith_proof_hint;
|
||||
|
||||
struct scope {
|
||||
unsigned m_bounds_lim;
|
||||
unsigned m_idiv_lim;
|
||||
|
@ -165,6 +218,7 @@ namespace arith {
|
|||
svector<euf::enode_pair> m_equalities; // asserted rows corresponding to equalities.
|
||||
svector<theory_var> m_definitions; // asserted rows corresponding to definitions
|
||||
svector<std::pair<euf::th_eq, bool>> m_delayed_eqs;
|
||||
unsigned m_delayed_eqs_qhead = 0;
|
||||
|
||||
literal_vector m_asserted;
|
||||
expr* m_not_handled{ nullptr };
|
||||
|
@ -414,15 +468,15 @@ namespace arith {
|
|||
void set_conflict();
|
||||
void set_conflict_or_lemma(literal_vector const& core, bool is_conflict);
|
||||
void set_evidence(lp::constraint_index idx);
|
||||
void assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs, sat::proof_hint const* pma);
|
||||
void assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs, euf::th_proof_hint const* pma);
|
||||
|
||||
void false_case_of_check_nla(const nla::lemma& l);
|
||||
void dbg_finalize_model(model& mdl);
|
||||
|
||||
sat::proof_hint m_arith_hint;
|
||||
sat::proof_hint m_farkas2;
|
||||
sat::proof_hint const* explain(sat::hint_type ty, sat::literal lit = sat::null_literal);
|
||||
sat::proof_hint const* explain_implied_eq(euf::enode* a, euf::enode* b);
|
||||
arith_proof_hint_builder m_arith_hint;
|
||||
|
||||
arith_proof_hint const* explain(hint_type ty, sat::literal lit = sat::null_literal);
|
||||
arith_proof_hint const* explain_implied_eq(euf::enode* a, euf::enode* b);
|
||||
void explain_assumptions();
|
||||
|
||||
|
||||
|
|
|
@ -265,7 +265,8 @@ namespace array {
|
|||
args1.push_back(e1);
|
||||
args2.push_back(e2);
|
||||
for (func_decl* f : funcs) {
|
||||
expr* k = m.mk_app(f, e1, e2);
|
||||
expr_ref k(m.mk_app(f, e1, e2), m);
|
||||
rewrite(k);
|
||||
args1.push_back(k);
|
||||
args2.push_back(k);
|
||||
}
|
||||
|
@ -699,6 +700,23 @@ namespace array {
|
|||
n->unmark1();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check that lambda expressions are beta redexes.
|
||||
* The array solver is not a decision procedure for lambdas that do not occur in beta
|
||||
* redexes.
|
||||
*/
|
||||
bool solver::check_lambdas() {
|
||||
unsigned num_vars = get_num_vars();
|
||||
for (unsigned i = 0; i < num_vars; i++) {
|
||||
auto* n = var2enode(i);
|
||||
if (a.is_as_array(n->get_expr()) || is_lambda(n->get_expr()))
|
||||
for (euf::enode* p : euf::enode_parents(n))
|
||||
if (!ctx.is_beta_redex(p, n))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool solver::is_shared_arg(euf::enode* r) {
|
||||
SASSERT(r->is_root());
|
||||
for (euf::enode* n : euf::enode_parents(r)) {
|
||||
|
|
|
@ -252,6 +252,8 @@ namespace array {
|
|||
return p->get_arg(0)->get_root() == n->get_root();
|
||||
if (a.is_map(p->get_expr()))
|
||||
return true;
|
||||
if (a.is_store(p->get_expr()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,7 +108,9 @@ namespace array {
|
|||
if (m_delay_qhead < m_axiom_trail.size())
|
||||
return sat::check_result::CR_CONTINUE;
|
||||
|
||||
|
||||
if (!check_lambdas())
|
||||
return sat::check_result::CR_GIVEUP;
|
||||
|
||||
// validate_check();
|
||||
return sat::check_result::CR_DONE;
|
||||
}
|
||||
|
|
|
@ -218,6 +218,7 @@ namespace array {
|
|||
bool should_prop_upward(var_data const& d) const;
|
||||
bool can_beta_reduce(euf::enode* n) const { return can_beta_reduce(n->get_expr()); }
|
||||
bool can_beta_reduce(expr* e) const;
|
||||
bool check_lambdas();
|
||||
|
||||
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]; }
|
||||
|
|
|
@ -49,16 +49,19 @@ namespace bv {
|
|||
update_glue(*other);
|
||||
|
||||
vv::push_to_front(m_queue, other);
|
||||
if (other == n) {
|
||||
bool do_gc = other == n;
|
||||
if (other == n)
|
||||
new_tmp();
|
||||
gc();
|
||||
}
|
||||
|
||||
if (other->m_glue == 0) {
|
||||
do_gc = false;
|
||||
remove(other);
|
||||
add_cc(v1, v2);
|
||||
}
|
||||
else if (other->m_count > m_propagate_high_watermark)
|
||||
s.s().set_should_simplify();
|
||||
else if (other->m_count > 2*m_propagate_high_watermark)
|
||||
propagate();
|
||||
if (do_gc)
|
||||
gc();
|
||||
}
|
||||
|
||||
void ackerman::used_diseq_eh(euf::theory_var v1, euf::theory_var v2) {
|
||||
|
@ -76,8 +79,8 @@ namespace bv {
|
|||
new_tmp();
|
||||
gc();
|
||||
}
|
||||
if (other->m_count > m_propagate_high_watermark)
|
||||
s.s().set_should_simplify();
|
||||
if (other->m_count > 2*m_propagate_high_watermark)
|
||||
propagate();
|
||||
}
|
||||
|
||||
void ackerman::update_glue(vv& v) {
|
||||
|
@ -137,6 +140,9 @@ namespace bv {
|
|||
if (m_num_propagations_since_last_gc <= s.get_config().m_dack_gc)
|
||||
return;
|
||||
m_num_propagations_since_last_gc = 0;
|
||||
|
||||
if (m_table.size() > m_gc_threshold)
|
||||
propagate();
|
||||
|
||||
while (m_table.size() > m_gc_threshold)
|
||||
remove(m_queue->prev());
|
||||
|
@ -147,7 +153,6 @@ namespace bv {
|
|||
}
|
||||
|
||||
void ackerman::propagate() {
|
||||
SASSERT(s.s().at_base_lvl());
|
||||
auto* n = m_queue;
|
||||
vv* k = nullptr;
|
||||
unsigned num_prop = static_cast<unsigned>(s.s().get_stats().m_conflict * s.get_config().m_dack_factor);
|
||||
|
|
|
@ -51,13 +51,13 @@ namespace bv {
|
|||
|
||||
solver& s;
|
||||
table_t m_table;
|
||||
vv* m_queue { nullptr };
|
||||
vv* m_tmp_vv { nullptr };
|
||||
vv* m_queue = nullptr;
|
||||
vv* m_tmp_vv = nullptr;
|
||||
|
||||
unsigned m_gc_threshold { 100 };
|
||||
unsigned m_propagate_high_watermark { 10000 };
|
||||
unsigned m_propagate_low_watermark { 10 };
|
||||
unsigned m_num_propagations_since_last_gc { 0 };
|
||||
unsigned m_gc_threshold = 100;
|
||||
unsigned m_propagate_high_watermark = 10000;
|
||||
unsigned m_propagate_low_watermark = 10;
|
||||
unsigned m_num_propagations_since_last_gc = 0;
|
||||
bool_vector m_diff_levels;
|
||||
|
||||
void update_glue(vv& v);
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace bv {
|
|||
return true;
|
||||
unsigned num_vars = e->get_num_args();
|
||||
for (expr* arg : *e)
|
||||
if (!m.is_value(arg))
|
||||
if (m.is_value(arg))
|
||||
--num_vars;
|
||||
if (num_vars <= 1)
|
||||
return true;
|
||||
|
@ -72,6 +72,55 @@ namespace bv {
|
|||
return expr_ref(bv.mk_numeral(val, get_bv_size(v)), m);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief expose the multiplication circuit lazily.
|
||||
It adds clauses for multiplier output one by one to enforce
|
||||
the semantics of multipliers.
|
||||
*/
|
||||
|
||||
bool solver::check_lazy_mul(app* e, expr* arg_value, expr* mul_value) {
|
||||
SASSERT(e->get_num_args() >= 2);
|
||||
expr_ref_vector args(m), new_args(m), new_out(m);
|
||||
lazy_mul* lz = nullptr;
|
||||
rational v0, v1;
|
||||
unsigned sz, diff = 0;
|
||||
VERIFY(bv.is_numeral(arg_value, v0, sz));
|
||||
VERIFY(bv.is_numeral(mul_value, v1));
|
||||
for (diff = 0; diff < sz; ++diff)
|
||||
if (v0.get_bit(diff) != v1.get_bit(diff))
|
||||
break;
|
||||
SASSERT(diff < sz);
|
||||
auto set_bits = [&](unsigned j, expr_ref_vector& bits) {
|
||||
bits.reset();
|
||||
for (unsigned i = 0; i < sz; ++i)
|
||||
bits.push_back(bv.mk_bit2bool(e->get_arg(0), j));
|
||||
};
|
||||
if (!m_lazymul.find(e, lz)) {
|
||||
set_bits(0, args);
|
||||
for (unsigned j = 1; j < e->get_num_args(); ++j) {
|
||||
new_out.reset();
|
||||
set_bits(j, new_args);
|
||||
m_bb.mk_multiplier(sz, args.data(), new_args.data(), new_out);
|
||||
new_out.swap(args);
|
||||
}
|
||||
lz = alloc(lazy_mul, e, args);
|
||||
m_lazymul.insert(e, lz);
|
||||
ctx.push(new_obj_trail(lz));
|
||||
ctx.push(insert_obj_map(m_lazymul, e));
|
||||
}
|
||||
if (lz->m_out.size() == lz->m_bits)
|
||||
return false;
|
||||
for (unsigned i = lz->m_bits; i <= diff; ++i) {
|
||||
sat::literal bit1 = mk_literal(lz->m_out.get(i));
|
||||
sat::literal bit2 = mk_literal(bv.mk_bit2bool(e, i));
|
||||
add_equiv(bit1, bit2);
|
||||
}
|
||||
ctx.push(value_trail(lz->m_bits));
|
||||
IF_VERBOSE(1, verbose_stream() << "expand lazy mul " << mk_pp(e, m) << " to " << diff << "\n");
|
||||
lz->m_bits = diff;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool solver::check_mul(app* e) {
|
||||
SASSERT(e->get_num_args() >= 2);
|
||||
expr_ref_vector args(m);
|
||||
|
@ -96,6 +145,12 @@ namespace bv {
|
|||
if (!check_mul_invertibility(e, args, r1))
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
// unsound?
|
||||
|
||||
if (!check_lazy_mul(e, r1, r2))
|
||||
return false;
|
||||
#endif
|
||||
// Some other possible approaches:
|
||||
// algebraic rules:
|
||||
// x*(y+z), and there are nodes for x*y or x*z -> x*(y+z) = x*y + x*z
|
||||
|
@ -177,18 +232,17 @@ namespace bv {
|
|||
bool solver::check_mul_zero(app* n, expr_ref_vector const& arg_values, expr* mul_value, expr* arg_value) {
|
||||
SASSERT(mul_value != arg_value);
|
||||
SASSERT(!(bv.is_zero(mul_value) && bv.is_zero(arg_value)));
|
||||
if (bv.is_zero(arg_value)) {
|
||||
if (bv.is_zero(arg_value) && false) {
|
||||
unsigned sz = n->get_num_args();
|
||||
expr_ref_vector args(m, sz, n->get_args());
|
||||
for (unsigned i = 0; i < sz && !s().inconsistent(); ++i) {
|
||||
|
||||
args[i] = arg_value;
|
||||
expr_ref r(m.mk_app(n->get_decl(), args), m);
|
||||
set_delay_internalize(r, internalize_mode::init_bits_only_i); // do not bit-blast this multiplier.
|
||||
args[i] = n->get_arg(i);
|
||||
add_unit(eq_internalize(r, arg_value));
|
||||
}
|
||||
IF_VERBOSE(2, verbose_stream() << "delay internalize @" << s().scope_lvl() << "\n");
|
||||
IF_VERBOSE(2, verbose_stream() << "delay internalize @" << s().scope_lvl() << " " << mk_pp(n, m) << "\n");
|
||||
return false;
|
||||
}
|
||||
if (bv.is_zero(mul_value)) {
|
||||
|
|
|
@ -139,7 +139,9 @@ namespace bv {
|
|||
return true;
|
||||
|
||||
SASSERT(!n || !n->is_attached_to(get_id()));
|
||||
bool suppress_args = !reflect() && !m.is_considered_uninterpreted(a->get_decl());
|
||||
bool suppress_args = !reflect()
|
||||
&& !m.is_considered_uninterpreted(a->get_decl())
|
||||
&& !bv.is_int2bv(e) && !bv.is_bv2int(e);
|
||||
if (!n)
|
||||
n = mk_enode(e, suppress_args);
|
||||
|
||||
|
@ -314,7 +316,6 @@ namespace bv {
|
|||
euf::enode* n = bool_var2enode(l.var());
|
||||
if (!n->is_attached_to(get_id()))
|
||||
mk_var(n);
|
||||
|
||||
set_bit_eh(v, l, idx);
|
||||
}
|
||||
|
||||
|
@ -435,7 +436,9 @@ namespace bv {
|
|||
args.push_back(m.mk_ite(b, m_autil.mk_int(power2(i++)), zero));
|
||||
expr_ref sum(m_autil.mk_add(sz, args.data()), m);
|
||||
sat::literal lit = eq_internalize(n, sum);
|
||||
add_unit(lit);
|
||||
m_bv2ints.push_back(expr2enode(n));
|
||||
ctx.push(push_back_vector<euf::enode_vector>(m_bv2ints));
|
||||
add_unit(lit);
|
||||
}
|
||||
|
||||
void solver::internalize_int2bv(app* n) {
|
||||
|
@ -454,6 +457,12 @@ namespace bv {
|
|||
* Create the axioms:
|
||||
* bit2bool(i,n) == ((e div 2^i) mod 2 != 0)
|
||||
* for i = 0,.., sz-1
|
||||
*
|
||||
* Alternative axiomatization:
|
||||
* e = sum bit2bool(i,n)*2^i + 2^n * (div(e, 2^n))
|
||||
* possibly term div(e,2^n) is not correct with respect to adapted semantics?
|
||||
* if not, use fresh variable or similar. Overall should be much beter.
|
||||
* Note: based on superb question raised at workshop on 9/1/22.
|
||||
*/
|
||||
void solver::assert_int2bv_axiom(app* n) {
|
||||
expr* e = nullptr;
|
||||
|
@ -464,8 +473,8 @@ 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));
|
||||
sat::literal eq_lit = eq_internalize(lhs, rhs);
|
||||
add_unit(eq_lit);
|
||||
sat::literal eq_lit = eq_internalize(lhs, rhs);
|
||||
add_unit(eq_lit);
|
||||
|
||||
expr_ref_vector n_bits(m);
|
||||
get_bits(n_enode, n_bits);
|
||||
|
@ -476,8 +485,8 @@ namespace bv {
|
|||
rhs = m_autil.mk_mod(rhs, m_autil.mk_int(2));
|
||||
rhs = mk_eq(rhs, m_autil.mk_int(1));
|
||||
lhs = n_bits.get(i);
|
||||
eq_lit = eq_internalize(lhs, rhs);
|
||||
add_unit(eq_lit);
|
||||
eq_lit = eq_internalize(lhs, rhs);
|
||||
add_unit(eq_lit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,27 +543,27 @@ namespace bv {
|
|||
internalize_binary(a, bin);
|
||||
}
|
||||
|
||||
void solver::internalize_interp(app* n, std::function<expr*(expr*, expr*)>& ibin, std::function<expr*(expr*)>& iun) {
|
||||
void solver::internalize_interp(app* n, std::function<expr* (expr*, expr*)>& ibin, std::function<expr* (expr*)>& iun) {
|
||||
bv_rewriter_params p(s().params());
|
||||
expr* arg1 = n->get_arg(0);
|
||||
expr* arg2 = n->get_arg(1);
|
||||
mk_bits(get_th_var(n));
|
||||
sat::literal eq_lit;
|
||||
sat::literal eq_lit;
|
||||
if (p.hi_div0()) {
|
||||
eq_lit = eq_internalize(n, ibin(arg1, arg2));
|
||||
add_unit(eq_lit);
|
||||
}
|
||||
else {
|
||||
unsigned sz = bv.get_bv_size(n);
|
||||
expr_ref zero(bv.mk_numeral(0, sz), m);
|
||||
sat::literal eqZ = eq_internalize(arg2, zero);
|
||||
sat::literal eqU = eq_internalize(n, iun(arg1));
|
||||
sat::literal eqI = eq_internalize(n, ibin(arg1, arg2));
|
||||
add_clause(~eqZ, eqU);
|
||||
add_clause(eqZ, eqI);
|
||||
ctx.add_aux(~eqZ, eqU);
|
||||
ctx.add_aux(eqZ, eqI);
|
||||
}
|
||||
add_unit(eq_lit);
|
||||
}
|
||||
else {
|
||||
unsigned sz = bv.get_bv_size(n);
|
||||
expr_ref zero(bv.mk_numeral(0, sz), m);
|
||||
sat::literal eqZ = eq_internalize(arg2, zero);
|
||||
sat::literal eqU = mk_literal(iun(arg1));
|
||||
sat::literal eqI = mk_literal(ibin(arg1, arg2));
|
||||
add_clause(~eqZ, eqU);
|
||||
add_clause(eqZ, eqI);
|
||||
ctx.add_aux(~eqZ, eqU);
|
||||
ctx.add_aux(eqZ, eqI);
|
||||
}
|
||||
}
|
||||
|
||||
void solver::internalize_unary(app* n, std::function<void(unsigned, expr* const*, expr_ref_vector&)>& fn) {
|
||||
|
@ -574,11 +583,9 @@ namespace bv {
|
|||
init_bits(n, bits);
|
||||
}
|
||||
|
||||
|
||||
void solver::internalize_binary(app* e, std::function<void(unsigned, expr* const*, expr* const*, expr_ref_vector&)>& fn) {
|
||||
SASSERT(e->get_num_args() >= 1);
|
||||
expr_ref_vector bits(m), new_bits(m), arg_bits(m);
|
||||
|
||||
expr_ref_vector bits(m), new_bits(m), arg_bits(m);
|
||||
get_arg_bits(e, 0, bits);
|
||||
for (unsigned i = 1; i < e->get_num_args(); ++i) {
|
||||
arg_bits.reset();
|
||||
|
@ -658,7 +665,7 @@ namespace bv {
|
|||
conc.push_back(arg);
|
||||
expr_ref r(bv.mk_concat(conc), m);
|
||||
mk_bits(get_th_var(e));
|
||||
sat::literal eq_lit = eq_internalize(e, r);
|
||||
sat::literal eq_lit = eq_internalize(e, r);
|
||||
add_unit(eq_lit);
|
||||
}
|
||||
|
||||
|
@ -667,9 +674,8 @@ namespace bv {
|
|||
expr* arg = nullptr;
|
||||
VERIFY(bv.is_bit2bool(n, arg, idx));
|
||||
euf::enode* argn = expr2enode(arg);
|
||||
if (!argn->is_attached_to(get_id())) {
|
||||
mk_var(argn);
|
||||
}
|
||||
if (!argn->is_attached_to(get_id()))
|
||||
mk_var(argn);
|
||||
theory_var v_arg = argn->get_th_var(get_id());
|
||||
SASSERT(idx < get_bv_size(v_arg));
|
||||
sat::literal lit = expr2literal(n);
|
||||
|
@ -771,7 +777,7 @@ namespace bv {
|
|||
e1 = bv.mk_bit2bool(o1, i);
|
||||
e2 = bv.mk_bit2bool(o2, i);
|
||||
literal eq = eq_internalize(e1, e2);
|
||||
add_clause(eq, ~oeq);
|
||||
add_clause(eq, ~oeq);
|
||||
eqs.push_back(~eq);
|
||||
}
|
||||
TRACE("bv", for (auto l : eqs) tout << mk_bounded_pp(literal2expr(l), m) << " "; tout << "\n";);
|
||||
|
|
|
@ -212,19 +212,32 @@ namespace bv {
|
|||
return;
|
||||
}
|
||||
euf::enode* n1 = var2enode(eq.v1());
|
||||
for (euf::enode* bv2int : euf::enode_class(n1)) {
|
||||
if (!bv.is_bv2int(bv2int->get_expr()))
|
||||
continue;
|
||||
|
||||
auto propagate_bv2int = [&](euf::enode* bv2int) {
|
||||
euf::enode* bv2int_arg = bv2int->get_arg(0);
|
||||
for (euf::enode* p : euf::enode_parents(n1->get_root())) {
|
||||
if (bv.is_int2bv(p->get_expr()) && p->get_sort() == bv2int_arg->get_sort() && p->get_root() != bv2int_arg->get_root()) {
|
||||
euf::enode_pair_vector eqs;
|
||||
eqs.push_back({ n1, p->get_arg(0) });
|
||||
eqs.push_back({ n1, bv2int });
|
||||
ctx.propagate(p, bv2int_arg, euf::th_explain::propagate(*this, eqs, p, bv2int_arg));
|
||||
theory_var v1 = get_th_var(p);
|
||||
theory_var v2 = get_th_var(bv2int_arg);
|
||||
SASSERT(v1 != euf::null_theory_var);
|
||||
SASSERT(v2 != euf::null_theory_var);
|
||||
ctx.propagate(p, bv2int_arg, mk_bv2int_justification(v1, v2, n1, p->get_arg(0), bv2int));
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (m_bv2ints.size() < n1->class_size()) {
|
||||
for (auto* bv2int : m_bv2ints) {
|
||||
if (bv2int->get_root() == n1->get_root())
|
||||
propagate_bv2int(bv2int);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (euf::enode* bv2int : euf::enode_class(n1)) {
|
||||
if (bv.is_bv2int(bv2int->get_expr()))
|
||||
propagate_bv2int(bv2int);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,6 +295,8 @@ namespace bv {
|
|||
++m_stats.m_num_ne2bit;
|
||||
s().assign(consequent, mk_ne2bit_justification(undef_idx, v1, v2, consequent, antecedent));
|
||||
}
|
||||
else if (!get_config().m_bv_eq_axioms)
|
||||
;
|
||||
else if (s().at_search_lvl()) {
|
||||
force_push();
|
||||
assert_ackerman(v1, v2);
|
||||
|
@ -368,6 +383,11 @@ namespace bv {
|
|||
r.push_back(b);
|
||||
break;
|
||||
}
|
||||
case bv_justification::kind_t::bv2int: {
|
||||
ctx.add_antecedent(c.a, c.b);
|
||||
ctx.add_antecedent(c.a, c.c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!probing && ctx.use_drat())
|
||||
log_drat(c);
|
||||
|
@ -375,19 +395,26 @@ namespace bv {
|
|||
|
||||
void solver::log_drat(bv_justification const& c) {
|
||||
// introduce dummy literal for equality.
|
||||
sat::literal leq(s().num_vars() + 1, false);
|
||||
expr_ref eq(m);
|
||||
if (c.m_kind != bv_justification::kind_t::bit2ne) {
|
||||
sat::literal leq1(s().num_vars() + 1, false);
|
||||
sat::literal leq2(s().num_vars() + 2, false);
|
||||
expr_ref eq1(m), eq2(m);
|
||||
if (c.m_kind == bv_justification::kind_t::bv2int) {
|
||||
eq1 = m.mk_eq(c.a->get_expr(), c.b->get_expr());
|
||||
eq2 = m.mk_eq(c.a->get_expr(), c.c->get_expr());
|
||||
ctx.set_tmp_bool_var(leq1.var(), eq1);
|
||||
ctx.set_tmp_bool_var(leq2.var(), eq1);
|
||||
}
|
||||
else if (c.m_kind != bv_justification::kind_t::bit2ne) {
|
||||
expr* e1 = var2expr(c.m_v1);
|
||||
expr* e2 = var2expr(c.m_v2);
|
||||
eq = m.mk_eq(e1, e2);
|
||||
ctx.drat_eq_def(leq, eq);
|
||||
eq1 = m.mk_eq(e1, e2);
|
||||
ctx.set_tmp_bool_var(leq1.var(), eq1);
|
||||
}
|
||||
|
||||
sat::literal_vector lits;
|
||||
switch (c.m_kind) {
|
||||
case bv_justification::kind_t::eq2bit:
|
||||
lits.push_back(~leq);
|
||||
lits.push_back(~leq1);
|
||||
lits.push_back(~c.m_antecedent);
|
||||
lits.push_back(c.m_consequent);
|
||||
break;
|
||||
|
@ -396,10 +423,10 @@ namespace bv {
|
|||
lits.push_back(c.m_consequent);
|
||||
break;
|
||||
case bv_justification::kind_t::bit2eq:
|
||||
get_antecedents(leq, c.to_index(), lits, true);
|
||||
get_antecedents(leq1, c.to_index(), lits, true);
|
||||
for (auto& lit : lits)
|
||||
lit.neg();
|
||||
lits.push_back(leq);
|
||||
lits.push_back(leq1);
|
||||
break;
|
||||
case bv_justification::kind_t::bit2ne:
|
||||
get_antecedents(c.m_consequent, c.to_index(), lits, true);
|
||||
|
@ -407,9 +434,20 @@ namespace bv {
|
|||
lit.neg();
|
||||
lits.push_back(c.m_consequent);
|
||||
break;
|
||||
case bv_justification::kind_t::bv2int:
|
||||
get_antecedents(leq1, c.to_index(), lits, true);
|
||||
get_antecedents(leq2, c.to_index(), lits, true);
|
||||
for (auto& lit : lits)
|
||||
lit.neg();
|
||||
lits.push_back(leq1);
|
||||
lits.push_back(leq2);
|
||||
break;
|
||||
}
|
||||
ctx.get_drat().add(lits, status());
|
||||
// TBD, a proper way would be to delete the lemma after use.
|
||||
ctx.set_tmp_bool_var(leq1.var(), nullptr);
|
||||
ctx.set_tmp_bool_var(leq2.var(), nullptr);
|
||||
|
||||
}
|
||||
|
||||
void solver::asserted(literal l) {
|
||||
|
@ -665,7 +703,9 @@ namespace bv {
|
|||
return out << "bv <- v" << v1 << "[" << cidx << "] != v" << v2 << "[" << cidx << "] " << m_bits[v1][cidx] << " != " << m_bits[v2][cidx];
|
||||
}
|
||||
case bv_justification::kind_t::ne2bit:
|
||||
return out << "bv <- " << m_bits[v1] << " != " << m_bits[v2] << " @" << cidx;
|
||||
return out << "bv <- " << m_bits[v1] << " != " << m_bits[v2] << " @" << cidx;
|
||||
case bv_justification::kind_t::bv2int:
|
||||
return out << "bv <- v" << v1 << " == v" << v2 << " <== " << ctx.bpp(c.a) << " == " << ctx.bpp(c.b) << " == " << ctx.bpp(c.c);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
@ -826,28 +866,41 @@ namespace bv {
|
|||
void* mem = get_region().allocate(bv_justification::get_obj_size());
|
||||
sat::constraint_base::initialize(mem, this);
|
||||
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(v1, v2, c, a);
|
||||
return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index());
|
||||
auto jst = sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index());
|
||||
TRACE("bv", tout << jst << " " << constraint << "\n");
|
||||
return jst;
|
||||
}
|
||||
|
||||
sat::ext_justification_idx solver::mk_bit2eq_justification(theory_var v1, theory_var v2) {
|
||||
void* mem = get_region().allocate(bv_justification::get_obj_size());
|
||||
sat::constraint_base::initialize(mem, this);
|
||||
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(v1, v2);
|
||||
return constraint->to_index();
|
||||
auto jst = constraint->to_index();
|
||||
return jst;
|
||||
}
|
||||
|
||||
sat::justification solver::mk_bit2ne_justification(unsigned idx, sat::literal c) {
|
||||
void* mem = get_region().allocate(bv_justification::get_obj_size());
|
||||
sat::constraint_base::initialize(mem, this);
|
||||
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(idx, c);
|
||||
return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index());
|
||||
auto jst = sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index());
|
||||
return jst;
|
||||
}
|
||||
|
||||
sat::justification solver::mk_ne2bit_justification(unsigned idx, theory_var v1, theory_var v2, sat::literal c, sat::literal a) {
|
||||
void* mem = get_region().allocate(bv_justification::get_obj_size());
|
||||
sat::constraint_base::initialize(mem, this);
|
||||
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(idx, v1, v2, c, a);
|
||||
return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index());
|
||||
auto jst = sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index());
|
||||
return jst;
|
||||
}
|
||||
|
||||
sat::ext_constraint_idx solver::mk_bv2int_justification(theory_var v1, theory_var v2, euf::enode* a, euf::enode* b, euf::enode* c) {
|
||||
void* mem = get_region().allocate(bv_justification::get_obj_size());
|
||||
sat::constraint_base::initialize(mem, this);
|
||||
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(v1, v2, a, b, c);
|
||||
auto jst = constraint->to_index();
|
||||
return jst;
|
||||
}
|
||||
|
||||
bool solver::assign_bit(literal consequent, theory_var v1, theory_var v2, unsigned idx, literal antecedent, bool propagate_eqc) {
|
||||
|
|
|
@ -27,6 +27,15 @@ namespace euf {
|
|||
|
||||
namespace bv {
|
||||
|
||||
struct lazy_mul {
|
||||
expr_ref_vector m_out;
|
||||
unsigned m_bits;
|
||||
lazy_mul(app* a, expr_ref_vector& out):
|
||||
m_out(out),
|
||||
m_bits(0) {
|
||||
}
|
||||
};
|
||||
|
||||
class solver : public euf::th_euf_solver {
|
||||
typedef rational numeral;
|
||||
typedef euf::theory_var theory_var;
|
||||
|
@ -52,13 +61,15 @@ namespace bv {
|
|||
};
|
||||
|
||||
struct bv_justification {
|
||||
enum kind_t { eq2bit, ne2bit, bit2eq, bit2ne };
|
||||
enum kind_t { eq2bit, ne2bit, bit2eq, bit2ne, bv2int };
|
||||
kind_t m_kind;
|
||||
unsigned m_idx{ UINT_MAX };
|
||||
theory_var m_v1{ euf::null_theory_var };
|
||||
theory_var m_v2 { euf::null_theory_var };
|
||||
unsigned m_idx = UINT_MAX;
|
||||
theory_var m_v1 = euf::null_theory_var;
|
||||
theory_var m_v2 = euf::null_theory_var;
|
||||
sat::literal m_consequent;
|
||||
sat::literal m_antecedent;
|
||||
euf::enode* a, *b, *c;
|
||||
|
||||
bv_justification(theory_var v1, theory_var v2, sat::literal c, sat::literal a) :
|
||||
m_kind(bv_justification::kind_t::eq2bit), m_v1(v1), m_v2(v2), m_consequent(c), m_antecedent(a) {}
|
||||
bv_justification(theory_var v1, theory_var v2):
|
||||
|
@ -67,6 +78,8 @@ namespace bv {
|
|||
m_kind(bv_justification::kind_t::bit2ne), m_idx(idx), m_consequent(c) {}
|
||||
bv_justification(unsigned idx, theory_var v1, theory_var v2, sat::literal c, sat::literal a) :
|
||||
m_kind(bv_justification::kind_t::ne2bit), m_idx(idx), m_v1(v1), m_v2(v2), m_consequent(c), m_antecedent(a) {}
|
||||
bv_justification(theory_var v1, theory_var v2, euf::enode* a, euf::enode* b, euf::enode* c):
|
||||
m_kind(bv_justification::kind_t::bv2int), m_v1(v1), m_v2(v2), a(a), b(b), c(c) {}
|
||||
sat::ext_constraint_idx to_index() const {
|
||||
return sat::constraint_base::mem2base(this);
|
||||
}
|
||||
|
@ -80,6 +93,7 @@ namespace bv {
|
|||
sat::ext_justification_idx mk_bit2eq_justification(theory_var v1, theory_var v2);
|
||||
sat::justification mk_bit2ne_justification(unsigned idx, sat::literal c);
|
||||
sat::justification mk_ne2bit_justification(unsigned idx, theory_var v1, theory_var v2, sat::literal c, sat::literal a);
|
||||
sat::ext_constraint_idx mk_bv2int_justification(theory_var v1, theory_var v2, euf::enode* a, euf::enode* b, euf::enode* c);
|
||||
void log_drat(bv_justification const& c);
|
||||
|
||||
|
||||
|
@ -210,8 +224,10 @@ namespace bv {
|
|||
literal_vector m_tmp_literals;
|
||||
svector<propagation_item> m_prop_queue;
|
||||
unsigned_vector m_prop_queue_lim;
|
||||
unsigned m_prop_queue_head { 0 };
|
||||
sat::literal m_true { sat::null_literal };
|
||||
unsigned m_prop_queue_head = 0;
|
||||
sat::literal m_true = sat::null_literal;
|
||||
euf::enode_vector m_bv2ints;
|
||||
obj_map<app, lazy_mul*> m_lazymul;
|
||||
|
||||
// internalize
|
||||
void insert_bv2a(bool_var bv, atom * a) { m_bool_var2atom.setx(bv, a, 0); }
|
||||
|
@ -312,6 +328,7 @@ namespace bv {
|
|||
bool m_cheap_axioms{ true };
|
||||
bool should_bit_blast(app * n);
|
||||
bool check_delay_internalized(expr* e);
|
||||
bool check_lazy_mul(app* e, expr* mul_value, expr* arg_value);
|
||||
bool check_mul(app* e);
|
||||
bool check_mul_invertibility(app* n, expr_ref_vector const& arg_values, expr* value);
|
||||
bool check_mul_zero(app* n, expr_ref_vector const& arg_values, expr* value1, expr* value2);
|
||||
|
|
|
@ -167,7 +167,7 @@ namespace euf {
|
|||
lit = lit2;
|
||||
}
|
||||
|
||||
TRACE("euf", tout << "attach " << v << " " << mk_bounded_pp(e, m) << "\n";);
|
||||
TRACE("euf", tout << "attach v" << v << " " << mk_bounded_pp(e, m) << "\n";);
|
||||
m_bool_var2expr.reserve(v + 1, nullptr);
|
||||
if (m_bool_var2expr[v] && m_egraph.find(e)) {
|
||||
if (m_egraph.find(e)->bool_var() != v) {
|
||||
|
@ -264,7 +264,11 @@ namespace euf {
|
|||
sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id());
|
||||
if (sz <= 1)
|
||||
return;
|
||||
if (sz <= distinct_max_args) {
|
||||
sort* srt = e->get_arg(0)->get_sort();
|
||||
auto sort_sz = srt->get_num_elements();
|
||||
if (sort_sz.is_finite() && sort_sz.size() < sz)
|
||||
s().add_clause(0, nullptr, st);
|
||||
else if (sz <= distinct_max_args) {
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
for (unsigned j = i + 1; j < sz; ++j) {
|
||||
expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr());
|
||||
|
@ -274,8 +278,7 @@ namespace euf {
|
|||
}
|
||||
}
|
||||
else {
|
||||
// dist-f(x_1) = v_1 & ... & dist-f(x_n) = v_n
|
||||
sort* srt = e->get_arg(0)->get_sort();
|
||||
// dist-f(x_1) = v_1 & ... & dist-f(x_n) = v_n
|
||||
SASSERT(!m.is_bool(srt));
|
||||
sort_ref u(m.mk_fresh_sort("distinct-elems"), m);
|
||||
func_decl_ref f(m.mk_fresh_func_decl("dist-f", "", 1, &srt, u), m);
|
||||
|
|
|
@ -16,96 +16,26 @@ Author:
|
|||
--*/
|
||||
|
||||
#include "sat/smt/euf_solver.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace euf {
|
||||
|
||||
void solver::init_drat() {
|
||||
if (!m_drat_initialized) {
|
||||
void solver::init_proof() {
|
||||
if (!m_proof_initialized) {
|
||||
get_drat().add_theory(get_id(), symbol("euf"));
|
||||
get_drat().add_theory(m.get_basic_family_id(), symbol("bool"));
|
||||
}
|
||||
m_drat_initialized = true;
|
||||
}
|
||||
|
||||
void solver::drat_log_expr1(expr* e) {
|
||||
if (is_app(e)) {
|
||||
app* a = to_app(e);
|
||||
drat_log_decl(a->get_decl());
|
||||
std::stringstream strm;
|
||||
strm << mk_ismt2_func(a->get_decl(), m);
|
||||
get_drat().def_begin('e', e->get_id(), strm.str());
|
||||
for (expr* arg : *a)
|
||||
get_drat().def_add_arg(arg->get_id());
|
||||
get_drat().def_end();
|
||||
if (!m_proof_out && s().get_config().m_drat &&
|
||||
(get_config().m_lemmas2console || s().get_config().m_smt_proof.is_non_empty_string())) {
|
||||
TRACE("euf", tout << "init-proof\n");
|
||||
m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out);
|
||||
if (get_config().m_lemmas2console)
|
||||
get_drat().set_clause_eh(*this);
|
||||
if (s().get_config().m_smt_proof.is_non_empty_string())
|
||||
get_drat().set_clause_eh(*this);
|
||||
}
|
||||
else if (is_var(e)) {
|
||||
var* v = to_var(e);
|
||||
get_drat().def_begin('v', v->get_id(), "" + mk_pp(e->get_sort(), m));
|
||||
get_drat().def_add_arg(v->get_idx());
|
||||
get_drat().def_end();
|
||||
}
|
||||
else if (is_quantifier(e)) {
|
||||
quantifier* q = to_quantifier(e);
|
||||
std::stringstream strm;
|
||||
strm << "(" << (is_forall(q) ? "forall" : (is_exists(q) ? "exists" : "lambda"));
|
||||
for (unsigned i = 0; i < q->get_num_decls(); ++i)
|
||||
strm << " (" << q->get_decl_name(i) << " " << mk_pp(q->get_decl_sort(i), m) << ")";
|
||||
strm << ")";
|
||||
get_drat().def_begin('q', q->get_id(), strm.str());
|
||||
get_drat().def_add_arg(q->get_expr()->get_id());
|
||||
get_drat().def_end();
|
||||
}
|
||||
else
|
||||
UNREACHABLE();
|
||||
m_drat_asts.insert(e);
|
||||
push(insert_obj_trail<ast>(m_drat_asts, e));
|
||||
}
|
||||
|
||||
void solver::drat_log_expr(expr* e) {
|
||||
if (m_drat_asts.contains(e))
|
||||
return;
|
||||
ptr_vector<expr>::scoped_stack _sc(m_drat_todo);
|
||||
m_drat_todo.push_back(e);
|
||||
while (!m_drat_todo.empty()) {
|
||||
e = m_drat_todo.back();
|
||||
unsigned sz = m_drat_todo.size();
|
||||
if (is_app(e))
|
||||
for (expr* arg : *to_app(e))
|
||||
if (!m_drat_asts.contains(arg))
|
||||
m_drat_todo.push_back(arg);
|
||||
if (is_quantifier(e)) {
|
||||
expr* arg = to_quantifier(e)->get_expr();
|
||||
if (!m_drat_asts.contains(arg))
|
||||
m_drat_todo.push_back(arg);
|
||||
}
|
||||
if (m_drat_todo.size() != sz)
|
||||
continue;
|
||||
if (!m_drat_asts.contains(e))
|
||||
drat_log_expr1(e);
|
||||
m_drat_todo.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void solver::drat_bool_def(sat::bool_var v, expr* e) {
|
||||
if (!use_drat())
|
||||
return;
|
||||
drat_log_expr(e);
|
||||
get_drat().bool_def(v, e->get_id());
|
||||
}
|
||||
|
||||
|
||||
void solver::drat_log_decl(func_decl* f) {
|
||||
if (f->get_family_id() != null_family_id)
|
||||
return;
|
||||
if (m_drat_asts.contains(f))
|
||||
return;
|
||||
m_drat_asts.insert(f);
|
||||
push(insert_obj_trail< ast>(m_drat_asts, f));
|
||||
std::ostringstream strm;
|
||||
smt2_pp_environment_dbg env(m);
|
||||
ast_smt2_pp(strm, f, env);
|
||||
get_drat().def_begin('f', f->get_small_id(), strm.str());
|
||||
get_drat().def_end();
|
||||
m_proof_initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,16 +74,20 @@ namespace euf {
|
|||
}
|
||||
}
|
||||
|
||||
void solver::set_tmp_bool_var(bool_var b, expr* e) {
|
||||
m_bool_var2expr.setx(b, e, nullptr);
|
||||
}
|
||||
|
||||
void solver::log_justification(literal l, th_explain const& jst) {
|
||||
literal_vector lits;
|
||||
unsigned nv = s().num_vars();
|
||||
expr_ref_vector eqs(m);
|
||||
unsigned nv = s().num_vars();
|
||||
auto add_lit = [&](enode_pair const& eq) {
|
||||
unsigned v = nv;
|
||||
++nv;
|
||||
literal lit(nv, false);
|
||||
eqs.push_back(m.mk_eq(eq.first->get_expr(), eq.second->get_expr()));
|
||||
drat_eq_def(lit, eqs.back());
|
||||
return lit;
|
||||
set_tmp_bool_var(v, eqs.back());
|
||||
return literal(v, false);
|
||||
};
|
||||
|
||||
for (auto lit : euf::th_explain::lits(jst))
|
||||
|
@ -167,18 +101,137 @@ namespace euf {
|
|||
if (jst.eq_consequent().first != nullptr)
|
||||
lits.push_back(add_lit(jst.eq_consequent()));
|
||||
get_drat().add(lits, sat::status::th(m_is_redundant, jst.ext().get_id(), jst.get_pragma()));
|
||||
for (unsigned i = s().num_vars(); i < nv; ++i)
|
||||
set_tmp_bool_var(i, nullptr);
|
||||
}
|
||||
|
||||
void solver::drat_eq_def(literal lit, expr* eq) {
|
||||
expr *a = nullptr, *b = nullptr;
|
||||
VERIFY(m.is_eq(eq, a, b));
|
||||
drat_log_expr(a);
|
||||
drat_log_expr(b);
|
||||
get_drat().def_begin('e', eq->get_id(), std::string("="));
|
||||
get_drat().def_add_arg(a->get_id());
|
||||
get_drat().def_add_arg(b->get_id());
|
||||
get_drat().def_end();
|
||||
get_drat().bool_def(lit.var(), eq->get_id());
|
||||
void solver::on_clause(unsigned n, literal const* lits, sat::status st) {
|
||||
TRACE("euf", tout << "on-clause " << n << "\n");
|
||||
on_lemma(n, lits, st);
|
||||
on_proof(n, lits, st);
|
||||
}
|
||||
|
||||
void solver::on_proof(unsigned n, literal const* lits, sat::status st) {
|
||||
if (!m_proof_out)
|
||||
return;
|
||||
flet<bool> _display_all_decls(m_display_all_decls, true);
|
||||
std::ostream& out = *m_proof_out;
|
||||
if (!visit_clause(out, n, lits))
|
||||
return;
|
||||
if (st.is_asserted())
|
||||
display_redundant(out, n, lits, status2proof_hint(st));
|
||||
else if (st.is_deleted())
|
||||
display_deleted(out, n, lits);
|
||||
else if (st.is_redundant())
|
||||
display_redundant(out, n, lits, status2proof_hint(st));
|
||||
else if (st.is_input())
|
||||
display_assume(out, n, lits);
|
||||
else
|
||||
UNREACHABLE();
|
||||
out.flush();
|
||||
}
|
||||
|
||||
void solver::on_lemma(unsigned n, literal const* lits, sat::status st) {
|
||||
if (!get_config().m_lemmas2console)
|
||||
return;
|
||||
if (!st.is_redundant() && !st.is_asserted())
|
||||
return;
|
||||
|
||||
std::ostream& out = std::cout;
|
||||
if (!visit_clause(out, n, lits))
|
||||
return;
|
||||
std::function<symbol(int)> ppth = [&](int th) {
|
||||
return m.get_family_name(th);
|
||||
};
|
||||
if (!st.is_sat())
|
||||
out << "; " << sat::status_pp(st, ppth) << "\n";
|
||||
|
||||
display_assert(out, n, lits);
|
||||
}
|
||||
|
||||
void solver::on_instantiation(unsigned n, sat::literal const* lits, unsigned k, euf::enode* const* bindings) {
|
||||
std::ostream& out = std::cout;
|
||||
for (unsigned i = 0; i < k; ++i)
|
||||
visit_expr(out, bindings[i]->get_expr());
|
||||
VERIFY(visit_clause(out, n, lits));
|
||||
out << "(instantiate";
|
||||
display_literals(out, n, lits);
|
||||
for (unsigned i = 0; i < k; ++i)
|
||||
display_expr(out << " :binding ", bindings[i]->get_expr());
|
||||
out << ")\n";
|
||||
}
|
||||
|
||||
bool solver::visit_clause(std::ostream& out, unsigned n, literal const* lits) {
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
expr* e = bool_var2expr(lits[i].var());
|
||||
if (!e)
|
||||
return false;
|
||||
visit_expr(out, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void solver::display_assert(std::ostream& out, unsigned n, literal const* lits) {
|
||||
display_literals(out << "(assert (or", n, lits) << "))\n";
|
||||
}
|
||||
|
||||
void solver::display_assume(std::ostream& out, unsigned n, literal const* lits) {
|
||||
display_literals(out << "(assume", n, lits) << ")\n";
|
||||
}
|
||||
|
||||
void solver::display_redundant(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint) {
|
||||
if (proof_hint)
|
||||
visit_expr(out, proof_hint);
|
||||
display_hint(display_literals(out << "(learn", n, lits), proof_hint) << ")\n";
|
||||
}
|
||||
|
||||
void solver::display_deleted(std::ostream& out, unsigned n, literal const* lits) {
|
||||
display_literals(out << "(del", n, lits) << ")\n";
|
||||
}
|
||||
|
||||
std::ostream& solver::display_hint(std::ostream& out, expr* proof_hint) {
|
||||
if (proof_hint)
|
||||
return display_expr(out << " ", proof_hint);
|
||||
else
|
||||
return out;
|
||||
}
|
||||
|
||||
expr_ref solver::status2proof_hint(sat::status st) {
|
||||
if (st.is_sat())
|
||||
return expr_ref(m.mk_const("rup", m.mk_proof_sort()), m); // provable by reverse unit propagation
|
||||
auto* h = reinterpret_cast<euf::th_proof_hint const*>(st.get_hint());
|
||||
if (!h)
|
||||
return expr_ref(m);
|
||||
|
||||
expr* e = h->get_hint(*this);
|
||||
if (e)
|
||||
return expr_ref(e, m);
|
||||
|
||||
return expr_ref(m);
|
||||
}
|
||||
|
||||
std::ostream& solver::display_literals(std::ostream& out, unsigned n, literal const* lits) {
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
expr* e = bool_var2expr(lits[i].var());
|
||||
if (lits[i].sign())
|
||||
display_expr(out << " (not ", e) << ")";
|
||||
else
|
||||
display_expr(out << " ", e);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void solver::visit_expr(std::ostream& out, expr* e) {
|
||||
m_clause_visitor.collect(e);
|
||||
if (m_display_all_decls)
|
||||
m_clause_visitor.display_decls(out);
|
||||
else
|
||||
m_clause_visitor.display_skolem_decls(out);
|
||||
m_clause_visitor.define_expr(out, e);
|
||||
}
|
||||
|
||||
std::ostream& solver::display_expr(std::ostream& out, expr* e) {
|
||||
return m_clause_visitor.display_expr_def(out, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
50
src/sat/smt/euf_proof_checker.cpp
Normal file
50
src/sat/smt/euf_proof_checker.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
euf_proof_checker.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Plugin manager for checking EUF proofs
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2020-08-25
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/ast_pp.h"
|
||||
#include "sat/smt/euf_proof_checker.h"
|
||||
#include "sat/smt/arith_proof_checker.h"
|
||||
|
||||
namespace euf {
|
||||
|
||||
proof_checker::proof_checker(ast_manager& m):
|
||||
m(m) {
|
||||
arith::proof_checker* apc = alloc(arith::proof_checker, m);
|
||||
m_plugins.push_back(apc);
|
||||
apc->register_plugins(*this);
|
||||
(void)m;
|
||||
}
|
||||
|
||||
proof_checker::~proof_checker() {}
|
||||
|
||||
void proof_checker::register_plugin(symbol const& rule, proof_checker_plugin* p) {
|
||||
m_map.insert(rule, p);
|
||||
}
|
||||
|
||||
bool proof_checker::check(expr_ref_vector const& clause, expr* e, expr_ref_vector& units) {
|
||||
if (!e || !is_app(e))
|
||||
return false;
|
||||
units.reset();
|
||||
app* a = to_app(e);
|
||||
proof_checker_plugin* p = nullptr;
|
||||
if (m_map.find(a->get_decl()->get_name(), p))
|
||||
return p->check(clause, a, units);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
46
src/sat/smt/euf_proof_checker.h
Normal file
46
src/sat/smt/euf_proof_checker.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
euf_proof_checker.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Plugin manager for checking EUF proofs
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-08-25
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/map.h"
|
||||
#include "util/scoped_ptr_vector.h"
|
||||
#include "ast/ast.h"
|
||||
|
||||
namespace euf {
|
||||
|
||||
class proof_checker;
|
||||
|
||||
class proof_checker_plugin {
|
||||
public:
|
||||
virtual ~proof_checker_plugin() {}
|
||||
virtual bool check(expr_ref_vector const& clause, app* jst, expr_ref_vector& units) = 0;
|
||||
virtual void register_plugins(proof_checker& pc) = 0;
|
||||
};
|
||||
|
||||
class proof_checker {
|
||||
ast_manager& m;
|
||||
scoped_ptr_vector<proof_checker_plugin> m_plugins;
|
||||
map<symbol, proof_checker_plugin*, symbol_hash_proc, symbol_eq_proc> m_map;
|
||||
public:
|
||||
proof_checker(ast_manager& m);
|
||||
~proof_checker();
|
||||
void register_plugin(symbol const& rule, proof_checker_plugin*);
|
||||
bool check(expr_ref_vector const& clause, expr* e, expr_ref_vector& units);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -49,7 +49,8 @@ namespace euf {
|
|||
m_lookahead(nullptr),
|
||||
m_to_m(&m),
|
||||
m_to_si(&si),
|
||||
m_values(m)
|
||||
m_values(m),
|
||||
m_clause_visitor(m)
|
||||
{
|
||||
updt_params(p);
|
||||
m_relevancy.set_enabled(get_config().m_relevancy_lvl > 2);
|
||||
|
@ -347,8 +348,7 @@ namespace euf {
|
|||
if (m_relevancy.enabled())
|
||||
m_relevancy.propagate();
|
||||
if (m_egraph.inconsistent()) {
|
||||
unsigned lvl = s().scope_lvl();
|
||||
s().set_conflict(sat::justification::mk_ext_justification(lvl, conflict_constraint().to_index()));
|
||||
set_conflict(conflict_constraint().to_index());
|
||||
return true;
|
||||
}
|
||||
bool propagated1 = false;
|
||||
|
@ -488,7 +488,8 @@ namespace euf {
|
|||
};
|
||||
if (merge_shared_bools())
|
||||
cont = true;
|
||||
for (auto* e : m_solvers) {
|
||||
for (unsigned i = 0; i < m_solvers.size(); ++i) {
|
||||
auto* e = m_solvers[i];
|
||||
if (!m.inc())
|
||||
return sat::check_result::CR_GIVEUP;
|
||||
if (e == m_qsolver)
|
||||
|
@ -519,7 +520,7 @@ namespace euf {
|
|||
bool merged = false;
|
||||
for (unsigned i = m_egraph.nodes().size(); i-- > 0; ) {
|
||||
euf::enode* n = m_egraph.nodes()[i];
|
||||
if (!is_shared(n) || !m.is_bool(n->get_expr()))
|
||||
if (!m.is_bool(n->get_expr()) || !is_shared(n))
|
||||
continue;
|
||||
if (n->value() == l_true && !m.is_true(n->get_root()->get_expr())) {
|
||||
m_egraph.merge(n, mk_true(), to_ptr(sat::literal(n->bool_var())));
|
||||
|
@ -616,15 +617,17 @@ namespace euf {
|
|||
else
|
||||
lit = si.internalize(e, false);
|
||||
VERIFY(lit.var() == v);
|
||||
if (!m_egraph.find(e) && (!m.is_iff(e) && !m.is_or(e) && !m.is_and(e) && !m.is_not(e))) {
|
||||
if (!m_egraph.find(e) && !m.is_iff(e) && !m.is_or(e) && !m.is_and(e) && !m.is_not(e) && !m.is_implies(e) && !m.is_xor(e)) {
|
||||
ptr_buffer<euf::enode> args;
|
||||
if (is_app(e))
|
||||
for (expr* arg : *to_app(e))
|
||||
args.push_back(e_internalize(arg));
|
||||
internalize(e, true);
|
||||
if (!m_egraph.find(e))
|
||||
mk_enode(e, args.size(), args.data());
|
||||
}
|
||||
attach_lit(lit, e);
|
||||
else
|
||||
attach_lit(lit, e);
|
||||
}
|
||||
|
||||
if (relevancy_enabled())
|
||||
|
@ -778,7 +781,7 @@ namespace euf {
|
|||
}
|
||||
for (auto const& thv : enode_th_vars(n)) {
|
||||
auto* th = m_id2solver.get(thv.get_id(), nullptr);
|
||||
if (th && !th->is_fixed(thv.get_var(), val, explain))
|
||||
if (th && th->is_fixed(thv.get_var(), val, explain))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -863,7 +866,13 @@ namespace euf {
|
|||
out << "bool-vars\n";
|
||||
for (unsigned v : m_var_trail) {
|
||||
expr* e = m_bool_var2expr[v];
|
||||
out << v << (is_relevant(v)?"":"n") << ": " << e->get_id() << " " << m_solver->value(v) << " " << mk_bounded_pp(e, m, 1) << "\n";
|
||||
out << v << (is_relevant(v)?"":"n") << ": " << e->get_id() << " " << m_solver->value(v) << " " << mk_bounded_pp(e, m, 1);
|
||||
euf::enode* n = m_egraph.find(e);
|
||||
if (n) {
|
||||
for (auto const& th : enode_th_vars(n))
|
||||
out << " " << m_id2solver[th.get_id()]->name();
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
for (auto* e : m_solvers)
|
||||
e->display(out);
|
||||
|
@ -1067,10 +1076,7 @@ namespace euf {
|
|||
user_propagator::fresh_eh_t& fresh_eh) {
|
||||
m_user_propagator = alloc(user_solver::solver, *this);
|
||||
m_user_propagator->add(ctx, push_eh, pop_eh, fresh_eh);
|
||||
for (unsigned i = m_scopes.size(); i-- > 0; )
|
||||
m_user_propagator->push();
|
||||
m_solvers.push_back(m_user_propagator);
|
||||
m_id2solver.setx(m_user_propagator->get_id(), m_user_propagator, nullptr);
|
||||
add_solver(m_user_propagator);
|
||||
}
|
||||
|
||||
bool solver::watches_fixed(enode* n) const {
|
||||
|
|
|
@ -60,11 +60,10 @@ namespace euf {
|
|||
std::ostream& display(std::ostream& out) const;
|
||||
};
|
||||
|
||||
class solver : public sat::extension, public th_internalizer, public th_decompile {
|
||||
class solver : public sat::extension, public th_internalizer, public th_decompile, public sat::clause_eh {
|
||||
typedef top_sort<euf::enode> deps_t;
|
||||
friend class ackerman;
|
||||
class user_sort;
|
||||
// friend class sat::ba_solver;
|
||||
struct stats {
|
||||
unsigned m_ackerman;
|
||||
unsigned m_final_checks;
|
||||
|
@ -161,7 +160,6 @@ namespace euf {
|
|||
void collect_dependencies(user_sort& us, deps_t& deps);
|
||||
void values2model(deps_t const& deps, model_ref& mdl);
|
||||
void validate_model(model& mdl);
|
||||
void display_validation_failure(std::ostream& out, model& mdl, enode* n);
|
||||
|
||||
// solving
|
||||
void propagate_literals();
|
||||
|
@ -175,19 +173,22 @@ namespace euf {
|
|||
void log_antecedents(std::ostream& out, literal l, literal_vector const& r);
|
||||
void log_antecedents(literal l, literal_vector const& r);
|
||||
void log_justification(literal l, th_explain const& jst);
|
||||
void drat_log_decl(func_decl* f);
|
||||
void drat_log_expr1(expr* n);
|
||||
ptr_vector<expr> m_drat_todo;
|
||||
obj_hashtable<ast> m_drat_asts;
|
||||
bool m_drat_initialized{ false };
|
||||
void init_drat();
|
||||
|
||||
bool m_proof_initialized = false;
|
||||
void init_proof();
|
||||
ast_pp_util m_clause_visitor;
|
||||
bool m_display_all_decls = false;
|
||||
void on_clause(unsigned n, literal const* lits, sat::status st) override;
|
||||
void on_lemma(unsigned n, literal const* lits, sat::status st);
|
||||
void on_proof(unsigned n, literal const* lits, sat::status st);
|
||||
std::ostream& display_literals(std::ostream& out, unsigned n, sat::literal const* lits);
|
||||
void display_assume(std::ostream& out, unsigned n, literal const* lits);
|
||||
void display_redundant(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint);
|
||||
void display_deleted(std::ostream& out, unsigned n, literal const* lits);
|
||||
std::ostream& display_hint(std::ostream& out, expr* proof_hint);
|
||||
expr_ref status2proof_hint(sat::status st);
|
||||
|
||||
// relevancy
|
||||
//bool_vector m_relevant_expr_ids;
|
||||
//bool_vector m_relevant_visited;
|
||||
//ptr_vector<expr> m_relevant_todo;
|
||||
//void init_relevant_expr_ids();
|
||||
//void push_relevant(sat::bool_var v);
|
||||
bool is_propagated(sat::literal lit);
|
||||
// invariant
|
||||
void check_eqc_bool_assignment() const;
|
||||
|
@ -340,11 +341,16 @@ namespace euf {
|
|||
|
||||
|
||||
// proof
|
||||
bool use_drat() { return s().get_config().m_drat && (init_drat(), true); }
|
||||
bool use_drat() { return s().get_config().m_drat && (init_proof(), true); }
|
||||
sat::drat& get_drat() { return s().get_drat(); }
|
||||
void drat_bool_def(sat::bool_var v, expr* n);
|
||||
void drat_eq_def(sat::literal lit, expr* eq);
|
||||
void drat_log_expr(expr* n);
|
||||
|
||||
void set_tmp_bool_var(sat::bool_var b, expr* e);
|
||||
bool visit_clause(std::ostream& out, unsigned n, literal const* lits);
|
||||
void display_assert(std::ostream& out, unsigned n, literal const* lits);
|
||||
void visit_expr(std::ostream& out, expr* e);
|
||||
std::ostream& display_expr(std::ostream& out, expr* e);
|
||||
void on_instantiation(unsigned n, sat::literal const* lits, unsigned k, euf::enode* const* bindings);
|
||||
scoped_ptr<std::ostream> m_proof_out;
|
||||
|
||||
// decompile
|
||||
bool extract_pb(std::function<void(unsigned sz, literal const* c, unsigned k)>& card,
|
||||
|
@ -403,6 +409,7 @@ namespace euf {
|
|||
obj_map<expr, enode*> const& values2root();
|
||||
void model_updated(model_ref& mdl);
|
||||
expr* node2value(enode* n) const;
|
||||
void display_validation_failure(std::ostream& out, model& mdl, enode* n);
|
||||
|
||||
// diagnostics
|
||||
func_decl_ref_vector const& unhandled_functions() { return m_unhandled_functions; }
|
||||
|
|
|
@ -1430,10 +1430,9 @@ namespace pb {
|
|||
IF_VERBOSE(0, verbose_stream() << *c << "\n");
|
||||
VERIFY(c->well_formed());
|
||||
if (m_solver && m_solver->get_config().m_drat) {
|
||||
std::function<void(std::ostream& out)> fn = [&](std::ostream& out) {
|
||||
out << "c ba constraint " << *c << " 0\n";
|
||||
};
|
||||
m_solver->get_drat().log_adhoc(fn);
|
||||
auto * out = s().get_drat().out();
|
||||
if (out)
|
||||
*out << "c ba constraint " << *c << " 0\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -372,16 +372,21 @@ namespace q {
|
|||
}
|
||||
|
||||
void ematch::propagate(bool is_conflict, unsigned idx, sat::ext_justification_idx j_idx) {
|
||||
if (is_conflict) {
|
||||
if (is_conflict)
|
||||
++m_stats.m_num_conflicts;
|
||||
ctx.set_conflict(j_idx);
|
||||
}
|
||||
else {
|
||||
else
|
||||
++m_stats.m_num_propagations;
|
||||
auto& j = justification::from_index(j_idx);
|
||||
auto lit = instantiate(j.m_clause, j.m_binding, j.m_clause[idx]);
|
||||
ctx.propagate(lit, j_idx);
|
||||
}
|
||||
|
||||
auto& j = justification::from_index(j_idx);
|
||||
sat::literal_vector lits;
|
||||
lits.push_back(~j.m_clause.m_literal);
|
||||
for (unsigned i = 0; i < j.m_clause.size(); ++i)
|
||||
lits.push_back(instantiate(j.m_clause, j.m_binding, j.m_clause[i]));
|
||||
m_qs.log_instantiation(lits, &j);
|
||||
euf::th_proof_hint* ph = nullptr;
|
||||
if (ctx.use_drat())
|
||||
ph = q_proof_hint::mk(ctx, j.m_clause.size(), j.m_binding);
|
||||
m_qs.add_clause(lits, ph);
|
||||
}
|
||||
|
||||
bool ematch::flush_prop_queue() {
|
||||
|
@ -408,6 +413,7 @@ namespace q {
|
|||
void ematch::add_instantiation(clause& c, binding& b, sat::literal lit) {
|
||||
m_evidence.reset();
|
||||
ctx.propagate(lit, mk_justification(UINT_MAX, c, b.nodes()));
|
||||
m_qs.log_instantiation(~c.m_literal, lit);
|
||||
}
|
||||
|
||||
sat::literal ematch::instantiate(clause& c, euf::enode* const* binding, lit const& l) {
|
||||
|
|
|
@ -47,21 +47,21 @@ namespace q {
|
|||
unsigned lim = m_indirect_nodes.size();
|
||||
lit l = c[i];
|
||||
lbool cmp = compare(n, binding, l.lhs, l.rhs, evidence);
|
||||
TRACE("q", tout << l.lhs << " ~~ " << l.rhs << " is " << cmp << "\n";);
|
||||
switch (cmp) {
|
||||
case l_false:
|
||||
case l_false:
|
||||
m_indirect_nodes.shrink(lim);
|
||||
if (!l.sign)
|
||||
break;
|
||||
c.m_watch = i;
|
||||
return l_true;
|
||||
case l_true:
|
||||
case l_true:
|
||||
m_indirect_nodes.shrink(lim);
|
||||
if (l.sign)
|
||||
break;
|
||||
break;
|
||||
c.m_watch = i;
|
||||
return l_true;
|
||||
case l_undef:
|
||||
TRACE("q", tout << l.lhs << " ~~ " << l.rhs << " is undef\n";);
|
||||
if (idx != UINT_MAX) {
|
||||
idx = UINT_MAX;
|
||||
return l_undef;
|
||||
|
|
|
@ -1961,7 +1961,7 @@ namespace q {
|
|||
for (unsigned i = 0; i < num_args; i++)
|
||||
m_args[i] = m_registers[pc->m_iregs[i]]->get_root();
|
||||
for (enode* n : euf::enode_class(r)) {
|
||||
if (n->get_decl() == f) {
|
||||
if (n->get_decl() == f && num_args == n->num_args()) {
|
||||
unsigned i = 0;
|
||||
for (; i < num_args; i++) {
|
||||
if (n->get_arg(i)->get_root() != m_args[i])
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace q {
|
|||
|
||||
static mam * mk(euf::solver& ctx, ematch& em);
|
||||
|
||||
virtual ~mam() {}
|
||||
virtual ~mam() = default;
|
||||
|
||||
virtual void add_pattern(quantifier * q, app * mp) = 0;
|
||||
|
||||
|
|
|
@ -68,10 +68,21 @@ namespace q {
|
|||
}
|
||||
}
|
||||
m_max_cex += ctx.get_config().m_mbqi_max_cexs;
|
||||
for (auto const& [qlit, fml, generation] : m_instantiations) {
|
||||
for (auto const& [qlit, fml, inst, generation] : m_instantiations) {
|
||||
euf::solver::scoped_generation sg(ctx, generation + 1);
|
||||
sat::literal lit = ctx.mk_literal(fml);
|
||||
m_qs.add_clause(~qlit, ~lit);
|
||||
euf::th_proof_hint* ph = nullptr;
|
||||
if (!inst.empty()) {
|
||||
ph = q_proof_hint::mk(ctx, inst.size(), inst.data());
|
||||
sat::literal_vector lits;
|
||||
lits.push_back(~qlit);
|
||||
lits.push_back(~lit);
|
||||
m_qs.add_clause(lits, ph);
|
||||
}
|
||||
else {
|
||||
m_qs.add_clause(~qlit, ~lit);
|
||||
}
|
||||
m_qs.log_instantiation(~qlit, ~lit);
|
||||
}
|
||||
m_instantiations.reset();
|
||||
if (result != l_true)
|
||||
|
@ -223,10 +234,31 @@ namespace q {
|
|||
TRACE("q", tout << "project: " << proj << "\n";);
|
||||
IF_VERBOSE(11, verbose_stream() << "mbi:\n" << mk_pp(q, m) << "\n" << proj << "\n");
|
||||
++m_stats.m_num_instantiations;
|
||||
unsigned generation = ctx.get_max_generation(proj);
|
||||
m_instantiations.push_back(instantiation_t(qlit, proj, generation));
|
||||
unsigned generation = ctx.get_max_generation(proj);
|
||||
expr_ref_vector inst = extract_binding(q);
|
||||
m_instantiations.push_back(instantiation_t(qlit, proj, inst, generation));
|
||||
}
|
||||
|
||||
expr_ref_vector mbqi::extract_binding(quantifier* q) {
|
||||
if (!m_defs.empty()) {
|
||||
expr_safe_replace sub(m);
|
||||
for (unsigned i = m_defs.size(); i-- > 0; ) {
|
||||
sub(m_defs[i].term);
|
||||
sub.insert(m_defs[i].var, m_defs[i].term);
|
||||
}
|
||||
q_body* qb = q2body(q);
|
||||
expr_ref_vector inst(m);
|
||||
for (expr* v : qb->vars) {
|
||||
expr_ref t(m);
|
||||
sub(v, t);
|
||||
inst.push_back(t);
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
return expr_ref_vector(m);
|
||||
}
|
||||
|
||||
|
||||
void mbqi::add_universe_restriction(q_body& qb) {
|
||||
for (app* v : qb.vars) {
|
||||
sort* s = v->get_sort();
|
||||
|
@ -283,6 +315,7 @@ namespace q {
|
|||
expr_ref_vector fmls(qb.vbody);
|
||||
app_ref_vector vars(qb.vars);
|
||||
bool fmls_extracted = false;
|
||||
m_defs.reset();
|
||||
TRACE("q",
|
||||
tout << "Project\n";
|
||||
tout << fmls << "\n";
|
||||
|
@ -313,16 +346,22 @@ namespace q {
|
|||
fmls_extracted = true;
|
||||
}
|
||||
if (!p)
|
||||
continue;
|
||||
if (!(*p)(*m_model, vars, fmls))
|
||||
return expr_ref(nullptr, m);
|
||||
continue;
|
||||
if (ctx.use_drat()) {
|
||||
if (!p->project(*m_model, vars, fmls, m_defs))
|
||||
return expr_ref(m);
|
||||
}
|
||||
else if (!(*p)(*m_model, vars, fmls))
|
||||
return expr_ref(m);
|
||||
}
|
||||
for (app* v : vars) {
|
||||
expr_ref term(m);
|
||||
expr_ref val = (*m_model)(v);
|
||||
val = m_model->unfold_as_array(val);
|
||||
term = replace_model_value(val);
|
||||
rep.insert(v, term);
|
||||
rep.insert(v, term);
|
||||
if (ctx.use_drat())
|
||||
m_defs.push_back(mbp::def(expr_ref(v, m), term));
|
||||
eqs.push_back(m.mk_eq(v, val));
|
||||
}
|
||||
rep(fmls);
|
||||
|
@ -596,8 +635,8 @@ namespace q {
|
|||
void mbqi::collect_statistics(statistics& st) const {
|
||||
if (m_solver)
|
||||
m_solver->collect_statistics(st);
|
||||
st.update("q-num-instantiations", m_stats.m_num_instantiations);
|
||||
st.update("q-num-checks", m_stats.m_num_checks);
|
||||
st.update("q mbi instantiations", m_stats.m_num_instantiations);
|
||||
st.update("q mbi num checks", m_stats.m_num_checks);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,15 +66,17 @@ namespace q {
|
|||
scoped_ptr_vector<obj_hashtable<expr>> m_values;
|
||||
scoped_ptr_vector<mbp::project_plugin> m_plugins;
|
||||
obj_map<quantifier, q_body*> m_q2body;
|
||||
unsigned m_max_cex{ 1 };
|
||||
unsigned m_max_quick_check_rounds { 100 };
|
||||
unsigned m_max_unbounded_equalities { 10 };
|
||||
unsigned m_max_choose_candidates { 10 };
|
||||
unsigned m_generation_bound{ UINT_MAX };
|
||||
unsigned m_generation_max { UINT_MAX };
|
||||
typedef std::tuple<sat::literal, expr_ref, unsigned> instantiation_t;
|
||||
unsigned m_max_cex = 1;
|
||||
unsigned m_max_quick_check_rounds = 100;
|
||||
unsigned m_max_unbounded_equalities = 10;
|
||||
unsigned m_max_choose_candidates = 10;
|
||||
unsigned m_generation_bound = UINT_MAX;
|
||||
unsigned m_generation_max = UINT_MAX;
|
||||
typedef std::tuple<sat::literal, expr_ref, expr_ref_vector, unsigned> instantiation_t;
|
||||
vector<instantiation_t> m_instantiations;
|
||||
vector<mbp::def> m_defs;
|
||||
|
||||
expr_ref_vector extract_binding(quantifier* q);
|
||||
void restrict_to_universe(expr * sk, ptr_vector<expr> const & universe);
|
||||
// void register_value(expr* e);
|
||||
expr_ref replace_model_value(expr* e);
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace q {
|
|||
ast_manager& m;
|
||||
public:
|
||||
projection_function(ast_manager& m) : m(m) {}
|
||||
virtual ~projection_function() {}
|
||||
virtual ~projection_function() = default;
|
||||
virtual expr* mk_lt(expr* a, expr* b) = 0;
|
||||
expr* mk_le(expr* a, expr* b) { return m.mk_not(mk_lt(b, a)); }
|
||||
virtual bool operator()(expr* a, expr* b) const = 0;
|
||||
|
|
|
@ -24,6 +24,7 @@ Author:
|
|||
#include "sat/smt/euf_solver.h"
|
||||
#include "sat/smt/sat_th.h"
|
||||
#include "qe/lite/qe_lite.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace q {
|
||||
|
@ -356,4 +357,43 @@ namespace q {
|
|||
m_ematch.get_antecedents(l, idx, r, probing);
|
||||
}
|
||||
|
||||
void solver::log_instantiation(unsigned n, sat::literal const* lits, justification* j) {
|
||||
TRACE("q", for (unsigned i = 0; i < n; ++i) tout << literal2expr(lits[i]) << "\n";);
|
||||
if (get_config().m_instantiations2console) {
|
||||
ctx.on_instantiation(n, lits, j ? j->m_clause.num_decls() : 0, j ? j->m_binding : nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned n, euf::enode* const* bindings) {
|
||||
auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n));
|
||||
q_proof_hint* ph = new (mem) q_proof_hint();
|
||||
ph->m_num_bindings = n;
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
ph->m_bindings[i] = bindings[i]->get_expr();
|
||||
return ph;
|
||||
}
|
||||
|
||||
q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned n, expr* const* bindings) {
|
||||
auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n));
|
||||
q_proof_hint* ph = new (mem) q_proof_hint();
|
||||
ph->m_num_bindings = n;
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
ph->m_bindings[i] = bindings[i];
|
||||
return ph;
|
||||
}
|
||||
|
||||
expr* q_proof_hint::get_hint(euf::solver& s) const {
|
||||
ast_manager& m = s.get_manager();
|
||||
expr_ref_vector args(m);
|
||||
sort_ref_vector sorts(m);
|
||||
for (unsigned i = 0; i < m_num_bindings; ++i) {
|
||||
args.push_back(m_bindings[i]);
|
||||
sorts.push_back(args.back()->get_sort());
|
||||
}
|
||||
sort* range = m.mk_proof_sort();
|
||||
func_decl* d = m.mk_func_decl(symbol("inst"), args.size(), sorts.data(), range);
|
||||
expr* r = m.mk_app(d, args);
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,16 @@ namespace euf {
|
|||
|
||||
namespace q {
|
||||
|
||||
struct q_proof_hint : public euf::th_proof_hint {
|
||||
unsigned m_num_bindings;
|
||||
expr* m_bindings[0];
|
||||
q_proof_hint() {}
|
||||
static size_t get_obj_size(unsigned num_bindings) { return sizeof(q_proof_hint) + num_bindings*sizeof(expr*); }
|
||||
static q_proof_hint* mk(euf::solver& s, unsigned n, euf::enode* const* bindings);
|
||||
static q_proof_hint* mk(euf::solver& s, unsigned n, expr* const* bindings);
|
||||
expr* get_hint(euf::solver& s) const override;
|
||||
};
|
||||
|
||||
class solver : public euf::th_euf_solver {
|
||||
|
||||
typedef obj_map<quantifier, quantifier*> flat_table;
|
||||
|
@ -88,5 +98,9 @@ namespace q {
|
|||
sat::literal_vector const& universal() const { return m_universal; }
|
||||
quantifier* flatten(quantifier* q);
|
||||
|
||||
void log_instantiation(sat::literal q, sat::literal i, justification* j = nullptr) { sat::literal lits[2] = { q, i }; log_instantiation(2, lits, j); }
|
||||
void log_instantiation(sat::literal_vector const& lits, justification* j) { log_instantiation(lits.size(), lits.data(), j); }
|
||||
void log_instantiation(unsigned n, sat::literal const* lits, justification* j);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ Author:
|
|||
namespace sat {
|
||||
class sat_internalizer {
|
||||
public:
|
||||
virtual ~sat_internalizer() {}
|
||||
virtual ~sat_internalizer() = default;
|
||||
virtual bool is_bool_op(expr* e) const = 0;
|
||||
virtual literal internalize(expr* e, bool learned) = 0;
|
||||
virtual bool_var to_bool_var(expr* e) = 0;
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace euf {
|
|||
pop_core(n);
|
||||
}
|
||||
|
||||
sat::status th_euf_solver::mk_status(sat::proof_hint const* ps) {
|
||||
sat::status th_euf_solver::mk_status(th_proof_hint const* ps) {
|
||||
return sat::status::th(m_is_redundant, get_id(), ps);
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ namespace euf {
|
|||
return add_clause(2, lits);
|
||||
}
|
||||
|
||||
bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::proof_hint const* ps) {
|
||||
bool th_euf_solver::add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps) {
|
||||
sat::literal lits[2] = { a, b };
|
||||
return add_clause(2, lits, ps);
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ namespace euf {
|
|||
return add_clause(4, lits);
|
||||
}
|
||||
|
||||
bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, sat::proof_hint const* ps) {
|
||||
bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps) {
|
||||
bool was_true = false;
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
was_true |= is_true(lits[i]);
|
||||
|
@ -226,13 +226,14 @@ namespace euf {
|
|||
return ctx.s().rand()();
|
||||
}
|
||||
|
||||
size_t th_explain::get_obj_size(unsigned num_lits, unsigned num_eqs, sat::proof_hint const* pma) {
|
||||
return sat::constraint_base::obj_size(sizeof(th_explain) + sizeof(sat::literal) * num_lits + sizeof(enode_pair) * num_eqs + (pma?pma->to_string().length()+1:1));
|
||||
size_t th_explain::get_obj_size(unsigned num_lits, unsigned num_eqs) {
|
||||
return sat::constraint_base::obj_size(sizeof(th_explain) + sizeof(sat::literal) * num_lits + sizeof(enode_pair) * num_eqs);
|
||||
}
|
||||
|
||||
th_explain::th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& p, sat::proof_hint const* pma) {
|
||||
th_explain::th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& p, th_proof_hint const* pma) {
|
||||
m_consequent = c;
|
||||
m_eq = p;
|
||||
m_proof_hint = pma;
|
||||
m_num_literals = n_lits;
|
||||
m_num_eqs = n_eqs;
|
||||
char * base_ptr = reinterpret_cast<char*>(this) + sizeof(th_explain);
|
||||
|
@ -244,33 +245,24 @@ namespace euf {
|
|||
m_eqs = reinterpret_cast<enode_pair*>(base_ptr);
|
||||
for (i = 0; i < n_eqs; ++i)
|
||||
m_eqs[i] = eqs[i];
|
||||
base_ptr += sizeof(enode_pair) * n_eqs;
|
||||
m_pragma = reinterpret_cast<char*>(base_ptr);
|
||||
i = 0;
|
||||
if (pma) {
|
||||
std::string s = pma->to_string();
|
||||
for (i = 0; s[i]; ++i)
|
||||
m_pragma[i] = s[i];
|
||||
}
|
||||
m_pragma[i] = 0;
|
||||
}
|
||||
|
||||
th_explain* th_explain::mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, sat::proof_hint const* pma) {
|
||||
th_explain* th_explain::mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, th_proof_hint const* pma) {
|
||||
region& r = th.ctx.get_region();
|
||||
void* mem = r.allocate(get_obj_size(n_lits, n_eqs, pma));
|
||||
void* mem = r.allocate(get_obj_size(n_lits, n_eqs));
|
||||
sat::constraint_base::initialize(mem, &th);
|
||||
return new (sat::constraint_base::ptr2mem(mem)) th_explain(n_lits, lits, n_eqs, eqs, c, enode_pair(x, y));
|
||||
return new (sat::constraint_base::ptr2mem(mem)) th_explain(n_lits, lits, n_eqs, eqs, c, enode_pair(x, y), pma);
|
||||
}
|
||||
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, sat::proof_hint const* pma) {
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, th_proof_hint const* pma) {
|
||||
return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent, nullptr, nullptr, pma);
|
||||
}
|
||||
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma) {
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma) {
|
||||
return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y, pma);
|
||||
}
|
||||
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma) {
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma) {
|
||||
return mk(th, 0, nullptr, eqs.size(), eqs.data(), sat::null_literal, x, y, pma);
|
||||
}
|
||||
|
||||
|
@ -313,8 +305,8 @@ namespace euf {
|
|||
out << "--> " << m_consequent;
|
||||
if (m_eq.first != nullptr)
|
||||
out << "--> " << m_eq.first->get_expr_id() << " == " << m_eq.second->get_expr_id();
|
||||
if (m_pragma != nullptr)
|
||||
out << " p " << m_pragma;
|
||||
if (m_proof_hint != nullptr)
|
||||
out << " p ";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace euf {
|
|||
virtual bool post_visit(expr* e, bool sign, bool root) { return false; }
|
||||
|
||||
public:
|
||||
virtual ~th_internalizer() {}
|
||||
virtual ~th_internalizer() = default;
|
||||
|
||||
virtual sat::literal internalize(expr* e, bool sign, bool root, bool redundant) = 0;
|
||||
|
||||
|
@ -58,9 +58,10 @@ namespace euf {
|
|||
|
||||
};
|
||||
|
||||
|
||||
class th_decompile {
|
||||
public:
|
||||
virtual ~th_decompile() {}
|
||||
virtual ~th_decompile() = default;
|
||||
|
||||
virtual bool to_formulas(std::function<expr_ref(sat::literal)>& lit2expr, expr_ref_vector& fmls) { return false; }
|
||||
};
|
||||
|
@ -68,7 +69,7 @@ namespace euf {
|
|||
class th_model_builder {
|
||||
public:
|
||||
|
||||
virtual ~th_model_builder() {}
|
||||
virtual ~th_model_builder() = default;
|
||||
|
||||
/**
|
||||
\brief compute the value for enode \c n and store the value in \c values
|
||||
|
@ -138,6 +139,11 @@ namespace euf {
|
|||
|
||||
};
|
||||
|
||||
class th_proof_hint : public sat::proof_hint {
|
||||
public:
|
||||
virtual expr* get_hint(euf::solver& s) const = 0;
|
||||
};
|
||||
|
||||
class th_euf_solver : public th_solver {
|
||||
protected:
|
||||
solver& ctx;
|
||||
|
@ -150,16 +156,16 @@ namespace euf {
|
|||
region& get_region();
|
||||
|
||||
|
||||
sat::status mk_status(sat::proof_hint const* ps = nullptr);
|
||||
sat::status mk_status(th_proof_hint const* ps = nullptr);
|
||||
bool add_unit(sat::literal lit);
|
||||
bool add_units(sat::literal_vector const& lits);
|
||||
bool add_clause(sat::literal lit) { return add_unit(lit); }
|
||||
bool add_clause(sat::literal a, sat::literal b);
|
||||
bool add_clause(sat::literal a, sat::literal b, sat::proof_hint const* ps);
|
||||
bool add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps);
|
||||
bool add_clause(sat::literal a, sat::literal b, sat::literal c);
|
||||
bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d);
|
||||
bool add_clause(sat::literal_vector const& lits, sat::proof_hint const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); }
|
||||
bool add_clause(unsigned n, sat::literal* lits, sat::proof_hint const* ps = nullptr);
|
||||
bool add_clause(sat::literal_vector const& lits, th_proof_hint const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); }
|
||||
bool add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps = nullptr);
|
||||
void add_equiv(sat::literal a, sat::literal b);
|
||||
void add_equiv_and(sat::literal a, sat::literal_vector const& bs);
|
||||
|
||||
|
@ -220,16 +226,16 @@ namespace euf {
|
|||
* that retrieve literals on demand.
|
||||
*/
|
||||
class th_explain {
|
||||
sat::literal m_consequent = sat::null_literal; // literal consequent for propagations
|
||||
enode_pair m_eq = enode_pair(); // equality consequent for propagations
|
||||
sat::literal m_consequent = sat::null_literal; // literal consequent for propagations
|
||||
enode_pair m_eq = enode_pair(); // equality consequent for propagations
|
||||
th_proof_hint const* m_proof_hint;
|
||||
unsigned m_num_literals;
|
||||
unsigned m_num_eqs;
|
||||
sat::literal* m_literals;
|
||||
enode_pair* m_eqs;
|
||||
char* m_pragma = nullptr;
|
||||
static size_t get_obj_size(unsigned num_lits, unsigned num_eqs, sat::proof_hint const* pma);
|
||||
th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, sat::proof_hint const* pma = nullptr);
|
||||
static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, sat::proof_hint const* pma = nullptr);
|
||||
static size_t get_obj_size(unsigned num_lits, unsigned num_eqs);
|
||||
th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, th_proof_hint const* pma = nullptr);
|
||||
static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, th_proof_hint const* pma = nullptr);
|
||||
|
||||
public:
|
||||
static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs);
|
||||
|
@ -240,9 +246,9 @@ namespace euf {
|
|||
static th_explain* conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y);
|
||||
static th_explain* conflict(th_euf_solver& th, euf::enode* x, euf::enode* y);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y);
|
||||
static th_explain* propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma = nullptr);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, sat::proof_hint const* pma = nullptr);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma = nullptr);
|
||||
static th_explain* propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma = nullptr);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, th_proof_hint const* pma = nullptr);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma = nullptr);
|
||||
|
||||
sat::ext_constraint_idx to_index() const {
|
||||
return sat::constraint_base::mem2base(this);
|
||||
|
@ -277,7 +283,7 @@ namespace euf {
|
|||
|
||||
enode_pair eq_consequent() const { return m_eq; }
|
||||
|
||||
sat::proof_hint const* get_pragma() const { return nullptr; } //*m_pragma ? m_pragma : nullptr; }
|
||||
th_proof_hint const* get_pragma() const { return m_proof_hint; }
|
||||
|
||||
};
|
||||
|
||||
|
|
79
src/sat/smt/xor_solver.cpp
Normal file
79
src/sat/smt/xor_solver.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
xor_solver.h
|
||||
|
||||
Abstract:
|
||||
|
||||
XOR solver.
|
||||
Interface outline.
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "sat/smt/xor_solver.h"
|
||||
#include "sat/sat_simplifier_params.hpp"
|
||||
#include "sat/sat_xor_finder.h"
|
||||
|
||||
namespace xr {
|
||||
|
||||
solver::solver(euf::solver& ctx):
|
||||
th_solver(ctx.get_manager(), symbol("xor-solver"), ctx.get_manager().get_family_id("xor-solver"))
|
||||
{}
|
||||
|
||||
euf::th_solver* solver::clone(euf::solver& ctx) {
|
||||
// and relevant copy internal state
|
||||
return alloc(solver, ctx);
|
||||
}
|
||||
|
||||
void solver::asserted(sat::literal l) {
|
||||
|
||||
}
|
||||
|
||||
bool solver::unit_propagate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx,
|
||||
sat::literal_vector & r, bool probing) {
|
||||
|
||||
}
|
||||
|
||||
sat::check_result solver::check() {
|
||||
return sat::check_result::CR_DONE;
|
||||
}
|
||||
|
||||
void solver::push() {
|
||||
}
|
||||
|
||||
void solver::pop(unsigned n) {
|
||||
}
|
||||
|
||||
// inprocessing
|
||||
// pre_simplify: decompile all xor constraints to allow other in-processing.
|
||||
// simplify: recompile clauses to xor constraints
|
||||
// literals that get added to xor constraints are tagged with the theory.
|
||||
void solver::pre_simplify() {
|
||||
|
||||
}
|
||||
|
||||
void solver::simplify() {
|
||||
|
||||
}
|
||||
|
||||
std::ostream& solver::display(std::ostream& out) const {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const {
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
48
src/sat/smt/xor_solver.h
Normal file
48
src/sat/smt/xor_solver.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
xor_solver.h
|
||||
|
||||
Abstract:
|
||||
|
||||
XOR solver.
|
||||
Interface outline.
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sat/smt/euf_solver.h"
|
||||
|
||||
namespace xr {
|
||||
class solver : public euf::th_solver {
|
||||
public:
|
||||
solver(euf::solver& ctx);
|
||||
|
||||
th_solver* clone(euf::solver& ctx) override;
|
||||
|
||||
sat::literal internalize(expr* e, bool sign, bool root, bool redundant) override { UNREACHABLE(); return sat::null_literal; }
|
||||
|
||||
void internalize(expr* e, bool redundant) override { UNREACHABLE(); }
|
||||
|
||||
|
||||
void asserted(sat::literal l) override;
|
||||
bool unit_propagate() override;
|
||||
void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override;
|
||||
|
||||
void pre_simplify() override;
|
||||
void simplify() 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -75,7 +75,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
func_decl_ref_vector m_unhandled_funs;
|
||||
bool m_default_external;
|
||||
bool m_euf { false };
|
||||
bool m_drat { false };
|
||||
bool m_is_redundant { false };
|
||||
bool m_top_level { false };
|
||||
sat::literal_vector aig_lits;
|
||||
|
@ -102,7 +101,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
m_ite_extra = p.get_bool("ite_extra", true);
|
||||
m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
|
||||
m_euf = sp.euf();
|
||||
m_drat = sp.drat_file().is_non_empty_string();
|
||||
}
|
||||
|
||||
void throw_op_not_handled(std::string const& s) {
|
||||
|
@ -169,15 +167,9 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
if (m_expr2var_replay && m_expr2var_replay->find(n, v))
|
||||
return v;
|
||||
v = m_solver.add_var(is_ext);
|
||||
log_def(v, n);
|
||||
return v;
|
||||
}
|
||||
|
||||
void log_def(sat::bool_var v, expr* n) {
|
||||
if (m_drat && m_euf)
|
||||
ensure_euf()->drat_bool_def(v, n);
|
||||
}
|
||||
|
||||
sat::bool_var to_bool_var(expr* e) override {
|
||||
sat::literal l;
|
||||
sat::bool_var v = m_map.to_bool_var(e);
|
||||
|
@ -1013,6 +1005,11 @@ goal2sat::~goal2sat() {
|
|||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
euf::solver* goal2sat::ensure_euf() {
|
||||
return m_imp->ensure_euf();
|
||||
}
|
||||
|
||||
|
||||
void goal2sat::collect_param_descrs(param_descrs & r) {
|
||||
insert_max_memory(r);
|
||||
r.insert("ite_extra", CPK_BOOL, "(default: true) add redundant clauses (that improve unit propagation) when encoding if-then-else formulas");
|
||||
|
|
|
@ -33,6 +33,10 @@ Notes:
|
|||
#include "sat/smt/atom2bool_var.h"
|
||||
#include "sat/smt/sat_internalizer.h"
|
||||
|
||||
namespace euf {
|
||||
class solver;
|
||||
}
|
||||
|
||||
class goal2sat {
|
||||
public:
|
||||
typedef obj_map<expr, sat::literal> dep2asm_map;
|
||||
|
@ -41,7 +45,6 @@ private:
|
|||
imp * m_imp;
|
||||
unsigned m_scopes = 0;
|
||||
|
||||
void init(ast_manager& m, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external);
|
||||
|
||||
public:
|
||||
goal2sat();
|
||||
|
@ -66,6 +69,9 @@ public:
|
|||
|
||||
void operator()(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external = false);
|
||||
|
||||
void init(ast_manager& m, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external);
|
||||
|
||||
|
||||
void assumptions(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external = false);
|
||||
|
||||
void get_interpreted_funs(func_decl_ref_vector& funs);
|
||||
|
@ -82,4 +88,6 @@ public:
|
|||
|
||||
void user_pop(unsigned n);
|
||||
|
||||
euf::solver* ensure_euf();
|
||||
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue