/*++ Copyright (c) 2011 Microsoft Corporation Module Name: bit_blaster_tactic.cpp Abstract: Apply bit-blasting to a given goal Author: Leonardo (leonardo) 2011-10-25 Notes: --*/ #include "tactic/tactical.h" #include "tactic/bv/bit_blaster_model_converter.h" #include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" #include "ast/ast_pp.h" #include "model/model_pp.h" #include "ast/rewriter/rewriter_types.h" class bit_blaster_tactic : public tactic { struct imp { bit_blaster_rewriter m_base_rewriter; bit_blaster_rewriter* m_rewriter; unsigned m_num_steps; bool m_blast_quant; imp(ast_manager & m, bit_blaster_rewriter* rw, params_ref const & p): m_base_rewriter(m, p), m_rewriter(rw?rw:&m_base_rewriter) { updt_params(p); } void updt_params_core(params_ref const & p) { m_blast_quant = p.get_bool("blast_quant", false); } void updt_params(params_ref const & p) { m_rewriter->updt_params(p); updt_params_core(p); } ast_manager & m() const { return m_rewriter->m(); } void operator()(goal_ref const & g, goal_ref_buffer & result) { bool proofs_enabled = g->proofs_enabled(); if (proofs_enabled && m_blast_quant) throw tactic_exception("quantified variable blasting does not support proof generation"); tactic_report report("bit-blast", *g); TRACE(before_bit_blaster, g->display(tout);); m_num_steps = 0; m_rewriter->start_rewrite(); expr_ref new_curr(m()); proof_ref new_pr(m()); unsigned size = g->size(); bool change = false; for (unsigned idx = 0; idx < size; idx++) { if (g->inconsistent()) break; expr * curr = g->form(idx); (*m_rewriter)(curr, new_curr, new_pr); m_num_steps += m_rewriter->get_num_steps(); if (proofs_enabled) { proof * pr = g->pr(idx); new_pr = m().mk_modus_ponens(pr, new_pr); } if (curr != new_curr) { change = true; TRACE(bit_blaster, tout << mk_pp(curr, m()) << " -> " << new_curr << "\n";); g->update(idx, new_curr, new_pr, g->dep(idx)); } } if (change && g->models_enabled()) { obj_map const2bits; ptr_vector newbits; m_rewriter->end_rewrite(const2bits, newbits); g->add(mk_bit_blaster_model_converter(m(), const2bits, newbits)); } g->inc_depth(); result.push_back(g.get()); TRACE(after_bit_blaster, g->display(tout); if (g->mc()) g->mc()->display(tout); tout << "\n";); m_rewriter->cleanup(); } unsigned get_num_steps() const { return m_num_steps; } }; imp * m_imp; bit_blaster_rewriter* m_rewriter; params_ref m_params; public: bit_blaster_tactic(ast_manager & m, bit_blaster_rewriter* rw, params_ref const & p): m_rewriter(rw), m_params(p) { m_imp = alloc(imp, m, m_rewriter, p); } tactic * translate(ast_manager & m) override { SASSERT(!m_rewriter); // assume translation isn't used where rewriter is external. return alloc(bit_blaster_tactic, m, nullptr, m_params); } ~bit_blaster_tactic() override { dealloc(m_imp); } char const* name() const override { return "bit_blaster"; } void updt_params(params_ref const & p) override { m_params.append(p); m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); r.insert("blast_mul", CPK_BOOL, "bit-blast multipliers (and dividers, remainders).", "true"); r.insert("blast_add", CPK_BOOL, "bit-blast adders.", "true"); r.insert("blast_quant", CPK_BOOL, "bit-blast quantified variables.", "false"); r.insert("blast_full", CPK_BOOL, "bit-blast any term with bit-vector sort, this option will make E-matching ineffective in any pattern containing bit-vector terms.", "false"); } void operator()(goal_ref const & g, goal_ref_buffer & result) override { try { (*m_imp)(g, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.what()); } } void cleanup() override { imp * d = alloc(imp, m_imp->m(), m_rewriter, m_params); std::swap(d, m_imp); dealloc(d); } unsigned get_num_steps() const { return m_imp->get_num_steps(); } }; tactic * mk_bit_blaster_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(bit_blaster_tactic, m, nullptr, p)); } tactic * mk_bit_blaster_tactic(ast_manager & m, bit_blaster_rewriter* rw, params_ref const & p) { return clean(alloc(bit_blaster_tactic, m, rw, p)); }