From e423fabf6a8808c36d906cdd62dda9c90773992d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Dec 2022 20:35:36 -0800 Subject: [PATCH] tactic Signed-off-by: Nikolaj Bjorner --- doc/mk_tactic_doc.py | 10 +- src/tactic/bv/bv_bounds_tactic.cpp | 165 +++++++++++--------------- src/tactic/bv/bv_bounds_tactic.h | 27 ++++- src/tactic/bv/bvarray2uf_tactic.h | 26 ++-- src/tactic/bv/dt2bv_tactic.h | 23 +++- src/tactic/bv/elim_small_bv_tactic.h | 16 +++ src/tactic/bv/max_bv_sharing_tactic.h | 20 +++- 7 files changed, 170 insertions(+), 117 deletions(-) diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py index e4c71341a..6f4837cdd 100644 --- a/doc/mk_tactic_doc.py +++ b/doc/mk_tactic_doc.py @@ -53,13 +53,21 @@ def extract_tactic_doc(ous, f): if is_doc.search(line): generate_tactic_doc(ous, f, ins) +def find_tactic_name(path): + with open(path) as ins: + for line in ins: + m = is_tac_name.search(line) + if m: + return m.group(1) + return "" + def presort_files(): tac_files = [] for root, dirs, files in os.walk(doc_path("../src")): for f in files: if f.endswith("tactic.h"): tac_files += [(f, os.path.join(root, f))] - tac_files = sorted(tac_files, key = lambda x: x[0]) + tac_files = sorted(tac_files, key = lambda x: find_tactic_name(x[1])) return tac_files def help(ous): diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index 72f0266c1..58183287d 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -35,11 +35,12 @@ namespace { struct interval { // l < h: [l, h] // l > h: [0, h] U [l, UMAX_INT] - uint64_t l, h; - unsigned sz; - bool tight; + uint64_t l = 0, h = 0; + unsigned sz = 0; + bool tight = true; interval() {} + interval(uint64_t l, uint64_t h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { // canonicalize full set if (is_wrapped() && l == h + 1) { @@ -50,8 +51,7 @@ namespace { } bool invariant() const { - return l <= uMaxInt(sz) && h <= uMaxInt(sz) && - (!is_wrapped() || l != h+1); + return l <= uMaxInt(sz) && h <= uMaxInt(sz) && (!is_wrapped() || l != h+1); } bool is_full() const { return l == 0 && h == uMaxInt(sz); } @@ -67,22 +67,17 @@ namespace { bool implies(const interval& b) const { if (b.is_full()) return true; - if (is_full()) + else if (is_full()) return false; - - if (is_wrapped()) { + else if (is_wrapped()) // l >= b.l >= b.h >= h - return b.is_wrapped() && h <= b.h && l >= b.l; - } - else if (b.is_wrapped()) { + return b.is_wrapped() && h <= b.h && l >= b.l; + else if (b.is_wrapped()) // b.l > b.h >= h >= l // h >= l >= b.l > b.h - return h <= b.h || l >= b.l; - } - else { - // - return l >= b.l && h <= b.h; - } + return h <= b.h || l >= b.l; + else + return l >= b.l && h <= b.h; } /// return false if intersection is unsat @@ -98,28 +93,26 @@ namespace { if (is_wrapped()) { if (b.is_wrapped()) { - if (h >= b.l) { + if (h >= b.l) result = b; - } else if (b.h >= l) { + else if (b.h >= l) result = *this; - } else { + else result = interval(std::max(l, b.l), std::min(h, b.h), sz); - } - } else { - return b.intersect(*this, result); } + else + return b.intersect(*this, result); } else if (b.is_wrapped()) { // ... b.h ... l ... h ... b.l .. - if (h < b.l && l > b.h) { - return false; - } + if (h < b.l && l > b.h) + return false; // ... l ... b.l ... h ... - if (h >= b.l && l <= b.h) { + if (h >= b.l && l <= b.h) result = b; - } else if (h >= b.l) { + else if (h >= b.l) result = interval(b.l, h, sz); - } else { + else { // ... l .. b.h .. h .. b.l ... SASSERT(l <= b.h); result = interval(l, std::min(h, b.h), sz); @@ -136,20 +129,16 @@ namespace { /// return false if negation is empty bool negate(interval& result) const { - if (!tight) { + if (!tight) result = interval(0, uMaxInt(sz), true); - return true; - } - - if (is_full()) + else if (is_full()) return false; - if (l == 0) { + else if (l == 0) result = interval(h + 1, uMaxInt(sz), sz); - } else if (uMaxInt(sz) == h) { + else if (uMaxInt(sz) == h) result = interval(0, l - 1, sz); - } else { - result = interval(h + 1, l - 1, sz); - } + else + result = interval(h + 1, l - 1, sz); return true; } }; @@ -163,9 +152,9 @@ namespace { struct undo_bound { - expr* e { nullptr }; + expr* e = nullptr; interval b; - bool fresh { false }; + bool fresh = false; undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {} }; @@ -176,7 +165,7 @@ namespace { ast_manager& m; params_ref m_params; - bool m_propagate_eq; + bool m_propagate_eq = false; bv_util m_bv; vector m_scopes; map m_bound; @@ -224,7 +213,8 @@ namespace { v = lhs; return true; } - } else if (m.is_eq(e, lhs, rhs)) { + } + else if (m.is_eq(e, lhs, rhs)) { if (is_number(lhs, n, sz)) { if (m_bv.is_numeral(rhs)) return false; @@ -252,7 +242,7 @@ namespace { } static void get_param_descrs(param_descrs& r) { - r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); + r.insert("propagate-eq", CPK_BOOL, "propagate equalities from inequalities", "false"); } ~bv_bounds_simplifier() override { @@ -546,22 +536,19 @@ namespace { } static void get_param_descrs(param_descrs& r) { - r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); + r.insert("propagate-eq", CPK_BOOL, "propagate equalities from inequalities", "false"); } ~dom_bv_bounds_simplifier() override { - for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { - dealloc(m_expr_vars[i]); - } - for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { - dealloc(m_bound_exprs[i]); - } + for (auto* e : m_expr_vars) + dealloc(e); + for (auto* b : m_bound_exprs) + dealloc(b); } bool assert_expr(expr * t, bool sign) override { - while (m.is_not(t, t)) { - sign = !sign; - } + while (m.is_not(t, t)) + sign = !sign; interval b; expr* t1; @@ -581,7 +568,8 @@ namespace { return true; m_scopes.push_back(undo_bound(t1, old, false)); old = intr; - } else { + } + else { m_bound.insert(t1, b); m_scopes.push_back(undo_bound(t1, interval(), true)); } @@ -602,9 +590,8 @@ namespace { return; bool sign = false; - while (m.is_not(t, t)) { - sign = !sign; - } + while (m.is_not(t, t)) + sign = !sign; if (!is_bound(t, t1, b)) return; @@ -619,27 +606,21 @@ namespace { interval ctx, intr; bool was_updated = true; - if (b.is_full() && b.tight) { - r = m.mk_true(); - } + if (b.is_full() && b.tight) + r = m.mk_true(); else if (m_bound.find(t1, ctx)) { - if (ctx.implies(b)) { - r = m.mk_true(); - } - else if (!b.intersect(ctx, intr)) { - r = m.mk_false(); - } - else if (m_propagate_eq && intr.is_singleton()) { + if (ctx.implies(b)) + r = m.mk_true(); + else if (!b.intersect(ctx, intr)) + r = m.mk_false(); + else if (m_propagate_eq && intr.is_singleton()) r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), - t1->get_sort())); - } - else { - was_updated = false; - } - } - else { - was_updated = false; + t1->get_sort())); + else + was_updated = false; } + else + was_updated = false; TRACE("bv", tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";); if (sign && was_updated) @@ -654,18 +635,16 @@ namespace { while (!todo.empty()) { t = todo.back(); todo.pop_back(); - if (mark.is_marked(t)) { - continue; - } + if (mark.is_marked(t)) + continue; if (t == v) { todo.reset(); return true; } mark.mark(t); - if (!is_app(t)) { - continue; - } + if (!is_app(t)) + continue; app* a = to_app(t); todo.append(a->get_num_args(), a->get_args()); } @@ -680,14 +659,11 @@ namespace { while (!todo.empty()) { t = todo.back(); todo.pop_back(); - if (mark1.is_marked(t)) { - continue; - } - mark1.mark(t); - - if (!is_app(t)) { - continue; - } + if (mark1.is_marked(t)) + continue; + mark1.mark(t); + if (!is_app(t)) + continue; interval b; expr* e; if (is_bound(t, e, b)) { @@ -718,14 +694,13 @@ namespace { m_scopes.reset(); return; } - for (unsigned i = m_scopes.size()-1; i >= target; --i) { + for (unsigned i = m_scopes.size(); i-- > target; ) { undo_bound& undo = m_scopes[i]; SASSERT(m_bound.contains(undo.e)); - if (undo.fresh) { + if (undo.fresh) m_bound.erase(undo.e); - } else { - m_bound.insert(undo.e, undo.b); - } + else + m_bound.insert(undo.e, undo.b); } m_scopes.shrink(target); } diff --git a/src/tactic/bv/bv_bounds_tactic.h b/src/tactic/bv/bv_bounds_tactic.h index 58de42199..325cca89e 100644 --- a/src/tactic/bv/bv_bounds_tactic.h +++ b/src/tactic/bv/bv_bounds_tactic.h @@ -5,15 +5,34 @@ Module Name: bv_bounds_tactic.h -Abstract: - - Contextual bounds simplification tactic. - Author: Nuno Lopes (nlopes) 2016-2-12 Nikolaj Bjorner (nbjorner) +Tactic Documentation: + +## Tactic propagate-bv-bounds + +### Short Description + +Contextual bounds simplification tactic. + +### Example + +```z3 +(declare-const x (_ BitVec 32)) +(declare-const y (_ BitVec 32)) +(declare-const z (_ BitVec 32)) +(assert (bvule (_ bv4 32) x)) +(assert (bvule x (_ bv24 32))) +(assert (or (bvule x (_ bv100 32)) (bvule (_ bv32 32) x))) +(apply propagate-bv-bounds) +``` + +### Notes + +* assumes that bit-vector inequalities have been simplified to use bvule/bvsle --*/ #pragma once diff --git a/src/tactic/bv/bvarray2uf_tactic.h b/src/tactic/bv/bvarray2uf_tactic.h index a22a78f86..393ab164c 100644 --- a/src/tactic/bv/bvarray2uf_tactic.h +++ b/src/tactic/bv/bvarray2uf_tactic.h @@ -3,18 +3,30 @@ Copyright (c) 2015 Microsoft Corporation Module Name: - bvarray2ufbvarray2uf_tactic.h - -Abstract: - - Tactic that rewrites bit-vector arrays into bit-vector - (uninterpreted) functions. + bvarray2uf_tactic.h Author: Christoph (cwinter) 2015-11-04 -Notes: +Tactic Documentation: + +## Tactic bvarray2uf + +### Short Description + +Tactic that rewrites bit-vector arrays into bit-vector +(uninterpreted) functions. + +### Example + +```z3 +(declare-const a (Array (_ BitVec 32) (_ BitVec 32))) +(declare-const b (_ BitVec 32)) +(declare-const c (_ BitVec 32)) +(assert (= (select a b) c)) +(apply bvarray2uf) +``` --*/ #pragma once diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index 906386ed4..05713dfd6 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -5,15 +5,28 @@ Module Name: dt2bv_tactic.h -Abstract: - - Tactic that eliminates finite domain data-types. - Author: nbjorner 2016-07-22 -Revision History: +Tactic Documentation + +## Tactic dt2bv + +### Short Description + +Tactic that eliminates finite domain data-types. + +### Example + +```z3 +(declare-datatypes ((Color 0)) (((Red) (Blue) (Green) (DarkBlue) (MetallicBlack) (MetallicSilver) (Silver) (Black)))) +(declare-const x Color) +(declare-const y Color) +(assert (not (= x y))) +(assert (not (= x Red))) +(apply dt2bv) +``` --*/ #pragma once diff --git a/src/tactic/bv/elim_small_bv_tactic.h b/src/tactic/bv/elim_small_bv_tactic.h index e4a91f70f..46e6dca39 100644 --- a/src/tactic/bv/elim_small_bv_tactic.h +++ b/src/tactic/bv/elim_small_bv_tactic.h @@ -15,6 +15,22 @@ Author: Revision History: +Tactic Documentation + +## Tactic elim-small-bv + +### Short Description + +Eliminate small, quantified bit-vectors by expansion + +### Example + +```z3 +(declare-fun p ((_ BitVec 2)) Bool) +(assert (forall ((x (_ BitVec 2))) (p x))) +(apply elim-small-bv) +``` + --*/ #pragma once diff --git a/src/tactic/bv/max_bv_sharing_tactic.h b/src/tactic/bv/max_bv_sharing_tactic.h index bf14e9f14..2f21ee4b9 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.h +++ b/src/tactic/bv/max_bv_sharing_tactic.h @@ -7,16 +7,26 @@ Module Name: Abstract: - Rewriter for "maximing" the number of shared terms. - The idea is to rewrite AC terms to maximize sharing. - This rewriter is particularly useful for reducing - the number of Adders and Multipliers before "bit-blasting". + Author: Leonardo de Moura (leonardo) 2011-12-29. -Revision History: +Tactic Documentation + +## Tactic max-bv-sharing + +### Short Description + +Use heuristics to maximize the sharing of bit-vector expressions such as adders and multipliers + +### Long Description + +Rewriter for "maximing" the number of shared terms. +The idea is to rewrite AC terms to maximize sharing. +This rewriter is particularly useful for reducing +the number of Adders and Multipliers before "bit-blasting". --*/ #pragma once