Skip to content

Commit dd064a5

Browse files
delay digit axioms until solving itos succeeds
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent e3e6959 commit dd064a5

File tree

4 files changed

+179
-180
lines changed

4 files changed

+179
-180
lines changed

src/smt/seq_axioms.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ namespace smt {
4747
expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(seq.str.mk_concat(e1, e2, e3), m); }
4848
expr_ref mk_concat(expr* e1, expr* e2) { return expr_ref(seq.str.mk_concat(e1, e2), m); }
4949
expr_ref mk_nth(expr* e, unsigned i) { return expr_ref(seq.str.mk_nth_i(e, a.mk_int(i)), m); }
50-
literal mk_ge(expr* e, int k) { return mk_ge_e(e, a.mk_int(k)); }
51-
literal mk_le(expr* e, int k) { return mk_le_e(e, a.mk_int(k)); }
52-
literal mk_ge(expr* e, rational const& k) { return mk_ge_e(e, a.mk_int(k)); }
53-
literal mk_le(expr* e, rational const& k) { return mk_le_e(e, a.mk_int(k)); }
5450
literal mk_ge_e(expr* x, expr* y) { return mk_literal(a.mk_ge(x, y)); }
5551
literal mk_le_e(expr* x, expr* y) { return mk_literal(a.mk_le(x, y)); }
5652
void add_axiom(literal l1, literal l2 = null_literal, literal l3 = null_literal,
@@ -90,7 +86,12 @@ namespace smt {
9086
void add_le_axiom(expr* n);
9187
void add_unit_axiom(expr* n);
9288
void add_length_axiom(expr* n);
89+
9390
literal is_digit(expr* ch);
91+
literal mk_ge(expr* e, int k) { return mk_ge_e(e, a.mk_int(k)); }
92+
literal mk_le(expr* e, int k) { return mk_le_e(e, a.mk_int(k)); }
93+
literal mk_ge(expr* e, rational const& k) { return mk_ge_e(e, a.mk_int(k)); }
94+
literal mk_le(expr* e, rational const& k) { return mk_le_e(e, a.mk_int(k)); }
9495

9596
expr_ref add_length_limit(expr* s, unsigned k);
9697
};

src/smt/seq_eq_solver.cpp

Lines changed: 167 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Module Name:
1212
Author:
1313
1414
Nikolaj Bjorner (nbjorner) 2015-6-12
15+
Thai Minh Trinh 2017
1516
*/
1617

1718
#include <typeinfo>
@@ -95,18 +96,13 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de
9596
}
9697
TRACE("seq", tout << "inserting equality\n";);
9798
bool updated = false;
98-
if (!m_len_offset.empty()) {
99-
// Find a better equivalent term for lhs of an equation based on length constraints
100-
expr_ref_vector new_ls(m);
101-
if (find_better_rep(ls, rs, idx, deps, new_ls)) {
102-
eq const & new_eq = eq(m_eq_id++, new_ls, rs, deps);
103-
m_eqs.push_back(new_eq);
104-
TRACE("seq", tout << "find_better_rep\n";);
105-
TRACE("seq", display_equation(tout, new_eq););
106-
updated = true;
107-
}
99+
expr_ref_vector new_ls(m);
100+
if (!m_len_offset.empty() &&
101+
find_better_rep(ls, rs, idx, deps, new_ls)) {
102+
// Find a better equivalent term for lhs of an equation based on length constraints
103+
m_eqs.push_back(eq(m_eq_id++, new_ls, rs, deps));
108104
}
109-
if (!updated) {
105+
else {
110106
m_eqs.push_back(eq(m_eq_id++, ls, rs, deps));
111107
}
112108
TRACE("seq", tout << "simplified\n";);
@@ -115,6 +111,122 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de
115111
return false;
116112
}
117113

114+
bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) {
115+
if (l == r) {
116+
return true;
117+
}
118+
if (is_var(l) && !occurs(l, r) && add_solution(l, r, deps)) {
119+
return true;
120+
}
121+
if (is_var(r) && !occurs(r, l) && add_solution(r, l, deps)) {
122+
return true;
123+
}
124+
return false;
125+
}
126+
127+
bool theory_seq::solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* deps) {
128+
if (l.size() == 1 && is_var(l[0]) && !occurs(l[0], r) && add_solution(l[0], mk_concat(r, m.get_sort(l[0])), deps)) {
129+
return true;
130+
}
131+
if (r.size() == 1 && is_var(r[0]) && !occurs(r[0], l) && add_solution(r[0], mk_concat(l, m.get_sort(r[0])), deps)) {
132+
return true;
133+
}
134+
return false;
135+
}
136+
137+
bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) {
138+
context& ctx = get_context();
139+
ptr_vector<expr> xs, ys;
140+
expr_ref x(m), y(m);
141+
bool is_binary =
142+
is_binary_eq(ls, rs, x, xs, ys, y) ||
143+
is_binary_eq(rs, ls, x, xs, ys, y);
144+
if (!is_binary) {
145+
return false;
146+
}
147+
// Equation is of the form x ++ xs = ys ++ y
148+
// where xs, ys are units.
149+
if (x != y) {
150+
return false;
151+
}
152+
if (xs.size() != ys.size()) {
153+
TRACE("seq", tout << "binary conflict\n";);
154+
set_conflict(dep);
155+
return false;
156+
}
157+
if (xs.empty()) {
158+
// this should have been solved already
159+
UNREACHABLE();
160+
return false;
161+
}
162+
163+
// Equation is of the form x ++ xs = ys ++ x
164+
// where |xs| = |ys| are units of same length
165+
// then xs is a wrap-around of ys
166+
// x ++ ab = ba ++ x
167+
//
168+
if (xs.size() == 1) {
169+
enode* n1 = ensure_enode(xs[0]);
170+
enode* n2 = ensure_enode(ys[0]);
171+
if (n1->get_root() == n2->get_root()) {
172+
return false;
173+
}
174+
literal eq = mk_eq(xs[0], ys[0], false);
175+
switch (ctx.get_assignment(eq)) {
176+
case l_false: {
177+
literal_vector conflict;
178+
conflict.push_back(~eq);
179+
TRACE("seq", tout << conflict << "\n";);
180+
set_conflict(dep, conflict);
181+
break;
182+
}
183+
case l_true:
184+
break;
185+
case l_undef:
186+
ctx.mark_as_relevant(eq);
187+
propagate_lit(dep, 0, nullptr, eq);
188+
m_new_propagation = true;
189+
break;
190+
}
191+
}
192+
return false;
193+
}
194+
195+
196+
bool theory_seq::occurs(expr* a, expr_ref_vector const& b) {
197+
for (auto const& elem : b) {
198+
if (a == elem || m.is_ite(elem)) return true;
199+
}
200+
return false;
201+
}
202+
203+
bool theory_seq::occurs(expr* a, expr* b) {
204+
// true if a occurs under an interpreted function or under left/right selector.
205+
SASSERT(is_var(a));
206+
SASSERT(m_todo.empty());
207+
expr* e1 = nullptr, *e2 = nullptr;
208+
m_todo.push_back(b);
209+
while (!m_todo.empty()) {
210+
b = m_todo.back();
211+
if (a == b || m.is_ite(b)) {
212+
m_todo.reset();
213+
return true;
214+
}
215+
m_todo.pop_back();
216+
if (m_util.str.is_concat(b, e1, e2)) {
217+
m_todo.push_back(e1);
218+
m_todo.push_back(e2);
219+
}
220+
else if (m_util.str.is_unit(b, e1)) {
221+
m_todo.push_back(e1);
222+
}
223+
else if (m_util.str.is_nth_i(b, e1, e2)) {
224+
m_todo.push_back(e1);
225+
}
226+
}
227+
return false;
228+
}
229+
118230
// TODO: propagate length offsets for last vars
119231
bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned idx,
120232
dependency*& deps, expr_ref_vector & res) {
@@ -492,16 +604,12 @@ bool theory_seq::split_lengths(dependency* dep,
492604

493605
SASSERT(X != Y);
494606

495-
496607
// |b| < |X| <= |b| + |Y| => x = bY1, Y = Y1Y2
497608
expr_ref lenXE = mk_len(X);
498609
expr_ref lenYE = mk_len(Y);
499610
expr_ref lenb = mk_len(b);
500-
expr_ref le1(m_autil.mk_le(mk_sub(lenXE, lenb), m_autil.mk_int(0)), m);
501-
expr_ref le2(m_autil.mk_le(mk_sub(mk_sub(lenXE, lenb), lenYE),
502-
m_autil.mk_int(0)), m);
503-
literal lit1(~mk_literal(le1));
504-
literal lit2(mk_literal(le2));
611+
literal lit1 = ~m_ax.mk_le(mk_sub(lenXE, lenb), 0);
612+
literal lit2 = m_ax.mk_le(mk_sub(mk_sub(lenXE, lenb), lenYE), 0);
505613
literal_vector lits;
506614
lits.push_back(lit1);
507615
lits.push_back(lit2);
@@ -738,7 +846,7 @@ unsigned_vector theory_seq::overlap2(expr_ref_vector const& ls, expr_ref_vector
738846
}
739847
unsigned_vector result;
740848
for (unsigned i = 0; i < ls.size(); ++i) {
741-
if (eq_unit(ls[i],rs[0])) {
849+
if (eq_unit(ls[i], rs[0])) {
742850
bool same = true;
743851
unsigned j = i+1;
744852
while (j < ls.size() && j-i < rs.size()) {
@@ -757,7 +865,7 @@ unsigned_vector theory_seq::overlap2(expr_ref_vector const& ls, expr_ref_vector
757865
}
758866

759867
bool theory_seq::branch_ternary_variable_base(
760-
dependency* dep, unsigned_vector indexes,
868+
dependency* dep, unsigned_vector const& indexes,
761869
expr* const& x, expr_ref_vector const& xs, expr* const& y1, expr_ref_vector const& ys, expr* const& y2) {
762870
context& ctx = get_context();
763871
bool change = false;
@@ -854,31 +962,30 @@ bool theory_seq::branch_ternary_variable(eq const& e, bool flag1) {
854962
propagate_eq(dep, lits, y2, ZxsE, true);
855963
#endif
856964
}
857-
else {
858-
expr_ref ge(m_autil.mk_ge(mk_len(y2), m_autil.mk_int(xs.size())), m);
859-
literal lit2 = mk_literal(ge);
860-
if (ctx.get_assignment(lit2) == l_undef) {
861-
TRACE("seq", tout << "rec case init\n";);
862-
ctx.mark_as_relevant(lit2);
863-
ctx.force_phase(lit2);
864-
}
865-
else if (ctx.get_assignment(lit2) == l_true) {
866-
TRACE("seq", tout << "true branch\n";);
867-
TRACE("seq", display_equation(tout, e););
868-
literal_vector lits;
869-
lits.push_back(lit2);
870-
dependency* dep = e.dep();
871-
propagate_eq(dep, lits, x, y1ysZ, true);
872-
propagate_eq(dep, lits, y2, ZxsE, true);
873-
}
874-
else {
875-
return branch_ternary_variable_base(e.dep(), indexes, x, xs, y1, ys, y2);
876-
}
965+
966+
literal ge = m_ax.mk_ge(mk_len(y2), xs.size());
967+
dependency* dep = e.dep();
968+
literal_vector lits;
969+
switch (ctx.get_assignment(ge)) {
970+
case l_undef:
971+
TRACE("seq", tout << "rec case init\n";);
972+
ctx.mark_as_relevant(ge);
973+
ctx.force_phase(ge);
974+
break;
975+
case l_true:
976+
TRACE("seq", tout << "true branch\n";);
977+
TRACE("seq", display_equation(tout, e););
978+
lits.push_back(ge);
979+
propagate_eq(dep, lits, x, y1ysZ, true);
980+
propagate_eq(dep, lits, y2, ZxsE, true);
981+
break;
982+
default:
983+
return branch_ternary_variable_base(e.dep(), indexes, x, xs, y1, ys, y2);
877984
}
878985
return true;
879986
}
880987

881-
bool theory_seq::branch_ternary_variable_base2(dependency* dep, unsigned_vector indexes,
988+
bool theory_seq::branch_ternary_variable_base2(dependency* dep, unsigned_vector const& indexes,
882989
expr_ref_vector const& xs, expr* const& x, expr* const& y1, expr_ref_vector const& ys, expr* const& y2) {
883990
context& ctx = get_context();
884991
bool change = false;
@@ -970,18 +1077,17 @@ bool theory_seq::branch_ternary_variable2(eq const& e, bool flag1) {
9701077
propagate_eq(dep, lits, y1, xsZ, true);
9711078
}
9721079
else {
973-
expr_ref ge(m_autil.mk_ge(mk_len(y1), m_autil.mk_int(xs.size())), m);
974-
literal lit2 = mk_literal(ge);
975-
if (ctx.get_assignment(lit2) == l_undef) {
1080+
literal ge = m_ax.mk_ge(mk_len(y1), xs.size());
1081+
if (ctx.get_assignment(ge) == l_undef) {
9761082
TRACE("seq", tout << "rec case init\n";);
977-
ctx.mark_as_relevant(lit2);
978-
ctx.force_phase(lit2);
1083+
ctx.mark_as_relevant(ge);
1084+
ctx.force_phase(ge);
9791085
}
980-
else if (ctx.get_assignment(lit2) == l_true) {
1086+
else if (ctx.get_assignment(ge) == l_true) {
9811087
TRACE("seq", tout << "true branch\n";);
9821088
TRACE("seq", display_equation(tout, e););
9831089
literal_vector lits;
984-
lits.push_back(lit2);
1090+
lits.push_back(ge);
9851091
dependency* dep = e.dep();
9861092
propagate_eq(dep, lits, x, Zysy2, true);
9871093
propagate_eq(dep, lits, y1, xsZ, true);
@@ -1035,36 +1141,34 @@ bool theory_seq::branch_quat_variable(eq const& e) {
10351141
expr_ref x1(x1_l, m);
10361142
expr_ref y1(y1_l, m);
10371143
expr_ref sub(mk_sub(mk_len(x1_l), mk_len(y1_l)), m);
1038-
expr_ref le(m_autil.mk_le(sub, m_autil.mk_int(0)), m);
1039-
literal lit2 = mk_literal(le);
1040-
if (ctx.get_assignment(lit2) == l_undef) {
1144+
literal le = m_ax.mk_le(sub, 0);
1145+
literal_vector lits;
1146+
if (ctx.get_assignment(le) == l_undef) {
10411147
TRACE("seq", tout << "init branch\n";);
10421148
TRACE("seq", display_equation(tout, e););
1043-
ctx.mark_as_relevant(lit2);
1044-
ctx.force_phase(lit2);
1149+
ctx.mark_as_relevant(le);
1150+
ctx.force_phase(le);
10451151
}
1046-
else if (ctx.get_assignment(lit2) == l_false) {
1152+
else if (ctx.get_assignment(le) == l_false) {
10471153
// |x1| > |y1| => x1 = y1 ++ z1, z1 ++ xs ++ x2 = ys ++ y2
10481154
TRACE("seq", tout << "false branch\n";);
10491155
TRACE("seq", display_equation(tout, e););
10501156
expr_ref Z1 = m_sk.mk_align(ysy2, xsx2, x1, y1);
10511157
expr_ref y1Z1 = mk_concat(y1, Z1);
10521158
expr_ref Z1xsx2 = mk_concat(Z1, xsx2);
1053-
literal_vector lits;
1054-
lits.push_back(~lit2);
1159+
lits.push_back(~le);
10551160
dependency* dep = e.dep();
10561161
propagate_eq(dep, lits, x1, y1Z1, true);
10571162
propagate_eq(dep, lits, Z1xsx2, ysy2, true);
10581163
}
1059-
else if (ctx.get_assignment(lit2) == l_true) {
1164+
else if (ctx.get_assignment(le) == l_true) {
10601165
// |x1| <= |y1| => x1 ++ z2 = y1, xs ++ x2 = z2 ++ ys ++ y2
10611166
TRACE("seq", tout << "true branch\n";);
10621167
TRACE("seq", display_equation(tout, e););
10631168
expr_ref Z2 = m_sk.mk_align(xsx2, ysy2, y1, x1);
10641169
expr_ref x1Z2 = mk_concat(x1, Z2);
10651170
expr_ref Z2ysy2 = mk_concat(Z2, ysy2);
1066-
literal_vector lits;
1067-
lits.push_back(lit2);
1171+
lits.push_back(le);
10681172
dependency* dep = e.dep();
10691173
propagate_eq(dep, lits, x1Z2, y1, true);
10701174
propagate_eq(dep, lits, xsx2, Z2ysy2, true);
@@ -1798,6 +1902,11 @@ bool theory_seq::solve_nth_eq2(expr_ref_vector const& ls, expr_ref_vector const&
17981902
return false;
17991903
}
18001904

1905+
/**
1906+
match
1907+
x = unit(nth_i(x,0)) + unit(nth_i(x,1)) + .. + unit(nth_i(x,k-1))
1908+
*/
1909+
18011910
bool theory_seq::solve_nth_eq1(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) {
18021911
if (solve_nth_eq2(ls, rs, dep)) {
18031912
return true;
@@ -1822,12 +1931,3 @@ bool theory_seq::solve_nth_eq1(expr_ref_vector const& ls, expr_ref_vector const&
18221931
return true;
18231932
}
18241933

1825-
bool theory_seq::solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* deps) {
1826-
if (l.size() == 1 && is_var(l[0]) && !occurs(l[0], r) && add_solution(l[0], mk_concat(r, m.get_sort(l[0])), deps)) {
1827-
return true;
1828-
}
1829-
if (r.size() == 1 && is_var(r[0]) && !occurs(r[0], l) && add_solution(r[0], mk_concat(l, m.get_sort(r[0])), deps)) {
1830-
return true;
1831-
}
1832-
return false;
1833-
}

0 commit comments

Comments
 (0)