3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-05 09:04:07 +00:00

fix unsoundness in quantifier propagation #6116 and add initial lemma logging

This commit is contained in:
Nikolaj Bjorner 2022-08-23 19:09:50 -07:00
parent 912b284602
commit ce1f3987d9
15 changed files with 78 additions and 13 deletions

View file

@ -27,7 +27,7 @@ def init_project_def():
add_lib('params', ['util'])
add_lib('smt_params', ['params'], 'smt/params')
add_lib('grobner', ['ast', 'dd', 'simplex'], 'math/grobner')
add_lib('sat', ['util', 'dd', 'grobner'])
add_lib('sat', ['params', 'util', 'dd', 'grobner'])
add_lib('nlsat', ['polynomial', 'sat'])
add_lib('lp', ['util', 'nlsat', 'grobner', 'interval', 'smt_params'], 'math/lp')
add_lib('rewriter', ['ast', 'polynomial', 'automata', 'params'], 'ast/rewriter')

View file

@ -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,7 +197,7 @@ 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_drat = !p.drat_disable() && (sp.lemmas2console() || m_drat_check_unsat || m_drat_file.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();
@ -248,8 +251,8 @@ 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))

View file

@ -690,6 +690,7 @@ namespace sat {
if (m_out) dump(1, &l, st);
if (m_bout) bdump(1, &l, st);
if (m_check) append(l, st);
if (m_print_clause) m_print_clause(1, &l, st);
}
void drat::add(literal l1, literal l2, status st) {
if (st.is_deleted())
@ -700,6 +701,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_print_clause) m_print_clause(2, ls, st);
}
void drat::add(clause& c, status st) {
if (st.is_deleted())
@ -709,6 +711,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_print_clause) m_print_clause(c.size(), c.begin(), st);
}
void drat::add(literal_vector const& lits, status st) {
@ -729,6 +732,9 @@ namespace sat {
}
if (m_out)
dump(sz, lits, st);
if (m_print_clause)
m_print_clause(sz, lits, st);
}
void drat::add(literal_vector const& c) {
@ -748,6 +754,8 @@ namespace sat {
}
}
}
if (m_print_clause)
m_print_clause(c.size(), c.data(), status::redundant());
}
void drat::del(literal l) {

View file

@ -92,6 +92,8 @@ namespace sat {
bool m_trim = false;
stats m_stats;
std::function<void(unsigned, literal const*, status)> m_print_clause;
void dump_activity();
void dump(unsigned n, literal const* c, status st);
void bdump(unsigned n, literal const* c, status st);
@ -138,6 +140,10 @@ namespace sat {
void add(literal_vector const& c); // add learned clause
void add(unsigned sz, literal const* lits, status st);
void set_print_clause(std::function<void(unsigned, literal const*, status)>& print_clause) {
m_print_clause = print_clause;
}
// 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);

View file

@ -46,6 +46,7 @@ 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'),
('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'),

View file

@ -412,6 +412,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);
@ -420,8 +421,10 @@ 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) {
@ -435,7 +438,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;

View file

@ -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 {

View file

@ -16,6 +16,8 @@ Author:
--*/
#include "sat/smt/euf_solver.h"
#include "ast/ast_util.h"
#include <iostream>
namespace euf {
@ -192,4 +194,23 @@ namespace euf {
get_drat().bool_def(lit.var(), eq->get_id());
}
void solver::log_clause(unsigned n, literal const* lits, sat::status st) {
if (get_config().m_lemmas2console) {
std::function<symbol(int)> ppth = [&](int th) {
return m.get_family_name(th);
};
if (st.is_redundant() || st.is_asserted()) {
expr_ref_vector clause(m);
for (unsigned i = 0; i < n; ++i) {
expr_ref e = literal2expr(lits[i]);
if (!e)
return;
clause.push_back(e);
}
expr_ref cl = mk_or(clause);
std::cout << sat::status_pp(st, ppth) << " " << cl << "\n";
}
}
}
}

View file

@ -169,6 +169,14 @@ namespace euf {
TRACE("before_search", s().display(tout););
for (auto* s : m_solvers)
s->init_search();
if (get_config().m_lemmas2console) {
std::function<void(unsigned, sat::literal const*, sat::status)> on_clause =
[&](unsigned n, sat::literal const* lits, sat::status st) {
log_clause(n, lits, st);
};
get_drat().set_print_clause(on_clause);
}
}
bool solver::is_external(bool_var v) {

View file

@ -182,6 +182,7 @@ namespace euf {
obj_hashtable<ast> m_drat_asts;
bool m_drat_initialized{ false };
void init_drat();
void log_clause(unsigned n, literal const* lits, sat::status st);
// relevancy
//bool_vector m_relevant_expr_ids;

View file

@ -379,9 +379,14 @@ namespace q {
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);
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);
m_qs.add_clause(lits);
}
}
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) {

View file

@ -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;

View file

@ -71,6 +71,7 @@ namespace q {
for (auto const& [qlit, fml, generation] : m_instantiations) {
euf::solver::scoped_generation sg(ctx, generation + 1);
sat::literal lit = ctx.mk_literal(fml);
m_qs.log_instantiation(~qlit, ~lit);
m_qs.add_clause(~qlit, ~lit);
}
m_instantiations.reset();

View file

@ -356,4 +356,7 @@ namespace q {
m_ematch.get_antecedents(l, idx, r, probing);
}
void solver::log_instantiation(unsigned n, sat::literal const* lits) {
TRACE("q", for (unsigned i = 0; i < n; ++i) tout << literal2expr(lits[i]) << "\n";);
}
}

View file

@ -88,5 +88,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) { sat::literal lits[2] = { q, i }; log_instantiation(2, lits); }
void log_instantiation(sat::literal_vector const& lits) { log_instantiation(lits.size(), lits.data()); }
void log_instantiation(unsigned n, sat::literal const* lits);
};
}