From ece5ad90e04cdf09634d7356154828a91928ed17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 20 Jan 2018 17:09:43 -0800 Subject: [PATCH] fix model conversion bugs Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/cmd_context/cmd_context.cpp | 20 ++++----- src/cmd_context/cmd_context.h | 2 +- src/cmd_context/pdecl.cpp | 4 +- src/sat/sat_model_converter.cpp | 40 +++++++++--------- src/sat/sat_model_converter.h | 2 + src/sat/sat_simplifier.cpp | 15 ++++--- src/sat/sat_solver/inc_sat_solver.cpp | 42 +++++++------------ src/tactic/generic_model_converter.cpp | 1 + .../portfolio/bounded_int2bv_solver.cpp | 8 ++-- src/tactic/portfolio/enum2bv_solver.cpp | 6 +-- src/tactic/portfolio/pb2bv_solver.cpp | 16 +++---- 11 files changed, 68 insertions(+), 88 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 0b2decec8..f82f8868d 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1419,7 +1419,9 @@ void cmd_context::restore_assertions(unsigned old_sz) { SASSERT(m_assertions.empty()); return; } - SASSERT(old_sz <= m_assertions.size()); + if (old_sz == m_assertions.size()) + return; + SASSERT(old_sz < m_assertions.size()); SASSERT(!m_interactive_mode || m_assertions.size() == m_assertion_strings.size()); restore(m(), m_assertions, old_sz); if (produce_unsat_cores()) @@ -1520,7 +1522,6 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions } display_sat_result(r); if (r == l_true) { - complete_model(); validate_model(); } validate_check_sat_result(r); @@ -1528,9 +1529,8 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions // get_opt()->display_assignment(regular_stream()); } - if (r == l_true && m_params.m_dump_models) { - model_ref md; - get_check_sat_result()->get_model(md); + model_ref md; + if (r == l_true && m_params.m_dump_models && is_model_available(md)) { display_model(md); } } @@ -1695,14 +1695,10 @@ struct contains_underspecified_op_proc { /** \brief Complete the model if necessary. */ -void cmd_context::complete_model() { - model_ref md; - if (!is_model_available(md) || - gparams::get_value("model.completion") != "true") +void cmd_context::complete_model(model_ref& md) const { + if (gparams::get_value("model.completion") != "true" || !md.get()) return; - get_check_sat_result()->get_model(md); - SASSERT(md.get() != 0); params_ref p; p.set_uint("max_degree", UINT_MAX); // evaluate algebraic numbers of any degree. p.set_uint("sort_store", true); @@ -1770,7 +1766,6 @@ void cmd_context::validate_model() { return; if (!is_model_available(md)) return; - get_check_sat_result()->get_model(md); SASSERT(md.get() != 0); params_ref p; p.set_uint("max_degree", UINT_MAX); // evaluate algebraic numbers of any degree. @@ -1902,6 +1897,7 @@ bool cmd_context::is_model_available(model_ref& md) const { has_manager() && (cs_state() == css_sat || cs_state() == css_unknown)) { get_check_sat_result()->get_model(md); + complete_model(md); return md.get() != 0; } return false; diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index dc85ad2e0..253384f35 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -365,7 +365,7 @@ public: void set_check_sat_result(check_sat_result * r) { m_check_sat_result = r; } check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); } check_sat_state cs_state() const; - void complete_model(); + void complete_model(model_ref& mdl) const; void validate_model(); void display_model(model_ref& mdl); diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 7a85e87a2..51220b1d0 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "cmd_context/pdecl.h" #include "ast/datatype_decl_plugin.h" +#include <sstream> using namespace format_ns; class psort_inst_cache { @@ -866,8 +867,6 @@ psort * pdecl_manager::mk_psort_cnst(sort * s) { } psort * pdecl_manager::register_psort(psort * n) { - enable_trace("register_psort"); - TRACE("register_psort", tout << "registering psort...\n"; n->display(tout); tout << "\n";); psort * r = m_table.insert_if_not_there(n); if (r != n) { del_decl_core(n); @@ -947,7 +946,6 @@ void pdecl_manager::del_decl_core(pdecl * p) { } void pdecl_manager::del_decl(pdecl * p) { -enable_trace("register_psort"); TRACE("register_psort", tout << "del psort "; p->display(tout); tout << "\n";); if (p->is_psort()) { psort * _p = static_cast<psort*>(p); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index ce059a07b..7a2b4f5f4 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -347,6 +347,17 @@ namespace sat { return result; } + void model_converter::swap(bool_var v, unsigned sz, literal_vector& clause) { + for (unsigned j = 0; j < sz; ++j) { + if (v == clause[j].var()) { + std::swap(clause[0], clause[j]); + return; + } + } + IF_VERBOSE(0, verbose_stream() << "not found: v" << v << " " << clause << "\n";); + UNREACHABLE(); + } + void model_converter::expand(literal_vector& update_stack) { sat::literal_vector clause; for (entry const& e : m_entries) { @@ -357,34 +368,23 @@ namespace sat { if (l == null_literal) { elim_stack* st = e.m_elim_stack[index]; if (st) { - // clause sizes increase - elim_stackv const& stack = st->stack(); - unsigned sz = stack.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned csz = stack[i].first; - literal lit = stack[i].second; - BOOL found = false; - unsigned j = 0; - for (j = 0; j < csz; ++j) { - if (clause[j] == lit) { - std::swap(clause[j], clause[0]); - found = true; - break; - } - } - SASSERT(found); + // clause sizes increase, so we can always swap + // the blocked literal to the front from the prefix. + for (auto const& p : st->stack()) { + unsigned csz = p.first; + literal lit = p.second; + swap(lit.var(), csz, clause); update_stack.append(csz, clause.c_ptr()); update_stack.push_back(null_literal); } } + swap(e.var(), clause.size(), clause); update_stack.append(clause); update_stack.push_back(null_literal); clause.reset(); - continue; } - clause.push_back(l); - if (l.var() == e.var()) { - std::swap(clause[0], clause.back()); + else { + clause.push_back(l); } } } diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index 88fdfe5b7..be7d03188 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -94,6 +94,8 @@ namespace sat { bool legal_to_flip(bool_var v) const; + void swap(bool_var v, unsigned sz, literal_vector& clause); + public: model_converter(); ~model_converter(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b983a0da3..66e0baa89 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -231,7 +231,7 @@ namespace sat { if (bce_enabled() || abce_enabled() || bca_enabled()) { elim_blocked_clauses(); } - si.check_watches(); + if (!m_need_cleanup) si.check_watches(); if (!learned) { m_num_calls++; @@ -680,7 +680,7 @@ namespace sat { } void simplifier::elim_lit(clause & c, literal l) { - TRACE("elim_lit", tout << "processing: " << c << "\n";); + TRACE("elim_lit", tout << "processing: " << l << " @ " << c << "\n";); m_need_cleanup = true; m_num_elim_lits++; insert_elim_todo(l.var()); @@ -979,23 +979,23 @@ namespace sat { void operator()() { integrity_checker si(s.s); - si.check_watches(); + //si.check_watches(); if (s.bce_enabled()) { block_clauses(); } - si.check_watches(); + //si.check_watches(); if (s.abce_enabled()) { cce<false>(); } - si.check_watches(); + //si.check_watches(); if (s.cce_enabled()) { cce<true>(); } - si.check_watches(); + //si.check_watches(); if (s.bca_enabled()) { bca(); } - si.check_watches(); + //si.check_watches(); } void block_clauses() { @@ -1829,7 +1829,6 @@ namespace sat { return true; } } - return true; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0ad665c5e..03f6e6d0b 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -54,7 +54,6 @@ class inc_sat_solver : public solver { unsigned m_fmls_head; expr_ref_vector m_core; atom2bool_var m_map; - model_ref m_model; scoped_ptr<bit_blaster_rewriter> m_bb_rewriter; tactic_ref m_preprocess; unsigned m_num_scopes; @@ -183,7 +182,6 @@ public: TRACE("sat", tout << _assumptions << "\n";); dep2asm_t dep2asm; - m_model = 0; lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(sz, _assumptions.c_ptr(), dep2asm); @@ -289,12 +287,6 @@ public: r.reset(); r.append(m_core.size(), m_core.c_ptr()); } - virtual void get_model_core(model_ref & mdl) { - if (!m_model.get()) { - extract_model(); - } - mdl = m_model; - } virtual proof * get_proof() { UNREACHABLE(); return 0; @@ -302,7 +294,6 @@ public: virtual expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) { if (!is_internalized()) { - m_model = 0; lbool r = internalize_formulas(); if (r != l_true) return expr_ref_vector(m); } @@ -789,14 +780,14 @@ private: } } - void extract_model() { + virtual void get_model_core(model_ref & mdl) { TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); if (!m_solver.model_is_current()) { - m_model = 0; + mdl = nullptr; return; } sat::model const & ll_m = m_solver.get_model(); - model_ref md = alloc(model, m); + mdl = alloc(model, m); for (auto const& kv : m_map) { expr * n = kv.m_key; if (is_app(n) && to_app(n)->get_num_args() > 0) { @@ -805,40 +796,39 @@ private: sat::bool_var v = kv.m_value; switch (sat::value_at(v, ll_m)) { case l_true: - md->register_decl(to_app(n)->get_decl(), m.mk_true()); + mdl->register_decl(to_app(n)->get_decl(), m.mk_true()); break; case l_false: - md->register_decl(to_app(n)->get_decl(), m.mk_false()); + mdl->register_decl(to_app(n)->get_decl(), m.mk_false()); break; default: break; } } - m_model = md; - //IF_VERBOSE(0, model_v2_pp(verbose_stream(), *m_model, true);); + //IF_VERBOSE(0, model_v2_pp(verbose_stream(), *mdl, true);); if (m_sat_mc) { - // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n");); - (*m_sat_mc)(m_model); + //IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n");); + (*m_sat_mc)(mdl); } insert_const2bits(); if (m_mc0) { - // IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n");); - (*m_mc0)(m_model); + //IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n");); + (*m_mc0)(mdl); } - TRACE("sat", model_smt2_pp(tout, m, *m_model, 0);); + TRACE("sat", model_smt2_pp(tout, m, *mdl, 0);); + + // IF_VERBOSE(0, model_smt2_pp(verbose_stream() << "after\n", m, *mdl, 0);); - // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "after\n");); - -#if 1 +#if 0 IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); - model_evaluator eval(*m_model); + model_evaluator eval(*mdl); for (expr * f : m_fmls) { expr_ref tmp(m); eval(f, tmp); CTRACE("sat", !m.is_true(tmp), tout << "Evaluation failed: " << mk_pp(f, m) << " to " << mk_pp(f, m) << "\n"; - model_smt2_pp(tout, m, *(m_model.get()), 0);); + model_smt2_pp(tout, m, *(mdl.get()), 0);); if (!m.is_true(tmp)) { IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n";); IF_VERBOSE(0, verbose_stream() << m_params << "\n";); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 139355d5f..485682858 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -38,6 +38,7 @@ void generic_model_converter::add(func_decl * d, expr* e) { void generic_model_converter::operator()(model_ref & md) { TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); + // IF_VERBOSE(0, verbose_stream() << "Apply converter " << m_orig << "\n";); model_evaluator ev(*(md.get())); ev.set_model_completion(true); ev.set_expand_array_equalities(false); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index ee6630fd3..7d198468c 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -152,14 +152,14 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - model_converter_ref mc = bounded_model_converter(); + model_converter_ref mc = local_model_converter(); if (mc) (*mc)(mdl); } } model_converter* external_model_converter() const { - return concat(mc0(), bounded_model_converter()); + return concat(mc0(), local_model_converter()); } - model_converter* bounded_model_converter() const { + model_converter* local_model_converter() const { if (m_int2bv.empty() && m_bv_fns.empty()) return nullptr; generic_model_converter* mc = alloc(generic_model_converter, m, "bounded_int2bv"); for (func_decl* f : m_bv_fns) @@ -178,7 +178,7 @@ public: } virtual model_converter_ref get_model_converter() const { - model_converter_ref mc = concat(mc0(), bounded_model_converter()); + model_converter_ref mc = external_model_converter(); mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 9567f369f..527d9aeb3 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -92,11 +92,11 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - model_converter_ref mc = enum_model_converter(); + model_converter_ref mc = local_model_converter(); if (mc) (*mc)(mdl); } } - model_converter* enum_model_converter() const { + model_converter* local_model_converter() const { if (m_rewriter.enum2def().empty() && m_rewriter.enum2bv().empty()) { return nullptr; @@ -110,7 +110,7 @@ public: } model_converter* external_model_converter() const { - return concat(mc0(), enum_model_converter()); + return concat(mc0(), local_model_converter()); } virtual model_converter_ref get_model_converter() const { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 6660e1bb4..14e58a637 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -91,14 +91,15 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - filter_model(mdl); + model_converter_ref mc = local_model_converter(); + if (mc) (*mc)(mdl); } } model_converter* external_model_converter() const { - return concat(mc0(), filter_model_converter()); + return concat(mc0(), local_model_converter()); } virtual model_converter_ref get_model_converter() const { - model_converter_ref mc = concat(mc0(), filter_model_converter()); + model_converter_ref mc = external_model_converter(); mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } @@ -113,7 +114,7 @@ public: flush_assertions(); return m_solver->get_consequences(asms, vars, consequences); } - model_converter* filter_model_converter() const { + model_converter* local_model_converter() const { if (m_rewriter.fresh_constants().empty()) { return nullptr; } @@ -125,13 +126,6 @@ public: return filter; } - void filter_model(model_ref& mdl) { - model_converter_ref mc = filter_model_converter(); - if (mc.get()) { - (*mc)(mdl); - } - } - virtual unsigned get_num_assertions() const { flush_assertions(); return m_solver->get_num_assertions();