Skip to content

Commit 4431a53

Browse files
fix #2450 - track assumptions across lazy explanations and variable equalities
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent db5af30 commit 4431a53

7 files changed

+86
-55
lines changed

src/nlsat/nlsat_evaluator.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ namespace nlsat {
488488
return sign;
489489
}
490490

491-
interval_set_ref infeasible_intervals(ineq_atom * a, bool neg) {
491+
interval_set_ref infeasible_intervals(ineq_atom * a, bool neg, clause const* cls) {
492492
sign_table & table = m_sign_table_tmp;
493493
table.reset();
494494
unsigned num_ps = a->size();
@@ -543,7 +543,7 @@ namespace nlsat {
543543
curr_root_id = table.get_root_id(c-1);
544544
}
545545
set = m_ism.mk(prev_open, prev_inf, table.get_root(prev_root_id),
546-
curr_open, false, table.get_root(curr_root_id), jst);
546+
curr_open, false, table.get_root(curr_root_id), jst, cls);
547547
result = m_ism.mk_union(result, set);
548548
prev_sat = true;
549549
}
@@ -554,7 +554,7 @@ namespace nlsat {
554554
if (c == 0) {
555555
if (num_cells == 1) {
556556
// (-oo, oo)
557-
result = m_ism.mk(true, true, dummy, true, true, dummy, jst);
557+
result = m_ism.mk(true, true, dummy, true, true, dummy, jst, cls);
558558
}
559559
else {
560560
// save -oo as beginning of infeasible interval
@@ -583,7 +583,7 @@ namespace nlsat {
583583
if (c == num_cells - 1) {
584584
// last cell add interval with (prev, oo)
585585
set = m_ism.mk(prev_open, prev_inf, table.get_root(prev_root_id),
586-
true, true, dummy, jst);
586+
true, true, dummy, jst, cls);
587587
result = m_ism.mk_union(result, set);
588588
}
589589
}
@@ -592,7 +592,7 @@ namespace nlsat {
592592
return result;
593593
}
594594

595-
interval_set_ref infeasible_intervals(root_atom * a, bool neg) {
595+
interval_set_ref infeasible_intervals(root_atom * a, bool neg, clause const* cls) {
596596
atom::kind k = a->get_kind();
597597
unsigned i = a->i();
598598
SASSERT(i > 0);
@@ -613,46 +613,46 @@ namespace nlsat {
613613
result = m_ism.mk_empty();
614614
}
615615
else {
616-
result = m_ism.mk(true, true, dummy, true, true, dummy, jst); // (-oo, oo)
616+
result = m_ism.mk(true, true, dummy, true, true, dummy, jst, cls); // (-oo, oo)
617617
}
618618
}
619619
else {
620620
anum const & r_i = roots[i-1];
621621
switch (k) {
622622
case atom::ROOT_EQ:
623623
if (neg) {
624-
result = m_ism.mk(false, false, r_i, false, false, r_i, jst); // [r_i, r_i]
624+
result = m_ism.mk(false, false, r_i, false, false, r_i, jst, cls); // [r_i, r_i]
625625
}
626626
else {
627627
interval_set_ref s1(m_ism), s2(m_ism);
628-
s1 = m_ism.mk(true, true, dummy, true, false, r_i, jst); // (-oo, r_i)
629-
s2 = m_ism.mk(true, false, r_i, true, true, dummy, jst); // (r_i, oo)
628+
s1 = m_ism.mk(true, true, dummy, true, false, r_i, jst, cls); // (-oo, r_i)
629+
s2 = m_ism.mk(true, false, r_i, true, true, dummy, jst, cls); // (r_i, oo)
630630
result = m_ism.mk_union(s1, s2);
631631
}
632632
break;
633633
case atom::ROOT_LT:
634634
if (neg)
635-
result = m_ism.mk(true, true, dummy, true, false, r_i, jst); // (-oo, r_i)
635+
result = m_ism.mk(true, true, dummy, true, false, r_i, jst, cls); // (-oo, r_i)
636636
else
637-
result = m_ism.mk(false, false, r_i, true, true, dummy, jst); // [r_i, oo)
637+
result = m_ism.mk(false, false, r_i, true, true, dummy, jst, cls); // [r_i, oo)
638638
break;
639639
case atom::ROOT_GT:
640640
if (neg)
641-
result = m_ism.mk(true, false, r_i, true, true, dummy, jst); // (r_i, oo)
641+
result = m_ism.mk(true, false, r_i, true, true, dummy, jst, cls); // (r_i, oo)
642642
else
643-
result = m_ism.mk(true, true, dummy, false, false, r_i, jst); // (-oo, r_i]
643+
result = m_ism.mk(true, true, dummy, false, false, r_i, jst, cls); // (-oo, r_i]
644644
break;
645645
case atom::ROOT_LE:
646646
if (neg)
647-
result = m_ism.mk(true, true, dummy, false, false, r_i, jst); // (-oo, r_i]
647+
result = m_ism.mk(true, true, dummy, false, false, r_i, jst, cls); // (-oo, r_i]
648648
else
649-
result = m_ism.mk(true, false, r_i, true, true, dummy, jst); // (r_i, oo)
649+
result = m_ism.mk(true, false, r_i, true, true, dummy, jst, cls); // (r_i, oo)
650650
break;
651651
case atom::ROOT_GE:
652652
if (neg)
653-
result = m_ism.mk(false, false, r_i, true, true, dummy, jst); // [r_i, oo)
653+
result = m_ism.mk(false, false, r_i, true, true, dummy, jst, cls); // [r_i, oo)
654654
else
655-
result = m_ism.mk(true, true, dummy, true, false, r_i, jst); // (-oo, r_i)
655+
result = m_ism.mk(true, true, dummy, true, false, r_i, jst, cls); // (-oo, r_i)
656656
break;
657657
default:
658658
UNREACHABLE();
@@ -663,8 +663,8 @@ namespace nlsat {
663663
return result;
664664
}
665665

666-
interval_set_ref infeasible_intervals(atom * a, bool neg) {
667-
return a->is_ineq_atom() ? infeasible_intervals(to_ineq_atom(a), neg) : infeasible_intervals(to_root_atom(a), neg);
666+
interval_set_ref infeasible_intervals(atom * a, bool neg, clause const* cls) {
667+
return a->is_ineq_atom() ? infeasible_intervals(to_ineq_atom(a), neg, cls) : infeasible_intervals(to_root_atom(a), neg, cls);
668668
}
669669
};
670670

@@ -684,8 +684,8 @@ namespace nlsat {
684684
return m_imp->eval(a, neg);
685685
}
686686

687-
interval_set_ref evaluator::infeasible_intervals(atom * a, bool neg) {
688-
return m_imp->infeasible_intervals(a, neg);
687+
interval_set_ref evaluator::infeasible_intervals(atom * a, bool neg, clause const* cls) {
688+
return m_imp->infeasible_intervals(a, neg, cls);
689689
}
690690

691691
void evaluator::push() {

src/nlsat/nlsat_evaluator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ namespace nlsat {
5252
Let x be a->max_var(). Then, the resultant set specifies which
5353
values of x falsify the given literal.
5454
*/
55-
interval_set_ref infeasible_intervals(atom * a, bool neg);
55+
interval_set_ref infeasible_intervals(atom * a, bool neg, clause const* cls);
5656

5757
void push();
5858
void pop(unsigned num_scopes);

src/nlsat/nlsat_explain.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,14 +1382,14 @@ namespace nlsat {
13821382
literal l = core[i];
13831383
atom * a = m_atoms[l.var()];
13841384
SASSERT(a != 0);
1385-
interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign());
1385+
interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign(), nullptr);
13861386
r = ism.mk_union(inf, r);
13871387
if (ism.is_full(r)) {
13881388
// Done
13891389
return false;
13901390
}
13911391
}
1392-
TRACE("nlsat_mininize", tout << "interval set after adding partial core:\n" << r << "\n";);
1392+
TRACE("nlsat_minimize", tout << "interval set after adding partial core:\n" << r << "\n";);
13931393
if (todo.size() == 1) {
13941394
// Done
13951395
core.push_back(todo[0]);
@@ -1401,7 +1401,7 @@ namespace nlsat {
14011401
literal l = todo[i];
14021402
atom * a = m_atoms[l.var()];
14031403
SASSERT(a != 0);
1404-
interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign());
1404+
interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign(), nullptr);
14051405
r = ism.mk_union(inf, r);
14061406
if (ism.is_full(r)) {
14071407
// literal l must be in the core
@@ -1425,15 +1425,15 @@ namespace nlsat {
14251425
todo.reset(); core.reset();
14261426
todo.append(num, ls);
14271427
while (true) {
1428-
TRACE("nlsat_mininize", tout << "core minimization:\n"; display(tout, todo); tout << "\nCORE:\n"; display(tout, core););
1428+
TRACE("nlsat_minimize", tout << "core minimization:\n"; display(tout, todo); tout << "\nCORE:\n"; display(tout, core););
14291429
if (!minimize_core(todo, core))
14301430
break;
14311431
std::reverse(todo.begin(), todo.end());
1432-
TRACE("nlsat_mininize", tout << "core minimization:\n"; display(tout, todo); tout << "\nCORE:\n"; display(tout, core););
1432+
TRACE("nlsat_minimize", tout << "core minimization:\n"; display(tout, todo); tout << "\nCORE:\n"; display(tout, core););
14331433
if (!minimize_core(todo, core))
14341434
break;
14351435
}
1436-
TRACE("nlsat_mininize", tout << "core:\n"; display(tout, core););
1436+
TRACE("nlsat_minimize", tout << "core:\n"; display(tout, core););
14371437
r.append(core.size(), core.c_ptr());
14381438
}
14391439

src/nlsat/nlsat_interval_set.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace nlsat {
2828
unsigned m_lower_inf:1;
2929
unsigned m_upper_inf:1;
3030
literal m_justification;
31+
clause const* m_clause;
3132
anum m_lower;
3233
anum m_upper;
3334
};
@@ -147,7 +148,7 @@ namespace nlsat {
147148

148149
interval_set * interval_set_manager::mk(bool lower_open, bool lower_inf, anum const & lower,
149150
bool upper_open, bool upper_inf, anum const & upper,
150-
literal justification) {
151+
literal justification, clause const* cls) {
151152
void * mem = m_allocator.allocate(interval_set::get_obj_size(1));
152153
interval_set * new_set = new (mem) interval_set();
153154
new_set->m_num_intervals = 1;
@@ -159,6 +160,7 @@ namespace nlsat {
159160
i->m_upper_open = upper_open;
160161
i->m_upper_inf = upper_inf;
161162
i->m_justification = justification;
163+
i->m_clause = cls;
162164
if (!lower_inf)
163165
m_am.set(i->m_lower, lower);
164166
if (!upper_inf)
@@ -644,8 +646,9 @@ namespace nlsat {
644646
return true;
645647
}
646648

647-
void interval_set_manager::get_justifications(interval_set const * s, literal_vector & js) {
649+
void interval_set_manager::get_justifications(interval_set const * s, literal_vector & js, ptr_vector<clause>& clauses) {
648650
js.reset();
651+
clauses.reset();
649652
unsigned num = num_intervals(s);
650653
for (unsigned i = 0; i < num; i++) {
651654
literal l = s->m_intervals[i].m_justification;
@@ -654,6 +657,9 @@ namespace nlsat {
654657
continue;
655658
m_already_visited.setx(lidx, true, false);
656659
js.push_back(l);
660+
if (s->m_intervals[i].m_clause) {
661+
clauses.push_back(const_cast<clause*>(s->m_intervals[i].m_clause));
662+
}
657663
}
658664
for (unsigned i = 0; i < num; i++) {
659665
literal l = s->m_intervals[i].m_justification;

src/nlsat/nlsat_interval_set.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace nlsat {
4747
*/
4848
interval_set * mk(bool lower_open, bool lower_inf, anum const & lower,
4949
bool upper_open, bool upper_inf, anum const & upper,
50-
literal justification);
50+
literal justification, clause const* cls);
5151

5252
/**
5353
\brief Return the union of two sets.
@@ -91,7 +91,7 @@ namespace nlsat {
9191
/**
9292
\brief Return a set of literals that justify s.
9393
*/
94-
void get_justifications(interval_set const * s, literal_vector & js);
94+
void get_justifications(interval_set const * s, literal_vector & js, ptr_vector<clause>& clauses );
9595

9696
std::ostream& display(std::ostream & out, interval_set const * s) const;
9797

src/nlsat/nlsat_justification.h

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,24 @@ namespace nlsat {
3838

3939
class lazy_justification {
4040
unsigned m_num_literals;
41-
literal m_literals[0];
41+
unsigned m_num_clauses;
42+
char m_data[0];
43+
nlsat::clause* const* clauses() const { return (nlsat::clause *const*)(m_data); }
4244
public:
43-
static unsigned get_obj_size(unsigned num) { return sizeof(lazy_justification) + sizeof(literal)*num; }
44-
lazy_justification(unsigned num, literal const * lits):
45-
m_num_literals(num) {
46-
memcpy(m_literals, lits, sizeof(literal)*num);
45+
static unsigned get_obj_size(unsigned nl, unsigned nc) { return sizeof(lazy_justification) + sizeof(literal)*nl + sizeof(nlsat::clause*)*nc; }
46+
lazy_justification(unsigned nl, literal const * lits, unsigned nc, nlsat::clause * const* clss):
47+
m_num_literals(nl),
48+
m_num_clauses(nc) {
49+
memcpy(m_data + 0, clss, sizeof(nlsat::clause const*)*nc);
50+
memcpy(m_data + sizeof(nlsat::clause*)*nc, lits, sizeof(literal)*nl);
4751
}
48-
unsigned size() const { return m_num_literals; }
49-
literal operator[](unsigned i) const { SASSERT(i < size()); return m_literals[i]; }
50-
literal const * lits() const { return m_literals; }
52+
unsigned num_lits() const { return m_num_literals; }
53+
literal lit(unsigned i) const { SASSERT(i < num_lits()); return lits()[i]; }
54+
literal const * lits() const { return (literal const*)(m_data + m_num_clauses*sizeof(nlsat::clause*)); }
55+
56+
unsigned num_clauses() const { return m_num_clauses; }
57+
nlsat::clause const& clause(unsigned i) const { SASSERT(i < num_clauses()); return *(clauses()[i]); }
58+
5159
};
5260

5361
class justification {
@@ -83,15 +91,15 @@ namespace nlsat {
8391
const justification decided_justification(true);
8492

8593
inline justification mk_clause_jst(clause const * c) { return justification(const_cast<clause*>(c)); }
86-
inline justification mk_lazy_jst(small_object_allocator & a, unsigned num, literal const * lits) {
87-
void * mem = a.allocate(lazy_justification::get_obj_size(num));
88-
return justification(new (mem) lazy_justification(num, lits));
94+
inline justification mk_lazy_jst(small_object_allocator & a, unsigned nl, literal const * lits, unsigned nc, clause *const* clauses) {
95+
void * mem = a.allocate(lazy_justification::get_obj_size(nl, nc));
96+
return justification(new (mem) lazy_justification(nl, lits, nc, clauses));
8997
}
9098

9199
inline void del_jst(small_object_allocator & a, justification jst) {
92100
if (jst.is_lazy()) {
93101
lazy_justification * ptr = jst.get_lazy();
94-
unsigned obj_sz = lazy_justification::get_obj_size(ptr->size());
102+
unsigned obj_sz = lazy_justification::get_obj_size(ptr->num_lits(), ptr->num_clauses());
95103
a.deallocate(obj_sz, ptr);
96104
}
97105
}

0 commit comments

Comments
 (0)