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