3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 13:28:47 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2022-12-15 20:35:36 -08:00
parent 0768a2ead1
commit e423fabf6a
7 changed files with 170 additions and 117 deletions

View file

@ -53,13 +53,21 @@ def extract_tactic_doc(ous, f):
if is_doc.search(line): if is_doc.search(line):
generate_tactic_doc(ous, f, ins) 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(): def presort_files():
tac_files = [] tac_files = []
for root, dirs, files in os.walk(doc_path("../src")): for root, dirs, files in os.walk(doc_path("../src")):
for f in files: for f in files:
if f.endswith("tactic.h"): if f.endswith("tactic.h"):
tac_files += [(f, os.path.join(root, f))] 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 return tac_files
def help(ous): def help(ous):

View file

@ -35,11 +35,12 @@ namespace {
struct interval { struct interval {
// l < h: [l, h] // l < h: [l, h]
// l > h: [0, h] U [l, UMAX_INT] // l > h: [0, h] U [l, UMAX_INT]
uint64_t l, h; uint64_t l = 0, h = 0;
unsigned sz; unsigned sz = 0;
bool tight; bool tight = true;
interval() {} interval() {}
interval(uint64_t l, uint64_t h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { interval(uint64_t l, uint64_t h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) {
// canonicalize full set // canonicalize full set
if (is_wrapped() && l == h + 1) { if (is_wrapped() && l == h + 1) {
@ -50,8 +51,7 @@ namespace {
} }
bool invariant() const { bool invariant() const {
return l <= uMaxInt(sz) && h <= uMaxInt(sz) && return l <= uMaxInt(sz) && h <= uMaxInt(sz) && (!is_wrapped() || l != h+1);
(!is_wrapped() || l != h+1);
} }
bool is_full() const { return l == 0 && h == uMaxInt(sz); } bool is_full() const { return l == 0 && h == uMaxInt(sz); }
@ -67,23 +67,18 @@ namespace {
bool implies(const interval& b) const { bool implies(const interval& b) const {
if (b.is_full()) if (b.is_full())
return true; return true;
if (is_full()) else if (is_full())
return false; return false;
else if (is_wrapped())
if (is_wrapped()) {
// l >= b.l >= b.h >= h // l >= b.l >= b.h >= h
return b.is_wrapped() && h <= b.h && l >= b.l; return b.is_wrapped() && h <= b.h && l >= b.l;
} else if (b.is_wrapped())
else if (b.is_wrapped()) {
// b.l > b.h >= h >= l // b.l > b.h >= h >= l
// h >= l >= b.l > b.h // h >= l >= b.l > b.h
return h <= b.h || l >= b.l; return h <= b.h || l >= b.l;
} else
else {
//
return l >= b.l && h <= b.h; return l >= b.l && h <= b.h;
} }
}
/// return false if intersection is unsat /// return false if intersection is unsat
bool intersect(const interval& b, interval& result) const { bool intersect(const interval& b, interval& result) const {
@ -98,28 +93,26 @@ namespace {
if (is_wrapped()) { if (is_wrapped()) {
if (b.is_wrapped()) { if (b.is_wrapped()) {
if (h >= b.l) { if (h >= b.l)
result = b; result = b;
} else if (b.h >= l) { else if (b.h >= l)
result = *this; result = *this;
} else { else
result = interval(std::max(l, b.l), std::min(h, b.h), sz); result = interval(std::max(l, b.l), std::min(h, b.h), sz);
} }
} else { else
return b.intersect(*this, result); return b.intersect(*this, result);
} }
}
else if (b.is_wrapped()) { else if (b.is_wrapped()) {
// ... b.h ... l ... h ... b.l .. // ... b.h ... l ... h ... b.l ..
if (h < b.l && l > b.h) { if (h < b.l && l > b.h)
return false; return false;
}
// ... l ... b.l ... h ... // ... l ... b.l ... h ...
if (h >= b.l && l <= b.h) { if (h >= b.l && l <= b.h)
result = b; result = b;
} else if (h >= b.l) { else if (h >= b.l)
result = interval(b.l, h, sz); result = interval(b.l, h, sz);
} else { else {
// ... l .. b.h .. h .. b.l ... // ... l .. b.h .. h .. b.l ...
SASSERT(l <= b.h); SASSERT(l <= b.h);
result = interval(l, std::min(h, b.h), sz); result = interval(l, std::min(h, b.h), sz);
@ -136,20 +129,16 @@ namespace {
/// return false if negation is empty /// return false if negation is empty
bool negate(interval& result) const { bool negate(interval& result) const {
if (!tight) { if (!tight)
result = interval(0, uMaxInt(sz), true); result = interval(0, uMaxInt(sz), true);
return true; else if (is_full())
}
if (is_full())
return false; return false;
if (l == 0) { else if (l == 0)
result = interval(h + 1, uMaxInt(sz), sz); result = interval(h + 1, uMaxInt(sz), sz);
} else if (uMaxInt(sz) == h) { else if (uMaxInt(sz) == h)
result = interval(0, l - 1, sz); result = interval(0, l - 1, sz);
} else { else
result = interval(h + 1, l - 1, sz); result = interval(h + 1, l - 1, sz);
}
return true; return true;
} }
}; };
@ -163,9 +152,9 @@ namespace {
struct undo_bound { struct undo_bound {
expr* e { nullptr }; expr* e = nullptr;
interval b; interval b;
bool fresh { false }; bool fresh = false;
undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {} undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {}
}; };
@ -176,7 +165,7 @@ namespace {
ast_manager& m; ast_manager& m;
params_ref m_params; params_ref m_params;
bool m_propagate_eq; bool m_propagate_eq = false;
bv_util m_bv; bv_util m_bv;
vector<undo_bound> m_scopes; vector<undo_bound> m_scopes;
map m_bound; map m_bound;
@ -224,7 +213,8 @@ namespace {
v = lhs; v = lhs;
return true; 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 (is_number(lhs, n, sz)) {
if (m_bv.is_numeral(rhs)) if (m_bv.is_numeral(rhs))
return false; return false;
@ -252,7 +242,7 @@ namespace {
} }
static void get_param_descrs(param_descrs& r) { 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 { ~bv_bounds_simplifier() override {
@ -546,22 +536,19 @@ namespace {
} }
static void get_param_descrs(param_descrs& r) { 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 { ~dom_bv_bounds_simplifier() override {
for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { for (auto* e : m_expr_vars)
dealloc(m_expr_vars[i]); dealloc(e);
} for (auto* b : m_bound_exprs)
for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { dealloc(b);
dealloc(m_bound_exprs[i]);
}
} }
bool assert_expr(expr * t, bool sign) override { bool assert_expr(expr * t, bool sign) override {
while (m.is_not(t, t)) { while (m.is_not(t, t))
sign = !sign; sign = !sign;
}
interval b; interval b;
expr* t1; expr* t1;
@ -581,7 +568,8 @@ namespace {
return true; return true;
m_scopes.push_back(undo_bound(t1, old, false)); m_scopes.push_back(undo_bound(t1, old, false));
old = intr; old = intr;
} else { }
else {
m_bound.insert(t1, b); m_bound.insert(t1, b);
m_scopes.push_back(undo_bound(t1, interval(), true)); m_scopes.push_back(undo_bound(t1, interval(), true));
} }
@ -602,9 +590,8 @@ namespace {
return; return;
bool sign = false; bool sign = false;
while (m.is_not(t, t)) { while (m.is_not(t, t))
sign = !sign; sign = !sign;
}
if (!is_bound(t, t1, b)) if (!is_bound(t, t1, b))
return; return;
@ -619,27 +606,21 @@ namespace {
interval ctx, intr; interval ctx, intr;
bool was_updated = true; bool was_updated = true;
if (b.is_full() && b.tight) { if (b.is_full() && b.tight)
r = m.mk_true(); r = m.mk_true();
}
else if (m_bound.find(t1, ctx)) { else if (m_bound.find(t1, ctx)) {
if (ctx.implies(b)) { if (ctx.implies(b))
r = m.mk_true(); r = m.mk_true();
} else if (!b.intersect(ctx, intr))
else if (!b.intersect(ctx, intr)) {
r = m.mk_false(); r = m.mk_false();
} else if (m_propagate_eq && intr.is_singleton())
else if (m_propagate_eq && intr.is_singleton()) {
r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()),
t1->get_sort())); t1->get_sort()));
} else
else {
was_updated = false; was_updated = false;
} }
} else
else {
was_updated = false; was_updated = false;
}
TRACE("bv", tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";); TRACE("bv", tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";);
if (sign && was_updated) if (sign && was_updated)
@ -654,18 +635,16 @@ namespace {
while (!todo.empty()) { while (!todo.empty()) {
t = todo.back(); t = todo.back();
todo.pop_back(); todo.pop_back();
if (mark.is_marked(t)) { if (mark.is_marked(t))
continue; continue;
}
if (t == v) { if (t == v) {
todo.reset(); todo.reset();
return true; return true;
} }
mark.mark(t); mark.mark(t);
if (!is_app(t)) { if (!is_app(t))
continue; continue;
}
app* a = to_app(t); app* a = to_app(t);
todo.append(a->get_num_args(), a->get_args()); todo.append(a->get_num_args(), a->get_args());
} }
@ -680,14 +659,11 @@ namespace {
while (!todo.empty()) { while (!todo.empty()) {
t = todo.back(); t = todo.back();
todo.pop_back(); todo.pop_back();
if (mark1.is_marked(t)) { if (mark1.is_marked(t))
continue; continue;
}
mark1.mark(t); mark1.mark(t);
if (!is_app(t))
if (!is_app(t)) {
continue; continue;
}
interval b; interval b;
expr* e; expr* e;
if (is_bound(t, e, b)) { if (is_bound(t, e, b)) {
@ -718,15 +694,14 @@ namespace {
m_scopes.reset(); m_scopes.reset();
return; 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]; undo_bound& undo = m_scopes[i];
SASSERT(m_bound.contains(undo.e)); SASSERT(m_bound.contains(undo.e));
if (undo.fresh) { if (undo.fresh)
m_bound.erase(undo.e); m_bound.erase(undo.e);
} else { else
m_bound.insert(undo.e, undo.b); m_bound.insert(undo.e, undo.b);
} }
}
m_scopes.shrink(target); m_scopes.shrink(target);
} }

View file

@ -5,15 +5,34 @@ Module Name:
bv_bounds_tactic.h bv_bounds_tactic.h
Abstract:
Contextual bounds simplification tactic.
Author: Author:
Nuno Lopes (nlopes) 2016-2-12 Nuno Lopes (nlopes) 2016-2-12
Nikolaj Bjorner (nbjorner) 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 #pragma once

View file

@ -3,18 +3,30 @@ Copyright (c) 2015 Microsoft Corporation
Module Name: Module Name:
bvarray2ufbvarray2uf_tactic.h bvarray2uf_tactic.h
Abstract:
Tactic that rewrites bit-vector arrays into bit-vector
(uninterpreted) functions.
Author: Author:
Christoph (cwinter) 2015-11-04 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 #pragma once

View file

@ -5,15 +5,28 @@ Module Name:
dt2bv_tactic.h dt2bv_tactic.h
Abstract:
Tactic that eliminates finite domain data-types.
Author: Author:
nbjorner 2016-07-22 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 #pragma once

View file

@ -15,6 +15,22 @@ Author:
Revision History: 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 #pragma once

View file

@ -7,16 +7,26 @@ Module Name:
Abstract: 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: Author:
Leonardo de Moura (leonardo) 2011-12-29. 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 #pragma once