mirror of
https://github.com/Z3Prover/z3
synced 2025-04-14 21:08:46 +00:00
seq
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
071a654a9a
commit
739043e273
|
@ -25,6 +25,14 @@ Notes:
|
|||
#include"automaton.h"
|
||||
|
||||
|
||||
struct display_expr1 {
|
||||
ast_manager& m;
|
||||
display_expr1(ast_manager& m): m(m) {}
|
||||
std::ostream& display(std::ostream& out, expr* e) const {
|
||||
return out << mk_pp(e, m);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
re2automaton::re2automaton(ast_manager& m): m(m), u(m) {}
|
||||
|
||||
|
@ -36,6 +44,7 @@ eautomaton* re2automaton::operator()(expr* e) {
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
eautomaton* re2automaton::re2aut(expr* e) {
|
||||
SASSERT(u.is_re(e));
|
||||
expr* e1, *e2;
|
||||
|
@ -230,8 +239,8 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
|
|||
result = m_util.str.mk_string(s1 + s2);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.str.is_concat(b, c, d)) {
|
||||
result = m_util.str.mk_concat(m_util.str.mk_concat(a, c), d);
|
||||
if (m_util.str.is_concat(a, c, d)) {
|
||||
result = m_util.str.mk_concat(c, m_util.str.mk_concat(d, b));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m_util.str.is_empty(a)) {
|
||||
|
|
|
@ -84,6 +84,12 @@ private:
|
|||
mutable uint_set m_visited;
|
||||
mutable unsigned_vector m_todo;
|
||||
|
||||
struct default_display {
|
||||
std::ostream& display(std::ostream& out, T* t) {
|
||||
return out << t;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// The empty automaton:
|
||||
|
@ -216,7 +222,7 @@ public:
|
|||
mvs.push_back(move(m, 0, a.init() + offset1));
|
||||
append_moves(offset1, a, mvs);
|
||||
for (unsigned i = 0; i < a.m_final_states.size(); ++i) {
|
||||
mvs.push_back(move(m, a.m_final_states[i], b.init()));
|
||||
mvs.push_back(move(m, a.m_final_states[i], b.init() + offset2));
|
||||
}
|
||||
append_moves(offset2, b, mvs);
|
||||
append_final(offset2, b, final);
|
||||
|
@ -278,7 +284,7 @@ public:
|
|||
for (unsigned j = 0; found && j < mvs.size(); ++j) {
|
||||
found = (mvs[j].dst() == m_init) && mvs[j].is_epsilon();
|
||||
}
|
||||
if (!found) {
|
||||
if (!found && state != m_init) {
|
||||
add(move(m, state, m_init));
|
||||
}
|
||||
}
|
||||
|
@ -301,7 +307,7 @@ public:
|
|||
if (src == dst) {
|
||||
// just remove this edge.
|
||||
}
|
||||
else if (1 == in_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) {
|
||||
else if (1 == in_degree(src) && 1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) {
|
||||
move const& mv0 = m_delta_inv[src][0];
|
||||
unsigned src0 = mv0.src();
|
||||
T* t = mv0.t();
|
||||
|
@ -311,8 +317,9 @@ public:
|
|||
}
|
||||
add(move(m, src0, dst, t));
|
||||
remove(src0, src, t);
|
||||
|
||||
}
|
||||
else if (1 == out_degree(dst) && init() != dst && (!is_final_state(dst) || is_final_state(src))) {
|
||||
else if (1 == out_degree(dst) && 1 == in_degree(dst) && init() != dst && (!is_final_state(dst) || is_final_state(src))) {
|
||||
move const& mv1 = m_delta[dst][0];
|
||||
unsigned dst1 = mv1.dst();
|
||||
T* t = mv1.t();
|
||||
|
@ -322,6 +329,7 @@ public:
|
|||
}
|
||||
add(move(m, src, dst1, t));
|
||||
remove(dst, dst1, t);
|
||||
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
|
@ -422,8 +430,8 @@ public:
|
|||
get_moves(state, m_delta_inv, mvs, epsilon_closure);
|
||||
}
|
||||
|
||||
template<class D>
|
||||
std::ostream& display(std::ostream& out, D& displayer) const {
|
||||
template<class D = default_display>
|
||||
std::ostream& display(std::ostream& out, D& displayer = D()) const {
|
||||
out << "init: " << init() << "\n";
|
||||
out << "final: ";
|
||||
for (unsigned i = 0; i < m_final_states.size(); ++i) out << m_final_states[i] << " ";
|
||||
|
|
|
@ -146,7 +146,6 @@ theory_seq::theory_seq(ast_manager& m):
|
|||
m_axioms(m),
|
||||
m_axioms_head(0),
|
||||
m_branch_variable_head(0),
|
||||
m_model_completion(false),
|
||||
m_mg(0),
|
||||
m_rewrite(m),
|
||||
m_util(m),
|
||||
|
@ -157,14 +156,12 @@ theory_seq::theory_seq(ast_manager& m):
|
|||
m_steps_qhead(0) {
|
||||
m_prefix = "seq.prefix.suffix";
|
||||
m_suffix = "seq.suffix.prefix";
|
||||
m_left = "seq.left";
|
||||
m_right = "seq.right";
|
||||
m_contains_left = "seq.contains.left";
|
||||
m_contains_right = "seq.contains.right";
|
||||
m_accept = "aut.accept";
|
||||
m_reject = "aut.reject";
|
||||
m_tail = "seq.tail";
|
||||
m_head_elem = "seq.head.elem";
|
||||
m_nth = "seq.nth";
|
||||
m_seq_first = "seq.first";
|
||||
m_seq_last = "seq.last";
|
||||
m_indexof_left = "seq.indexof.left";
|
||||
|
@ -196,7 +193,7 @@ final_check_status theory_seq::final_check_eh() {
|
|||
return FC_CONTINUE;
|
||||
}
|
||||
if (branch_variable()) {
|
||||
TRACE("seq", tout << "branch\n";);
|
||||
TRACE("seq", tout << "branch_variable\n";);
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (!check_length_coherence()) {
|
||||
|
@ -315,27 +312,27 @@ bool theory_seq::check_length_coherence() {
|
|||
if (m_length.empty()) return true;
|
||||
context& ctx = get_context();
|
||||
bool coherent = true;
|
||||
// each variable that canonizes to itself can have length 0.
|
||||
unsigned sz = get_num_vars();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
unsigned j = (i + m_branch_variable_head) % sz;
|
||||
enode* n = get_enode(j);
|
||||
expr* e = n->get_owner();
|
||||
if (m_util.is_re(e)) {
|
||||
continue;
|
||||
}
|
||||
SASSERT(m_util.is_seq(e));
|
||||
// extend length of variables.
|
||||
obj_hashtable<expr>::iterator it = m_length.begin(), end = m_length.end();
|
||||
for (; it != end; ++it) {
|
||||
expr* e = *it;
|
||||
enode_pair_dependency* dep = 0;
|
||||
expr* f = m_rep.find(e, dep);
|
||||
if (is_var(f) && f == e) {
|
||||
expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
|
||||
expr_ref head(m), tail(m);
|
||||
rational lo, hi;
|
||||
TRACE("seq", tout << "Unsolved " << mk_pp(e, m) << "\n";);
|
||||
TRACE("seq", tout << "Unsolved " << mk_pp(e, m);
|
||||
if (!lower_bound(e, lo)) lo = -rational::one();
|
||||
if (!upper_bound(e, hi)) hi = -rational::one();
|
||||
tout << " lo: " << lo << " ";
|
||||
tout << "hi: " << hi << " ";
|
||||
tout << "\n";
|
||||
ctx.display(tout);
|
||||
);
|
||||
|
||||
|
||||
if (lower_bound(e, lo) && lo.is_pos() && lo < rational(512)) {
|
||||
TRACE("seq", tout << "lower bound: " << mk_pp(e, m) << " " << lo << "\n";);
|
||||
expr_ref low(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)), m);
|
||||
literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true))));
|
||||
expr_ref seq(e, m);
|
||||
expr_ref_vector elems(m);
|
||||
unsigned _lo = lo.get_unsigned();
|
||||
|
@ -347,18 +344,14 @@ bool theory_seq::check_length_coherence() {
|
|||
elems.push_back(seq);
|
||||
tail = m_util.str.mk_concat(elems.size(), elems.c_ptr());
|
||||
// len(e) >= low => e = tail
|
||||
add_axiom(~mk_literal(low), mk_eq(e, tail, false));
|
||||
add_axiom(~low, mk_eq(e, tail, false));
|
||||
assume_equality(tail, e);
|
||||
if (upper_bound(e, hi) && hi == lo) {
|
||||
expr_ref high(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)), m);
|
||||
add_axiom(~mk_literal(high), mk_eq(seq, emp, false));
|
||||
if (upper_bound(e, hi)) {
|
||||
expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m);
|
||||
expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m);
|
||||
add_axiom(~mk_literal(high1), mk_literal(high2));
|
||||
}
|
||||
}
|
||||
else if (upper_bound(e, hi) && hi.is_zero()) {
|
||||
expr_ref len(m_util.str.mk_length(e), m);
|
||||
expr_ref zero(m_autil.mk_int(0), m);
|
||||
add_axiom(~mk_eq(len, zero, false), mk_eq(e, emp, false));
|
||||
}
|
||||
else if (!assume_equality(e, emp)) {
|
||||
mk_decompose(e, emp, head, tail);
|
||||
// e = emp \/ e = unit(head.elem(e))*tail(e)
|
||||
|
@ -366,7 +359,6 @@ bool theory_seq::check_length_coherence() {
|
|||
add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false));
|
||||
assume_equality(tail, emp);
|
||||
}
|
||||
m_branch_variable_head = j + 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -380,8 +372,8 @@ void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref&
|
|||
VERIFY(m_util.is_seq(m.get_sort(e), char_sort));
|
||||
emp = m_util.str.mk_empty(m.get_sort(e));
|
||||
if (m_util.str.is_empty(e)) {
|
||||
head = m_util.str.mk_unit(mk_skolem(m_head_elem, e, 0, 0, char_sort));
|
||||
tail = mk_skolem(m_tail, e);
|
||||
head = m_util.str.mk_unit(mk_skolem(m_nth, e, m_autil.mk_int(0), 0, char_sort));
|
||||
tail = e;
|
||||
}
|
||||
else if (m_util.str.is_string(e, s)) {
|
||||
head = m_util.str.mk_unit(m_util.str.mk_char(s, 0));
|
||||
|
@ -395,13 +387,18 @@ void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref&
|
|||
head = e1;
|
||||
tail = e2;
|
||||
}
|
||||
else if (is_skolem(m_tail, e)) {
|
||||
rational r;
|
||||
app* a = to_app(e);
|
||||
expr* s = a->get_arg(0);
|
||||
VERIFY (m_autil.is_numeral(a->get_arg(1), r));
|
||||
expr* idx = m_autil.mk_int(r.get_unsigned() + 1);
|
||||
head = m_util.str.mk_unit(mk_skolem(m_nth, s, idx, 0, char_sort));
|
||||
tail = mk_skolem(m_tail, s, idx);
|
||||
}
|
||||
else {
|
||||
head = m_util.str.mk_unit(mk_skolem(m_head_elem, e, 0, 0, char_sort));
|
||||
tail = mk_skolem(m_tail, e);
|
||||
if (!m_util.is_skolem(e)) {
|
||||
expr_ref conc(m_util.str.mk_concat(head, tail), m);
|
||||
add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false));
|
||||
}
|
||||
head = m_util.str.mk_unit(mk_skolem(m_nth, e, m_autil.mk_int(0), 0, char_sort));
|
||||
tail = mk_skolem(m_tail, e, m_autil.mk_int(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -531,6 +528,7 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps, bo
|
|||
}
|
||||
if (is_var(lh) && !occurs(lh, rh)) {
|
||||
propagated = add_solution(lh, rh, deps) || propagated;
|
||||
return true;
|
||||
}
|
||||
if (is_var(rh) && !occurs(rh, lh)) {
|
||||
propagated = add_solution(rh, lh, deps) || propagated;
|
||||
|
@ -547,19 +545,21 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps, bo
|
|||
bool theory_seq::occurs(expr* a, expr* b) {
|
||||
// true if a occurs under an interpreted function or under left/right selector.
|
||||
SASSERT(is_var(a));
|
||||
SASSERT(m_todo.empty());
|
||||
expr* e1, *e2;
|
||||
while (is_left_select(a, e1) || is_right_select(a, e1)) {
|
||||
a = e1;
|
||||
m_todo.push_back(b);
|
||||
while (!m_todo.empty()) {
|
||||
b = m_todo.back();
|
||||
if (a == b) {
|
||||
m_todo.reset();
|
||||
return true;
|
||||
}
|
||||
m_todo.pop_back();
|
||||
if (m_util.str.is_concat(b, e1, e2)) {
|
||||
m_todo.push_back(e1);
|
||||
m_todo.push_back(e2);
|
||||
}
|
||||
}
|
||||
if (m_util.str.is_concat(b, e1, e2)) {
|
||||
return occurs(a, e1) || occurs(a, e2);
|
||||
}
|
||||
while (is_left_select(b, e1) || is_right_select(b, e1)) {
|
||||
b = e1;
|
||||
}
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -572,16 +572,9 @@ bool theory_seq::is_var(expr* a) {
|
|||
!m_util.str.is_unit(a);
|
||||
}
|
||||
|
||||
bool theory_seq::is_left_select(expr* a, expr*& b) {
|
||||
return is_skolem(m_left, a) && (b = to_app(a)->get_arg(0), true);
|
||||
}
|
||||
|
||||
bool theory_seq::is_right_select(expr* a, expr*& b) {
|
||||
return is_skolem(m_right, a) && (b = to_app(a)->get_arg(0), true);
|
||||
}
|
||||
|
||||
bool theory_seq::is_head_elem(expr* e) const {
|
||||
return is_skolem(m_head_elem, e);
|
||||
return is_skolem(m_nth, e);
|
||||
}
|
||||
|
||||
bool theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) {
|
||||
|
@ -589,6 +582,7 @@ bool theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) {
|
|||
return false;
|
||||
}
|
||||
context& ctx = get_context();
|
||||
TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n";);
|
||||
m_rep.update(l, r, deps);
|
||||
// TBD: skip new equalities for non-internalized terms.
|
||||
if (ctx.e_internalized(l) && ctx.e_internalized(r) && ctx.get_enode(l)->get_root() != ctx.get_enode(r)->get_root()) {
|
||||
|
@ -768,9 +762,6 @@ bool theory_seq::internalize_term(app* term) {
|
|||
}
|
||||
mk_var(e);
|
||||
}
|
||||
if (m_util.str.is_length(term, arg) && !has_length(arg)) {
|
||||
add_length(arg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -889,20 +880,103 @@ void theory_seq::init_model(model_generator & mg) {
|
|||
mg.register_factory(m_factory);
|
||||
}
|
||||
|
||||
|
||||
class seq_value_proc : public model_value_proc {
|
||||
theory_seq& th;
|
||||
app* n;
|
||||
svector<model_value_dependency> m_dependencies;
|
||||
public:
|
||||
seq_value_proc(theory_seq& th, app* n): th(th), n(n) {
|
||||
}
|
||||
virtual ~seq_value_proc() {}
|
||||
void add_dependency(enode* n) { m_dependencies.push_back(model_value_dependency(n)); }
|
||||
virtual void get_dependencies(buffer<model_value_dependency> & result) {
|
||||
result.append(m_dependencies.size(), m_dependencies.c_ptr());
|
||||
}
|
||||
virtual app * mk_value(model_generator & mg, ptr_vector<expr> & values) {
|
||||
SASSERT(values.size() == m_dependencies.size());
|
||||
ast_manager& m = mg.get_manager();
|
||||
if (values.empty()) {
|
||||
return th.mk_value(n);
|
||||
}
|
||||
SASSERT(values.size() == n->get_num_args());
|
||||
return th.mk_value(mg.get_manager().mk_app(n->get_decl(), values.size(), values.c_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
|
||||
enode_pair_dependency* deps = 0;
|
||||
expr_ref e(n->get_owner(), m);
|
||||
flet<bool> _model_completion(m_model_completion, true);
|
||||
m_rep.reset_cache();
|
||||
m_mg = &mg;
|
||||
e = canonize(e, deps);
|
||||
m_mg = 0;
|
||||
SASSERT(is_app(e));
|
||||
TRACE("seq", tout << mk_pp(n->get_owner(), m) << " -> " << e << "\n";);
|
||||
m_factory->add_trail(e);
|
||||
return alloc(expr_wrapper_proc, to_app(e));
|
||||
context& ctx = get_context();
|
||||
enode_pair_dependency* dep = 0;
|
||||
expr* e = m_rep.find(n->get_owner(), dep);
|
||||
expr* e1, *e2;
|
||||
seq_value_proc* sv = alloc(seq_value_proc, *this, to_app(e));
|
||||
if (m_util.str.is_concat(e, e1, e2)) {
|
||||
sv->add_dependency(ctx.get_enode(e1));
|
||||
sv->add_dependency(ctx.get_enode(e2));
|
||||
}
|
||||
else if (m_util.str.is_unit(e, e1)) {
|
||||
sv->add_dependency(ctx.get_enode(e1));
|
||||
}
|
||||
return sv;
|
||||
}
|
||||
|
||||
app* theory_seq::mk_value(app* e) {
|
||||
expr* e1;
|
||||
expr_ref result(e, m);
|
||||
if (m_util.str.is_unit(e, e1)) {
|
||||
enode_pair_dependency* deps = 0;
|
||||
result = expand(e1, deps);
|
||||
bv_util bv(m);
|
||||
rational val;
|
||||
unsigned sz;
|
||||
if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) {
|
||||
svector<bool> val_as_bits;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
val_as_bits.push_back(!val.is_even());
|
||||
val = div(val, rational(2));
|
||||
}
|
||||
result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr()));
|
||||
}
|
||||
else {
|
||||
result = m_util.str.mk_unit(result);
|
||||
}
|
||||
}
|
||||
else if (is_var(e)) {
|
||||
SASSERT(m_factory);
|
||||
expr_ref val(m);
|
||||
val = m_factory->get_some_value(m.get_sort(e));
|
||||
if (val) {
|
||||
result = val;
|
||||
}
|
||||
else {
|
||||
result = e;
|
||||
}
|
||||
}
|
||||
else if (is_head_elem(e)) {
|
||||
enode* n = get_context().get_enode(e)->get_root();
|
||||
enode* n0 = n;
|
||||
bool found_value = false;
|
||||
do {
|
||||
result = n->get_owner();
|
||||
found_value = m.is_model_value(result);
|
||||
}
|
||||
while (n0 != n && !found_value);
|
||||
|
||||
if (!found_value) {
|
||||
if (m_util.is_char(result)) {
|
||||
result = m_util.str.mk_char('#');
|
||||
}
|
||||
else {
|
||||
result = m_mg->get_some_value(m.get_sort(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
m_rewrite(result);
|
||||
m_factory->add_trail(result);
|
||||
TRACE("seq", tout << mk_pp(e, m) << " -> " << result << "\n";);
|
||||
return to_app(result);
|
||||
}
|
||||
|
||||
|
||||
theory_var theory_seq::mk_var(enode* n) {
|
||||
|
@ -957,49 +1031,6 @@ expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) {
|
|||
else if (m_util.str.is_contains(e, e1, e2)) {
|
||||
result = m_util.str.mk_contains(expand(e1, deps), expand(e2, deps));
|
||||
}
|
||||
else if (m_model_completion && is_var(e)) {
|
||||
SASSERT(m_factory);
|
||||
expr_ref val(m);
|
||||
val = m_factory->get_some_value(m.get_sort(e));
|
||||
if (val) {
|
||||
m_rep.update(e, val, 0);
|
||||
result = val;
|
||||
}
|
||||
else {
|
||||
result = e;
|
||||
}
|
||||
}
|
||||
else if (m_model_completion && m_util.str.is_unit(e, e1)) {
|
||||
result = expand(e1, deps);
|
||||
bv_util bv(m);
|
||||
rational val;
|
||||
unsigned sz;
|
||||
if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) {
|
||||
svector<bool> val_as_bits;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
val_as_bits.push_back(!val.is_even());
|
||||
val = div(val, rational(2));
|
||||
}
|
||||
result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr()));
|
||||
}
|
||||
else {
|
||||
result = m_util.str.mk_unit(result);
|
||||
}
|
||||
}
|
||||
else if (m_model_completion && is_head_elem(e)) {
|
||||
enode* n = get_context().get_enode(e)->get_root();
|
||||
result = n->get_owner();
|
||||
if (!m.is_model_value(result)) {
|
||||
if (m_util.is_char(result)) {
|
||||
result = m_util.str.mk_char('#');
|
||||
}
|
||||
else {
|
||||
result = m_mg->get_some_value(m.get_sort(result));
|
||||
}
|
||||
}
|
||||
m_rep.update(e, result, 0);
|
||||
TRACE("seq", tout << mk_pp(e, m) << " |-> " << result << "\n";);
|
||||
}
|
||||
else {
|
||||
result = e;
|
||||
}
|
||||
|
@ -1193,15 +1224,6 @@ void theory_seq::add_elim_string_axiom(expr* n) {
|
|||
}
|
||||
|
||||
|
||||
void theory_seq::add_length_coherence_axiom(expr* n) {
|
||||
expr_ref len(n, m);
|
||||
m_rewrite(len);
|
||||
if (n != len) {
|
||||
TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";);
|
||||
add_axiom(mk_eq(n, len, false));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
let n = len(x)
|
||||
|
||||
|
@ -1212,9 +1234,18 @@ void theory_seq::add_length_coherence_axiom(expr* n) {
|
|||
void theory_seq::add_length_axiom(expr* n) {
|
||||
expr* x;
|
||||
VERIFY(m_util.str.is_length(n, x));
|
||||
if (!m_util.str.is_unit(x) &&
|
||||
!m_util.str.is_empty(x) &&
|
||||
!m_util.str.is_string(x)) {
|
||||
if (m_util.str.is_concat(x) ||
|
||||
m_util.str.is_unit(x) ||
|
||||
m_util.str.is_empty(x) ||
|
||||
m_util.str.is_string(x)) {
|
||||
expr_ref len(n, m);
|
||||
m_rewrite(len);
|
||||
if (n != len) {
|
||||
TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";);
|
||||
add_axiom(mk_eq(n, len, false));
|
||||
}
|
||||
}
|
||||
else {
|
||||
expr_ref zero(m_autil.mk_int(0), m);
|
||||
expr_ref emp(m_util.str.mk_empty(m.get_sort(x)), m);
|
||||
literal eq1(mk_eq(zero, n, false));
|
||||
|
@ -1223,12 +1254,6 @@ void theory_seq::add_length_axiom(expr* n) {
|
|||
add_axiom(~eq1, eq2);
|
||||
add_axiom(~eq2, eq1);
|
||||
}
|
||||
if (m_util.str.is_concat(x) ||
|
||||
m_util.str.is_unit(x) ||
|
||||
m_util.str.is_empty(x) ||
|
||||
m_util.str.is_string(x)) {
|
||||
add_length_coherence_axiom(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1638,8 +1663,7 @@ void theory_seq::restart_eh() {
|
|||
}
|
||||
|
||||
void theory_seq::relevant_eh(app* n) {
|
||||
if (m_util.str.is_length(n) ||
|
||||
m_util.str.is_index(n) ||
|
||||
if (m_util.str.is_index(n) ||
|
||||
m_util.str.is_replace(n) ||
|
||||
m_util.str.is_extract(n) ||
|
||||
m_util.str.is_at(n) ||
|
||||
|
@ -1647,6 +1671,11 @@ void theory_seq::relevant_eh(app* n) {
|
|||
is_step(n)) {
|
||||
enque_axiom(n);
|
||||
}
|
||||
|
||||
expr* arg;
|
||||
if (m_util.str.is_length(n, arg) && !has_length(arg)) {
|
||||
enforce_length(get_context().get_enode(arg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1729,24 +1758,28 @@ expr_ref theory_seq::mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned
|
|||
void theory_seq::add_accept2step(expr* acc) {
|
||||
context& ctx = get_context();
|
||||
SASSERT(ctx.get_assignment(acc) == l_true);
|
||||
expr* s, *re;
|
||||
expr* e, *re;
|
||||
unsigned src;
|
||||
eautomaton* aut = 0;
|
||||
VERIFY(is_accept(acc, s, re, src, aut));
|
||||
VERIFY(is_accept(acc, e, re, src, aut));
|
||||
if (!aut) return;
|
||||
if (m_util.str.is_empty(s)) return;
|
||||
if (m_util.str.is_empty(e)) return;
|
||||
eautomaton::moves mvs;
|
||||
aut->get_moves_from(src, mvs);
|
||||
expr_ref head(m), tail(m), emp(m), step(m);
|
||||
mk_decompose(s, emp, head, tail);
|
||||
mk_decompose(e, emp, head, tail);
|
||||
if (!m_util.is_skolem(e)) {
|
||||
expr_ref conc(m_util.str.mk_concat(head, tail), m);
|
||||
add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false));
|
||||
}
|
||||
literal_vector lits;
|
||||
lits.push_back(~ctx.get_literal(acc));
|
||||
if (aut->is_final_state(src)) {
|
||||
lits.push_back(mk_eq(emp, s, false));
|
||||
lits.push_back(mk_eq(emp, e, false));
|
||||
}
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
eautomaton::move mv = mvs[i];
|
||||
step = mk_step(s, tail, re, src, mv.dst(), mv.t());
|
||||
step = mk_step(e, tail, re, src, mv.dst(), mv.t());
|
||||
lits.push_back(mk_literal(step));
|
||||
}
|
||||
TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";);
|
||||
|
@ -1778,22 +1811,26 @@ void theory_seq::add_step2accept(expr* step) {
|
|||
void theory_seq::add_reject2reject(expr* rej) {
|
||||
context& ctx = get_context();
|
||||
SASSERT(ctx.get_assignment(rej) == l_true);
|
||||
expr* s, *re;
|
||||
expr* e, *re;
|
||||
unsigned src;
|
||||
eautomaton* aut = 0;
|
||||
VERIFY(is_reject(rej, s, re, src, aut));
|
||||
VERIFY(is_reject(rej, e, re, src, aut));
|
||||
if (!aut) return;
|
||||
if (m_util.str.is_empty(s)) return;
|
||||
if (m_util.str.is_empty(e)) return;
|
||||
eautomaton::moves mvs;
|
||||
aut->get_moves_from(src, mvs);
|
||||
expr_ref head(m), tail(m), emp(m), conc(m);
|
||||
mk_decompose(s, emp, head, tail);
|
||||
mk_decompose(e, emp, head, tail);
|
||||
if (!m_util.is_skolem(e)) {
|
||||
expr_ref conc(m_util.str.mk_concat(head, tail), m);
|
||||
add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false));
|
||||
}
|
||||
literal rej1 = ctx.get_literal(rej);
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
eautomaton::move const& mv = mvs[i];
|
||||
conc = m_util.str.mk_concat(m_util.str.mk_unit(mv.t()), tail);
|
||||
literal rej2 = mk_reject(tail, re, m_autil.mk_int(mv.dst()));
|
||||
add_axiom(~rej1, ~mk_eq(s, conc, false), rej2);
|
||||
add_axiom(~rej1, ~mk_eq(e, conc, false), rej2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -259,17 +259,17 @@ namespace smt {
|
|||
unsigned m_axioms_head; // index of first axiom to add.
|
||||
unsigned m_branch_variable_head; // index of first equation to examine.
|
||||
bool m_incomplete; // is the solver (clearly) incomplete for the fragment.
|
||||
obj_hashtable<expr> m_length; // is length applied
|
||||
bool m_model_completion; // during model construction, invent values in canonizer
|
||||
obj_hashtable<expr> m_length; // is length applied
|
||||
model_generator* m_mg;
|
||||
th_rewriter m_rewrite;
|
||||
seq_util m_util;
|
||||
arith_util m_autil;
|
||||
th_trail_stack m_trail_stack;
|
||||
stats m_stats;
|
||||
symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_left, m_right, m_accept, m_reject;
|
||||
symbol m_tail, m_head_elem, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step;
|
||||
symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_accept, m_reject;
|
||||
symbol m_tail, m_nth, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step;
|
||||
symbol m_extract_prefix, m_at_left, m_at_right;
|
||||
ptr_vector<expr> m_todo;
|
||||
|
||||
// maintain automata with regular expressions.
|
||||
scoped_ptr_vector<eautomaton> m_automata;
|
||||
|
@ -348,7 +348,6 @@ namespace smt {
|
|||
void add_replace_axiom(expr* e);
|
||||
void add_extract_axiom(expr* e);
|
||||
void add_length_axiom(expr* n);
|
||||
void add_length_coherence_axiom(expr* n);
|
||||
|
||||
bool has_length(expr *e) const { return m_length.contains(e); }
|
||||
void add_length(expr* e);
|
||||
|
@ -407,6 +406,9 @@ namespace smt {
|
|||
theory_seq(ast_manager& m);
|
||||
virtual ~theory_seq();
|
||||
|
||||
// model building
|
||||
app* mk_value(app* a);
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue