mirror of
https://github.com/Z3Prover/z3
synced 2025-04-13 20:38:43 +00:00
* na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix #4037 * nicer output for skolem functions * more overhaul of seq, some bug fixes * na * added offset_eq file * na * fix #4044 * fix #4040 * fix #4045 * updated ignore * new rewrites for indexof based on #4036 * add shortcuts * updated ne solver for seq, fix #4025 * use pair vectors for equalities that are reduced by seq_rewriter * use erase_and_swap * remove unit-walk * na * add check for #3200 * nits Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * name a type Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remove fp check Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remove unsound axiom instantiation for non-contains Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix rewrites Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix #4053 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix #4052 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
134 lines
3.6 KiB
C++
134 lines
3.6 KiB
C++
/*++
|
|
Copyright (c) 2011 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
seq_offset_eq.h
|
|
|
|
Abstract:
|
|
|
|
Container for maintaining equalities between lengths of sequences.
|
|
|
|
Author:
|
|
|
|
Thai Minh Trinh 2017
|
|
Nikolaj Bjorner (nbjorner) 2020-4-16
|
|
|
|
--*/
|
|
|
|
#include "ast/ast_pp.h"
|
|
#include "smt/seq_offset_eq.h"
|
|
#include "smt/smt_context.h"
|
|
|
|
using namespace smt;
|
|
|
|
/**
|
|
Match:
|
|
e == val where val is an integer
|
|
e == r1 - r2
|
|
r1 == len(e1)
|
|
r2 == len(e2)
|
|
update m_offset_equalities to contain.
|
|
r1 |-> [r2 |-> val]
|
|
*/
|
|
|
|
seq_offset_eq::seq_offset_eq(theory& th, ast_manager& m):
|
|
th(th), m(m), seq(m), a(m), m_propagation_level(-1) {
|
|
}
|
|
|
|
bool seq_offset_eq::match_x_minus_y(expr* e, expr*& x, expr*& y) const {
|
|
expr* z = nullptr, *u = nullptr;
|
|
rational fact;
|
|
return
|
|
a.is_add(e, x, z) &&
|
|
a.is_mul(z, u, y) &&
|
|
a.is_numeral(u, fact) &&
|
|
fact.is_minus_one();
|
|
}
|
|
|
|
|
|
void seq_offset_eq::len_offset(expr* e, int val) {
|
|
context & ctx = th.get_context();
|
|
expr *x = nullptr, *y = nullptr;
|
|
expr *e1 = nullptr, *e2 = nullptr;
|
|
if (match_x_minus_y(e, x, y) &&
|
|
ctx.e_internalized(x) &&
|
|
ctx.e_internalized(y)) {
|
|
TRACE("seq", tout << "eqc: " << mk_pp(e, m) << "\n";);
|
|
enode* r1 = th.get_root(x);
|
|
enode* r2 = th.get_root(y);
|
|
for (enode* n1 : *r1) {
|
|
if (!seq.str.is_length(n1->get_owner(), e1))
|
|
continue;
|
|
for (enode* n2 : *r2) {
|
|
if (!seq.str.is_length(n2->get_owner(), e2))
|
|
continue;
|
|
if (r1->get_owner_id() > r2->get_owner_id()) {
|
|
std::swap(r1, r2);
|
|
val = -val;
|
|
}
|
|
m_offset_equalities.insert(r1, r2, val);
|
|
m_has_offset_equality.insert(r1);
|
|
m_has_offset_equality.insert(r2);
|
|
TRACE("seq", tout << "a length pair: " << mk_pp(e1, m) << ", " << mk_pp(e2, m) << "\n";);
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find the length offset from the congruence closure core
|
|
void seq_offset_eq::prop_arith_to_len_offset() {
|
|
rational val;
|
|
for (enode* n : th.get_context().enodes()) {
|
|
if (a.is_numeral(n->get_owner(), val) && val.is_int32() && INT_MIN < val.get_int32()) {
|
|
TRACE("seq", tout << "offset: " << mk_pp(n->get_owner(), m) << "\n";);
|
|
enode *next = n->get_next();
|
|
while (next != n) {
|
|
len_offset(next->get_owner(), val.get_int32());
|
|
next = next->get_next();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool seq_offset_eq::find(enode* n1, enode* n2, int& offset) const {
|
|
n1 = n1->get_root();
|
|
n2 = n2->get_root();
|
|
if (n1->get_owner_id() > n2->get_owner_id())
|
|
std::swap(n1, n2);
|
|
return
|
|
!a.is_numeral(n2->get_owner()) &&
|
|
!a.is_numeral(n2->get_owner()) &&
|
|
m_offset_equalities.find(n1, n2, offset);
|
|
}
|
|
|
|
bool seq_offset_eq::contains(enode* r) {
|
|
r = r->get_root();
|
|
return !a.is_numeral(r->get_owner()) && m_has_offset_equality.contains(r);
|
|
}
|
|
|
|
bool seq_offset_eq::propagate() {
|
|
context& ctx = th.get_context();
|
|
int lvl = (int) ctx.get_scope_level();
|
|
if (lvl > m_propagation_level) {
|
|
m_propagation_level = lvl;
|
|
prop_arith_to_len_offset();
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void seq_offset_eq::pop_scope_eh(unsigned num_scopes) {
|
|
context& ctx = th.get_context();
|
|
int new_lvl = (int) (ctx.get_scope_level() - num_scopes);
|
|
if (m_propagation_level > new_lvl) {
|
|
m_propagation_level = -1;
|
|
m_offset_equalities.reset();
|
|
m_has_offset_equality.reset();
|
|
}
|
|
}
|