Skip to content

Commit 02e71c7

Browse files
fix #2650, use datatype constructor producing smallest possible tree whenever possible
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent b0bf2f1 commit 02e71c7

File tree

5 files changed

+55
-41
lines changed

5 files changed

+55
-41
lines changed

src/ast/datatype_decl_plugin.cpp

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,28 +1105,24 @@ namespace datatype {
11051105
*/
11061106
func_decl * util::get_non_rec_constructor(sort * ty) {
11071107
SASSERT(is_datatype(ty));
1108-
func_decl * r = nullptr;
1109-
if (m_datatype2nonrec_constructor.find(ty, r))
1110-
return r;
1111-
r = nullptr;
1108+
cnstr_depth cd;
1109+
if (m_datatype2nonrec_constructor.find(ty, cd))
1110+
return cd.first;
11121111
ptr_vector<sort> forbidden_set;
11131112
forbidden_set.push_back(ty);
11141113
TRACE("util_bug", tout << "invoke get-non-rec: " << sort_ref(ty, m) << "\n";);
1115-
r = get_non_rec_constructor_core(ty, forbidden_set);
1114+
cd = get_non_rec_constructor_core(ty, forbidden_set);
11161115
SASSERT(forbidden_set.back() == ty);
1117-
SASSERT(r);
1118-
m_asts.push_back(ty);
1119-
m_asts.push_back(r);
1120-
m_datatype2nonrec_constructor.insert(ty, r);
1121-
return r;
1116+
SASSERT(cd.first);
1117+
return cd.first;
11221118
}
11231119

11241120
/**
11251121
\brief Return a constructor mk(T_1, ..., T_n) where
11261122
each T_i is not a datatype or it is a datatype t not in forbidden_set,
11271123
and get_non_rec_constructor_core(T_i, forbidden_set union { T_i })
11281124
*/
1129-
func_decl * util::get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set) {
1125+
util::cnstr_depth util::get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set) {
11301126
// We must select a constructor c(T_1, ..., T_n):T such that
11311127
// 1) T_i's are not recursive
11321128
// If there is no such constructor, then we select one that
@@ -1135,32 +1131,22 @@ namespace datatype {
11351131
ptr_vector<func_decl> const& constructors = *get_datatype_constructors(ty);
11361132
unsigned sz = constructors.size();
11371133
array_util autil(m);
1134+
cnstr_depth result(nullptr, 0);
1135+
if (m_datatype2nonrec_constructor.find(ty, result))
1136+
return result;
11381137
TRACE("util_bug", tout << "get-non-rec constructor: " << sort_ref(ty, m) << "\n";
11391138
tout << "forbidden: ";
11401139
for (sort* s : forbidden_set) tout << sort_ref(s, m) << " ";
11411140
tout << "\n";
11421141
tout << "constructors: " << sz << "\n";
11431142
for (func_decl* f : constructors) tout << func_decl_ref(f, m) << "\n";
11441143
);
1145-
// step 1)
1146-
unsigned start = ++m_start;
1147-
for (unsigned j = 0; j < sz; ++j) {
1148-
func_decl * c = constructors[(j + start) % sz];
1149-
TRACE("util_bug", tout << "checking " << sort_ref(ty, m) << ": " << func_decl_ref(c, m) << "\n";);
1150-
unsigned num_args = c->get_arity();
1151-
unsigned i = 0;
1152-
for (; i < num_args && !is_datatype(autil.get_array_range_rec(c->get_domain(i))); i++);
1153-
if (i == num_args) {
1154-
TRACE("util_bug", tout << "found non-rec " << func_decl_ref(c, m) << "\n";);
1155-
return c;
1156-
}
1157-
}
1158-
// step 2)
1159-
for (unsigned j = 0; j < sz; ++j) {
1160-
func_decl * c = constructors[(j + start) % sz];
1161-
TRACE("util_bug", tout << "non_rec_constructor c: " << j << " " << func_decl_ref(c, m) << "\n";);
1144+
unsigned min_depth = INT_MAX;
1145+
for (func_decl * c : constructors) {
1146+
TRACE("util_bug", tout << "non_rec_constructor c: " << func_decl_ref(c, m) << "\n";);
11621147
unsigned num_args = c->get_arity();
11631148
unsigned i = 0;
1149+
unsigned max_depth = 0;
11641150
for (; i < num_args; i++) {
11651151
sort * T_i = autil.get_array_range_rec(c->get_domain(i));
11661152
TRACE("util_bug", tout << "c: " << i << " " << sort_ref(T_i, m) << "\n";);
@@ -1173,17 +1159,26 @@ namespace datatype {
11731159
break;
11741160
}
11751161
forbidden_set.push_back(T_i);
1176-
func_decl * nested_c = get_non_rec_constructor_core(T_i, forbidden_set);
1162+
cnstr_depth nested_c = get_non_rec_constructor_core(T_i, forbidden_set);
11771163
SASSERT(forbidden_set.back() == T_i);
11781164
forbidden_set.pop_back();
1179-
if (nested_c == nullptr)
1165+
if (nested_c.first == nullptr)
11801166
break;
1181-
TRACE("util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";);
1167+
TRACE("util_bug", tout << "nested_c: " << nested_c.first->get_name() << "\n";);
1168+
max_depth = std::max(nested_c.second + 1, max_depth);
1169+
}
1170+
if (i == num_args && max_depth < min_depth) {
1171+
result.first = c;
1172+
result.second = max_depth;
1173+
min_depth = max_depth;
11821174
}
1183-
if (i == num_args)
1184-
return c;
11851175
}
1186-
return nullptr;
1176+
if (result.first) {
1177+
m_asts.push_back(result.first);
1178+
m_asts.push_back(ty);
1179+
m_datatype2nonrec_constructor.insert(ty, result);
1180+
}
1181+
return result;
11871182
}
11881183

11891184
unsigned util::get_constructor_idx(func_decl * f) const {

src/ast/datatype_decl_plugin.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,10 @@ namespace datatype {
292292
ast_manager & m;
293293
family_id m_family_id;
294294
mutable decl::plugin* m_plugin;
295-
295+
typedef std::pair<func_decl*, unsigned> cnstr_depth;
296296

297297
obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors;
298-
obj_map<sort, func_decl *> m_datatype2nonrec_constructor;
298+
obj_map<sort, cnstr_depth> m_datatype2nonrec_constructor;
299299
obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors;
300300
obj_map<func_decl, func_decl *> m_constructor2recognizer;
301301
obj_map<func_decl, func_decl *> m_recognizer2constructor;
@@ -309,7 +309,7 @@ namespace datatype {
309309
unsigned m_start;
310310
mutable ptr_vector<sort> m_fully_interp_trail;
311311

312-
func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
312+
cnstr_depth get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
313313

314314
friend class decl::plugin;
315315

src/nlsat/nlsat_evaluator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ namespace nlsat {
423423
scoped_anum_vector & roots = m_tmp_values;
424424
roots.reset();
425425
m_am.isolate_roots(polynomial_ref(a->p(), m_pm), undef_var_assignment(m_assignment, a->x()), roots);
426-
TRACE("nlsat",
426+
TRACE("nlsat_evaluator",
427427
m_solver.display(tout << (neg?"!":""), *a); tout << "\n";
428428
if (roots.empty()) {
429429
tout << "No roots\n";

src/nlsat/nlsat_solver.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,24 @@ namespace nlsat {
826826
}
827827
IF_VERBOSE(0, verbose_stream() << "check\n";);
828828
lbool r = checker.check();
829+
if (r == l_true) {
830+
for (bool_var b : tr) {
831+
literal lit(b, false);
832+
IF_VERBOSE(0, checker.display(verbose_stream(), lit) << " := " << checker.value(lit) << "\n");
833+
TRACE("nlsat", checker.display(tout, lit) << " := " << checker.value(lit) << "\n";);
834+
}
835+
for (clause* c : m_learned) {
836+
bool found = false;
837+
for (literal lit: *c) {
838+
literal tlit(tr[lit.var()], lit.sign());
839+
found |= checker.value(tlit) == l_true;
840+
}
841+
if (!found) {
842+
IF_VERBOSE(0, display(verbose_stream() << "violdated clause: ", *c) << "\n");
843+
TRACE("nlsat", display(tout << "violdated clause: ", *c) << "\n";);
844+
}
845+
}
846+
}
829847
VERIFY(r == l_false);
830848
for (bool_var b : tr) {
831849
checker.dec_ref(b);
@@ -1738,7 +1756,7 @@ namespace nlsat {
17381756
tout << "new valid clause:\n";
17391757
display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()) << "\n";);
17401758

1741-
if (m_check_lemmas && false) {
1759+
if (false && m_check_lemmas) {
17421760
check_lemma(m_lazy_clause.size(), m_lazy_clause.c_ptr(), true, nullptr);
17431761
}
17441762

src/smt/theory_datatype.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,7 @@ namespace smt {
885885
unassigned_idx = idx;
886886
num_unassigned++;
887887
}
888+
TRACE("datatype", tout << "propagate " << num_unassigned << " eqs: " << eqs.size() << "\n";);
888889
if (num_unassigned == 0) {
889890
// conflict
890891
SASSERT(!lits.empty());
@@ -938,13 +939,13 @@ namespace smt {
938939
enode * n = get_enode(v);
939940
sort * s = m.get_sort(n->get_owner());
940941
func_decl * non_rec_c = m_util.get_non_rec_constructor(s);
941-
TRACE("datatype_bug", tout << "non_rec_c: " << non_rec_c->get_name() << "\n";);
942942
unsigned non_rec_idx = m_util.get_constructor_idx(non_rec_c);
943943
var_data * d = m_var_data[v];
944944
SASSERT(d->m_constructor == nullptr);
945945
func_decl * r = nullptr;
946946
m_stats.m_splits++;
947947

948+
TRACE("datatype_bug", tout << "non_rec_c: " << non_rec_c->get_name() << " #rec: " << d->m_recognizers.size() << "\n";);
948949

949950
if (d->m_recognizers.empty()) {
950951
r = m_util.get_constructor_is(non_rec_c);
@@ -987,7 +988,7 @@ namespace smt {
987988
return; // all recognizers are asserted to false... conflict will be detected...
988989
}
989990
}
990-
SASSERT(r != 0);
991+
SASSERT(r != nullptr);
991992
app * r_app = m.mk_app(r, n->get_owner());
992993
TRACE("datatype", tout << "creating split: " << mk_pp(r_app, m) << "\n";);
993994
ctx.internalize(r_app, false);

0 commit comments

Comments
 (0)