Skip to content

Commit e6feb84

Browse files
sls: fix bug where unsat remains empty after a literal is flipped. The new satisfiable subset should be checked
refined interface between solvers to expose fixed variables for tabu objectives
1 parent 24c3cd3 commit e6feb84

8 files changed

+118
-30
lines changed

src/ast/sls/sls_arith_base.cpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,7 @@ namespace sls {
19681968

19691969
template<typename num_t>
19701970
bool arith_base<num_t>::set_value(expr* e, expr* v) {
1971+
19711972
if (!a.is_int_real(e))
19721973
return false;
19731974
var_t w = m_expr2var.get(e->get_id(), UINT_MAX);
@@ -1984,7 +1985,14 @@ namespace sls {
19841985
}
19851986
if (n == value(w))
19861987
return true;
1987-
return update(w, n);
1988+
bool r = update(w, n);
1989+
1990+
if (!r) {
1991+
IF_VERBOSE(2,
1992+
verbose_stream() << "set value failed " << mk_pp(e, m) << " := " << mk_pp(v, m) << "\n";
1993+
display(verbose_stream(), w) << " := " << value(w) << "\n");
1994+
}
1995+
return r;
19881996
}
19891997

19901998
template<typename num_t>
@@ -1996,6 +2004,23 @@ namespace sls {
19962004
return expr_ref(a.mk_numeral(m_vars[v].value().to_rational(), a.is_int(e)), m);
19972005
}
19982006

2007+
template<typename num_t>
2008+
bool arith_base<num_t>::is_fixed(expr* e, expr_ref& value) {
2009+
if (!a.is_int_real(e))
2010+
return false;
2011+
num_t n;
2012+
if (is_num(e, n)) {
2013+
value = expr_ref(a.mk_numeral(n.to_rational(), a.is_int(e)), m);
2014+
return true;
2015+
}
2016+
auto v = mk_term(e);
2017+
if (is_fixed(v)) {
2018+
value = expr_ref(a.mk_numeral(m_vars[v].value().to_rational(), a.is_int(e)), m);
2019+
return true;
2020+
}
2021+
return false;
2022+
}
2023+
19992024
template<typename num_t>
20002025
bool arith_base<num_t>::is_sat() {
20012026
invariant();

src/ast/sls/sls_arith_base.h

+1
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ namespace sls {
280280
void register_term(expr* e) override;
281281
bool set_value(expr* e, expr* v) override;
282282
expr_ref get_value(expr* e) override;
283+
bool is_fixed(expr* e, expr_ref& value) override;
283284
void initialize() override;
284285
void propagate_literal(sat::literal lit) override;
285286
bool propagate() override;

src/ast/sls/sls_arith_plugin.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ namespace sls {
6464
WITH_FALLBACK(get_value(e));
6565
}
6666

67+
bool arith_plugin::is_fixed(expr* e, expr_ref& value) {
68+
WITH_FALLBACK(is_fixed(e, value));
69+
}
70+
6771
void arith_plugin::initialize() {
6872
APPLY_BOTH(initialize());
6973
}

src/ast/sls/sls_arith_plugin.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace sls {
3232
~arith_plugin() override {}
3333
void register_term(expr* e) override;
3434
expr_ref get_value(expr* e) override;
35+
bool is_fixed(expr* e, expr_ref& value) override;
3536
void initialize() override;
3637
void propagate_literal(sat::literal lit) override;
3738
bool propagate() override;

src/ast/sls/sls_context.cpp

+16-6
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ namespace sls {
172172
}
173173

174174
void context::propagate_boolean_assignment() {
175+
start_propagation:
175176
reinit_relevant();
176177

177178
for (auto p : m_plugins)
@@ -180,9 +181,12 @@ namespace sls {
180181

181182
for (sat::literal lit : root_literals())
182183
propagate_literal(lit);
183-
184-
if (m_new_constraint)
185-
return;
184+
185+
if (any_of(root_literals(), [&](sat::literal lit) { return !is_true(lit); })) {
186+
if (unsat().empty())
187+
goto start_propagation;
188+
return;
189+
}
186190

187191
while (!m_new_constraint && m.inc() && (!m_repair_up.empty() || !m_repair_down.empty())) {
188192
while (!m_repair_down.empty() && !m_new_constraint && m.inc()) {
@@ -258,9 +262,6 @@ namespace sls {
258262
auto p = m_plugins.get(fid, nullptr);
259263
if (p)
260264
p->propagate_literal(lit);
261-
if (!is_true(lit)) {
262-
m_new_constraint = true;
263-
}
264265
}
265266

266267
bool context::is_true(expr* e) {
@@ -291,6 +292,14 @@ namespace sls {
291292
bool context::set_value(expr * e, expr * v) {
292293
return any_of(m_plugins, [&](auto p) { return p && p->set_value(e, v); });
293294
}
295+
296+
bool context::is_fixed(expr* e, expr_ref& value) {
297+
if (m.is_value(e)) {
298+
value = e;
299+
return true;
300+
}
301+
return any_of(m_plugins, [&](auto p) { return p && p->is_fixed(e, value); });
302+
}
294303

295304
bool context::is_relevant(expr* e) {
296305
unsigned id = e->get_id();
@@ -317,6 +326,7 @@ namespace sls {
317326
m_constraint_trail.push_back(e);
318327
add_clause(e);
319328
m_new_constraint = true;
329+
verbose_stream() << "add constraint\n";
320330
++m_stats.m_num_constraints;
321331
}
322332

src/ast/sls/sls_context.h

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace sls {
4242
virtual family_id fid() { return m_fid; }
4343
virtual void register_term(expr* e) = 0;
4444
virtual expr_ref get_value(expr* e) = 0;
45+
virtual bool is_fixed(expr* e, expr_ref& value) { return false; }
4546
virtual void initialize() = 0;
4647
virtual void start_propagation() {};
4748
virtual bool propagate() = 0;
@@ -192,6 +193,7 @@ namespace sls {
192193

193194
// Between plugin solvers
194195
expr_ref get_value(expr* e);
196+
bool is_fixed(expr* v, expr_ref& value);
195197
bool set_value(expr* e, expr* v);
196198
void new_value_eh(expr* e);
197199
bool is_true(expr* e);

src/ast/sls/sls_seq_plugin.cpp

+66-21
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Alternate to lookahead strategy:
6363
- create a priority buffer array of vector<ptr_vector<expr>> based on depth.
6464
- walk from lowest depth up. Reset each inner buffer when processed. Parents always
6565
have higher depth.
66-
- calculate repair/break score when hitting a predicate based on bval1.
66+
- calculate repair/break depth when hitting a predicate based on bval1.
6767
- strval1 and bval1 are modified by
6868
- use a global timestamp.
6969
- label each eval subterm by a timestamp that gets set.
@@ -145,9 +145,26 @@ namespace sls {
145145
auto ve = ctx.get_value(e);
146146
if (a.is_numeral(ve, r) && r == sx.length())
147147
continue;
148-
update(e, rational(sx.length()));
148+
// set e to length of x or
149+
// set x to a string of length e
150+
151+
if (r == 0 || sx.length() == 0) {
152+
verbose_stream() << "todo-create lemma: len(x) = 0 <=> x = \"\"\n";
153+
// create a lemma: len(x) = 0 => x = ""
154+
}
155+
if (ctx.rand(2) == 0 && update(e, rational(sx.length())))
156+
return false;
157+
if (r < sx.length() && update(x, sx.extract(0, r.get_unsigned())))
158+
return false;
159+
if (update(e, rational(sx.length())))
160+
return false;
161+
if (r > sx.length() && update(x, sx + zstring(m_chars[ctx.rand(m_chars.size())])))
162+
return false;
163+
verbose_stream() << mk_pp(x, m) << " = " << sx << " " << ve << "\n";
164+
NOT_IMPLEMENTED_YET();
149165
return false;
150166
}
167+
151168
if ((seq.str.is_index(e, x, y, z) || seq.str.is_index(e, x, y)) && seq.is_string(x->get_sort())) {
152169
auto sx = strval0(x);
153170
auto sy = strval0(y);
@@ -603,21 +620,32 @@ namespace sls {
603620
auto const& R = rhs(eq);
604621
unsigned i = 0, j = 0; // position into current string
605622
unsigned ni = 0, nj = 0; // current string in concatenation
606-
double depth = 1.0; // priority of update. Doubled when depth of equal strings are increased.
623+
double score = 1.0; // priority of update. Doubled when score of equal strings are increased.
624+
625+
IF_VERBOSE(4,
626+
verbose_stream() << "unify: \"" << strval0(eq->get_arg(0)) << "\" == \"" << strval0(eq->get_arg(1)) << "\"\n";
627+
for (auto x : L) verbose_stream() << mk_pp(x, m) << " ";
628+
verbose_stream() << " == ";
629+
for (auto x : R) verbose_stream() << mk_pp(x, m) << " ";
630+
verbose_stream() << "\n";
631+
for (auto x : L) verbose_stream() << "\"" << strval0(x) << "\" ";
632+
verbose_stream() << " == ";
633+
for (auto x : R) verbose_stream() << "\"" << strval0(x) << "\" ";
634+
verbose_stream() << "\n";
635+
);
636+
607637
while (ni < L.size() && nj < R.size()) {
608638
auto const& xi = L[ni];
609639
auto const& yj = R[nj];
610640
auto const& vi = strval0(xi);
611641
auto const& vj = strval0(yj);
612-
IF_VERBOSE(4,
613-
verbose_stream() << "unify: \"" << vi << "\" = \"" << vj << "\" incides " << i << " " << j << "\n";
614-
verbose_stream() << vi.length() << " " << vj.length() << "\n");
642+
615643
if (vi.length() == i && vj.length() == j) {
616-
depth *= 2;
644+
score *= 2;
617645
if (nj + 1 < R.size() && !strval0(R[nj + 1]).empty())
618-
m_str_updates.push_back({ xi, vi + zstring(strval0(R[nj + 1])[0]), depth });
646+
m_str_updates.push_back({ xi, vi + zstring(strval0(R[nj + 1])[0]), score });
619647
if (ni + 1 < L.size() && !strval0(L[ni + 1]).empty())
620-
m_str_updates.push_back({ yj, vj + zstring(strval0(L[ni + 1])[0]), depth });
648+
m_str_updates.push_back({ yj, vj + zstring(strval0(L[ni + 1])[0]), score });
621649
i = 0;
622650
j = 0;
623651
++ni;
@@ -627,48 +655,51 @@ namespace sls {
627655
if (vi.length() == i) {
628656
// xi -> vi + vj[j]
629657
SASSERT(j < vj.length());
630-
m_str_updates.push_back({ xi, vi + zstring(vj[j]), depth});
631-
depth *= 2;
658+
m_str_updates.push_back({ xi, vi + zstring(vj[j]), score});
659+
score *= 2;
632660
i = 0;
633661
++ni;
634662
continue;
635663
}
636664
if (vj.length() == j) {
637665
// yj -> vj + vi[i]
638666
SASSERT(i < vi.length());
639-
m_str_updates.push_back({ yj, vj + zstring(vi[i]), depth });
640-
depth *= 2;
667+
m_str_updates.push_back({ yj, vj + zstring(vi[i]), score });
668+
score *= 2;
641669
j = 0;
642670
++nj;
643671
continue;
644672
}
645673
SASSERT(i < vi.length());
646674
SASSERT(j < vj.length());
647675
if (is_value(xi) && is_value(yj)) {
676+
if (vi[i] != vj[j])
677+
score = 1;
648678
++i, ++j;
649679
continue;
650680
}
681+
651682
if (vi[i] == vj[j]) {
652683
++i, ++j;
653684
continue;
654685
}
655686
if (!is_value(xi)) {
656-
m_str_updates.push_back({ xi, vi.extract(0, i), depth });
657-
m_str_updates.push_back({ xi, vi.extract(0, i) + zstring(vj[j]), depth});
687+
m_str_updates.push_back({ xi, vi.extract(0, i), score });
688+
m_str_updates.push_back({ xi, vi.extract(0, i) + zstring(vj[j]), score});
658689
}
659690
if (!is_value(yj)) {
660-
m_str_updates.push_back({ yj, vj.extract(0, j), depth });
661-
m_str_updates.push_back({ yj, vj.extract(0, j) + zstring(vi[i]), depth });
691+
m_str_updates.push_back({ yj, vj.extract(0, j), score });
692+
m_str_updates.push_back({ yj, vj.extract(0, j) + zstring(vi[i]), score });
662693
}
663694
break;
664695
}
665696
for (; ni < L.size(); ++ni)
666-
if (!is_value(L[ni]))
667-
m_str_updates.push_back({ L[ni], zstring(), depth });
697+
if (!is_value(L[ni]) && !strval0(L[ni]).empty())
698+
m_str_updates.push_back({ L[ni], zstring(), 1 });
668699

669700
for (; nj < R.size(); ++nj)
670-
if (!is_value(R[nj]))
671-
m_str_updates.push_back({ R[nj], zstring(), depth });
701+
if (!is_value(R[nj]) && !strval0(R[nj]).empty())
702+
m_str_updates.push_back({ R[nj], zstring(), 1 });
672703

673704
return apply_update();
674705
}
@@ -1092,6 +1123,13 @@ namespace sls {
10921123
sum_scores += score;
10931124
for (auto const& [e, val, score] : m_int_updates)
10941125
sum_scores += score;
1126+
1127+
IF_VERBOSE(4,
1128+
for (auto const& [e, val, score] : m_str_updates)
1129+
verbose_stream() << mk_pp(e, m) << " := \"" << val << "\" score: " << score << "\n";
1130+
for (auto const& [e, val, score] : m_int_updates)
1131+
verbose_stream() << mk_pp(e, m) << " := " << val << " score: " << score << "\n";
1132+
);
10951133

10961134
while (!m_str_updates.empty() || !m_int_updates.empty()) {
10971135
bool is_str_update = false;
@@ -1165,6 +1203,7 @@ namespace sls {
11651203
if (m_initialized)
11661204
return;
11671205
m_initialized = true;
1206+
expr_ref val(m);
11681207
for (auto lit : ctx.unit_literals()) {
11691208
auto e = ctx.atom(lit.var());
11701209
expr* x, * y, * z;
@@ -1214,6 +1253,12 @@ namespace sls {
12141253
if (len_r.is_unsigned())
12151254
ev.max_length = std::min(ev.max_length, len_r.get_unsigned());
12161255
}
1256+
// TBD: assumes arithmetic is already initialized
1257+
if (seq.str.is_length(t, x) && ctx.is_fixed(t, val) &&
1258+
a.is_numeral(val, len_r) && len_r.is_unsigned()) {
1259+
auto& ev = get_eval(x);
1260+
ev.min_length = ev.max_length = len_r.get_unsigned();
1261+
}
12171262
}
12181263
}
12191264

src/tactic/sls/sls_tactic.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ class sls_smt_tactic : public tactic {
7878
try {
7979
res = m_sls->check();
8080
}
81-
catch (z3_exception&) {
81+
catch (z3_exception& ex) {
82+
IF_VERBOSE(1, verbose_stream() << "SLS threw an exception: " << ex.what() << "\n");
8283
m_sls->collect_statistics(m_st);
8384
throw;
8485
}
@@ -98,7 +99,6 @@ class sls_smt_tactic : public tactic {
9899
}
99100
else
100101
mc = nullptr;
101-
102102
}
103103

104104
void operator()(goal_ref const& g,

0 commit comments

Comments
 (0)