1 
2 /*++
3 Copyright (c) 2015 Microsoft Corporation
4 
5 --*/
6 
7 // ---------------------
8 // datatypes
9 // Quantifier elimination routine for recursive data-types.
10 //
11 
12 
13 //
14 // reduce implementation is modeled after Hodges:
15 // subst implementation is using QE "for dummies".
16 
17 // for dummies:
18 // -----------
19 //
20 // Step 1. ensure x is recognized.
21 //
22 //    exists x . phi[x] -> \/_i exists x. R_C(x) & phi[x]
23 //
24 // Step 2. non-recursive data-types
25 //
26 //    exists x . R_C(x) & phi[x] -> exists y . phi[C(y)]
27 //
28 // Step 2. recursive data-types, eliminate selectors.
29 //
30 //   exists x . R_C(x) & phi[x] -> exists y . phi[C(y)], x occurs with sel^C_i(x)
31 //
32 // Step 3. (recursive data-types)
33 //
34 //   Solve equations
35 //             . C[t] = C[s]   -> t = s
36 //             . C[x,t] = y    -> x = s1(y) /\ t = s2(y) /\ R_C(y)
37 //             . C[x,t] != y   -> can remain
38 //
39 // The remaining formula is in NNF where occurrences of 'x' are of the form
40 //      x = t_i or t[x] != s_j
41 //
42 // The last normalization step is:
43 //
44 //   exists x . R_C(x) & phi[x = t_i, t[x] != s_j]
45 //
46 //   -> \/_i R_C(t_i) & phi[t_i/x]  \/ phi[false, true]
47 //
48 //  Justification:
49 //  - We will assume that each of t_i, s_j are constructor terms.
50 //  - We can assume that x \notin t_i, x \notin s_j, or otherwise use simplification.
51 //  - We can assume that x occurs only in equalities or disequalities, or the recognizer, since
52 //    otherwise, we could simplify equalities, or QE does not apply.
53 //  - either x = t_i for some positive t_i, or we create
54 //      diag = C(t_1, ..., C(t_n, .. C(s_1, .. , C(s_m))))
55 //    and x is different from each t_i, s_j.
56 //
57 
58 //
59 // reduce:
60 // --------
61 // reduce set of literals containing x. The elimination procedure follows an adaptation of
62 // the proof (with corrections) in Hodges (shorter model theory).
63 //
64 // . x = t - (x \notin t) x is eliminated immediately.
65 //
66 // . x != t1, ..., x != t_n - (x \notin t_i) are collected into distrinct_terms.
67 //
68 // . recognizer(x) - is stored as pos_recognizer.
69 //
70 // . !recognizer(x) - is stored into neg_recognizers.
71 //
72 // . L[constructor(..,x,..)] -
73 //                      We could assume pre-processing introduces auxiliary
74 //                      variable y, Is_constructor(y), accessor_j(y) = arg_j.
75 //                      But we apply the following hack: re-introduce x' into vars,
76 //                      but also the variable y and the reduced formula.
77 //
78 // . L[accessor_i(x)] - if pos_recognizer(x) matches accessor,
79 //                      or if complement of neg_recognizers match accessor, then
80 //                      introduce x_1, .., x_n corresponding to accessor_i(x).
81 //
82 // The only way x is not in the scope of a data-type method is if it is in
83 // an equality or dis-equality of the form:
84 //
85 // . x (!)= acc_1(acc_2(..(acc_i(x)..) - would be false (true) if recognizer(..)
86 //                     is declared for each sub-term.
87 //
88 //
89 // - otherwise, each x should be in the scope of an accessor.
90 //
91 // Normalized literal elimination:
92 //
93 // .    exists x . Lits[accessor_i(x)] & Is_constructor(x)
94 //   ->
95 //      exists x_1, .., x_n . Lits[x_1, .., x_n] for each accessor_i(x).
96 //
97 
98 //
99 // maintain set of equations and disequations with x.
100 //
101 
102 #include "qe/qe.h"
103 #include "ast/datatype_decl_plugin.h"
104 #include "ast/rewriter/expr_safe_replace.h"
105 #include "util/obj_pair_hashtable.h"
106 #include "ast/for_each_expr.h"
107 #include "ast/ast_pp.h"
108 #include "ast/ast_ll_pp.h"
109 
110 namespace qe {
111 
112     class datatype_atoms {
113         ast_manager&     m;
114         app_ref_vector   m_recognizers;
115         expr_ref_vector  m_eqs;
116         expr_ref_vector  m_neqs;
117         app_ref_vector   m_eq_atoms;
118         app_ref_vector   m_neq_atoms;
119         app_ref_vector   m_unsat_atoms;
120         expr_ref_vector  m_eq_conds;
121         ast_mark         m_mark;
122         datatype_util    m_util;
123     public:
datatype_atoms(ast_manager & m)124         datatype_atoms(ast_manager& m) :
125             m(m),
126             m_recognizers(m),
127             m_eqs(m),
128             m_neqs(m),
129             m_eq_atoms(m), m_neq_atoms(m), m_unsat_atoms(m), m_eq_conds(m),
130             m_util(m) {}
131 
add_atom(contains_app & contains_x,bool is_pos,app * a)132         bool add_atom(contains_app& contains_x, bool is_pos, app* a) {
133             app* x = contains_x.x();
134             SASSERT(contains_x(a));
135             if (m_mark.is_marked(a)) {
136                 return true;
137             }
138             m_mark.mark(a, true);
139             func_decl* f = a->get_decl();
140             if (m_util.is_recognizer(f) && a->get_arg(0) == x) {
141                 m_recognizers.push_back(a);
142                 TRACE("qe", tout << "add recognizer:" << mk_pp(a, m) << "\n";);
143                 return true;
144             }
145             if (!m.is_eq(a)) {
146                 return false;
147             }
148             if (add_eq(contains_x, is_pos, a->get_arg(0), a->get_arg(1))) {
149                 add_atom(a, is_pos);
150                 return true;
151             }
152             if (add_eq(contains_x, is_pos, a->get_arg(1), a->get_arg(0))) {
153                 add_atom(a, is_pos);
154                 return true;
155             }
156             if (add_unsat_eq(contains_x, a, a->get_arg(0), a->get_arg(1))) {
157                 return true;
158             }
159             return false;
160         }
161 
num_eqs()162         unsigned num_eqs() { return m_eqs.size(); }
eq(unsigned i)163         expr* eq(unsigned i) { return m_eqs[i].get(); }
eq_cond(unsigned i)164         expr* eq_cond(unsigned i) { return m_eq_conds[i].get(); }
eq_atom(unsigned i)165         app*  eq_atom(unsigned i) { return m_eq_atoms[i].get(); }
166 
num_neqs()167         unsigned num_neqs() { return m_neq_atoms.size(); }
neq_atom(unsigned i)168         app*  neq_atom(unsigned i) { return m_neq_atoms[i].get(); }
169 
num_neq_terms() const170         unsigned num_neq_terms() const { return m_neqs.size(); }
neq_term(unsigned i) const171         expr* neq_term(unsigned i) const { return m_neqs[i]; }
neq_terms() const172         expr* const* neq_terms() const { return m_neqs.data(); }
173 
num_recognizers()174         unsigned num_recognizers() { return m_recognizers.size(); }
recognizer(unsigned i)175         app*   recognizer(unsigned i) { return m_recognizers[i].get(); }
176 
num_unsat()177         unsigned num_unsat() { return m_unsat_atoms.size(); }
unsat_atom(unsigned i)178         app*     unsat_atom(unsigned i) { return m_unsat_atoms[i].get(); }
179 
180     private:
181 
182         //
183         // perform occurs check on equality.
184         //
add_unsat_eq(contains_app & contains_x,app * atom,expr * a,expr * b)185         bool add_unsat_eq(contains_app& contains_x, app* atom, expr* a, expr* b) {
186             app* x = contains_x.x();
187             if (x != a) {
188                 std::swap(a, b);
189             }
190             if (x != a) {
191                 return false;
192             }
193             if (!contains_x(b)) {
194                 return false;
195             }
196             ptr_vector<expr> todo;
197             ast_mark mark;
198             todo.push_back(b);
199             while (!todo.empty()) {
200                 b = todo.back();
201                 todo.pop_back();
202                 if (mark.is_marked(b)) {
203                     continue;
204                 }
205                 mark.mark(b, true);
206                 if (!is_app(b)) {
207                     continue;
208                 }
209                 if (b == x) {
210                     m_unsat_atoms.push_back(atom);
211                     return true;
212                 }
213                 app* b_app = to_app(b);
214                 if (!m_util.is_constructor(b_app)) {
215                     continue;
216                 }
217                 for (unsigned i = 0; i < b_app->get_num_args(); ++i) {
218                     todo.push_back(b_app->get_arg(i));
219                 }
220             }
221             return false;
222         }
223 
add_atom(app * a,bool is_pos)224         void add_atom(app* a, bool is_pos) {
225             TRACE("qe", tout << "add atom:" << mk_pp(a, m) << " " << (is_pos?"pos":"neg") << "\n";);
226             if (is_pos) {
227                 m_eq_atoms.push_back(a);
228             }
229             else {
230                 m_neq_atoms.push_back(a);
231             }
232         }
233 
add_eq(contains_app & contains_x,bool is_pos,expr * a,expr * b)234         bool add_eq(contains_app& contains_x, bool is_pos, expr* a, expr* b) {
235             if (contains_x(b)) {
236                 return false;
237             }
238             if (is_pos) {
239                 return solve_eq(contains_x, a, b, m.mk_true());
240             }
241             else {
242                 return solve_diseq(contains_x, a, b);
243             }
244             return false;
245         }
246 
solve_eq(contains_app & contains_x,expr * _a,expr * b,expr * cond0)247         bool solve_eq(contains_app& contains_x, expr* _a, expr* b, expr* cond0) {
248             SASSERT(contains_x(_a));
249             SASSERT(!contains_x(b));
250             app* x = contains_x.x();
251             if (!is_app(_a)) {
252                 return false;
253             }
254             app* a = to_app(_a);
255             if (x == a) {
256                 m_eqs.push_back(b);
257                 m_eq_conds.push_back(cond0);
258                 return true;
259             }
260             if (!m_util.is_constructor(a)) {
261                 return false;
262             }
263             func_decl* c = a->get_decl();
264             func_decl_ref r(m_util.get_constructor_is(c), m);
265             ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c);
266             SASSERT(acc.size() == a->get_num_args());
267             //
268             // It suffices to solve just the first available equality.
269             // The others are determined by the first.
270             //
271             expr_ref cond(m.mk_and(m.mk_app(r, b), cond0), m);
272             for (unsigned i = 0; i < a->get_num_args(); ++i) {
273                 expr* l = a->get_arg(i);
274                 if (contains_x(l)) {
275                     expr_ref r(m.mk_app(acc[i], b), m);
276                     if (solve_eq(contains_x, l, r, cond)) {
277                         return true;
278                     }
279                 }
280             }
281             return false;
282         }
283 
284         //
285         // check that some occurrence of 'x' is in a constructor sequence.
286         //
solve_diseq(contains_app & contains_x,expr * a0,expr * b)287         bool solve_diseq(contains_app& contains_x, expr* a0, expr* b) {
288             SASSERT(!contains_x(b));
289             SASSERT(contains_x(a0));
290             app* x = contains_x.x();
291             ptr_vector<expr> todo;
292             ast_mark mark;
293             todo.push_back(a0);
294             while (!todo.empty()) {
295                 a0 = todo.back();
296                 todo.pop_back();
297                 if (mark.is_marked(a0)) {
298                     continue;
299                 }
300                 mark.mark(a0, true);
301                 if (!is_app(a0)) {
302                     continue;
303                 }
304                 app* a = to_app(a0);
305                 if (a == x) {
306                     m_neqs.push_back(b);
307                     return true;
308                 }
309                 if (!m_util.is_constructor(a)) {
310                     continue;
311                 }
312                 for (unsigned i = 0; i < a->get_num_args(); ++i) {
313                     todo.push_back(a->get_arg(i));
314                 }
315             }
316             return false;
317         }
318     };
319 
320     //
321     // eliminate foreign variable under datatype functions (constructors).
322     // (= C(x,y) t) -> (R_C(t) && x = s1(t) && x = s2(t))
323     //
324 
325     class lift_foreign_vars : public map_proc {
326         ast_manager&      m;
327         bool              m_change;
328         datatype_util&    m_util;
329         i_solver_context& m_ctx;
330     public:
lift_foreign_vars(ast_manager & m,datatype_util & util,i_solver_context & ctx)331         lift_foreign_vars(ast_manager& m, datatype_util& util, i_solver_context& ctx):
332             map_proc(m), m(m), m_change(false), m_util(util), m_ctx(ctx) {}
333 
lift(expr_ref & fml)334         bool lift(expr_ref& fml) {
335             m_change = false;
336             for_each_expr(*this, fml.get());
337             if (m_change) {
338                 fml = get_expr(fml.get());
339                 TRACE("qe", tout << "lift:\n" << mk_pp(fml.get(), m) << "\n";);
340             }
341             return m_change;
342         }
343 
operator ()(var * v)344         void operator()(var* v) {
345             visit(v);
346         }
347 
operator ()(quantifier * q)348         void operator()(quantifier* q) {
349             visit(q);
350         }
351 
operator ()(app * a)352         void operator()(app* a) {
353             expr* l, *r;
354             if (m.is_eq(a, l, r)) {
355                 if (reduce_eq(a, l, r)) {
356                     m_change = true;
357                     return;
358                 }
359                 if (reduce_eq(a, r, l)) {
360                     m_change = true;
361                     return;
362                 }
363             }
364             reconstruct(a);
365         }
366 
367     private:
368 
reduce_eq(app * a,expr * _l,expr * r)369         bool reduce_eq(app* a, expr* _l, expr* r) {
370             if (!is_app(_l)) {
371                 return false;
372             }
373             app* l = to_app(_l);
374             if (!m_util.is_constructor(l)) {
375                 return false;
376             }
377 
378             if (!contains_foreign(l)) {
379                 return false;
380             }
381             func_decl* c = l->get_decl();
382             ptr_vector<func_decl> const& acc = *m_util.get_constructor_accessors(c);
383             func_decl* rec = m_util.get_constructor_is(c);
384             expr_ref_vector conj(m);
385             conj.push_back(m.mk_app(rec, r));
386             for (unsigned i = 0; i < acc.size(); ++i) {
387                 expr* r_i = m.mk_app(acc[i], r);
388                 expr* l_i = l->get_arg(i);
389                 conj.push_back(m.mk_eq(l_i, r_i));
390             }
391             expr* e = m.mk_and(conj.size(), conj.data());
392             m_map.insert(a, e, nullptr);
393             TRACE("qe", tout << "replace: " << mk_pp(a, m) << " ==> \n" << mk_pp(e, m) << "\n";);
394             return true;
395         }
396 
contains_foreign(app * a)397         bool contains_foreign(app* a) {
398             unsigned num_vars = m_ctx.get_num_vars();
399             for (unsigned i = 0; i < num_vars; ++i) {
400                 contains_app& v = m_ctx.contains(i);
401                 sort* s = v.x()->get_decl()->get_range();
402 
403                 //
404                 // data-type contains arithmetical term or bit-vector.
405                 //
406                 if (!m_util.is_datatype(s) &&
407                     !m.is_bool(s) &&
408                     v(a)) {
409                     return true;
410                 }
411             }
412             return false;
413         }
414 
415     };
416 
417 
418     class datatype_plugin : public qe_solver_plugin  {
419         typedef std::pair<app*,ptr_vector<app> > subst_clos;
420         typedef obj_pair_map<app,  expr, datatype_atoms*> eqs_cache;
421         typedef obj_pair_map<app, func_decl, subst_clos*> subst_map;
422 
423         datatype_util              m_datatype_util;
424         expr_safe_replace          m_replace;
425         eqs_cache                  m_eqs_cache;
426         subst_map                  m_subst_cache;
427         ast_ref_vector             m_trail;
428 
429     public:
datatype_plugin(i_solver_context & ctx,ast_manager & m)430         datatype_plugin(i_solver_context& ctx, ast_manager& m) :
431             qe_solver_plugin(m, m.mk_family_id("datatype"), ctx),
432             m_datatype_util(m),
433             m_replace(m),
434             m_trail(m)
435         {
436         }
437 
~datatype_plugin()438         ~datatype_plugin() override {
439             {
440                 eqs_cache::iterator it = m_eqs_cache.begin(), end = m_eqs_cache.end();
441                 for (; it != end; ++it) {
442                     dealloc(it->get_value());
443                 }
444             }
445             {
446                 subst_map::iterator it = m_subst_cache.begin(), end = m_subst_cache.end();
447                 for (; it != end; ++it) {
448                     dealloc(it->get_value());
449                 }
450             }
451 
452         }
453 
get_num_branches(contains_app & x,expr * fml,rational & num_branches)454         bool get_num_branches( contains_app& x, expr* fml, rational& num_branches) override {
455             sort* s = x.x()->get_decl()->get_range();
456             SASSERT(m_datatype_util.is_datatype(s));
457             if (m_datatype_util.is_recursive(s)) {
458                 return get_num_branches_rec(x, fml, num_branches);
459             }
460             else {
461                 return get_num_branches_nonrec(x, fml, num_branches);
462             }
463         }
464 
465 
assign(contains_app & x,expr * fml,rational const & vl)466         void assign(contains_app& x, expr* fml, rational const& vl) override {
467             sort* s = x.x()->get_decl()->get_range();
468             SASSERT(m_datatype_util.is_datatype(s));
469             TRACE("qe", tout << mk_pp(x.x(), m) << " " << vl << "\n";);
470             if (m_datatype_util.is_recursive(s)) {
471                 assign_rec(x, fml, vl);
472             }
473             else {
474                 assign_nonrec(x, fml, vl);
475             }
476         }
477 
subst(contains_app & x,rational const & vl,expr_ref & fml,expr_ref * def)478         void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override {
479             sort* s = x.x()->get_decl()->get_range();
480             SASSERT(m_datatype_util.is_datatype(s));
481             TRACE("qe", tout << mk_pp(x.x(), m) << " " << vl << "\n";);
482             if (m_datatype_util.is_recursive(s)) {
483                 subst_rec(x, vl, fml, def);
484             }
485             else {
486                 subst_nonrec(x, vl, fml, def);
487             }
488         }
489 
get_weight(contains_app & x,expr * fml)490         unsigned get_weight( contains_app& x, expr* fml) override {
491             return UINT_MAX;
492         }
493 
solve(conj_enum & conj,expr * fml)494         bool solve( conj_enum& conj, expr* fml) override {
495             return false;
496         }
497 
simplify(expr_ref & fml)498         bool simplify( expr_ref& fml) override {
499             lift_foreign_vars lift(m, m_datatype_util, m_ctx);
500             return lift.lift(fml);
501         }
502 
mk_atom(expr * e,bool p,expr_ref & result)503         bool mk_atom(expr* e, bool p, expr_ref& result) override {
504             return false;
505         }
506 
507 
get_cost(contains_app &,expr * fml)508         virtual rational get_cost(contains_app&, expr* fml) {
509             return rational(0);
510         }
511 
512     private:
513 
add_def(expr * term,expr_ref * def)514         void add_def(expr* term, expr_ref* def) {
515             if (def) {
516                 *def = term;
517             }
518         }
519 
520         //
521         // replace x by C(y1,..,yn) where y1,..,yn are fresh variables.
522         //
subst_constructor(contains_app & x,func_decl * c,expr_ref & fml,expr_ref * def)523         void subst_constructor(contains_app& x, func_decl* c, expr_ref& fml, expr_ref* def) {
524             subst_clos* sub = nullptr;
525 
526             if (m_subst_cache.find(x.x(), c, sub)) {
527                 m_replace.apply_substitution(x.x(), sub->first, fml);
528                 add_def(sub->first, def);
529                 for (unsigned i = 0; i < sub->second.size(); ++i) {
530                     m_ctx.add_var(sub->second[i]);
531                 }
532                 return;
533             }
534             sub = alloc(subst_clos);
535             unsigned arity = c->get_arity();
536             expr_ref_vector vars(m);
537             for (unsigned i = 0; i < arity; ++i) {
538                 sort* sort_x = c->get_domain()[i];
539                 app_ref fresh_x(m.mk_fresh_const("x", sort_x), m);
540                 m_ctx.add_var(fresh_x.get());
541                 vars.push_back(fresh_x.get());
542                 sub->second.push_back(fresh_x.get());
543             }
544             app_ref t(m.mk_app(c, vars.size(), vars.data()), m);
545             m_trail.push_back(x.x());
546             m_trail.push_back(c);
547             m_trail.push_back(t);
548 
549             add_def(t, def);
550             m_replace.apply_substitution(x.x(), t, fml);
551             sub->first = t;
552             m_subst_cache.insert(x.x(), c, sub);
553         }
554 
get_recognizers(expr * fml,ptr_vector<app> & recognizers)555         void get_recognizers(expr* fml, ptr_vector<app>& recognizers) {
556             conj_enum conjs(m, fml);
557             conj_enum::iterator it = conjs.begin(), end = conjs.end();
558             for (; it != end; ++it) {
559                 expr* e = *it;
560                 if (is_app(e)) {
561                     app* a = to_app(e);
562                     func_decl* f = a->get_decl();
563                     if (m_datatype_util.is_recognizer(f)) {
564                         recognizers.push_back(a);
565                     }
566                 }
567             }
568         }
569 
has_recognizer(app * x,expr * fml,func_decl * & r,func_decl * & c)570         bool has_recognizer(app* x, expr* fml, func_decl*& r, func_decl*& c) {
571             ptr_vector<app> recognizers;
572             get_recognizers(fml, recognizers);
573             for (unsigned i = 0; i < recognizers.size(); ++i) {
574                 app* a = recognizers[i];
575                 if (a->get_arg(0) == x) {
576                     r = a->get_decl();
577                     c = m_datatype_util.get_recognizer_constructor(a->get_decl());
578                     return true;
579                 }
580             }
581             return false;
582         }
583 
get_num_branches_rec(contains_app & x,expr * fml,rational & num_branches)584         bool get_num_branches_rec( contains_app& x, expr* fml, rational& num_branches) {
585             sort* s = x.x()->get_decl()->get_range();
586             SASSERT(m_datatype_util.is_datatype(s));
587             SASSERT(m_datatype_util.is_recursive(s));
588 
589             unsigned sz = m_datatype_util.get_datatype_num_constructors(s);
590             num_branches = rational(sz);
591             func_decl* c = nullptr, *r = nullptr;
592 
593             //
594             // If 'x' does not yet have a recognizer, then branch according to recognizers.
595             //
596             if (!has_recognizer(x.x(), fml, r, c)) {
597                 return true;
598             }
599             //
600             // eliminate 'x' by applying constructor to fresh variables.
601             //
602             if (has_selector(x, fml, c)) {
603                 num_branches = rational(1);
604                 return true;
605             }
606 
607             //
608             // 'x' has a recognizer. Count number of equalities and disequalities.
609             //
610             if (update_eqs(x, fml)) {
611                 datatype_atoms& eqs = get_eqs(x.x(), fml);
612                 num_branches = rational(eqs.num_eqs() + 1);
613                 return true;
614             }
615             TRACE("qe", tout << "could not get number of branches " << mk_pp(x.x(), m) << "\n";);
616             return false;
617         }
618 
619 
assign_rec(contains_app & contains_x,expr * fml,rational const & vl)620         void assign_rec(contains_app& contains_x, expr* fml, rational const& vl) {
621             app* x = contains_x.x();
622             sort* s = x->get_decl()->get_range();
623             func_decl* c = nullptr, *r = nullptr;
624 
625             //
626             // If 'x' does not yet have a recognizer, then branch according to recognizers.
627             //
628             if (!has_recognizer(x, fml, r, c)) {
629                 c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned());
630                 r = m_datatype_util.get_constructor_is(c);
631                 app* is_c = m.mk_app(r, x);
632                 // assert v => r(x)
633                 m_ctx.add_constraint(true, is_c);
634                 return;
635             }
636 
637             //
638             // eliminate 'x' by applying constructor to fresh variables.
639             //
640             if (has_selector(contains_x, fml, c)) {
641                 return;
642             }
643 
644             //
645             // 'x' has a recognizer. The branch ID id provided by the index of the equality.
646             //
647             datatype_atoms& eqs = get_eqs(x, fml);
648             SASSERT(vl.is_unsigned());
649             unsigned idx = vl.get_unsigned();
650             SASSERT(idx <= eqs.num_eqs());
651 
652             if (idx < eqs.num_eqs()) {
653                 expr_ref eq(m.mk_eq(x, eqs.eq(idx)), m);
654                 m_ctx.add_constraint(true, eq);
655             }
656             else {
657                 for (unsigned i = 0; i < eqs.num_eqs(); ++i) {
658                     expr_ref ne(m.mk_not(m.mk_eq(x, eqs.eq(i))), m);
659                     m_ctx.add_constraint(true, ne);
660                 }
661             }
662         }
663 
subst_rec(contains_app & contains_x,rational const & vl,expr_ref & fml,expr_ref * def)664         void subst_rec(contains_app& contains_x, rational const& vl, expr_ref& fml, expr_ref* def) {
665             app* x = contains_x.x();
666             sort* s = x->get_decl()->get_range();
667             SASSERT(m_datatype_util.is_datatype(s));
668             func_decl* c = nullptr, *r = nullptr;
669 
670             TRACE("qe", tout << mk_pp(x, m) << " " << vl << " " << mk_pp(fml, m) << " " << (def != 0) << "\n";);
671             //
672             // Add recognizer to formula.
673             // Introduce auxiliary variable to eliminate.
674             //
675             if (!has_recognizer(x, fml, r, c)) {
676                 c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned());
677                 r = m_datatype_util.get_constructor_is(c);
678                 app* is_c = m.mk_app(r, x);
679                 fml = m.mk_and(is_c, fml);
680                 app_ref fresh_x(m.mk_fresh_const("x", s), m);
681                 m_ctx.add_var(fresh_x);
682                 m_replace.apply_substitution(x, fresh_x, fml);
683                 add_def(fresh_x, def);
684                 TRACE("qe", tout << "Add recognizer " << mk_pp(is_c, m) << "\n";);
685                 return;
686             }
687 
688 
689             if (has_selector(contains_x, fml, c)) {
690                 TRACE("qe", tout << "Eliminate selector " << mk_ll_pp(c, m) << "\n";);
691                 subst_constructor(contains_x, c, fml, def);
692                 return;
693             }
694 
695             //
696             // 'x' has a recognizer. The branch ID id provided by the index of the equality.
697             //
698             datatype_atoms& eqs = get_eqs(x, fml);
699             SASSERT(vl.is_unsigned());
700             unsigned idx = vl.get_unsigned();
701             SASSERT(idx <= eqs.num_eqs());
702 
703             for (unsigned i = 0; i < eqs.num_recognizers(); ++i) {
704                 app* rec = eqs.recognizer(i);
705                 if (rec->get_decl() == r) {
706                     m_replace.apply_substitution(rec, m.mk_true(), fml);
707                 }
708                 else {
709                     m_replace.apply_substitution(rec, m.mk_false(), fml);
710                 }
711             }
712 
713             for (unsigned i = 0; i < eqs.num_unsat(); ++i) {
714                 m_replace.apply_substitution(eqs.unsat_atom(i), m.mk_false(), fml);
715             }
716 
717             if (idx < eqs.num_eqs()) {
718                 expr* t = eqs.eq(idx);
719                 expr* c = eqs.eq_cond(idx);
720                 add_def(t, def);
721                 m_replace.apply_substitution(x, t, fml);
722                 if (!m.is_true(c)) {
723                     fml = m.mk_and(c, fml);
724                 }
725             }
726             else {
727                 for (unsigned i = 0; i < eqs.num_eqs(); ++i) {
728                     m_replace.apply_substitution(eqs.eq_atom(i), m.mk_false(), fml);
729                 }
730 
731                 for (unsigned i = 0; i < eqs.num_neqs(); ++i) {
732                     m_replace.apply_substitution(eqs.neq_atom(i), m.mk_false(), fml);
733                 }
734                 if (def) {
735                     sort* s = x->get_sort();
736                     ptr_vector<sort> sorts;
737                     sorts.resize(eqs.num_neq_terms(), s);
738                     func_decl* diag = m.mk_func_decl(symbol("diag"), sorts.size(), sorts.data(), s);
739                     expr_ref t(m);
740                     t = m.mk_app(diag, eqs.num_neq_terms(), eqs.neq_terms());
741                     add_def(t, def);
742                 }
743             }
744             TRACE("qe", tout << "reduced " << mk_pp(fml.get(), m) << "\n";);
745         }
746 
get_num_branches_nonrec(contains_app & x,expr * fml,rational & num_branches)747         bool get_num_branches_nonrec( contains_app& x, expr* fml, rational& num_branches) {
748             sort* s = x.x()->get_decl()->get_range();
749             unsigned sz = m_datatype_util.get_datatype_num_constructors(s);
750             num_branches = rational(sz);
751             func_decl* c = nullptr, *r = nullptr;
752 
753             if (sz != 1 && has_recognizer(x.x(), fml, r, c)) {
754                 TRACE("qe", tout << mk_pp(x.x(), m) << " has a recognizer\n";);
755                 num_branches = rational(1);
756             }
757             TRACE("qe", tout << mk_pp(x.x(), m) << " branches: " << sz << "\n";);
758             return true;
759         }
760 
assign_nonrec(contains_app & contains_x,expr * fml,rational const & vl)761         void assign_nonrec(contains_app& contains_x, expr* fml, rational const& vl) {
762             app* x = contains_x.x();
763             sort* s = x->get_decl()->get_range();
764             SASSERT(m_datatype_util.is_datatype(s));
765             unsigned sz = m_datatype_util.get_datatype_num_constructors(s);
766             SASSERT(vl.is_unsigned());
767             SASSERT(vl.get_unsigned() < sz);
768             if (sz == 1) {
769                 return;
770             }
771             func_decl* c = nullptr, *r = nullptr;
772             if (has_recognizer(x, fml, r, c)) {
773                 TRACE("qe", tout << mk_pp(x, m) << " has a recognizer\n";);
774                 return;
775             }
776 
777             c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned());
778             r = m_datatype_util.get_constructor_is(c);
779             app* is_c = m.mk_app(r, x);
780 
781             // assert v => r(x)
782 
783             m_ctx.add_constraint(true, is_c);
784         }
785 
subst_nonrec(contains_app & x,rational const & vl,expr_ref & fml,expr_ref * def)786         virtual void subst_nonrec(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) {
787             sort* s = x.x()->get_decl()->get_range();
788             SASSERT(m_datatype_util.is_datatype(s));
789             SASSERT(!m_datatype_util.is_recursive(s));
790             func_decl* c = nullptr, *r = nullptr;
791             if (has_recognizer(x.x(), fml, r, c)) {
792                 TRACE("qe", tout << mk_pp(x.x(), m) << " has a recognizer\n";);
793             }
794             else {
795                 SASSERT(vl.is_unsigned());
796                 SASSERT(vl.get_unsigned() < m_datatype_util.get_datatype_num_constructors(s));
797                 c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned());
798             }
799             subst_constructor(x, c, fml, def);
800         }
801 
802 
803         class has_select : public i_expr_pred {
804             app* m_x;
805             func_decl* m_c;
806             datatype_util& m_util;
807         public:
has_select(app * x,func_decl * c,datatype_util & u)808             has_select(app* x, func_decl* c, datatype_util& u): m_x(x), m_c(c), m_util(u) {}
809 
operator ()(expr * e)810             bool operator()(expr* e) override {
811                 if (!is_app(e)) return false;
812                 app* a = to_app(e);
813                 if (!m_util.is_accessor(a)) return false;
814                 if (a->get_arg(0) != m_x) return false;
815                 func_decl* f = a->get_decl();
816                 return m_c == m_util.get_accessor_constructor(f);
817             }
818         };
819 
has_selector(contains_app & x,expr * fml,func_decl * c)820         bool has_selector(contains_app& x, expr* fml, func_decl* c) {
821             has_select hs(x.x(), c, m_datatype_util);
822             check_pred ch(hs, m);
823             return ch(fml);
824         }
825 
get_eqs(app * x,expr * fml)826         datatype_atoms& get_eqs(app* x, expr* fml) {
827             datatype_atoms* eqs = nullptr;
828             VERIFY (m_eqs_cache.find(x, fml, eqs));
829             return *eqs;
830         }
831 
update_eqs(contains_app & contains_x,expr * fml)832         bool update_eqs(contains_app& contains_x, expr* fml) {
833             datatype_atoms* eqs = nullptr;
834             if (m_eqs_cache.find(contains_x.x(), fml, eqs)) {
835                 return true;
836             }
837             eqs = alloc(datatype_atoms, m);
838 
839             if (!update_eqs(*eqs, contains_x, fml, m_ctx.pos_atoms(), true)) {
840                 dealloc(eqs);
841                 return false;
842             }
843             if (!update_eqs(*eqs, contains_x, fml, m_ctx.neg_atoms(), false)) {
844                 dealloc(eqs);
845                 return false;
846             }
847 
848             m_trail.push_back(contains_x.x());
849             m_trail.push_back(fml);
850             m_eqs_cache.insert(contains_x.x(), fml, eqs);
851             return true;
852         }
853 
update_eqs(datatype_atoms & eqs,contains_app & contains_x,expr * fml,atom_set const & tbl,bool is_pos)854         bool update_eqs(datatype_atoms& eqs, contains_app& contains_x, expr* fml, atom_set const& tbl, bool is_pos) {
855             atom_set::iterator it = tbl.begin(), end = tbl.end();
856             for (; it != end; ++it) {
857                 app* e = *it;
858                 if (!contains_x(e)) {
859                     continue;
860                 }
861                 if (!eqs.add_atom(contains_x, is_pos, e)) {
862                     return false;
863                 }
864             }
865             return true;
866         }
867     };
868 
mk_datatype_plugin(i_solver_context & ctx)869     qe_solver_plugin* mk_datatype_plugin(i_solver_context& ctx) {
870         return alloc(datatype_plugin, ctx, ctx.get_manager());
871     }
872 }
873