mirror of
https://github.com/Z3Prover/z3
synced 2026-06-27 02:48:48 +00:00
Use lookahead for regex decomposition
Make snode const
This commit is contained in:
parent
671dfedebe
commit
be627007e1
22 changed files with 1868 additions and 2066 deletions
|
|
@ -19,8 +19,9 @@ static euf::enode* get_node(euf::egraph& g, seq_util& seq, expr* e) {
|
|||
if (n) return n;
|
||||
euf::enode_vector args;
|
||||
if (is_app(e))
|
||||
for (expr* arg : *to_app(e))
|
||||
for (expr* arg : *to_app(e)) {
|
||||
args.push_back(get_node(g, seq, arg));
|
||||
}
|
||||
n = g.mk(e, 0, args.size(), args.data());
|
||||
if (seq.is_seq(e) || seq.is_re(e))
|
||||
g.add_th_var(n, ++s_var, seq.get_family_id());
|
||||
|
|
@ -42,20 +43,20 @@ static void test_sgraph_basic() {
|
|||
expr_ref empty(seq.str.mk_empty(str_sort), m);
|
||||
expr_ref xy(seq.str.mk_concat(x, y), m);
|
||||
|
||||
euf::snode* sx = sg.mk(x);
|
||||
euf::snode const* sx = sg.mk(x);
|
||||
SASSERT(sx);
|
||||
SASSERT(sx->is_var());
|
||||
SASSERT(!sx->is_ground());
|
||||
SASSERT(sx->is_regex_free());
|
||||
SASSERT(sx->length() == 1);
|
||||
|
||||
euf::snode* se = sg.mk(empty);
|
||||
euf::snode const* se = sg.mk(empty);
|
||||
SASSERT(se);
|
||||
SASSERT(se->is_empty());
|
||||
SASSERT(se->is_ground());
|
||||
SASSERT(se->length() == 0);
|
||||
|
||||
euf::snode* sxy = sg.mk(xy);
|
||||
euf::snode const* sxy = sg.mk(xy);
|
||||
SASSERT(sxy);
|
||||
SASSERT(sxy->is_concat());
|
||||
SASSERT(!sxy->is_ground());
|
||||
|
|
@ -169,7 +170,7 @@ static void test_seq_plugin_star_merge() {
|
|||
|
||||
// register in sgraph
|
||||
sg.mk(star_star);
|
||||
euf::snode* s = sg.find(star_x);
|
||||
euf::snode const* s = sg.find(star_x);
|
||||
SASSERT(s && s->is_star());
|
||||
|
||||
std::cout << g << "\n";
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ static void test_sgraph_classify() {
|
|||
reg_decl_plugins(m);
|
||||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
seq_util seq(m);
|
||||
sort_ref str_sort(seq.str.mk_string_sort(), m);
|
||||
const seq_util seq(m);
|
||||
const sort_ref str_sort(seq.str.mk_string_sort(), m);
|
||||
|
||||
// string variable
|
||||
expr_ref x(m.mk_const("x", str_sort), m);
|
||||
euf::snode* sx = sg.mk(x);
|
||||
const expr_ref x(m.mk_const("x", str_sort), m);
|
||||
euf::snode const* sx = sg.mk(x);
|
||||
SASSERT(sx && sx->is_var());
|
||||
SASSERT(!sx->is_ground());
|
||||
SASSERT(sx->is_regex_free());
|
||||
|
|
@ -43,8 +43,8 @@ static void test_sgraph_classify() {
|
|||
SASSERT(sx->is_token());
|
||||
|
||||
// empty string
|
||||
expr_ref empty(seq.str.mk_empty(str_sort), m);
|
||||
euf::snode* se = sg.mk(empty);
|
||||
const expr_ref empty(seq.str.mk_empty(str_sort), m);
|
||||
euf::snode const* se = sg.mk(empty);
|
||||
SASSERT(se && se->is_empty());
|
||||
SASSERT(se->is_ground());
|
||||
SASSERT(se->level() == 0);
|
||||
|
|
@ -52,9 +52,9 @@ static void test_sgraph_classify() {
|
|||
SASSERT(!se->is_token());
|
||||
|
||||
// character unit with literal char
|
||||
expr_ref ch(seq.str.mk_char('A'), m);
|
||||
expr_ref unit_a(seq.str.mk_unit(ch), m);
|
||||
euf::snode* sca = sg.mk(unit_a);
|
||||
const expr_ref ch(seq.str.mk_char('A'), m);
|
||||
const expr_ref unit_a(seq.str.mk_unit(ch), m);
|
||||
euf::snode const* sca = sg.mk(unit_a);
|
||||
SASSERT(sca && sca->is_char());
|
||||
SASSERT(sca->is_ground());
|
||||
SASSERT(sca->level() == 1);
|
||||
|
|
@ -62,9 +62,9 @@ static void test_sgraph_classify() {
|
|||
SASSERT(sca->is_token());
|
||||
|
||||
// concat of two variables
|
||||
expr_ref y(m.mk_const("y", str_sort), m);
|
||||
expr_ref xy(seq.str.mk_concat(x, y), m);
|
||||
euf::snode* sxy = sg.mk(xy);
|
||||
const expr_ref y(m.mk_const("y", str_sort), m);
|
||||
const expr_ref xy(seq.str.mk_concat(x, y), m);
|
||||
euf::snode const* sxy = sg.mk(xy);
|
||||
SASSERT(sxy && sxy->is_concat());
|
||||
SASSERT(!sxy->is_ground());
|
||||
SASSERT(sxy->is_regex_free());
|
||||
|
|
@ -85,60 +85,60 @@ static void test_sgraph_regex() {
|
|||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
seq_util seq(m);
|
||||
sort_ref str_sort(seq.str.mk_string_sort(), m);
|
||||
const sort_ref str_sort(seq.str.mk_string_sort(), m);
|
||||
|
||||
expr_ref x(m.mk_const("x", str_sort), m);
|
||||
const expr_ref x(m.mk_const("x", str_sort), m);
|
||||
|
||||
// to_re
|
||||
expr_ref to_re_x(seq.re.mk_to_re(x), m);
|
||||
euf::snode* str = sg.mk(to_re_x);
|
||||
const expr_ref to_re_x(seq.re.mk_to_re(x), m);
|
||||
euf::snode const* str = sg.mk(to_re_x);
|
||||
SASSERT(str && str->is_to_re());
|
||||
SASSERT(!str->is_regex_free());
|
||||
SASSERT(str->num_args() == 1);
|
||||
|
||||
// star
|
||||
expr_ref star_x(seq.re.mk_star(to_re_x), m);
|
||||
euf::snode* ss = sg.mk(star_x);
|
||||
const expr_ref star_x(seq.re.mk_star(to_re_x), m);
|
||||
euf::snode const* ss = sg.mk(star_x);
|
||||
SASSERT(ss && ss->is_star());
|
||||
SASSERT(!ss->is_regex_free());
|
||||
SASSERT(ss->num_args() == 1);
|
||||
|
||||
// full_seq (.*)
|
||||
expr_ref full_seq(seq.re.mk_full_seq(str_sort), m);
|
||||
euf::snode* sfs = sg.mk(full_seq);
|
||||
const expr_ref full_seq(seq.re.mk_full_seq(str_sort), m);
|
||||
euf::snode const* sfs = sg.mk(full_seq);
|
||||
SASSERT(sfs && sfs->is_full_seq());
|
||||
SASSERT(sfs->is_ground());
|
||||
|
||||
// full_char (.)
|
||||
expr_ref full_char(seq.re.mk_full_char(str_sort), m);
|
||||
euf::snode* sfc = sg.mk(full_char);
|
||||
const expr_ref full_char(seq.re.mk_full_char(str_sort), m);
|
||||
euf::snode const* sfc = sg.mk(full_char);
|
||||
SASSERT(sfc && sfc->is_full_char());
|
||||
SASSERT(sfc->is_ground());
|
||||
|
||||
// empty set, fail
|
||||
sort_ref re_sort(seq.re.mk_re(str_sort), m);
|
||||
expr_ref empty_set(seq.re.mk_empty(re_sort), m);
|
||||
euf::snode* sfail = sg.mk(empty_set);
|
||||
const sort_ref re_sort(seq.re.mk_re(str_sort), m);
|
||||
const expr_ref empty_set(seq.re.mk_empty(re_sort), m);
|
||||
euf::snode const* sfail = sg.mk(empty_set);
|
||||
SASSERT(sfail && sfail->is_fail());
|
||||
|
||||
// union: to_re(x) | star(to_re(x)), nullable because star is
|
||||
expr_ref re_union(seq.re.mk_union(to_re_x, star_x), m);
|
||||
euf::snode* su = sg.mk(re_union);
|
||||
const expr_ref re_union(seq.re.mk_union(to_re_x, star_x), m);
|
||||
euf::snode const* su = sg.mk(re_union);
|
||||
SASSERT(su && su->is_union());
|
||||
|
||||
// intersection: to_re(x) & star(to_re(x)), nullable only if both are
|
||||
expr_ref re_inter(seq.re.mk_inter(to_re_x, star_x), m);
|
||||
euf::snode* si = sg.mk(re_inter);
|
||||
const expr_ref re_inter(seq.re.mk_inter(to_re_x, star_x), m);
|
||||
euf::snode const* si = sg.mk(re_inter);
|
||||
SASSERT(si && si->is_intersect());
|
||||
|
||||
// complement of to_re(x): nullable because to_re(x) is not nullable
|
||||
expr_ref re_comp(seq.re.mk_complement(to_re_x), m);
|
||||
euf::snode* sc = sg.mk(re_comp);
|
||||
const expr_ref re_comp(seq.re.mk_complement(to_re_x), m);
|
||||
euf::snode const* sc = sg.mk(re_comp);
|
||||
SASSERT(sc && sc->is_complement());
|
||||
|
||||
// in_re
|
||||
expr_ref in_re(seq.re.mk_in_re(x, star_x), m);
|
||||
euf::snode* sir = sg.mk(in_re);
|
||||
const expr_ref in_re(seq.re.mk_in_re(x, star_x), m);
|
||||
euf::snode const* sir = sg.mk(in_re);
|
||||
SASSERT(sir && sir->is_in_re());
|
||||
SASSERT(!sir->is_regex_free());
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ static void test_sgraph_power() {
|
|||
expr_ref n(arith.mk_int(3), m);
|
||||
expr_ref xn(seq.str.mk_power(x, n), m);
|
||||
|
||||
euf::snode* sp = sg.mk(xn);
|
||||
euf::snode const* sp = sg.mk(xn);
|
||||
SASSERT(sp && sp->is_power());
|
||||
SASSERT(!sp->is_ground()); // base x is not ground
|
||||
SASSERT(sp->is_regex_free());
|
||||
|
|
@ -258,8 +258,8 @@ static void test_sgraph_find_idempotent() {
|
|||
sort_ref str_sort(seq.str.mk_string_sort(), m);
|
||||
|
||||
expr_ref x(m.mk_const("x", str_sort), m);
|
||||
euf::snode* s1 = sg.mk(x);
|
||||
euf::snode* s2 = sg.mk(x); // calling mk again returns same node
|
||||
euf::snode const* s1 = sg.mk(x);
|
||||
euf::snode const* s2 = sg.mk(x); // calling mk again returns same node
|
||||
SASSERT(s1 == s2);
|
||||
SASSERT(s1 == sg.find(x));
|
||||
}
|
||||
|
|
@ -278,9 +278,9 @@ static void test_sgraph_mk_concat() {
|
|||
expr_ref y(m.mk_const("y", str_sort), m);
|
||||
expr_ref empty(seq.str.mk_empty(str_sort), m);
|
||||
|
||||
euf::snode* sx = sg.mk(x);
|
||||
euf::snode* sy = sg.mk(y);
|
||||
euf::snode* se = sg.mk(empty);
|
||||
euf::snode const* sx = sg.mk(x);
|
||||
euf::snode const* sy = sg.mk(y);
|
||||
euf::snode const* se = sg.mk(empty);
|
||||
|
||||
// concat with empty yields the non-empty side at sgraph level
|
||||
// (empty absorption is a property of the expression, checked via mk)
|
||||
|
|
@ -288,14 +288,14 @@ static void test_sgraph_mk_concat() {
|
|||
|
||||
// normal concat via expression
|
||||
expr_ref xy(seq.str.mk_concat(x, y), m);
|
||||
euf::snode* sxy = sg.mk(xy);
|
||||
euf::snode const* sxy = sg.mk(xy);
|
||||
SASSERT(sxy && sxy->is_concat());
|
||||
SASSERT(sxy->num_args() == 2);
|
||||
SASSERT(sxy->arg(0) == sx);
|
||||
SASSERT(sxy->arg(1) == sy);
|
||||
|
||||
// calling mk again with same expr returns same node
|
||||
euf::snode* sxy2 = sg.mk(xy);
|
||||
euf::snode const* sxy2 = sg.mk(xy);
|
||||
SASSERT(sxy == sxy2);
|
||||
}
|
||||
|
||||
|
|
@ -314,14 +314,14 @@ static void test_sgraph_mk_power() {
|
|||
expr_ref n(arith.mk_int(5), m);
|
||||
expr_ref xn(seq.str.mk_power(x, n), m);
|
||||
|
||||
euf::snode* sx = sg.mk(x);
|
||||
euf::snode* sp = sg.mk(xn);
|
||||
euf::snode const* sx = sg.mk(x);
|
||||
euf::snode const* sp = sg.mk(xn);
|
||||
SASSERT(sp && sp->is_power());
|
||||
SASSERT(sp->num_args() == 2);
|
||||
SASSERT(sp->arg(0) == sx);
|
||||
|
||||
// calling mk again returns same node
|
||||
euf::snode* sp2 = sg.mk(xn);
|
||||
euf::snode const* sp2 = sg.mk(xn);
|
||||
SASSERT(sp == sp2);
|
||||
}
|
||||
|
||||
|
|
@ -339,21 +339,21 @@ static void test_sgraph_first_last() {
|
|||
expr_ref b(m.mk_const("b", str_sort), m);
|
||||
expr_ref c(m.mk_const("c", str_sort), m);
|
||||
|
||||
euf::snode* sa = sg.mk(a);
|
||||
euf::snode* sb = sg.mk(b);
|
||||
euf::snode* sc = sg.mk(c);
|
||||
euf::snode const* sa = sg.mk(a);
|
||||
euf::snode const* sb = sg.mk(b);
|
||||
euf::snode const* sc = sg.mk(c);
|
||||
|
||||
// concat(concat(a,b),c): first=a, last=c
|
||||
expr_ref ab(seq.str.mk_concat(a, b), m);
|
||||
expr_ref ab_c(seq.str.mk_concat(ab, c), m);
|
||||
euf::snode* sab_c = sg.mk(ab_c);
|
||||
euf::snode const* sab_c = sg.mk(ab_c);
|
||||
SASSERT(sab_c->first() == sa);
|
||||
SASSERT(sab_c->last() == sc);
|
||||
|
||||
// concat(a,concat(b,c)): first=a, last=c
|
||||
expr_ref bc(seq.str.mk_concat(b, c), m);
|
||||
expr_ref a_bc(seq.str.mk_concat(a, bc), m);
|
||||
euf::snode* sa_bc = sg.mk(a_bc);
|
||||
euf::snode const* sa_bc = sg.mk(a_bc);
|
||||
SASSERT(sa_bc->first() == sa);
|
||||
SASSERT(sa_bc->last() == sc);
|
||||
|
||||
|
|
@ -378,13 +378,13 @@ static void test_sgraph_concat_metadata() {
|
|||
expr_ref ch(seq.str.mk_char('Z'), m);
|
||||
expr_ref unit_z(seq.str.mk_unit(ch), m);
|
||||
|
||||
euf::snode* sx = sg.mk(x);
|
||||
euf::snode* se = sg.mk(empty);
|
||||
euf::snode* sz = sg.mk(unit_z);
|
||||
euf::snode const* sx = sg.mk(x);
|
||||
euf::snode const* se = sg.mk(empty);
|
||||
euf::snode const* sz = sg.mk(unit_z);
|
||||
|
||||
// concat(x, unit('Z')): not ground (x is variable), regex_free, not nullable
|
||||
expr_ref xz(seq.str.mk_concat(x, unit_z), m);
|
||||
euf::snode* sxz = sg.mk(xz);
|
||||
euf::snode const* sxz = sg.mk(xz);
|
||||
SASSERT(!sxz->is_ground());
|
||||
SASSERT(sxz->is_regex_free());
|
||||
SASSERT(sxz->length() == 2);
|
||||
|
|
@ -392,14 +392,14 @@ static void test_sgraph_concat_metadata() {
|
|||
|
||||
// concat(empty, empty): nullable (both empty)
|
||||
expr_ref empty2(seq.str.mk_concat(empty, empty), m);
|
||||
euf::snode* see = sg.mk(empty2);
|
||||
euf::snode const* see = sg.mk(empty2);
|
||||
SASSERT(see->is_ground());
|
||||
SASSERT(see->length() == 0);
|
||||
|
||||
// deep chain: concat(concat(x,x),concat(x,x)) has level 3, length 4
|
||||
expr_ref xx(seq.str.mk_concat(x, x), m);
|
||||
expr_ref xxxx(seq.str.mk_concat(xx, xx), m);
|
||||
euf::snode* sxxxx = sg.mk(xxxx);
|
||||
euf::snode const* sxxxx = sg.mk(xxxx);
|
||||
SASSERT(sxxxx->level() == 3);
|
||||
SASSERT(sxxxx->length() == 4);
|
||||
}
|
||||
|
|
@ -437,40 +437,40 @@ static void test_sgraph_factory() {
|
|||
seq_util seq(m);
|
||||
|
||||
// mk_var
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
SASSERT(x && x->is_var());
|
||||
SASSERT(!x->is_ground());
|
||||
SASSERT(x->length() == 1);
|
||||
|
||||
// mk_char
|
||||
euf::snode* a = sg.mk_char('A');
|
||||
euf::snode const* a = sg.mk_char('A');
|
||||
SASSERT(a && a->is_char());
|
||||
SASSERT(a->is_ground());
|
||||
SASSERT(a->length() == 1);
|
||||
|
||||
// mk_empty
|
||||
euf::snode* e = sg.mk_empty_seq(seq.str.mk_string_sort());
|
||||
euf::snode const* e = sg.mk_empty_seq(seq.str.mk_string_sort());
|
||||
SASSERT(e && e->is_empty());
|
||||
SASSERT(e->length() == 0);
|
||||
|
||||
// mk_concat with empty absorption
|
||||
euf::snode* xe = sg.mk_concat(x, e);
|
||||
euf::snode const* xe = sg.mk_concat(x, e);
|
||||
SASSERT(xe == x);
|
||||
euf::snode* ex = sg.mk_concat(e, x);
|
||||
euf::snode const* ex = sg.mk_concat(e, x);
|
||||
SASSERT(ex == x);
|
||||
|
||||
// mk_concat of two variables
|
||||
euf::snode* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode* xy = sg.mk_concat(x, y);
|
||||
euf::snode const* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode const* xy = sg.mk_concat(x, y);
|
||||
SASSERT(xy && xy->is_concat());
|
||||
SASSERT(xy->length() == 2);
|
||||
SASSERT(xy->arg(0) == x);
|
||||
SASSERT(xy->arg(1) == y);
|
||||
|
||||
// mk_concat of multiple characters
|
||||
euf::snode* b = sg.mk_char('B');
|
||||
euf::snode* c = sg.mk_char('C');
|
||||
euf::snode* abc = sg.mk_concat(sg.mk_concat(a, b), c);
|
||||
euf::snode const* b = sg.mk_char('B');
|
||||
euf::snode const* c = sg.mk_char('C');
|
||||
euf::snode const* abc = sg.mk_concat(sg.mk_concat(a, b), c);
|
||||
SASSERT(abc->length() == 3);
|
||||
SASSERT(abc->is_ground());
|
||||
SASSERT(abc->first() == a);
|
||||
|
|
@ -486,15 +486,15 @@ static void test_sgraph_indexing() {
|
|||
euf::sgraph sg(m, eg);
|
||||
seq_util seq(m);
|
||||
|
||||
euf::snode* a = sg.mk_char('A');
|
||||
euf::snode* b = sg.mk_char('B');
|
||||
euf::snode* c = sg.mk_char('C');
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* a = sg.mk_char('A');
|
||||
euf::snode const* b = sg.mk_char('B');
|
||||
euf::snode const* c = sg.mk_char('C');
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
|
||||
// build concat(concat(a, b), concat(c, x)) => [A, B, C, x]
|
||||
euf::snode* ab = sg.mk_concat(a, b);
|
||||
euf::snode* cx = sg.mk_concat(c, x);
|
||||
euf::snode* abcx = sg.mk_concat(ab, cx);
|
||||
euf::snode const* ab = sg.mk_concat(a, b);
|
||||
euf::snode const* cx = sg.mk_concat(c, x);
|
||||
euf::snode const* abcx = sg.mk_concat(ab, cx);
|
||||
|
||||
SASSERT(abcx->length() == 4);
|
||||
|
||||
|
|
@ -519,7 +519,7 @@ static void test_sgraph_indexing() {
|
|||
SASSERT(a->at(1) == nullptr);
|
||||
|
||||
// empty: at(0) is nullptr
|
||||
euf::snode* e = sg.mk_empty_seq(seq.str.mk_string_sort());
|
||||
euf::snode const* e = sg.mk_empty_seq(seq.str.mk_string_sort());
|
||||
SASSERT(e->at(0) == nullptr);
|
||||
euf::snode_vector empty_tokens;
|
||||
e->collect_tokens(empty_tokens);
|
||||
|
|
@ -535,62 +535,62 @@ static void test_sgraph_drop() {
|
|||
euf::sgraph sg(m, eg);
|
||||
seq_util seq(m);
|
||||
|
||||
euf::snode* a = sg.mk_char('A');
|
||||
euf::snode* b = sg.mk_char('B');
|
||||
euf::snode* c = sg.mk_char('C');
|
||||
euf::snode* d = sg.mk_char('D');
|
||||
euf::snode const* a = sg.mk_char('A');
|
||||
euf::snode const* b = sg.mk_char('B');
|
||||
euf::snode const* c = sg.mk_char('C');
|
||||
euf::snode const* d = sg.mk_char('D');
|
||||
|
||||
// build concat(concat(a, b), concat(c, d)) => [A, B, C, D]
|
||||
euf::snode* ab = sg.mk_concat(a, b);
|
||||
euf::snode* cd = sg.mk_concat(c, d);
|
||||
euf::snode* abcd = sg.mk_concat(ab, cd);
|
||||
euf::snode const* ab = sg.mk_concat(a, b);
|
||||
euf::snode const* cd = sg.mk_concat(c, d);
|
||||
euf::snode const* abcd = sg.mk_concat(ab, cd);
|
||||
|
||||
SASSERT(abcd->length() == 4);
|
||||
|
||||
// drop_first: [A, B, C, D] => [B, C, D]
|
||||
euf::snode* bcd = sg.drop_first(abcd);
|
||||
euf::snode const* bcd = sg.drop_first(abcd);
|
||||
SASSERT(bcd->length() == 3);
|
||||
SASSERT(bcd->first() == b);
|
||||
SASSERT(bcd->last() == d);
|
||||
|
||||
// drop_last: [A, B, C, D] => [A, B, C]
|
||||
euf::snode* abc = sg.drop_last(abcd);
|
||||
euf::snode const* abc = sg.drop_last(abcd);
|
||||
SASSERT(abc->length() == 3);
|
||||
SASSERT(abc->first() == a);
|
||||
SASSERT(abc->last() == c);
|
||||
|
||||
// drop_left(2): [A, B, C, D] => [C, D]
|
||||
euf::snode* cd2 = sg.drop_left(abcd, 2);
|
||||
euf::snode const* cd2 = sg.drop_left(abcd, 2);
|
||||
SASSERT(cd2->length() == 2);
|
||||
SASSERT(cd2->first() == c);
|
||||
|
||||
// drop_left(1): [A, B, C, D] => [B, C, D]
|
||||
euf::snode* bcd2 = sg.drop_left(abcd, 1);
|
||||
euf::snode const* bcd2 = sg.drop_left(abcd, 1);
|
||||
SASSERT(bcd2->length() == 3);
|
||||
SASSERT(bcd2->first() == b);
|
||||
SASSERT(bcd2->last() == d);
|
||||
|
||||
// drop_right(2): [A, B, C, D] => [A, B]
|
||||
euf::snode* ab2 = sg.drop_right(abcd, 2);
|
||||
euf::snode const* ab2 = sg.drop_right(abcd, 2);
|
||||
SASSERT(ab2->length() == 2);
|
||||
SASSERT(ab2->last() == b);
|
||||
|
||||
// drop_right(1): [A, B, C, D] => [A, B, C]
|
||||
euf::snode* abc2 = sg.drop_right(abcd, 1);
|
||||
euf::snode const* abc2 = sg.drop_right(abcd, 1);
|
||||
SASSERT(abc2->length() == 3);
|
||||
SASSERT(abc2->first() == a);
|
||||
SASSERT(abc2->last() == c);
|
||||
|
||||
// drop all: [A, B, C, D] => empty
|
||||
euf::snode* empty = sg.drop_left(abcd, 4);
|
||||
euf::snode const* empty = sg.drop_left(abcd, 4);
|
||||
SASSERT(empty->is_empty());
|
||||
|
||||
// drop from single token: [A] => empty
|
||||
euf::snode* e = sg.drop_first(a);
|
||||
euf::snode const* e = sg.drop_first(a);
|
||||
SASSERT(e->is_empty());
|
||||
|
||||
// drop from empty: no change
|
||||
euf::snode* ee = sg.drop_first(sg.mk_empty_seq(seq.str.mk_string_sort()));
|
||||
euf::snode const* ee = sg.drop_first(sg.mk_empty_seq(seq.str.mk_string_sort()));
|
||||
SASSERT(ee->is_empty());
|
||||
}
|
||||
|
||||
|
|
@ -603,29 +603,29 @@ static void test_sgraph_subst() {
|
|||
euf::sgraph sg(m, eg);
|
||||
seq_util seq(m);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode* a = sg.mk_char('A');
|
||||
euf::snode* b = sg.mk_char('B');
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode const* a = sg.mk_char('A');
|
||||
euf::snode const* b = sg.mk_char('B');
|
||||
|
||||
// concat(x, concat(a, x)) with x -> b gives concat(b, concat(a, b))
|
||||
euf::snode* ax = sg.mk_concat(a, x);
|
||||
euf::snode* xax = sg.mk_concat(x, ax);
|
||||
euf::snode const* ax = sg.mk_concat(a, x);
|
||||
euf::snode const* xax = sg.mk_concat(x, ax);
|
||||
SASSERT(xax->length() == 3);
|
||||
|
||||
euf::snode* result = sg.subst(xax, x, b);
|
||||
euf::snode const* result = sg.subst(xax, x, b);
|
||||
SASSERT(result->length() == 3);
|
||||
SASSERT(result->first() == b);
|
||||
SASSERT(result->last() == b);
|
||||
SASSERT(result->at(1) == a); // middle is still 'A'
|
||||
|
||||
// substitution of non-occurring variable is identity
|
||||
euf::snode* same = sg.subst(xax, y, b);
|
||||
euf::snode const* same = sg.subst(xax, y, b);
|
||||
SASSERT(same == xax);
|
||||
|
||||
// substitution of variable with empty
|
||||
euf::snode* e = sg.mk_empty_seq(seq.str.mk_string_sort());
|
||||
euf::snode* collapsed = sg.subst(xax, x, e);
|
||||
euf::snode const* e = sg.mk_empty_seq(seq.str.mk_string_sort());
|
||||
euf::snode const* collapsed = sg.subst(xax, x, e);
|
||||
SASSERT(collapsed->length() == 1); // just 'a' remains
|
||||
SASSERT(collapsed == a);
|
||||
}
|
||||
|
|
@ -639,15 +639,15 @@ static void test_sgraph_complex_concat() {
|
|||
euf::sgraph sg(m, eg);
|
||||
|
||||
// build a string "HELLO" = concat(H, concat(E, concat(L, concat(L, O))))
|
||||
euf::snode* h = sg.mk_char('H');
|
||||
euf::snode* e = sg.mk_char('E');
|
||||
euf::snode* l = sg.mk_char('L');
|
||||
euf::snode* o = sg.mk_char('O');
|
||||
euf::snode const* h = sg.mk_char('H');
|
||||
euf::snode const* e = sg.mk_char('E');
|
||||
euf::snode const* l = sg.mk_char('L');
|
||||
euf::snode const* o = sg.mk_char('O');
|
||||
|
||||
euf::snode* lo = sg.mk_concat(l, o);
|
||||
euf::snode* llo = sg.mk_concat(l, lo);
|
||||
euf::snode* ello = sg.mk_concat(e, llo);
|
||||
euf::snode* hello = sg.mk_concat(h, ello);
|
||||
euf::snode const* lo = sg.mk_concat(l, o);
|
||||
euf::snode const* llo = sg.mk_concat(l, lo);
|
||||
euf::snode const* ello = sg.mk_concat(e, llo);
|
||||
euf::snode const* hello = sg.mk_concat(h, ello);
|
||||
|
||||
SASSERT(hello->length() == 5);
|
||||
SASSERT(hello->is_ground());
|
||||
|
|
@ -662,24 +662,24 @@ static void test_sgraph_complex_concat() {
|
|||
SASSERT(hello->at(4) == o);
|
||||
|
||||
// drop first 2 from "HELLO" => "LLO"
|
||||
euf::snode* llo2 = sg.drop_left(hello, 2);
|
||||
euf::snode const* llo2 = sg.drop_left(hello, 2);
|
||||
SASSERT(llo2->length() == 3);
|
||||
SASSERT(llo2->first() == l);
|
||||
|
||||
// drop last 3 from "HELLO" => "HE"
|
||||
euf::snode* he = sg.drop_right(hello, 3);
|
||||
euf::snode const* he = sg.drop_right(hello, 3);
|
||||
SASSERT(he->length() == 2);
|
||||
SASSERT(he->first() == h);
|
||||
SASSERT(he->last() == e);
|
||||
|
||||
// mixed variables and characters: concat(x, "AB", y)
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode* a = sg.mk_char('A');
|
||||
euf::snode* b = sg.mk_char('B');
|
||||
euf::snode* ab = sg.mk_concat(a, b);
|
||||
euf::snode* xab = sg.mk_concat(x, ab);
|
||||
euf::snode* xaby = sg.mk_concat(xab, y);
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode const* a = sg.mk_char('A');
|
||||
euf::snode const* b = sg.mk_char('B');
|
||||
euf::snode const* ab = sg.mk_concat(a, b);
|
||||
euf::snode const* xab = sg.mk_concat(x, ab);
|
||||
euf::snode const* xaby = sg.mk_concat(xab, y);
|
||||
|
||||
SASSERT(xaby->length() == 4);
|
||||
SASSERT(!xaby->is_ground());
|
||||
|
|
@ -706,18 +706,18 @@ static void test_sgraph_brzozowski() {
|
|||
expr_ref to_re_a(seq.re.mk_to_re(unit_a), m);
|
||||
expr_ref star_a(seq.re.mk_star(to_re_a), m);
|
||||
|
||||
euf::snode* s_star_a = sg.mk(star_a);
|
||||
euf::snode* s_unit_a = sg.mk(unit_a);
|
||||
euf::snode const* s_star_a = sg.mk(star_a);
|
||||
euf::snode const* s_unit_a = sg.mk(unit_a);
|
||||
|
||||
euf::snode* deriv = sg.brzozowski_deriv(s_star_a, s_unit_a);
|
||||
euf::snode const* deriv = sg.brzozowski_deriv(s_star_a, s_unit_a);
|
||||
SASSERT(deriv != nullptr);
|
||||
std::cout << " d/da(a*) kind: " << (int)deriv->kind() << "\n";
|
||||
|
||||
// derivative of re.empty w.r.t. 'a' should be re.empty
|
||||
sort_ref re_sort(seq.re.mk_re(str_sort), m);
|
||||
expr_ref re_empty(seq.re.mk_empty(re_sort), m);
|
||||
euf::snode* s_empty = sg.mk(re_empty);
|
||||
euf::snode* deriv_empty = sg.brzozowski_deriv(s_empty, s_unit_a);
|
||||
euf::snode const* s_empty = sg.mk(re_empty);
|
||||
euf::snode const* deriv_empty = sg.brzozowski_deriv(s_empty, s_unit_a);
|
||||
SASSERT(deriv_empty != nullptr);
|
||||
SASSERT(deriv_empty->is_fail()); // derivative of empty set is empty set
|
||||
std::cout << " d/da(empty) kind: " << (int)deriv_empty->kind() << "\n";
|
||||
|
|
@ -737,7 +737,7 @@ static void test_sgraph_minterms() {
|
|||
|
||||
// simple regex with no character predicates: re.all (.*)
|
||||
expr_ref re_all(seq.re.mk_full_seq(str_sort), m);
|
||||
euf::snode* s_re_all = sg.mk(re_all);
|
||||
euf::snode const* s_re_all = sg.mk(re_all);
|
||||
|
||||
euf::snode_vector minterms;
|
||||
sg.compute_minterms(s_re_all, minterms);
|
||||
|
|
@ -749,7 +749,7 @@ static void test_sgraph_minterms() {
|
|||
expr_ref evil(seq.re.mk_to_re(seq.str.mk_string(zstring("evil"))), m);
|
||||
expr_ref slash_evil(seq.re.mk_to_re(seq.str.mk_string(zstring("/evil"))), m);
|
||||
expr_ref union_re(seq.re.mk_union(evil, slash_evil), m);
|
||||
euf::snode* s_union_re = sg.mk(union_re);
|
||||
euf::snode const* s_union_re = sg.mk(union_re);
|
||||
|
||||
euf::snode_vector union_minterms;
|
||||
sg.compute_minterms(s_union_re, union_minterms);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static void test_nseq_instantiation() {
|
|||
euf::sgraph sg(m, eg);
|
||||
nseq_basic_dummy_solver solver;
|
||||
seq::context_solver_i context_solver;
|
||||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
const seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
SASSERT(ng.root() == nullptr);
|
||||
SASSERT(ng.num_nodes() == 0);
|
||||
std::cout << " ok\n";
|
||||
|
|
@ -50,7 +50,7 @@ static void test_nseq_instantiation() {
|
|||
// Test 2: parameter validation accepts "nseq"
|
||||
static void test_nseq_param_validation() {
|
||||
std::cout << "test_nseq_param_validation\n";
|
||||
smt_params p;
|
||||
const smt_params p;
|
||||
// Should not throw
|
||||
try {
|
||||
p.validate_string_solver(symbol("nseq"));
|
||||
|
|
@ -72,9 +72,9 @@ static void test_nseq_param_validation() {
|
|||
// Test 2b: parameter validation rejects invalid variants of "nseq"
|
||||
static void test_nseq_param_validation_rejects_invalid() {
|
||||
std::cout << "test_nseq_param_validation_rejects_invalid\n";
|
||||
smt_params p;
|
||||
const smt_params p;
|
||||
static const char* invalid_variants[] = { "nseq2", "NSEQ", "nseqq", "nse", "Nseq", "nseq ", "" };
|
||||
for (auto s : invalid_variants) {
|
||||
for (const auto s : invalid_variants) {
|
||||
bool threw = false;
|
||||
try {
|
||||
p.validate_string_solver(symbol(s));
|
||||
|
|
@ -94,7 +94,7 @@ static void test_nseq_simplification() {
|
|||
std::cout << "test_nseq_simplification\n";
|
||||
ast_manager m;
|
||||
reg_decl_plugins(m);
|
||||
seq_util su(m);
|
||||
const seq_util su(m);
|
||||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
nseq_basic_dummy_solver solver;
|
||||
|
|
@ -102,12 +102,12 @@ static void test_nseq_simplification() {
|
|||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
|
||||
// Add a trivial equality: empty = empty
|
||||
euf::snode* empty1 = sg.mk_empty_seq(su.str.mk_string_sort());
|
||||
euf::snode* empty2 = sg.mk_empty_seq(su.str.mk_string_sort());
|
||||
euf::snode const* empty1 = sg.mk_empty_seq(su.str.mk_string_sort());
|
||||
euf::snode const* empty2 = sg.mk_empty_seq(su.str.mk_string_sort());
|
||||
|
||||
ng.add_str_eq(empty1, empty2);
|
||||
|
||||
seq::nielsen_graph::search_result r = ng.solve();
|
||||
const seq::nielsen_graph::search_result r = ng.solve();
|
||||
// empty = empty is trivially satisfied
|
||||
SASSERT(r == seq::nielsen_graph::search_result::sat);
|
||||
std::cout << " ok: trivial equality solved as sat\n";
|
||||
|
|
@ -118,7 +118,7 @@ static void test_nseq_node_satisfied() {
|
|||
std::cout << "test_nseq_node_satisfied\n";
|
||||
ast_manager m;
|
||||
reg_decl_plugins(m);
|
||||
seq_util su(m);
|
||||
const seq_util su(m);
|
||||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
nseq_basic_dummy_solver solver;
|
||||
|
|
@ -130,15 +130,15 @@ static void test_nseq_node_satisfied() {
|
|||
SASSERT(node->is_satisfied());
|
||||
|
||||
// add a trivial equality
|
||||
euf::snode *empty = sg.mk_empty_seq(su.str.mk_string_sort());
|
||||
seq::dep_tracker dep = nullptr;
|
||||
seq::str_eq eq(empty, empty, dep);
|
||||
const euf::snode *empty = sg.mk_empty_seq(su.str.mk_string_sort());
|
||||
const seq::dep_tracker dep = nullptr;
|
||||
const seq::str_eq eq(empty, empty, dep);
|
||||
node->add_str_eq(eq);
|
||||
SASSERT(node->str_eqs().size() == 1);
|
||||
SASSERT(!node->str_eqs()[0].is_trivial() || node->str_eqs()[0].m_lhs == node->str_eqs()[0].m_rhs);
|
||||
// After simplification, trivial equalities should be removed
|
||||
ptr_vector<seq::nielsen_edge> cur_path;
|
||||
seq::simplify_result sr = node->simplify_and_init(cur_path);
|
||||
const ptr_vector<seq::nielsen_edge> cur_path;
|
||||
const seq::simplify_result sr = node->simplify_and_init(cur_path);
|
||||
|
||||
VERIFY(sr == seq::simplify_result::satisfied || sr == seq::simplify_result::proceed);
|
||||
std::cout << " ok\n";
|
||||
|
|
@ -155,11 +155,11 @@ static void test_nseq_symbol_clash() {
|
|||
seq::context_solver_i context_solver;
|
||||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
|
||||
euf::snode* a = sg.mk_char('a');
|
||||
euf::snode* b = sg.mk_char('b');
|
||||
euf::snode const* a = sg.mk_char('a');
|
||||
euf::snode const* b = sg.mk_char('b');
|
||||
ng.add_str_eq(a, b);
|
||||
|
||||
auto r = ng.solve();
|
||||
const auto r = ng.solve();
|
||||
SASSERT(r == seq::nielsen_graph::search_result::unsat);
|
||||
|
||||
// verify conflict explanation returns the equality index
|
||||
|
|
@ -183,10 +183,10 @@ static void test_nseq_var_eq_self() {
|
|||
seq::context_solver_i context_solver;
|
||||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
ng.add_str_eq(x, x);
|
||||
|
||||
auto r = ng.solve();
|
||||
const auto r = ng.solve();
|
||||
SASSERT(r == seq::nielsen_graph::search_result::sat);
|
||||
std::cout << " ok: x = x solved as sat\n";
|
||||
}
|
||||
|
|
@ -202,14 +202,14 @@ static void test_nseq_prefix_clash() {
|
|||
seq::context_solver_i context_solver;
|
||||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode* a = sg.mk_char('a');
|
||||
euf::snode* b = sg.mk_char('b');
|
||||
euf::snode* xa = sg.mk_concat(x, a);
|
||||
euf::snode* xb = sg.mk_concat(x, b);
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* a = sg.mk_char('a');
|
||||
euf::snode const* b = sg.mk_char('b');
|
||||
euf::snode const* xa = sg.mk_concat(x, a);
|
||||
euf::snode const* xb = sg.mk_concat(x, b);
|
||||
|
||||
ng.add_str_eq(xa, xb);
|
||||
auto r = ng.solve();
|
||||
const auto r = ng.solve();
|
||||
SASSERT(r == seq::nielsen_graph::search_result::unsat);
|
||||
std::cout << " ok: x·a = x·b detected as unsat\n";
|
||||
}
|
||||
|
|
@ -225,14 +225,14 @@ static void test_nseq_const_nielsen_solvable() {
|
|||
seq::context_solver_i context_solver;
|
||||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode* a = sg.mk_char('a');
|
||||
euf::snode* ax = sg.mk_concat(a, x);
|
||||
euf::snode* ay = sg.mk_concat(a, y);
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* y = sg.mk_var(symbol("y"), sg.get_str_sort());
|
||||
euf::snode const* a = sg.mk_char('a');
|
||||
euf::snode const* ax = sg.mk_concat(a, x);
|
||||
euf::snode const* ay = sg.mk_concat(a, y);
|
||||
|
||||
ng.add_str_eq(ax, ay);
|
||||
auto r = ng.solve();
|
||||
const auto r = ng.solve();
|
||||
// a·x = a·y simplifies to x = y which is satisfiable (x = y = ε)
|
||||
SASSERT(r == seq::nielsen_graph::search_result::sat);
|
||||
std::cout << " ok: a·x = a·y solved as sat\n";
|
||||
|
|
@ -248,12 +248,12 @@ static void test_nseq_length_mismatch() {
|
|||
nseq_basic_dummy_solver solver;
|
||||
seq::context_solver_i context_solver;
|
||||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
euf::snode* a = sg.mk_char('a');
|
||||
euf::snode* b = sg.mk_char('b');
|
||||
euf::snode* ab = sg.mk_concat(a, b);
|
||||
euf::snode const* a = sg.mk_char('a');
|
||||
euf::snode const* b = sg.mk_char('b');
|
||||
euf::snode const* ab = sg.mk_concat(a, b);
|
||||
|
||||
ng.add_str_eq(ab, a);
|
||||
auto r = ng.solve();
|
||||
const auto r = ng.solve();
|
||||
SASSERT(r == seq::nielsen_graph::search_result::unsat);
|
||||
std::cout << " ok: ab = a detected as unsat\n";
|
||||
}
|
||||
|
|
@ -270,15 +270,15 @@ static void test_setup_seq_str_dispatches_nseq() {
|
|||
smt::context ctx(m, params);
|
||||
|
||||
// Assert a string equality to trigger string theory setup during check()
|
||||
seq_util su(m);
|
||||
const seq_util su(m);
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
app_ref x(m.mk_const(symbol("x_setup_test"), str_sort), m);
|
||||
app_ref eq(m.mk_eq(x.get(), x.get()), m);
|
||||
const app_ref x(m.mk_const(symbol("x_setup_test"), str_sort), m);
|
||||
const app_ref eq(m.mk_eq(x.get(), x.get()), m);
|
||||
ctx.assert_expr(eq);
|
||||
ctx.check();
|
||||
|
||||
// Verify that theory_nseq (not theory_seq) was registered for the "seq" family
|
||||
family_id seq_fid = m.mk_family_id("seq");
|
||||
const family_id seq_fid = m.mk_family_id("seq");
|
||||
SASSERT(ctx.get_theory(seq_fid) != nullptr);
|
||||
SASSERT(dynamic_cast<smt::theory_nseq*>(ctx.get_theory(seq_fid)) != nullptr);
|
||||
std::cout << " ok: setup_seq_str dispatched to setup_nseq for 'nseq'\n";
|
||||
|
|
|
|||
|
|
@ -60,23 +60,23 @@ public:
|
|||
struct str_builder {
|
||||
euf::sgraph& sg;
|
||||
seq_util& su;
|
||||
euf::snode* vars[26] = {}; // vars['A'-'A'] .. vars['Z'-'A']
|
||||
euf::snode const* vars[26] = {}; // vars['A'-'A'] .. vars['Z'-'A']
|
||||
|
||||
str_builder(euf::sgraph& sg, seq_util& su) : sg(sg), su(su) {}
|
||||
|
||||
euf::snode* var(char c) {
|
||||
int idx = c - 'A';
|
||||
euf::snode const* var(const char c) {
|
||||
const int idx = c - 'A';
|
||||
if (!vars[idx])
|
||||
vars[idx] = sg.mk_var(symbol(std::string(1, c).c_str()), su.str.mk_string_sort());
|
||||
return vars[idx];
|
||||
}
|
||||
|
||||
euf::snode* parse(const char* s) {
|
||||
euf::snode* result = nullptr;
|
||||
euf::snode const* parse(const char* s) {
|
||||
euf::snode const* result = nullptr;
|
||||
for (const char* p = s; *p; ++p) {
|
||||
euf::snode* tok = (*p >= 'A' && *p <= 'Z')
|
||||
euf::snode const* tok = (*p >= 'A' && *p <= 'Z')
|
||||
? var(*p)
|
||||
: sg.mk_char((unsigned)(unsigned char)*p);
|
||||
: sg.mk_char((unsigned char)*p);
|
||||
result = result ? sg.mk_concat(result, tok) : tok;
|
||||
}
|
||||
return result ? result : sg.mk_empty_seq(su.str.mk_string_sort());
|
||||
|
|
@ -99,20 +99,20 @@ struct regex_builder {
|
|||
re_sort = su.re.mk_re(su.str.mk_string_sort());
|
||||
}
|
||||
|
||||
euf::snode* parse(const char* s) {
|
||||
euf::snode const* parse(const char* s) {
|
||||
int pos = 0;
|
||||
expr_ref e = parse_union(s, pos, (int)strlen(s));
|
||||
const expr_ref e = parse_union(s, pos, (int)strlen(s));
|
||||
SASSERT(pos == (int)strlen(s));
|
||||
return sg.mk(e.get());
|
||||
}
|
||||
|
||||
private:
|
||||
expr_ref mk_char_re(char c) {
|
||||
zstring zs(std::string(1, c).c_str());
|
||||
expr_ref mk_char_re(const char c) const {
|
||||
const zstring zs(std::string(1, c).c_str());
|
||||
return expr_ref(su.re.mk_to_re(su.str.mk_string(zs)), m);
|
||||
}
|
||||
|
||||
expr_ref parse_union(const char* s, int& pos, int len) {
|
||||
expr_ref parse_union(const char* s, int& pos, const int len) {
|
||||
expr_ref left = parse_inter(s, pos, len);
|
||||
while (pos < len && s[pos] == '|') {
|
||||
++pos;
|
||||
|
|
@ -122,7 +122,7 @@ private:
|
|||
return left;
|
||||
}
|
||||
|
||||
expr_ref parse_inter(const char* s, int& pos, int len) {
|
||||
expr_ref parse_inter(const char* s, int& pos, const int len) {
|
||||
expr_ref left = parse_concat(s, pos, len);
|
||||
while (pos < len && s[pos] == '&') {
|
||||
++pos;
|
||||
|
|
@ -132,7 +132,7 @@ private:
|
|||
return left;
|
||||
}
|
||||
|
||||
expr_ref parse_concat(const char* s, int& pos, int len) {
|
||||
expr_ref parse_concat(const char* s, int& pos, const int len) {
|
||||
expr_ref acc(m);
|
||||
while (pos < len && s[pos] != ')' && s[pos] != '|' && s[pos] != '&') {
|
||||
expr_ref tok = parse_repeat(s, pos, len);
|
||||
|
|
@ -141,7 +141,7 @@ private:
|
|||
return acc ? acc : expr_ref(su.re.mk_to_re(su.str.mk_string(zstring(""))), m);
|
||||
}
|
||||
|
||||
expr_ref parse_repeat(const char* s, int& pos, int len) {
|
||||
expr_ref parse_repeat(const char* s, int& pos, const int len) {
|
||||
// collect leading tildes (complement)
|
||||
int tildes = 0;
|
||||
while (pos < len && s[pos] == '~') { ++tildes; ++pos; }
|
||||
|
|
@ -160,10 +160,10 @@ private:
|
|||
return base;
|
||||
}
|
||||
|
||||
expr_ref parse_primary(const char* s, int& pos, int len) {
|
||||
expr_ref parse_primary(const char* s, int& pos, const int len) {
|
||||
if (pos >= len)
|
||||
return expr_ref(su.re.mk_to_re(su.str.mk_string(zstring(""))), m);
|
||||
char c = s[pos];
|
||||
const char c = s[pos];
|
||||
if (c == '(') {
|
||||
++pos;
|
||||
expr_ref inner = parse_union(s, pos, len);
|
||||
|
|
@ -197,8 +197,8 @@ struct nseq_fixture {
|
|||
: eg(init(m)), sg(m, eg), dummy_solver(), context_solver(), ng(sg, dummy_solver, context_solver), su(m), sb(sg, su), rb(m, su, sg)
|
||||
{}
|
||||
|
||||
euf::snode* S(const char* s) { return sb.parse(s); }
|
||||
euf::snode* R(const char* s) { return rb.parse(s); }
|
||||
euf::snode const* S(const char* s) { return sb.parse(s); }
|
||||
euf::snode const* R(const char* s) { return rb.parse(s); }
|
||||
};
|
||||
|
||||
static constexpr int TEST_TIMEOUT_SEC = 2;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -318,9 +318,9 @@ static void test_generate_constraints_ab_star() {
|
|||
arith_util arith(m);
|
||||
seq::seq_parikh parikh(sg);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
expr_ref re = mk_ab_star(m, seq);
|
||||
euf::snode* regex = sg.mk(re);
|
||||
euf::snode const* regex = sg.mk(re);
|
||||
seq::dep_manager dm;
|
||||
sat::literal lit = sat::null_literal; // dummy literal for dependency tracking
|
||||
seq::dep_tracker dep = dm.mk_leaf(lit);
|
||||
|
|
@ -364,11 +364,11 @@ static void test_generate_constraints_bounded_loop() {
|
|||
arith_util arith(m);
|
||||
seq::seq_parikh parikh(sg);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
// loop("ab", 1, 3): min_len=2, max_len=6, stride=2
|
||||
expr_ref ab = mk_to_re_ab(m, seq);
|
||||
expr_ref re(seq.re.mk_loop(ab, 1, 3), m);
|
||||
euf::snode* regex = sg.mk(re);
|
||||
euf::snode const* regex = sg.mk(re);
|
||||
seq::dep_manager dm;
|
||||
seq::dep_tracker dep = dm.mk_leaf(sat::null_literal);
|
||||
seq::str_mem mem(x, regex, dep);
|
||||
|
|
@ -402,10 +402,10 @@ static void test_generate_constraints_stride_one() {
|
|||
seq::seq_parikh parikh(sg);
|
||||
sort_ref str_sort(seq.str.mk_string_sort(), m);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
// full_seq: stride=1 → no modular constraint
|
||||
expr_ref re(seq.re.mk_full_seq(str_sort), m);
|
||||
euf::snode* regex = sg.mk(re);
|
||||
euf::snode const* regex = sg.mk(re);
|
||||
seq::dep_manager dm;
|
||||
seq::dep_tracker dep = dm.mk_leaf(sat::null_literal);
|
||||
seq::str_mem mem(x, regex, dep);
|
||||
|
|
@ -426,9 +426,9 @@ static void test_generate_constraints_fixed_length() {
|
|||
seq_util seq(m);
|
||||
seq::seq_parikh parikh(sg);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
expr_ref re = mk_to_re_ab(m, seq); // fixed len 2
|
||||
euf::snode* regex = sg.mk(re);
|
||||
euf::snode const* regex = sg.mk(re);
|
||||
seq::dep_manager dm;
|
||||
seq::dep_tracker dep = dm.mk_leaf(sat::null_literal);
|
||||
seq::str_mem mem(x, regex, dep);
|
||||
|
|
@ -449,9 +449,9 @@ static void test_generate_constraints_dep_propagated() {
|
|||
seq_util seq(m);
|
||||
seq::seq_parikh parikh(sg);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
expr_ref re = mk_ab_star(m, seq);
|
||||
euf::snode* regex = sg.mk(re);
|
||||
euf::snode const* regex = sg.mk(re);
|
||||
seq::dep_manager dm;
|
||||
sat::literal lit(7);
|
||||
seq::dep_tracker dep = dm.mk_leaf(lit);
|
||||
|
|
@ -490,9 +490,9 @@ static void test_apply_to_node_adds_constraints() {
|
|||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
seq::seq_parikh parikh(sg);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
expr_ref re = mk_ab_star(m, seq); // stride 2 → generates constraints
|
||||
euf::snode* regex = sg.mk(re);
|
||||
euf::snode const* regex = sg.mk(re);
|
||||
ng.add_str_mem(x, regex);
|
||||
|
||||
// root node should have no int_constraints initially
|
||||
|
|
@ -523,9 +523,9 @@ static void test_apply_to_node_stride_one_no_constraints() {
|
|||
seq::nielsen_graph ng(sg, solver, context_solver);
|
||||
seq::seq_parikh parikh(sg);
|
||||
|
||||
euf::snode* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
euf::snode const* x = sg.mk_var(symbol("x"), sg.get_str_sort());
|
||||
expr_ref re(seq.re.mk_full_seq(str_sort), m); // stride 1 → no constraints
|
||||
euf::snode* regex = sg.mk(re);
|
||||
euf::snode const* regex = sg.mk(re);
|
||||
ng.add_str_mem(x, regex);
|
||||
|
||||
unsigned before = ng.root()->constraints().size();
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ static void test_seq_regex_is_empty() {
|
|||
reg_decl_plugins(m);
|
||||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
seq::seq_regex nr(sg);
|
||||
const seq::seq_regex nr(sg);
|
||||
|
||||
seq_util su(m);
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
// re.none is the empty language
|
||||
expr_ref none_e(su.re.mk_empty(su.re.mk_re(str_sort)), m);
|
||||
euf::snode* none_n = sg.mk(none_e.get());
|
||||
const expr_ref none_e(su.re.mk_empty(su.re.mk_re(str_sort)), m);
|
||||
euf::snode const* none_n = sg.mk(none_e.get());
|
||||
SASSERT(nr.is_empty_regex(none_n));
|
||||
std::cout << " ok: re.none recognized as empty\n";
|
||||
}
|
||||
|
|
@ -60,13 +60,13 @@ static void test_seq_regex_is_full() {
|
|||
reg_decl_plugins(m);
|
||||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
seq::seq_regex nr(sg);
|
||||
const seq::seq_regex nr(sg);
|
||||
|
||||
seq_util su(m);
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
// re.all (full sequence regex) is not empty
|
||||
expr_ref full_e(su.re.mk_full_seq(su.re.mk_re(str_sort)), m);
|
||||
euf::snode* full_n = sg.mk(full_e.get());
|
||||
const expr_ref full_e(su.re.mk_full_seq(su.re.mk_re(str_sort)), m);
|
||||
euf::snode const* full_n = sg.mk(full_e.get());
|
||||
SASSERT(!nr.is_empty_regex(full_n));
|
||||
std::cout << " ok: re.all not recognized as empty\n";
|
||||
}
|
||||
|
|
@ -85,8 +85,8 @@ static void test_strengthened_stabilizer_null() {
|
|||
seq_util su(m);
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode* full_re = sg.mk(full_e);
|
||||
const expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode const* full_re = sg.mk(full_e);
|
||||
|
||||
SASSERT(nr.strengthened_stabilizer(full_re, nullptr) == nullptr);
|
||||
SASSERT(nr.strengthened_stabilizer(nullptr, full_re) == nullptr);
|
||||
|
|
@ -106,14 +106,14 @@ static void test_strengthened_stabilizer_single_char() {
|
|||
seq_util su(m);
|
||||
|
||||
// Build a*
|
||||
expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode* re_star_a = sg.mk(star_a);
|
||||
const expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode const* re_star_a = sg.mk(star_a);
|
||||
|
||||
// Build history = char 'a' (single token, no concat needed)
|
||||
euf::snode* tok_a = sg.mk_char('a');
|
||||
euf::snode* history = tok_a;
|
||||
euf::snode const* tok_a = sg.mk_char('a');
|
||||
euf::snode const* history = tok_a;
|
||||
|
||||
euf::snode* result = nr.strengthened_stabilizer(re_star_a, history);
|
||||
euf::snode const* result = nr.strengthened_stabilizer(re_star_a, history);
|
||||
// Should produce a non-null stabilizer body (to_re("a"))
|
||||
SASSERT(result != nullptr);
|
||||
std::cout << " ok: a* with history 'a' -> non-null stabilizer\n";
|
||||
|
|
@ -132,16 +132,16 @@ static void test_strengthened_stabilizer_two_char() {
|
|||
seq_util su(m);
|
||||
|
||||
// Build (ab)*
|
||||
expr_ref ab(su.re.mk_to_re(su.str.mk_string("ab")), m);
|
||||
expr_ref star_ab(su.re.mk_star(ab), m);
|
||||
euf::snode* re_star_ab = sg.mk(star_ab);
|
||||
const expr_ref ab(su.re.mk_to_re(su.str.mk_string("ab")), m);
|
||||
const expr_ref star_ab(su.re.mk_star(ab), m);
|
||||
euf::snode const* re_star_ab = sg.mk(star_ab);
|
||||
|
||||
// Build history: concat(char_a, char_b) using string concat
|
||||
euf::snode* tok_a = sg.mk_char('a');
|
||||
euf::snode* tok_b = sg.mk_char('b');
|
||||
euf::snode* history = sg.mk_concat(tok_a, tok_b);
|
||||
euf::snode const* tok_a = sg.mk_char('a');
|
||||
euf::snode const* tok_b = sg.mk_char('b');
|
||||
euf::snode const* history = sg.mk_concat(tok_a, tok_b);
|
||||
|
||||
euf::snode* result = nr.strengthened_stabilizer(re_star_ab, history);
|
||||
euf::snode const* result = nr.strengthened_stabilizer(re_star_ab, history);
|
||||
// Should produce a non-null stabilizer body
|
||||
SASSERT(result != nullptr);
|
||||
std::cout << " ok: (ab)* with history 'ab' -> non-null stabilizer\n";
|
||||
|
|
@ -154,16 +154,16 @@ static void test_filtered_stabilizer_star_empty() {
|
|||
reg_decl_plugins(m);
|
||||
euf::egraph eg(m);
|
||||
euf::sgraph sg(m, eg);
|
||||
seq::seq_regex nr(sg);
|
||||
const seq::seq_regex nr(sg);
|
||||
seq_util su(m);
|
||||
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode* full_re = sg.mk(full_e);
|
||||
euf::snode* tok_a = sg.mk_char('a');
|
||||
const expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode const* full_re = sg.mk(full_e);
|
||||
euf::snode const* tok_a = sg.mk_char('a');
|
||||
|
||||
euf::snode* result = nr.get_filtered_stabilizer_star(full_re, tok_a);
|
||||
euf::snode const* result = nr.get_filtered_stabilizer_star(full_re, tok_a);
|
||||
SASSERT(result == nullptr);
|
||||
std::cout << " ok: no stabilizers -> nullptr\n";
|
||||
}
|
||||
|
|
@ -179,17 +179,17 @@ static void test_filtered_stabilizer_star_with_stab() {
|
|||
seq_util su(m);
|
||||
|
||||
// Build a* as the regex state
|
||||
expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode* re_star_a = sg.mk(star_a);
|
||||
const expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode const* re_star_a = sg.mk(star_a);
|
||||
|
||||
// Register a stabilizer: to_re("b") — only accepts "b"
|
||||
expr_ref stab_b(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
euf::snode* stab_b_sn = sg.mk(stab_b);
|
||||
const expr_ref stab_b(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
euf::snode const* stab_b_sn = sg.mk(stab_b);
|
||||
nr.add_stabilizer(re_star_a, stab_b_sn);
|
||||
|
||||
// Exclude char 'a': D('a', to_re("b")) should be fail
|
||||
euf::snode* tok_a = sg.mk_char('a');
|
||||
euf::snode* result = nr.get_filtered_stabilizer_star(re_star_a, tok_a);
|
||||
euf::snode const* tok_a = sg.mk_char('a');
|
||||
euf::snode const* result = nr.get_filtered_stabilizer_star(re_star_a, tok_a);
|
||||
// to_re("b") should pass the filter → result is star(to_re("b"))
|
||||
SASSERT(result != nullptr);
|
||||
SASSERT(result->is_star());
|
||||
|
|
@ -207,17 +207,17 @@ static void test_filtered_stabilizer_star_filtered() {
|
|||
seq_util su(m);
|
||||
|
||||
// Build a* as the regex state
|
||||
expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode* re_star_a = sg.mk(star_a);
|
||||
const expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode const* re_star_a = sg.mk(star_a);
|
||||
|
||||
// Register a stabilizer: to_re("a") — accepts "a"
|
||||
expr_ref stab_a(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
euf::snode* stab_a_sn = sg.mk(stab_a);
|
||||
const expr_ref stab_a(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
euf::snode const* stab_a_sn = sg.mk(stab_a);
|
||||
nr.add_stabilizer(re_star_a, stab_a_sn);
|
||||
|
||||
// Exclude char 'a': D('a', to_re("a")) is NOT fail → filtered out
|
||||
euf::snode* tok_a = sg.mk_char('a');
|
||||
euf::snode* result = nr.get_filtered_stabilizer_star(re_star_a, tok_a);
|
||||
euf::snode const* tok_a = sg.mk_char('a');
|
||||
euf::snode const* result = nr.get_filtered_stabilizer_star(re_star_a, tok_a);
|
||||
SASSERT(result == nullptr);
|
||||
std::cout << " ok: filter removes to_re('a') when excluding 'a'\n";
|
||||
}
|
||||
|
|
@ -234,26 +234,26 @@ static void test_extract_cycle_history_basic() {
|
|||
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode* full_re = sg.mk(full_e);
|
||||
const expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode const* full_re = sg.mk(full_e);
|
||||
|
||||
euf::snode* tok_a = sg.mk_char('a');
|
||||
euf::snode* tok_b = sg.mk_char('b');
|
||||
euf::snode* tok_c = sg.mk_char('c');
|
||||
euf::snode const* tok_a = sg.mk_char('a');
|
||||
euf::snode const* tok_b = sg.mk_char('b');
|
||||
euf::snode const* tok_c = sg.mk_char('c');
|
||||
|
||||
// Ancestor history: just 'a' (length 1)
|
||||
euf::snode* anc_hist = tok_a;
|
||||
euf::snode const* anc_hist = tok_a;
|
||||
|
||||
// Current history: concat(concat(a, b), c) = a,b,c (length 3)
|
||||
euf::snode* cur_hist = sg.mk_concat(sg.mk_concat(tok_a, tok_b), tok_c);
|
||||
euf::snode const* cur_hist = sg.mk_concat(sg.mk_concat(tok_a, tok_b), tok_c);
|
||||
|
||||
euf::snode* empty_str = sg.mk_empty_seq(str_sort);
|
||||
seq::dep_tracker empty_dep = nullptr;
|
||||
euf::snode const* empty_str = sg.mk_empty_seq(str_sort);
|
||||
const seq::dep_tracker empty_dep = nullptr;
|
||||
|
||||
seq::str_mem ancestor(empty_str, full_re, empty_dep);
|
||||
seq::str_mem current(empty_str, full_re, empty_dep);
|
||||
const seq::str_mem ancestor(empty_str, full_re, empty_dep);
|
||||
const seq::str_mem current(empty_str, full_re, empty_dep);
|
||||
|
||||
euf::snode* cycle = nr.extract_cycle_history(current, ancestor);
|
||||
euf::snode const* cycle = nr.extract_cycle_history(current, ancestor);
|
||||
// Should return the last 2 tokens (b, c)
|
||||
SASSERT(cycle != nullptr);
|
||||
SASSERT(cycle->length() == 2);
|
||||
|
|
@ -272,20 +272,20 @@ static void test_extract_cycle_history_null_ancestor() {
|
|||
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode* full_re = sg.mk(full_e);
|
||||
const expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode const* full_re = sg.mk(full_e);
|
||||
|
||||
euf::snode* tok_a = sg.mk_char('a');
|
||||
euf::snode* tok_b = sg.mk_char('b');
|
||||
euf::snode* cur_hist = sg.mk_concat(tok_a, tok_b);
|
||||
euf::snode* empty_str = sg.mk_empty_seq(str_sort);
|
||||
seq::dep_tracker empty_dep = nullptr;
|
||||
euf::snode const* tok_a = sg.mk_char('a');
|
||||
euf::snode const* tok_b = sg.mk_char('b');
|
||||
euf::snode const* cur_hist = sg.mk_concat(tok_a, tok_b);
|
||||
euf::snode const* empty_str = sg.mk_empty_seq(str_sort);
|
||||
const seq::dep_tracker empty_dep = nullptr;
|
||||
|
||||
// Ancestor has no history (nullptr)
|
||||
seq::str_mem ancestor(empty_str, full_re, empty_dep);
|
||||
seq::str_mem current(empty_str, full_re, empty_dep);
|
||||
const seq::str_mem ancestor(empty_str, full_re, empty_dep);
|
||||
const seq::str_mem current(empty_str, full_re, empty_dep);
|
||||
|
||||
euf::snode* cycle = nr.extract_cycle_history(current, ancestor);
|
||||
euf::snode const* cycle = nr.extract_cycle_history(current, ancestor);
|
||||
// With null ancestor history, entire current history is the cycle
|
||||
SASSERT(cycle != nullptr);
|
||||
SASSERT(cycle->length() == 2);
|
||||
|
|
@ -304,9 +304,9 @@ static void test_bfs_empty_none() {
|
|||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
|
||||
expr_ref none_e(su.re.mk_empty(re_sort), m);
|
||||
euf::snode* none_re = sg.mk(none_e);
|
||||
lbool result = nr.is_empty_bfs(none_re);
|
||||
const expr_ref none_e(su.re.mk_empty(re_sort), m);
|
||||
euf::snode const* none_re = sg.mk(none_e);
|
||||
const lbool result = nr.is_empty_bfs(none_re);
|
||||
SASSERT(result == l_true);
|
||||
std::cout << " ok: re.none -> l_true (empty)\n";
|
||||
}
|
||||
|
|
@ -323,9 +323,9 @@ static void test_bfs_nonempty_full() {
|
|||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
|
||||
expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode* full_re = sg.mk(full_e);
|
||||
lbool result = nr.is_empty_bfs(full_re);
|
||||
const expr_ref full_e(su.re.mk_full_seq(re_sort), m);
|
||||
euf::snode const* full_re = sg.mk(full_e);
|
||||
const lbool result = nr.is_empty_bfs(full_re);
|
||||
SASSERT(result == l_false);
|
||||
std::cout << " ok: full_seq -> l_false (non-empty)\n";
|
||||
}
|
||||
|
|
@ -340,9 +340,9 @@ static void test_bfs_nonempty_to_re() {
|
|||
seq::seq_regex nr(sg);
|
||||
seq_util su(m);
|
||||
|
||||
expr_ref to_re_abc(su.re.mk_to_re(su.str.mk_string("abc")), m);
|
||||
euf::snode* re_abc = sg.mk(to_re_abc);
|
||||
lbool result = nr.is_empty_bfs(re_abc);
|
||||
const expr_ref to_re_abc(su.re.mk_to_re(su.str.mk_string("abc")), m);
|
||||
euf::snode const* re_abc = sg.mk(to_re_abc);
|
||||
const lbool result = nr.is_empty_bfs(re_abc);
|
||||
SASSERT(result == l_false);
|
||||
std::cout << " ok: to_re(\"abc\") -> l_false (non-empty)\n";
|
||||
}
|
||||
|
|
@ -357,9 +357,9 @@ static void test_bfs_nonempty_star() {
|
|||
seq::seq_regex nr(sg);
|
||||
seq_util su(m);
|
||||
|
||||
expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode* re_star_a = sg.mk(star_a);
|
||||
lbool result = nr.is_empty_bfs(re_star_a);
|
||||
const expr_ref star_a(su.re.mk_star(su.re.mk_to_re(su.str.mk_string("a"))), m);
|
||||
euf::snode const* re_star_a = sg.mk(star_a);
|
||||
const lbool result = nr.is_empty_bfs(re_star_a);
|
||||
SASSERT(result == l_false);
|
||||
std::cout << " ok: a* -> l_false (non-empty, accepts epsilon)\n";
|
||||
}
|
||||
|
|
@ -376,11 +376,11 @@ static void test_bfs_empty_union_of_empties() {
|
|||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
|
||||
expr_ref none1(su.re.mk_empty(re_sort), m);
|
||||
expr_ref none2(su.re.mk_empty(re_sort), m);
|
||||
expr_ref union_e(su.re.mk_union(none1, none2), m);
|
||||
euf::snode* re_union = sg.mk(union_e);
|
||||
lbool result = nr.is_empty_bfs(re_union);
|
||||
const expr_ref none1(su.re.mk_empty(re_sort), m);
|
||||
const expr_ref none2(su.re.mk_empty(re_sort), m);
|
||||
const expr_ref union_e(su.re.mk_union(none1, none2), m);
|
||||
euf::snode const* re_union = sg.mk(union_e);
|
||||
const lbool result = nr.is_empty_bfs(re_union);
|
||||
SASSERT(result == l_true);
|
||||
std::cout << " ok: union(none, none) -> l_true (empty)\n";
|
||||
}
|
||||
|
|
@ -396,11 +396,11 @@ static void test_bfs_nonempty_range() {
|
|||
seq_util su(m);
|
||||
sort* str_sort = su.str.mk_string_sort();
|
||||
|
||||
expr_ref lo(su.mk_char('a'), m);
|
||||
expr_ref hi(su.mk_char('z'), m);
|
||||
expr_ref range_e(su.re.mk_range(su.str.mk_unit(lo), su.str.mk_unit(hi)), m);
|
||||
euf::snode* re_range = sg.mk(range_e);
|
||||
lbool result = nr.is_empty_bfs(re_range);
|
||||
const expr_ref lo(su.mk_char('a'), m);
|
||||
const expr_ref hi(su.mk_char('z'), m);
|
||||
const expr_ref range_e(su.re.mk_range(su.str.mk_unit(lo), su.str.mk_unit(hi)), m);
|
||||
euf::snode const* re_range = sg.mk(range_e);
|
||||
const lbool result = nr.is_empty_bfs(re_range);
|
||||
SASSERT(result == l_false);
|
||||
std::cout << " ok: range('a','z') -> l_false (non-empty)\n";
|
||||
}
|
||||
|
|
@ -417,9 +417,9 @@ static void test_bfs_empty_complement_full() {
|
|||
sort* str_sort = su.str.mk_string_sort();
|
||||
sort* re_sort = su.re.mk_re(str_sort);
|
||||
|
||||
expr_ref comp_full(su.re.mk_complement(su.re.mk_full_seq(re_sort)), m);
|
||||
euf::snode* re_comp = sg.mk(comp_full);
|
||||
lbool result = nr.is_empty_bfs(re_comp);
|
||||
const expr_ref comp_full(su.re.mk_complement(su.re.mk_full_seq(re_sort)), m);
|
||||
euf::snode const* re_comp = sg.mk(comp_full);
|
||||
const lbool result = nr.is_empty_bfs(re_comp);
|
||||
SASSERT(result == l_true);
|
||||
std::cout << " ok: ~full_seq -> l_true (empty)\n";
|
||||
}
|
||||
|
|
@ -433,7 +433,7 @@ static void test_bfs_null_safety() {
|
|||
euf::sgraph sg(m, eg);
|
||||
seq::seq_regex nr(sg);
|
||||
|
||||
lbool result = nr.is_empty_bfs(nullptr);
|
||||
const lbool result = nr.is_empty_bfs(nullptr);
|
||||
SASSERT(result == l_undef);
|
||||
std::cout << " ok: nullptr -> l_undef\n";
|
||||
}
|
||||
|
|
@ -449,13 +449,13 @@ static void test_bfs_bounded() {
|
|||
seq_util su(m);
|
||||
|
||||
// (a|b)+ requires at least one char; with max_states=1 should bail
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
expr_ref ab_plus(su.re.mk_plus(ab_union), m);
|
||||
euf::snode* re_plus = sg.mk(ab_plus);
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
const expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
const expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
const expr_ref ab_plus(su.re.mk_plus(ab_union), m);
|
||||
euf::snode const* re_plus = sg.mk(ab_plus);
|
||||
|
||||
lbool result = nr.is_empty_bfs(re_plus, 1);
|
||||
const lbool result = nr.is_empty_bfs(re_plus, 1);
|
||||
SASSERT(result == l_undef);
|
||||
std::cout << " ok: (a|b)+ with max_states=1 -> l_undef (bounded)\n";
|
||||
}
|
||||
|
|
@ -469,13 +469,13 @@ static void test_char_set_is_subset() {
|
|||
std::cout << "test_char_set_is_subset\n";
|
||||
|
||||
// {a} ⊆ {a,b,c} = [97,100)
|
||||
char_set cs1(char_range('a', 'b')); // {a}
|
||||
char_set cs2(char_range('a', 'd')); // {a,b,c}
|
||||
const char_set cs1(char_range('a', 'b')); // {a}
|
||||
const char_set cs2(char_range('a', 'd')); // {a,b,c}
|
||||
SASSERT(cs1.is_subset(cs2));
|
||||
SASSERT(!cs2.is_subset(cs1));
|
||||
|
||||
// empty ⊆ anything
|
||||
char_set empty;
|
||||
const char_set empty;
|
||||
SASSERT(empty.is_subset(cs1));
|
||||
SASSERT(empty.is_subset(cs2));
|
||||
|
||||
|
|
@ -484,7 +484,7 @@ static void test_char_set_is_subset() {
|
|||
SASSERT(cs2.is_subset(cs2));
|
||||
|
||||
// disjoint: {x} not ⊆ {a}
|
||||
char_set cs3(char_range('x', 'y'));
|
||||
const char_set cs3(char_range('x', 'y'));
|
||||
SASSERT(!cs3.is_subset(cs1));
|
||||
|
||||
std::cout << " ok\n";
|
||||
|
|
@ -500,10 +500,10 @@ static void test_stabilizer_store_basic() {
|
|||
seq::seq_regex nr(sg);
|
||||
seq_util su(m);
|
||||
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
euf::snode* a_sn = sg.mk(a_re);
|
||||
euf::snode* b_sn = sg.mk(b_re);
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
const expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
euf::snode const* a_sn = sg.mk(a_re);
|
||||
euf::snode const* b_sn = sg.mk(b_re);
|
||||
|
||||
SASSERT(!nr.has_stabilizers(a_sn));
|
||||
nr.add_stabilizer(a_sn, b_sn);
|
||||
|
|
@ -532,16 +532,16 @@ static void test_self_stabilizing() {
|
|||
seq::seq_regex nr(sg);
|
||||
seq_util su(m);
|
||||
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
euf::snode* a_sn = sg.mk(a_re);
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
euf::snode const* a_sn = sg.mk(a_re);
|
||||
|
||||
SASSERT(!nr.is_self_stabilizing(a_sn));
|
||||
nr.set_self_stabilizing(a_sn);
|
||||
SASSERT(nr.is_self_stabilizing(a_sn));
|
||||
|
||||
// star should be detected as self-stabilizing
|
||||
expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
euf::snode* star_sn = sg.mk(star_a);
|
||||
const expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
euf::snode const* star_sn = sg.mk(star_a);
|
||||
SASSERT(nr.compute_self_stabilizing(star_sn));
|
||||
|
||||
std::cout << " ok\n";
|
||||
|
|
@ -558,19 +558,19 @@ static void test_check_intersection_sat() {
|
|||
seq_util su(m);
|
||||
|
||||
// a* ∩ (a|b)* should be non-empty (both accept "a")
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
expr_ref star_ab(su.re.mk_star(ab_union), m);
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
const expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
const expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
const expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
const expr_ref star_ab(su.re.mk_star(ab_union), m);
|
||||
|
||||
euf::snode* s1 = sg.mk(star_a);
|
||||
euf::snode* s2 = sg.mk(star_ab);
|
||||
ptr_vector<euf::snode> regexes;
|
||||
euf::snode const* s1 = sg.mk(star_a);
|
||||
euf::snode const* s2 = sg.mk(star_ab);
|
||||
euf::snode_vector regexes;
|
||||
regexes.push_back(s1);
|
||||
regexes.push_back(s2);
|
||||
|
||||
lbool result = nr.check_intersection_emptiness(regexes, UINT_MAX);
|
||||
const lbool result = nr.check_intersection_emptiness(regexes, UINT_MAX);
|
||||
SASSERT(result == l_false); // non-empty
|
||||
std::cout << " ok: a* ∩ (a|b)* is non-empty\n";
|
||||
}
|
||||
|
|
@ -587,15 +587,15 @@ static void test_check_intersection_unsat() {
|
|||
sort* str_sort = su.str.mk_string_sort();
|
||||
|
||||
// to_re("a") ∩ to_re("b") should be empty
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
euf::snode* s1 = sg.mk(a_re);
|
||||
euf::snode* s2 = sg.mk(b_re);
|
||||
ptr_vector<euf::snode> regexes;
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
const expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
euf::snode const* s1 = sg.mk(a_re);
|
||||
euf::snode const* s2 = sg.mk(b_re);
|
||||
euf::snode_vector regexes;
|
||||
regexes.push_back(s1);
|
||||
regexes.push_back(s2);
|
||||
|
||||
lbool result = nr.check_intersection_emptiness(regexes, UINT_MAX);
|
||||
const lbool result = nr.check_intersection_emptiness(regexes, UINT_MAX);
|
||||
SASSERT(result == l_true); // empty
|
||||
std::cout << " ok: to_re(a) ∩ to_re(b) is empty\n";
|
||||
}
|
||||
|
|
@ -611,16 +611,16 @@ static void test_is_language_subset_true() {
|
|||
seq_util su(m);
|
||||
|
||||
// a* ⊆ (a|b)* should be true
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
expr_ref star_ab(su.re.mk_star(ab_union), m);
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
const expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
const expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
const expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
const expr_ref star_ab(su.re.mk_star(ab_union), m);
|
||||
|
||||
euf::snode* subset = sg.mk(star_a);
|
||||
euf::snode* superset = sg.mk(star_ab);
|
||||
euf::snode const* subset = sg.mk(star_a);
|
||||
euf::snode const* superset = sg.mk(star_ab);
|
||||
|
||||
lbool result = nr.is_language_subset(subset, superset);
|
||||
const lbool result = nr.is_language_subset(subset, superset);
|
||||
SASSERT(result == l_true);
|
||||
std::cout << " ok: a* ⊆ (a|b)*\n";
|
||||
}
|
||||
|
|
@ -636,16 +636,16 @@ static void test_is_language_subset_false() {
|
|||
seq_util su(m);
|
||||
|
||||
// (a|b)* ⊄ a* should be false (b ∈ (a|b)* but b ∉ a*)
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
expr_ref star_ab(su.re.mk_star(ab_union), m);
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
const expr_ref star_a(su.re.mk_star(a_re), m);
|
||||
const expr_ref b_re(su.re.mk_to_re(su.str.mk_string("b")), m);
|
||||
const expr_ref ab_union(su.re.mk_union(a_re, b_re), m);
|
||||
const expr_ref star_ab(su.re.mk_star(ab_union), m);
|
||||
|
||||
euf::snode* subset = sg.mk(star_ab);
|
||||
euf::snode* superset = sg.mk(star_a);
|
||||
euf::snode const* subset = sg.mk(star_ab);
|
||||
euf::snode const* superset = sg.mk(star_a);
|
||||
|
||||
lbool result = nr.is_language_subset(subset, superset);
|
||||
const lbool result = nr.is_language_subset(subset, superset);
|
||||
SASSERT(result == l_false);
|
||||
std::cout << " ok: (a|b)* ⊄ a*\n";
|
||||
}
|
||||
|
|
@ -662,15 +662,15 @@ static void test_is_language_subset_trivial() {
|
|||
sort* str_sort = su.str.mk_string_sort();
|
||||
|
||||
// ∅ ⊆ anything = true
|
||||
expr_ref none(su.re.mk_empty(su.re.mk_re(str_sort)), m);
|
||||
expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
euf::snode* empty_sn = sg.mk(none);
|
||||
euf::snode* a_sn = sg.mk(a_re);
|
||||
const expr_ref none(su.re.mk_empty(su.re.mk_re(str_sort)), m);
|
||||
const expr_ref a_re(su.re.mk_to_re(su.str.mk_string("a")), m);
|
||||
euf::snode const* empty_sn = sg.mk(none);
|
||||
euf::snode const* a_sn = sg.mk(a_re);
|
||||
SASSERT(nr.is_language_subset(empty_sn, a_sn) == l_true);
|
||||
|
||||
// anything ⊆ Σ* = true
|
||||
expr_ref full(su.re.mk_full_seq(su.re.mk_re(str_sort)), m);
|
||||
euf::snode* full_sn = sg.mk(full);
|
||||
const expr_ref full(su.re.mk_full_seq(su.re.mk_re(str_sort)), m);
|
||||
euf::snode const* full_sn = sg.mk(full);
|
||||
SASSERT(nr.is_language_subset(a_sn, full_sn) == l_true);
|
||||
|
||||
// L ⊆ L = true (same pointer)
|
||||
|
|
@ -689,14 +689,14 @@ static void test_some_seq_in_re_excluded_low_regression() {
|
|||
seq_rewriter rw(m);
|
||||
th_rewriter tr(m);
|
||||
|
||||
expr_ref low(su.mk_char('A'), m);
|
||||
expr_ref high(su.mk_char('Z'), m);
|
||||
expr_ref range_az(su.re.mk_range(su.str.mk_unit(low), su.str.mk_unit(high)), m);
|
||||
expr_ref not_a(su.re.mk_complement(su.re.mk_to_re(su.str.mk_string("A"))), m);
|
||||
expr_ref re_expr(su.re.mk_inter(not_a, range_az), m);
|
||||
const expr_ref low(su.mk_char('A'), m);
|
||||
const expr_ref high(su.mk_char('Z'), m);
|
||||
const expr_ref range_az(su.re.mk_range(su.str.mk_unit(low), su.str.mk_unit(high)), m);
|
||||
const expr_ref not_a(su.re.mk_complement(su.re.mk_to_re(su.str.mk_string("A"))), m);
|
||||
const expr_ref re_expr(su.re.mk_inter(not_a, range_az), m);
|
||||
|
||||
expr_ref witness(m);
|
||||
lbool wr = rw.some_seq_in_re(re_expr, witness);
|
||||
const lbool wr = rw.some_seq_in_re(re_expr, witness);
|
||||
SASSERT(wr == l_true);
|
||||
SASSERT(witness);
|
||||
|
||||
|
|
@ -704,7 +704,7 @@ static void test_some_seq_in_re_excluded_low_regression() {
|
|||
SASSERT(su.str.is_string(witness, ws));
|
||||
SASSERT(ws != zstring("A"));
|
||||
|
||||
expr_ref in_re(su.re.mk_in_re(witness, re_expr), m);
|
||||
const expr_ref in_re(su.re.mk_in_re(witness, re_expr), m);
|
||||
expr_ref in_re_simpl(m);
|
||||
tr(in_re, in_re_simpl);
|
||||
SASSERT(m.is_true(in_re_simpl));
|
||||
|
|
@ -730,8 +730,8 @@ static void test_some_seq_in_re_inter_loop_regression() {
|
|||
return expr_ref(su.re.mk_to_re(su.str.mk_string(s)), m);
|
||||
};
|
||||
auto mk_range = [&](const char* lo, const char* hi) -> expr_ref {
|
||||
expr_ref l(su.mk_char(lo[0]), m);
|
||||
expr_ref h(su.mk_char(hi[0]), m);
|
||||
const expr_ref l(su.mk_char(lo[0]), m);
|
||||
const expr_ref h(su.mk_char(hi[0]), m);
|
||||
return expr_ref(su.re.mk_range(su.str.mk_unit(l), su.str.mk_unit(h)), m);
|
||||
};
|
||||
auto cat = [&](expr* a, expr* b) -> expr_ref {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue