mirror of
https://github.com/Z3Prover/z3
synced 2026-04-04 10:49:02 +00:00
Merge remote-tracking branch 'origin/master' into c3
# Conflicts: # .github/workflows/qf-s-benchmark.lock.yml # .github/workflows/qf-s-benchmark.md # .github/workflows/zipt-code-reviewer.lock.yml # .github/workflows/zipt-code-reviewer.md # .gitignore # src/ast/rewriter/seq_rewriter.cpp # src/test/main.cpp
This commit is contained in:
commit
6a6f9b1892
185 changed files with 16422 additions and 5692 deletions
|
|
@ -173,7 +173,7 @@ void act_cache::insert(expr * k, unsigned offset, expr * v) {
|
|||
DEBUG_CODE(expected_tag = 0;);
|
||||
}
|
||||
DEBUG_CODE({
|
||||
expr * v2;
|
||||
expr * v2 = nullptr;
|
||||
SASSERT(m_table.find(e, v2));
|
||||
SASSERT(v == UNTAG(expr*, v2));
|
||||
SASSERT(expected_tag == GET_TAG(v2));
|
||||
|
|
@ -195,7 +195,7 @@ expr * act_cache::find(expr * k, unsigned offset) {
|
|||
SASSERT(m_unused > 0);
|
||||
m_unused--;
|
||||
DEBUG_CODE({
|
||||
expr * v;
|
||||
expr * v = nullptr;
|
||||
SASSERT(m_table.find(e, v));
|
||||
SASSERT(GET_TAG(v) == 1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1402,6 +1402,7 @@ namespace euf {
|
|||
// to check it again.
|
||||
get_check_mark(reg) == NOT_CHECKED &&
|
||||
is_ground(m_registers[reg]) &&
|
||||
instr->m_enode != nullptr &&
|
||||
get_pat_lbl_hash(reg) == instr->m_enode->get_lbl_hash();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -354,8 +354,8 @@ void bit2int::visit(app* n) {
|
|||
//
|
||||
// (pos1 - neg1) mod e2 = (pos1 + (e2 - (neg1 mod e2))) mod e2
|
||||
//
|
||||
unsigned sz_p, sz_n, sz;
|
||||
bool sign_p, sign_n;
|
||||
unsigned sz_p = 0, sz_n = 0, sz;
|
||||
bool sign_p = false, sign_n = false;
|
||||
expr_ref tmp_p(m), tmp_n(m);
|
||||
VERIFY(extract_bv(pos1, sz_p, sign_p, tmp_p));
|
||||
VERIFY(extract_bv(neg1, sz_n, sign_n, tmp_n));
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ struct enum2bv_rewriter::imp {
|
|||
unsigned bv_size = get_bv_size(s);
|
||||
sort_ref bv_sort(m_bv.mk_sort(bv_size), m);
|
||||
if (is_unate(s))
|
||||
return m_bv.mk_numeral(rational((1 << idx) - 1), bv_sort.get());
|
||||
return m_bv.mk_numeral(rational((1u << idx) - 1), bv_sort.get());
|
||||
else
|
||||
return m_bv.mk_numeral(rational(idx), bv_sort.get());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,7 +226,6 @@ namespace seq {
|
|||
return
|
||||
e.ls.size() == 1 && e.rs.size() == 1 &&
|
||||
seq.str.is_ubv2s(e.ls[0], a) && seq.str.is_ubv2s(e.rs[0], b);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eq_solver::reduce_ubv2s1(eqr const& e, eq_ptr& r) {
|
||||
|
|
|
|||
|
|
@ -4391,6 +4391,8 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_FAILED;
|
||||
// disabled
|
||||
|
||||
#if 0
|
||||
|
||||
expr_ref hd(m()), tl(m());
|
||||
if (get_head_tail(a, hd, tl)) {
|
||||
//result = re().mk_in_re(tl, re().mk_derivative(hd, b));
|
||||
|
|
@ -4430,6 +4432,8 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
unsigned len = 0;
|
||||
if (has_fixed_length_constraint(b, len)) {
|
||||
|
|
|
|||
190
src/ast/simplifiers/injectivity_simplifier.h
Normal file
190
src/ast/simplifiers/injectivity_simplifier.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
injectivity_simplifier.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Dependent expression simplifier for injectivity rewriting.
|
||||
|
||||
- Discover axioms of the form `forall x. (= (g (f x)) x)`
|
||||
Mark `f` as injective
|
||||
|
||||
- Rewrite (sub)terms of the form `(= (f x) (f y))` to `(= x y)` whenever `f` is injective.
|
||||
|
||||
Author:
|
||||
|
||||
Nicolas Braud-Santoni (t-nibrau) 2017-08-10
|
||||
Ported to simplifier by Nikolaj Bjorner (nbjorner) 2023
|
||||
|
||||
Notes:
|
||||
* does not support cores nor proofs
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ast/simplifiers/dependent_expr_state.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
|
||||
class injectivity_simplifier : public dependent_expr_simplifier {
|
||||
|
||||
struct inj_map : public obj_map<func_decl, obj_hashtable<func_decl>*> {
|
||||
ast_manager& m;
|
||||
|
||||
inj_map(ast_manager& m) : m(m) {}
|
||||
|
||||
~inj_map() {
|
||||
for (auto& kv : *this) {
|
||||
for (func_decl* f : *kv.get_value())
|
||||
m.dec_ref(f);
|
||||
m.dec_ref(kv.m_key);
|
||||
dealloc(kv.m_value);
|
||||
}
|
||||
}
|
||||
|
||||
void insert(func_decl* f, func_decl* g) {
|
||||
obj_hashtable<func_decl>* inverses;
|
||||
if (!obj_map::find(f, inverses)) {
|
||||
m.inc_ref(f);
|
||||
inverses = alloc(obj_hashtable<func_decl>);
|
||||
obj_map::insert(f, inverses);
|
||||
}
|
||||
if (!inverses->contains(g)) {
|
||||
m.inc_ref(g);
|
||||
inverses->insert(g);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct rw_cfg : public default_rewriter_cfg {
|
||||
ast_manager& m;
|
||||
inj_map& m_map;
|
||||
|
||||
rw_cfg(ast_manager& m, inj_map& map) : m(m), m_map(map) {}
|
||||
|
||||
br_status reduce_app(func_decl* f, unsigned num, expr* const* args,
|
||||
expr_ref& result, proof_ref& result_pr) {
|
||||
if (num != 2 || !m.is_eq(f))
|
||||
return BR_FAILED;
|
||||
|
||||
if (!is_app(args[0]) || !is_app(args[1]))
|
||||
return BR_FAILED;
|
||||
|
||||
app* a = to_app(args[0]);
|
||||
app* b = to_app(args[1]);
|
||||
|
||||
if (a->get_decl() != b->get_decl())
|
||||
return BR_FAILED;
|
||||
|
||||
if (a->get_num_args() != 1 || b->get_num_args() != 1)
|
||||
return BR_FAILED;
|
||||
|
||||
if (!m_map.contains(a->get_decl()))
|
||||
return BR_FAILED;
|
||||
|
||||
SASSERT(a->get_arg(0)->get_sort() == b->get_arg(0)->get_sort());
|
||||
result = m.mk_eq(a->get_arg(0), b->get_arg(0));
|
||||
result_pr = nullptr;
|
||||
return BR_DONE;
|
||||
}
|
||||
};
|
||||
|
||||
struct rw : public rewriter_tpl<rw_cfg> {
|
||||
rw_cfg m_cfg;
|
||||
|
||||
rw(ast_manager& m, inj_map& map) :
|
||||
rewriter_tpl<rw_cfg>(m, false, m_cfg),
|
||||
m_cfg(m, map) {}
|
||||
};
|
||||
|
||||
inj_map m_map;
|
||||
rw m_rw;
|
||||
|
||||
bool is_axiom(expr* n, func_decl*& f, func_decl*& g) {
|
||||
if (!is_forall(n))
|
||||
return false;
|
||||
|
||||
quantifier* q = to_quantifier(n);
|
||||
if (q->get_num_decls() != 1)
|
||||
return false;
|
||||
|
||||
expr* body = q->get_expr();
|
||||
if (!m.is_eq(body))
|
||||
return false;
|
||||
|
||||
app* body_a = to_app(body);
|
||||
if (body_a->get_num_args() != 2)
|
||||
return false;
|
||||
|
||||
expr* a = body_a->get_arg(0);
|
||||
expr* b = body_a->get_arg(1);
|
||||
|
||||
if (is_app(a) && is_var(b)) {
|
||||
// keep a, b as-is
|
||||
}
|
||||
else if (is_app(b) && is_var(a)) {
|
||||
std::swap(a, b);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
app* a_app = to_app(a);
|
||||
var* b_var = to_var(b);
|
||||
|
||||
if (b_var->get_idx() != 0)
|
||||
return false;
|
||||
|
||||
if (a_app->get_num_args() != 1)
|
||||
return false;
|
||||
|
||||
g = a_app->get_decl();
|
||||
expr* a_body = a_app->get_arg(0);
|
||||
|
||||
if (!is_app(a_body))
|
||||
return false;
|
||||
|
||||
app* a_body_app = to_app(a_body);
|
||||
if (a_body_app->get_num_args() != 1)
|
||||
return false;
|
||||
|
||||
f = a_body_app->get_decl();
|
||||
expr* a_body_body = a_body_app->get_arg(0);
|
||||
|
||||
if (a_body_body != b_var)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
injectivity_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& s) :
|
||||
dependent_expr_simplifier(m, s), m_map(m), m_rw(m, m_map) {}
|
||||
|
||||
char const* name() const override { return "injectivity"; }
|
||||
|
||||
void reduce() override {
|
||||
// Phase 1: Scan for injectivity axioms
|
||||
for (unsigned idx : indices()) {
|
||||
auto const& d = m_fmls[idx];
|
||||
func_decl* fn = nullptr;
|
||||
func_decl* inv = nullptr;
|
||||
if (is_axiom(d.fml(), fn, inv)) {
|
||||
TRACE(injectivity, tout << "Marking " << fn->get_name() << " as injective\n";);
|
||||
m_map.insert(fn, inv);
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: Rewrite using injectivity
|
||||
expr_ref new_fml(m);
|
||||
proof_ref new_pr(m);
|
||||
for (unsigned idx : indices()) {
|
||||
auto const& d = m_fmls[idx];
|
||||
m_rw(d.fml(), new_fml, new_pr);
|
||||
if (new_fml != d.fml())
|
||||
m_fmls.update(idx, dependent_expr(m, new_fml, nullptr, d.dep()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -287,27 +287,36 @@ namespace sls {
|
|||
if (m.is_eq(e)) {
|
||||
a = g.find(to_app(e)->get_arg(0));
|
||||
b = g.find(to_app(e)->get_arg(1));
|
||||
}
|
||||
if (lit.sign() && m.is_eq(e)) {
|
||||
if (a->get_root() == b->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not disequal " << lit << " " << mk_pp(e, m) << "\n");
|
||||
ctx.display(verbose_stream());
|
||||
UNREACHABLE();
|
||||
if (lit.sign()) {
|
||||
if (a && b && a->get_root() == b->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not disequal " << lit << " " << mk_pp(e, m) << "\n");
|
||||
ctx.display(verbose_stream());
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (a && b && a->get_root() != b->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not equal " << lit << " " << mk_pp(e, m) << "\n");
|
||||
//UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!lit.sign() && m.is_eq(e)) {
|
||||
if (a->get_root() != b->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not equal " << lit << " " << mk_pp(e, m) << "\n");
|
||||
//UNREACHABLE();
|
||||
else if (to_app(e)->get_family_id() != basic_family_id) {
|
||||
auto* ne = g.find(e);
|
||||
if (lit.sign()) {
|
||||
auto* nf = g.find(m.mk_false());
|
||||
if (ne && nf && ne->get_root() != nf->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not false " << lit << " " << mk_pp(e, m) << "\n");
|
||||
//UNREACHABLE();
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto* nt = g.find(m.mk_true());
|
||||
if (ne && nt && ne->get_root() != nt->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not true " << lit << " " << mk_pp(e, m) << "\n");
|
||||
//UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (to_app(e)->get_family_id() != basic_family_id && lit.sign() && g.find(e)->get_root() != g.find(m.mk_false())->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not alse " << lit << " " << mk_pp(e, m) << "\n");
|
||||
//UNREACHABLE();
|
||||
}
|
||||
else if (to_app(e)->get_family_id() != basic_family_id && !lit.sign() && g.find(e)->get_root() != g.find(m.mk_true())->get_root()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "not true " << lit << " " << mk_pp(e, m) << "\n");
|
||||
//UNREACHABLE();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue