1 /*++ 2 Copyright (c) 2006 Microsoft Corporation 3 4 Module Name: 5 6 dl_context.cpp 7 8 Abstract: 9 10 <abstract> 11 12 Author: 13 14 Leonardo de Moura (leonardo) 2010-05-18. 15 16 Revision History: 17 18 --*/ 19 20 #include<sstream> 21 #include<limits> 22 #include "ast/arith_decl_plugin.h" 23 #include "ast/bv_decl_plugin.h" 24 #include "ast/for_each_expr.h" 25 #include "ast/ast_smt_pp.h" 26 #include "ast/ast_smt2_pp.h" 27 #include "ast/datatype_decl_plugin.h" 28 #include "ast/scoped_proof.h" 29 #include "ast/ast_pp_util.h" 30 #include "ast/ast_util.h" 31 #include "muz/base/dl_context.h" 32 #include "muz/base/fp_params.hpp" 33 34 namespace datalog { 35 36 // ----------------------------------- 37 // 38 // context::sort_domain 39 // 40 // ----------------------------------- 41 42 class context::sort_domain { 43 private: 44 sort_kind m_kind; 45 protected: 46 sort_ref m_sort; 47 bool m_limited_size; 48 uint64_t m_size; 49 sort_domain(sort_kind k,context & ctx,sort * s)50 sort_domain(sort_kind k, context & ctx, sort * s) 51 : m_kind(k), m_sort(s, ctx.get_manager()) { 52 m_limited_size = ctx.get_decl_util().try_get_size(s, m_size); 53 } 54 public: ~sort_domain()55 virtual ~sort_domain() {} 56 get_kind() const57 sort_kind get_kind() const { return m_kind; } 58 virtual unsigned get_constant_count() const = 0; 59 virtual void print_element(finite_element el_num, std::ostream & out) = 0; 60 }; 61 62 class context::symbol_sort_domain : public sort_domain { 63 typedef map<symbol, finite_element, symbol_hash_proc, symbol_eq_proc> sym2num; 64 typedef svector<symbol> num2sym; 65 66 sym2num m_el_numbers; 67 num2sym m_el_names; 68 public: symbol_sort_domain(context & ctx,sort * s)69 symbol_sort_domain(context & ctx, sort * s) : sort_domain(SK_SYMBOL, ctx, s) {} 70 get_number(symbol sym)71 finite_element get_number(symbol sym) { 72 //we number symbols starting from zero, so table->size() is equal to the 73 //index of the symbol to be added next 74 75 unsigned newIdx = m_el_numbers.size(); 76 77 unsigned idx = m_el_numbers.insert_if_not_there(sym, newIdx); 78 79 if (idx==newIdx) { 80 m_el_names.push_back(sym); 81 SASSERT(m_el_names.size()==m_el_numbers.size()); 82 } 83 84 if (m_limited_size && idx>=m_size) { 85 std::stringstream sstm; 86 sstm << "sort " << m_sort->get_name() << " contains more constants than its declared size " << m_size; 87 throw default_exception(sstm.str()); 88 } 89 return idx; 90 } 91 get_constant_count() const92 unsigned get_constant_count() const override { 93 return m_el_names.size(); 94 } print_element(finite_element el_num,std::ostream & out)95 void print_element(finite_element el_num, std::ostream & out) override { 96 if (el_num>=m_el_names.size()) { 97 out << el_num; 98 return; 99 } 100 out << m_el_names[el_num]; 101 } 102 }; 103 104 class context::uint64_sort_domain : public sort_domain { 105 typedef map<uint64_t, finite_element, uint64_hash, default_eq<uint64_t> > el2num; 106 typedef svector<uint64_t> num2el; 107 108 el2num m_el_numbers; 109 num2el m_el_names; 110 public: uint64_sort_domain(context & ctx,sort * s)111 uint64_sort_domain(context & ctx, sort * s) : sort_domain(SK_UINT64, ctx, s) {} 112 get_number(uint64_t el)113 finite_element get_number(uint64_t el) { 114 //we number symbols starting from zero, so table->size() is equal to the 115 //index of the symbol to be added next 116 117 unsigned newIdx = m_el_numbers.size(); 118 119 unsigned idx = m_el_numbers.insert_if_not_there(el, newIdx); 120 121 if (idx == newIdx) { 122 m_el_names.push_back(el); 123 SASSERT(m_el_names.size()==m_el_numbers.size()); 124 } 125 126 if (m_limited_size && idx>=m_size) { 127 std::stringstream sstm; 128 sstm << "sort " << m_sort->get_name() << " contains more constants than its declared size " << m_size; 129 throw default_exception(sstm.str()); 130 } 131 return idx; 132 } get_constant_count() const133 unsigned get_constant_count() const override { 134 return m_el_names.size(); 135 } print_element(finite_element el_num,std::ostream & out)136 void print_element(finite_element el_num, std::ostream & out) override { 137 if (el_num >= m_el_names.size()) { 138 out << "<unk " << m_sort->get_name() << ":" << el_num << '>'; 139 return; 140 } 141 out << m_el_names[el_num]; 142 } 143 }; 144 145 // ----------------------------------- 146 // 147 // trail stack for restoring rules 148 // 149 // ----------------------------------- 150 151 class context::restore_rules : public trail<context> { 152 rule_set* m_old_rules; reset()153 void reset() { 154 dealloc(m_old_rules); 155 m_old_rules = nullptr; 156 } 157 public: restore_rules(rule_set & r)158 restore_rules(rule_set& r): m_old_rules(alloc(rule_set, r)) {} 159 ~restore_rules()160 ~restore_rules() override {} 161 undo(context & ctx)162 void undo(context& ctx) override { 163 ctx.replace_rules(*m_old_rules); 164 reset(); 165 } 166 }; 167 168 template<typename Ctx, typename Vec> 169 class restore_vec_size_trail : public trail<Ctx> { 170 Vec& m_vector; 171 unsigned m_old_size; 172 public: restore_vec_size_trail(Vec & v)173 restore_vec_size_trail(Vec& v): m_vector(v), m_old_size(v.size()) {} ~restore_vec_size_trail()174 ~restore_vec_size_trail() override {} undo(Ctx & ctx)175 void undo(Ctx& ctx) override { m_vector.shrink(m_old_size); } 176 }; 177 push()178 void context::push() { 179 m_trail.push_scope(); 180 m_trail.push(restore_rules(m_rule_set)); 181 m_trail.push(restore_vec_size_trail<context,expr_ref_vector>(m_rule_fmls)); 182 m_trail.push(restore_vec_size_trail<context,expr_ref_vector>(m_background)); 183 } 184 pop()185 void context::pop() { 186 if (m_trail.get_num_scopes() == 0) { 187 throw default_exception("there are no backtracking points to pop to"); 188 } 189 throw default_exception("pop operation is not supported"); 190 m_trail.pop_scope(1); 191 } 192 193 // ----------------------------------- 194 // 195 // context 196 // 197 // ----------------------------------- 198 context(ast_manager & m,register_engine_base & re,smt_params & fp,params_ref const & pa)199 context::context(ast_manager & m, register_engine_base& re, smt_params& fp, params_ref const& pa): 200 m(m), 201 m_register_engine(re), 202 m_fparams(fp), 203 m_params_ref(pa), 204 m_params(alloc(fp_params, m_params_ref)), 205 m_decl_util(m), 206 m_rewriter(m), 207 m_var_subst(m), 208 m_rule_manager(*this), 209 m_contains_p(*this), 210 m_rule_properties(m, m_rule_manager, *this, m_contains_p), 211 m_transf(*this), 212 m_trail(*this), 213 m_pinned(m), 214 m_bind_variables(m), 215 m_rule_set(*this), 216 m_transformed_rule_set(*this), 217 m_rule_fmls_head(0), 218 m_rule_fmls(m), 219 m_background(m), 220 m_mc(nullptr), 221 m_rel(nullptr), 222 m_engine(nullptr), 223 m_closed(false), 224 m_saturation_was_run(false), 225 m_enable_bind_variables(true), 226 m_last_status(OK), 227 m_last_answer(m), 228 m_last_ground_answer(m), 229 m_engine_type(LAST_ENGINE) { 230 re.set_context(this); 231 updt_params(pa); 232 } 233 ~context()234 context::~context() { 235 reset(); 236 dealloc(m_params); 237 } 238 reset()239 void context::reset() { 240 m_trail.reset(); 241 m_rule_set.reset(); 242 m_rule_fmls_head = 0; 243 m_rule_fmls.reset(); 244 m_rule_names.reset(); 245 m_rule_bounds.reset(); 246 m_argument_var_names.reset(); 247 m_preds.reset(); 248 m_preds_by_name.reset(); 249 reset_dealloc_values(m_sorts); 250 m_engine = nullptr; 251 m_rel = nullptr; 252 } 253 is_fact(app * head) const254 bool context::is_fact(app * head) const { 255 return m_rule_manager.is_fact(head); 256 } 257 has_sort_domain(relation_sort s) const258 bool context::has_sort_domain(relation_sort s) const { 259 return m_sorts.contains(s); 260 } 261 get_sort_domain(relation_sort s)262 context::sort_domain & context::get_sort_domain(relation_sort s) { 263 return *m_sorts.find(s); 264 } 265 get_sort_domain(relation_sort s) const266 const context::sort_domain & context::get_sort_domain(relation_sort s) const { 267 return *m_sorts.find(s); 268 } 269 270 generate_proof_trace() const271 bool context::generate_proof_trace() const { return m_generate_proof_trace; } output_profile() const272 bool context::output_profile() const { return m_params->datalog_output_profile(); } output_tuples() const273 bool context::output_tuples() const { return m_params->datalog_print_tuples(); } use_map_names() const274 bool context::use_map_names() const { return m_params->datalog_use_map_names(); } fix_unbound_vars() const275 bool context::fix_unbound_vars() const { return m_params->xform_fix_unbound_vars(); } default_table() const276 symbol context::default_table() const { return m_params->datalog_default_table(); } default_relation() const277 symbol context::default_relation() const { return m_default_relation; } set_default_relation(symbol const & s)278 void context::set_default_relation(symbol const& s) { m_default_relation = s; } print_aig() const279 symbol context::print_aig() const { return m_params->print_aig(); } check_relation() const280 symbol context::check_relation() const { return m_params->datalog_check_relation(); } default_table_checker() const281 symbol context::default_table_checker() const { return m_params->datalog_default_table_checker(); } default_table_checked() const282 bool context::default_table_checked() const { return m_params->datalog_default_table_checked(); } dbg_fpr_nonempty_relation_signature() const283 bool context::dbg_fpr_nonempty_relation_signature() const { return m_params->datalog_dbg_fpr_nonempty_relation_signature(); } dl_profile_milliseconds_threshold() const284 unsigned context::dl_profile_milliseconds_threshold() const { return m_params->datalog_profile_timeout_milliseconds(); } all_or_nothing_deltas() const285 bool context::all_or_nothing_deltas() const { return m_params->datalog_all_or_nothing_deltas(); } compile_with_widening() const286 bool context::compile_with_widening() const { return m_params->datalog_compile_with_widening(); } unbound_compressor() const287 bool context::unbound_compressor() const { return m_unbound_compressor; } set_unbound_compressor(bool f)288 void context::set_unbound_compressor(bool f) { m_unbound_compressor = f; } soft_timeout() const289 unsigned context::soft_timeout() const { return m_params->datalog_timeout(); } similarity_compressor() const290 bool context::similarity_compressor() const { return m_params->datalog_similarity_compressor(); } similarity_compressor_threshold() const291 unsigned context::similarity_compressor_threshold() const { return m_params->datalog_similarity_compressor_threshold(); } initial_restart_timeout() const292 unsigned context::initial_restart_timeout() const { return m_params->datalog_initial_restart_timeout(); } generate_explanations() const293 bool context::generate_explanations() const { return m_params->datalog_generate_explanations(); } explanations_on_relation_level() const294 bool context::explanations_on_relation_level() const { return m_params->datalog_explanations_on_relation_level(); } magic_sets_for_queries() const295 bool context::magic_sets_for_queries() const { return m_params->datalog_magic_sets_for_queries(); } tab_selection() const296 symbol context::tab_selection() const { return m_params->tab_selection(); } xform_coi() const297 bool context::xform_coi() const { return m_params->xform_coi(); } xform_slice() const298 bool context::xform_slice() const { return m_params->xform_slice(); } xform_bit_blast() const299 bool context::xform_bit_blast() const { return m_params->xform_bit_blast(); } karr() const300 bool context::karr() const { return false; } scale() const301 bool context::scale() const { return m_params->xform_scale(); } magic() const302 bool context::magic() const { return m_params->xform_magic(); } compress_unbound() const303 bool context::compress_unbound() const { return m_params->xform_compress_unbound(); } quantify_arrays() const304 bool context::quantify_arrays() const { return m_params->xform_quantify_arrays(); } instantiate_quantifiers() const305 bool context::instantiate_quantifiers() const { return m_params->xform_instantiate_quantifiers(); } array_blast() const306 bool context::array_blast() const { return m_params->xform_array_blast(); } array_blast_full() const307 bool context::array_blast_full() const { return m_params->xform_array_blast_full(); } elim_term_ite() const308 bool context::elim_term_ite() const {return m_params->xform_elim_term_ite();} blast_term_ite_inflation() const309 unsigned context::blast_term_ite_inflation() const { 310 return m_params->xform_elim_term_ite_inflation(); 311 } 312 313 register_finite_sort(sort * s,sort_kind k)314 void context::register_finite_sort(sort * s, sort_kind k) { 315 m_pinned.push_back(s); 316 SASSERT(!m_sorts.contains(s)); 317 sort_domain * dom; 318 switch (k) { 319 case SK_SYMBOL: 320 dom = alloc(symbol_sort_domain, *this, s); 321 break; 322 case SK_UINT64: 323 dom = alloc(uint64_sort_domain, *this, s); 324 break; 325 default: 326 UNREACHABLE(); 327 } 328 m_sorts.insert(s, dom); 329 } 330 register_variable(func_decl * var)331 void context::register_variable(func_decl* var) { 332 m_bind_variables.add_var(m.mk_const(var)); 333 } 334 bind_vars(expr * fml,bool is_forall)335 expr_ref context::bind_vars(expr* fml, bool is_forall) { 336 if (m_enable_bind_variables) { 337 return m_bind_variables(fml, is_forall); 338 } 339 else { 340 return expr_ref(fml, m); 341 } 342 } 343 register_predicate(func_decl * decl,bool named)344 void context::register_predicate(func_decl * decl, bool named) { 345 if (!is_predicate(decl)) { 346 m_pinned.push_back(decl); 347 m_preds.insert(decl); 348 TRACE("dl", tout << mk_pp(decl, m) << "\n";); 349 if (named) { 350 m_preds_by_name.insert(decl->get_name(), decl); 351 } 352 } 353 } 354 restrict_predicates(func_decl_set const & preds)355 void context::restrict_predicates(func_decl_set const& preds) { 356 m_preds.reset(); 357 for (func_decl* p : preds) { 358 TRACE("dl", tout << mk_pp(p, m) << "\n";); 359 m_preds.insert(p); 360 } 361 } 362 get_constant_number(relation_sort srt,symbol sym)363 context::finite_element context::get_constant_number(relation_sort srt, symbol sym) { 364 sort_domain & dom0 = get_sort_domain(srt); 365 SASSERT(dom0.get_kind() == SK_SYMBOL); 366 symbol_sort_domain & dom = static_cast<symbol_sort_domain &>(dom0); 367 return dom.get_number(sym); 368 } 369 get_constant_number(relation_sort srt,uint64_t el)370 context::finite_element context::get_constant_number(relation_sort srt, uint64_t el) { 371 372 sort_domain & dom0 = get_sort_domain(srt); 373 if (dom0.get_kind() == SK_SYMBOL) 374 return (finite_element)(el); 375 else { 376 uint64_sort_domain & dom = static_cast<uint64_sort_domain &>(dom0); 377 return dom.get_number(el); 378 } 379 } 380 print_constant_name(relation_sort srt,uint64_t num,std::ostream & out)381 void context::print_constant_name(relation_sort srt, uint64_t num, std::ostream & out) 382 { 383 if (has_sort_domain(srt)) { 384 SASSERT(num<=UINT_MAX); 385 get_sort_domain(srt).print_element(static_cast<unsigned>(num), out); 386 } 387 else { 388 out << num; 389 } 390 } 391 try_get_sort_constant_count(relation_sort srt,uint64_t & constant_count)392 bool context::try_get_sort_constant_count(relation_sort srt, uint64_t & constant_count) { 393 if (!has_sort_domain(srt)) { 394 return false; 395 } 396 constant_count = get_sort_domain(srt).get_constant_count(); 397 return true; 398 } 399 get_sort_size_estimate(relation_sort srt)400 uint64_t context::get_sort_size_estimate(relation_sort srt) { 401 if (get_decl_util().is_rule_sort(srt)) { 402 return 1; 403 } 404 uint64_t res; 405 if (!try_get_sort_constant_count(srt, res)) { 406 const sort_size & sz = srt->get_num_elements(); 407 if (sz.is_finite()) { 408 res = sz.size(); 409 } 410 else { 411 res = std::numeric_limits<uint64_t>::max(); 412 } 413 } 414 return res; 415 } 416 set_argument_names(const func_decl * pred,const svector<symbol> & var_names)417 void context::set_argument_names(const func_decl * pred, const svector<symbol> & var_names) 418 { 419 SASSERT(!m_argument_var_names.contains(pred)); 420 m_argument_var_names.insert(pred, var_names); 421 } 422 get_argument_name(const func_decl * pred,unsigned arg_index)423 symbol context::get_argument_name(const func_decl * pred, unsigned arg_index) 424 { 425 pred2syms::obj_map_entry * e = m_argument_var_names.find_core(pred); 426 if (!e) { 427 std::stringstream name_stm; 428 name_stm << '#' << arg_index; 429 return symbol(name_stm.str()); 430 } 431 SASSERT(arg_index < e->get_data().m_value.size()); 432 return e->get_data().m_value[arg_index]; 433 } 434 435 set_predicate_representation(func_decl * pred,unsigned relation_name_cnt,symbol const * relation_names)436 void context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, 437 symbol const * relation_names) { 438 if (relation_name_cnt > 0) { 439 ensure_engine(); 440 } 441 if (relation_name_cnt > 0 && m_rel) { 442 m_rel->set_predicate_representation(pred, relation_name_cnt, relation_names); 443 } 444 } 445 mk_fresh_head_predicate(symbol const & prefix,symbol const & suffix,unsigned arity,sort * const * domain,func_decl * orig_pred)446 func_decl * context::mk_fresh_head_predicate(symbol const & prefix, symbol const & suffix, 447 unsigned arity, sort * const * domain, func_decl* orig_pred) { 448 func_decl* new_pred = 449 m.mk_fresh_func_decl(prefix, suffix, arity, domain, m.mk_bool_sort()); 450 451 register_predicate(new_pred, true); 452 453 if (m_rel) { 454 m_rel->inherit_predicate_kind(new_pred, orig_pred); 455 } 456 return new_pred; 457 } 458 add_rule(expr * rl,symbol const & name,unsigned bound)459 void context::add_rule(expr* rl, symbol const& name, unsigned bound) { 460 SASSERT(rl); 461 m_rule_fmls.push_back(rl); 462 m_rule_names.push_back(name); 463 m_rule_bounds.push_back(bound); 464 } 465 flush_add_rules()466 void context::flush_add_rules() { 467 datalog::rule_manager& rm = get_rule_manager(); 468 scoped_proof_mode _scp(m, generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); 469 while (m_rule_fmls_head < m_rule_fmls.size()) { 470 expr* fml = m_rule_fmls[m_rule_fmls_head].get(); 471 proof* p = generate_proof_trace()?m.mk_asserted(fml):nullptr; 472 rm.mk_rule(fml, p, m_rule_set, m_rule_names[m_rule_fmls_head]); 473 ++m_rule_fmls_head; 474 } 475 check_rules(m_rule_set); 476 } 477 478 // 479 // Update a rule with a new. 480 // It requires basic subsumption. 481 // update_rule(expr * rl,symbol const & name)482 void context::update_rule(expr* rl, symbol const& name) { 483 datalog::rule_manager& rm = get_rule_manager(); 484 proof* p = nullptr; 485 if (generate_proof_trace()) { 486 p = m.mk_asserted(rl); 487 } 488 unsigned size_before = m_rule_set.get_num_rules(); 489 rm.mk_rule(rl, p, m_rule_set, name); 490 unsigned size_after = m_rule_set.get_num_rules(); 491 if (size_before + 1 != size_after) { 492 std::stringstream strm; 493 strm << "Rule " << name << " has a non-trivial body. It cannot be modified"; 494 throw default_exception(strm.str()); 495 } 496 // The new rule is inserted last: 497 rule_ref r(m_rule_set.get_rule(size_before), rm); 498 rule_ref_vector const& rls = m_rule_set.get_rules(); 499 rule* old_rule = nullptr; 500 for (unsigned i = 0; i < size_before; ++i) { 501 if (rls[i]->name() == name) { 502 if (old_rule) { 503 std::stringstream strm; 504 strm << "Rule " << name << " occurs twice. It cannot be modified"; 505 m_rule_set.del_rule(r); 506 throw default_exception(strm.str()); 507 } 508 old_rule = rls[i]; 509 } 510 } 511 if (old_rule) { 512 if (!check_subsumes(*old_rule, *r)) { 513 std::stringstream strm; 514 strm << "Old rule "; 515 old_rule->display(*this, strm); 516 strm << "does not subsume new rule "; 517 r->display(*this, strm); 518 m_rule_set.del_rule(r); 519 throw default_exception(strm.str()); 520 } 521 m_rule_set.del_rule(old_rule); 522 } 523 } 524 check_subsumes(rule const & stronger_rule,rule const & weaker_rule)525 bool context::check_subsumes(rule const& stronger_rule, rule const& weaker_rule) { 526 if (stronger_rule.get_head() != weaker_rule.get_head()) { 527 return false; 528 } 529 for (unsigned i = 0; i < stronger_rule.get_tail_size(); ++i) { 530 app* t = stronger_rule.get_tail(i); 531 bool found = false; 532 for (unsigned j = 0; j < weaker_rule.get_tail_size(); ++j) { 533 app* s = weaker_rule.get_tail(j); 534 if (s == t) { 535 found = true; 536 break; 537 } 538 } 539 if (!found) { 540 return false; 541 } 542 } 543 return true; 544 } 545 get_num_levels(func_decl * pred)546 unsigned context::get_num_levels(func_decl* pred) { 547 ensure_engine(); 548 return m_engine->get_num_levels(pred); 549 } 550 get_cover_delta(int level,func_decl * pred)551 expr_ref context::get_cover_delta(int level, func_decl* pred) { 552 ensure_engine(); 553 return m_engine->get_cover_delta(level, pred); 554 } 555 get_reachable(func_decl * pred)556 expr_ref context::get_reachable(func_decl *pred) { 557 ensure_engine(); 558 return m_engine->get_reachable(pred); 559 } add_cover(int level,func_decl * pred,expr * property)560 void context::add_cover(int level, func_decl* pred, expr* property) { 561 ensure_engine(); 562 m_engine->add_cover(level, pred, property); 563 } 564 add_invariant(func_decl * pred,expr * property)565 void context::add_invariant(func_decl* pred, expr *property) 566 { 567 ensure_engine(); 568 m_engine->add_invariant(pred, property); 569 } 570 check_rules(rule_set & r)571 void context::check_rules(rule_set& r) { 572 m_rule_properties.set_generate_proof(generate_proof_trace()); 573 TRACE("dl", m_rule_set.display(tout);); 574 switch(get_engine()) { 575 case DATALOG_ENGINE: 576 m_rule_properties.collect(r); 577 m_rule_properties.check_quantifier_free(); 578 m_rule_properties.check_uninterpreted_free(); 579 m_rule_properties.check_nested_free(); 580 m_rule_properties.check_infinite_sorts(); 581 break; 582 case SPACER_ENGINE: 583 m_rule_properties.collect(r); 584 m_rule_properties.check_existential_tail(); 585 m_rule_properties.check_for_negated_predicates(); 586 m_rule_properties.check_uninterpreted_free(); 587 m_rule_properties.check_quantifier_free(exists_k); 588 break; 589 case BMC_ENGINE: 590 m_rule_properties.collect(r); 591 m_rule_properties.check_for_negated_predicates(); 592 break; 593 case QBMC_ENGINE: 594 m_rule_properties.collect(r); 595 m_rule_properties.check_existential_tail(); 596 m_rule_properties.check_for_negated_predicates(); 597 break; 598 case TAB_ENGINE: 599 m_rule_properties.collect(r); 600 m_rule_properties.check_existential_tail(); 601 m_rule_properties.check_for_negated_predicates(); 602 break; 603 case CLP_ENGINE: 604 m_rule_properties.collect(r); 605 m_rule_properties.check_existential_tail(); 606 m_rule_properties.check_for_negated_predicates(); 607 break; 608 case DDNF_ENGINE: 609 break; 610 case LAST_ENGINE: 611 default: 612 UNREACHABLE(); 613 break; 614 } 615 } 616 add_rule(rule_ref & r)617 void context::add_rule(rule_ref& r) { 618 m_rule_set.add_rule(r); 619 } 620 add_fact(func_decl * pred,const relation_fact & fact)621 void context::add_fact(func_decl * pred, const relation_fact & fact) { 622 if (get_engine() == DATALOG_ENGINE) { 623 ensure_engine(); 624 m_rel->add_fact(pred, fact); 625 } 626 else { 627 expr_ref rule(m.mk_app(pred, fact.size(), (expr*const*)fact.c_ptr()), m); 628 add_rule(rule, symbol::null); 629 } 630 } 631 632 add_fact(app * head)633 void context::add_fact(app * head) { 634 SASSERT(is_fact(head)); 635 relation_fact fact(get_manager()); 636 unsigned n = head->get_num_args(); 637 for (unsigned i = 0; i < n; i++) { 638 fact.push_back(to_app(head->get_arg(i))); 639 } 640 add_fact(head->get_decl(), fact); 641 } 642 has_facts(func_decl * pred) const643 bool context::has_facts(func_decl * pred) const { 644 return m_rel && m_rel->has_facts(pred); 645 } 646 add_table_fact(func_decl * pred,const table_fact & fact)647 void context::add_table_fact(func_decl * pred, const table_fact & fact) { 648 if (get_engine() == DATALOG_ENGINE) { 649 ensure_engine(); 650 m_rel->add_fact(pred, fact); 651 } 652 else { 653 relation_fact rfact(m); 654 for (unsigned i = 0; i < fact.size(); ++i) { 655 rfact.push_back(m_decl_util.mk_numeral(fact[i], pred->get_domain()[i])); 656 } 657 add_fact(pred, rfact); 658 } 659 } 660 add_table_fact(func_decl * pred,unsigned num_args,unsigned args[])661 void context::add_table_fact(func_decl * pred, unsigned num_args, unsigned args[]) { 662 if (pred->get_arity() != num_args) { 663 std::ostringstream out; 664 out << "mismatched number of arguments passed to " << mk_ismt2_pp(pred, m) << " " << num_args << " passed"; 665 throw default_exception(out.str()); 666 } 667 table_fact fact; 668 for (unsigned i = 0; i < num_args; ++i) { 669 fact.push_back(args[i]); 670 } 671 add_table_fact(pred, fact); 672 } 673 close()674 void context::close() { 675 SASSERT(!m_closed); 676 if (!m_rule_set.close()) { 677 throw default_exception("Negation is not stratified!"); 678 } 679 m_closed = true; 680 } 681 ensure_closed()682 void context::ensure_closed() { 683 if (!m_closed) { 684 close(); 685 } 686 } ensure_opened()687 void context::ensure_opened() { 688 if (m_closed) { 689 reopen(); 690 } 691 } 692 reopen()693 void context::reopen() { 694 SASSERT(m_closed); 695 m_rule_set.reopen(); 696 m_closed = false; 697 } 698 transform_rules(rule_transformer::plugin * plugin)699 void context::transform_rules(rule_transformer::plugin* plugin) { 700 flet<bool> _enable_bv(m_enable_bind_variables, false); 701 rule_transformer transformer(*this); 702 transformer.register_plugin(plugin); 703 transform_rules(transformer); 704 } 705 transform_rules(rule_transformer & transf)706 void context::transform_rules(rule_transformer& transf) { 707 SASSERT(m_closed); //we must finish adding rules before we start transforming them 708 TRACE("dl", display_rules(tout);); 709 if (transf(m_rule_set)) { 710 //we have already ensured the negation is stratified and transformations 711 //should not break the stratification 712 m_rule_set.ensure_closed(); 713 TRACE("dl", display_rules(tout);); 714 TRACE("dl_verbose", display(tout);); 715 } 716 } 717 replace_rules(rule_set const & rs)718 void context::replace_rules(rule_set const & rs) { 719 SASSERT(!m_closed); 720 m_rule_set.replace_rules(rs); 721 if (m_rel) { 722 m_rel->restrict_predicates(get_predicates()); 723 } 724 } 725 record_transformed_rules()726 void context::record_transformed_rules() { 727 m_transformed_rule_set.replace_rules(m_rule_set); 728 } 729 apply_default_transformation()730 void context::apply_default_transformation() { 731 } 732 collect_params(param_descrs & p)733 void context::collect_params(param_descrs& p) { 734 fp_params::collect_param_descrs(p); 735 insert_timeout(p); 736 insert_ctrl_c(p); 737 } 738 updt_params(params_ref const & p)739 void context::updt_params(params_ref const& p) { 740 m_params_ref.copy(p); 741 if (m_engine.get()) m_engine->updt_params(); 742 m_generate_proof_trace = m_params->generate_proof_trace(); 743 m_unbound_compressor = m_params->datalog_unbound_compressor(); 744 m_default_relation = m_params->datalog_default_relation(); 745 } 746 get_background_assertion()747 expr_ref context::get_background_assertion() { 748 return mk_and(m_background); 749 } 750 assert_expr(expr * e)751 void context::assert_expr(expr* e) { 752 TRACE("dl", tout << mk_ismt2_pp(e, m) << "\n";); 753 m_background.push_back(e); 754 } 755 cleanup()756 void context::cleanup() { 757 m_last_status = OK; 758 if (m_engine) m_engine->cleanup(); 759 } 760 761 class context::engine_type_proc { 762 ast_manager& m; 763 arith_util a; 764 datatype_util dt; 765 bv_util bv; 766 array_util ar; 767 DL_ENGINE m_engine_type; 768 is_large_bv(sort * s)769 bool is_large_bv(sort* s) { 770 return false; 771 } 772 773 public: engine_type_proc(ast_manager & m)774 engine_type_proc(ast_manager& m): m(m), a(m), dt(m), bv(m), ar(m), m_engine_type(DATALOG_ENGINE) {} 775 get_engine() const776 DL_ENGINE get_engine() const { return m_engine_type; } 777 operator ()(expr * e)778 void operator()(expr* e) { 779 if (a.is_int_real(e)) { 780 m_engine_type = SPACER_ENGINE; 781 } 782 else if (is_var(e) && m.is_bool(e)) { 783 m_engine_type = SPACER_ENGINE; 784 } 785 else if (dt.is_datatype(m.get_sort(e))) { 786 m_engine_type = SPACER_ENGINE; 787 } 788 else if (is_large_bv(m.get_sort(e))) { 789 m_engine_type = SPACER_ENGINE; 790 } 791 else if (!m.get_sort(e)->get_num_elements().is_finite()) { 792 m_engine_type = SPACER_ENGINE; 793 } 794 else if (ar.is_array(e)) { 795 m_engine_type = SPACER_ENGINE; 796 } 797 } 798 }; 799 configure_engine(expr * q)800 void context::configure_engine(expr* q) { 801 TRACE("dl", tout << mk_pp(q, m) << " " << m_engine_type << "\n";); 802 if (m_engine_type != LAST_ENGINE) { 803 return; 804 } 805 symbol e = m_params->engine(); 806 807 if (e == symbol("datalog")) { 808 m_engine_type = DATALOG_ENGINE; 809 } 810 else if (e == symbol("spacer")) { 811 m_engine_type = SPACER_ENGINE; 812 } 813 else if (e == symbol("bmc")) { 814 m_engine_type = BMC_ENGINE; 815 } 816 else if (e == symbol("qbmc")) { 817 m_engine_type = QBMC_ENGINE; 818 } 819 else if (e == symbol("tab")) { 820 m_engine_type = TAB_ENGINE; 821 } 822 else if (e == symbol("clp")) { 823 m_engine_type = CLP_ENGINE; 824 } 825 else if (e == symbol("ddnf")) { 826 m_engine_type = DDNF_ENGINE; 827 } 828 else if (e == symbol("auto-config")) { 829 830 } 831 else { 832 throw default_exception("unsupported datalog engine type"); 833 } 834 835 if (m_engine_type == LAST_ENGINE) { 836 expr_fast_mark1 mark; 837 engine_type_proc proc(m); 838 m_engine_type = DATALOG_ENGINE; 839 if (q) { 840 quick_for_each_expr(proc, mark, q); 841 m_engine_type = proc.get_engine(); 842 } 843 844 for (unsigned i = 0; m_engine_type == DATALOG_ENGINE && i < m_rule_set.get_num_rules(); ++i) { 845 rule * r = m_rule_set.get_rule(i); 846 quick_for_each_expr(proc, mark, r->get_head()); 847 for (unsigned j = 0; j < r->get_tail_size(); ++j) { 848 quick_for_each_expr(proc, mark, r->get_tail(j)); 849 } 850 m_engine_type = proc.get_engine(); 851 } 852 for (unsigned i = m_rule_fmls_head; m_engine_type == DATALOG_ENGINE && i < m_rule_fmls.size(); ++i) { 853 expr* fml = m_rule_fmls[i].get(); 854 while (is_quantifier(fml)) { 855 fml = to_quantifier(fml)->get_expr(); 856 } 857 quick_for_each_expr(proc, mark, fml); 858 m_engine_type = proc.get_engine(); 859 } 860 } 861 } 862 query(expr * query)863 lbool context::query(expr* query) { 864 expr_ref _query(query, m); 865 m_mc = mk_skip_model_converter(); 866 m_last_status = OK; 867 m_last_answer = nullptr; 868 m_last_ground_answer = nullptr; 869 switch (get_engine(query)) { 870 case DATALOG_ENGINE: 871 case SPACER_ENGINE: 872 case BMC_ENGINE: 873 case QBMC_ENGINE: 874 case TAB_ENGINE: 875 case CLP_ENGINE: 876 case DDNF_ENGINE: 877 flush_add_rules(); 878 break; 879 default: 880 UNREACHABLE(); 881 } 882 ensure_engine(query); 883 lbool r = m_engine->query(query); 884 if (r != l_undef && get_params().print_certificate()) { 885 display_certificate(std::cout) << "\n"; 886 } 887 return r; 888 } 889 is_monotone()890 bool context::is_monotone() { 891 // assumes flush_add_rules was called 892 return m_rule_properties.is_monotone(); 893 } 894 895 query_from_lvl(expr * query,unsigned lvl)896 lbool context::query_from_lvl (expr* query, unsigned lvl) { 897 m_mc = mk_skip_model_converter(); 898 m_last_status = OK; 899 m_last_answer = nullptr; 900 m_last_ground_answer = nullptr; 901 switch (get_engine()) { 902 case DATALOG_ENGINE: 903 case SPACER_ENGINE: 904 case BMC_ENGINE: 905 case QBMC_ENGINE: 906 case TAB_ENGINE: 907 case CLP_ENGINE: 908 flush_add_rules(); 909 break; 910 default: 911 UNREACHABLE(); 912 } 913 ensure_engine(); 914 return m_engine->query_from_lvl (query, lvl); 915 } get_model()916 model_ref context::get_model() { 917 ensure_engine(); 918 return m_engine->get_model(); 919 } 920 get_proof()921 proof_ref context::get_proof() { 922 ensure_engine(); 923 return m_engine->get_proof(); 924 } 925 ensure_engine(expr * e)926 void context::ensure_engine(expr* e) { 927 if (!m_engine.get()) { 928 m_engine = m_register_engine.mk_engine(get_engine(e)); 929 m_engine->updt_params(); 930 931 // break abstraction. 932 if (get_engine() == DATALOG_ENGINE) { 933 m_rel = dynamic_cast<rel_context_base*>(m_engine.get()); 934 } 935 936 } 937 } 938 rel_query(unsigned num_rels,func_decl * const * rels)939 lbool context::rel_query(unsigned num_rels, func_decl * const* rels) { 940 m_last_answer = nullptr; 941 ensure_engine(); 942 return m_engine->query(num_rels, rels); 943 } 944 get_answer_as_formula()945 expr* context::get_answer_as_formula() { 946 if (m_last_answer) { 947 return m_last_answer.get(); 948 } 949 ensure_engine(); 950 m_last_answer = m_engine->get_answer(); 951 return m_last_answer.get(); 952 } 953 get_ground_sat_answer()954 expr* context::get_ground_sat_answer () { 955 if (m_last_ground_answer) { 956 return m_last_ground_answer; 957 } 958 ensure_engine (); 959 m_last_ground_answer = m_engine->get_ground_sat_answer (); 960 return m_last_ground_answer; 961 } 962 get_rules_along_trace(rule_ref_vector & rules)963 void context::get_rules_along_trace (rule_ref_vector& rules) { 964 ensure_engine (); 965 m_engine->get_rules_along_trace (rules); 966 } 967 get_rules_along_trace_as_formulas(expr_ref_vector & rules,svector<symbol> & names)968 void context::get_rules_along_trace_as_formulas (expr_ref_vector& rules, svector<symbol>& names) { 969 rule_manager& rm = get_rule_manager (); 970 rule_ref_vector rv (rm); 971 get_rules_along_trace (rv); 972 expr_ref fml (m); 973 for (auto* r : rv) { 974 m_rule_manager.to_formula (*r, fml); 975 rules.push_back (fml); 976 // The concatenated names are already stored last-first, so do not need to be reversed here 977 const symbol& rule_name = r->name(); 978 names.push_back (rule_name); 979 980 TRACE ("dl", 981 if (rule_name == symbol::null) { 982 tout << "Encountered unnamed rule: "; 983 r->display(*this, tout); 984 tout << "\n"; 985 }); 986 } 987 } 988 display_certificate(std::ostream & out)989 std::ostream& context::display_certificate(std::ostream& out) { 990 ensure_engine(); 991 m_engine->display_certificate(out); 992 return out; 993 } 994 display(std::ostream & out) const995 void context::display(std::ostream & out) const { 996 display_rules(out); 997 if (m_rel) m_rel->display_facts(out); 998 } 999 display_profile(std::ostream & out) const1000 void context::display_profile(std::ostream& out) const { 1001 out << "\n---------------\n"; 1002 out << "Original rules\n"; 1003 display_rules(out); 1004 out << "\n---------------\n"; 1005 out << "Transformed rules\n"; 1006 m_transformed_rule_set.display(out); 1007 1008 if (m_rel) { 1009 m_rel->display_profile(out); 1010 } 1011 } 1012 reset_statistics()1013 void context::reset_statistics() { 1014 if (m_engine) { 1015 m_engine->reset_statistics(); 1016 } 1017 } 1018 collect_statistics(statistics & st) const1019 void context::collect_statistics(statistics& st) const { 1020 if (m_engine) { 1021 m_engine->collect_statistics(st); 1022 } 1023 get_memory_statistics(st); 1024 get_rlimit_statistics(m.limit(), st); 1025 } 1026 1027 get_status()1028 execution_result context::get_status() { return m_last_status; } 1029 result_contains_fact(relation_fact const & f)1030 bool context::result_contains_fact(relation_fact const& f) { 1031 return m_rel && m_rel->result_contains_fact(f); 1032 } 1033 1034 // NB: algebraic data-types declarations will not be printed. 1035 collect_free_funcs(unsigned sz,expr * const * exprs,ast_pp_util & v,mk_fresh_name & fresh_names)1036 static void collect_free_funcs(unsigned sz, expr* const* exprs, 1037 ast_pp_util& v, 1038 mk_fresh_name& fresh_names) { 1039 v.collect(sz, exprs); 1040 for (unsigned i = 0; i < sz; ++i) { 1041 expr* e = exprs[i]; 1042 while (is_quantifier(e)) { 1043 e = to_quantifier(e)->get_expr(); 1044 } 1045 fresh_names.add(e); 1046 } 1047 } 1048 get_raw_rule_formulas(expr_ref_vector & rules,svector<symbol> & names,unsigned_vector & bounds)1049 void context::get_raw_rule_formulas(expr_ref_vector& rules, svector<symbol>& names, unsigned_vector &bounds) { 1050 for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { 1051 expr_ref r = bind_vars(m_rule_fmls[i].get(), true); 1052 rules.push_back(r.get()); 1053 names.push_back(m_rule_names[i]); 1054 bounds.push_back(m_rule_bounds[i]); 1055 } 1056 } 1057 get_rules_as_formulas(expr_ref_vector & rules,expr_ref_vector & queries,svector<symbol> & names)1058 void context::get_rules_as_formulas(expr_ref_vector& rules, expr_ref_vector& queries, svector<symbol>& names) { 1059 expr_ref fml(m); 1060 rule_manager& rm = get_rule_manager(); 1061 1062 // ensure that rules are all using bound variables. 1063 for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { 1064 m_free_vars(m_rule_fmls[i].get()); 1065 if (!m_free_vars.empty()) { 1066 rm.mk_rule(m_rule_fmls[i].get(), nullptr, m_rule_set, m_rule_names[i]); 1067 m_rule_fmls[i] = m_rule_fmls.back(); 1068 m_rule_names[i] = m_rule_names.back(); 1069 m_rule_fmls.pop_back(); 1070 m_rule_names.pop_back(); 1071 m_rule_bounds.pop_back(); 1072 --i; 1073 } 1074 } 1075 for (rule* r : m_rule_set) { 1076 rm.to_formula(*r, fml); 1077 func_decl* h = r->get_decl(); 1078 if (m_rule_set.is_output_predicate(h)) { 1079 expr* body = fml; 1080 expr* e2; 1081 if (is_quantifier(body)) { 1082 quantifier* q = to_quantifier(body); 1083 expr* e = q->get_expr(); 1084 if (m.is_implies(e, body, e2)) { 1085 fml = m.mk_quantifier(exists_k, q->get_num_decls(), 1086 q->get_decl_sorts(), q->get_decl_names(), 1087 body); 1088 } 1089 else { 1090 fml = body; 1091 } 1092 } 1093 else { 1094 fml = body; 1095 if (m.is_implies(body, body, e2)) { 1096 fml = body; 1097 } 1098 } 1099 queries.push_back(fml); 1100 } 1101 else { 1102 rules.push_back(fml); 1103 names.push_back(r->name()); 1104 } 1105 } 1106 for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { 1107 rules.push_back(m_rule_fmls[i].get()); 1108 names.push_back(m_rule_names[i]); 1109 } 1110 } 1111 display_symbol(std::ostream & out,symbol const & nm)1112 static std::ostream& display_symbol(std::ostream& out, symbol const& nm) { 1113 if (is_smt2_quoted_symbol(nm)) { 1114 out << mk_smt2_quoted_symbol(nm); 1115 } 1116 else { 1117 out << nm; 1118 } 1119 return out; 1120 } 1121 display_smt2(unsigned num_queries,expr * const * qs,std::ostream & out)1122 void context::display_smt2(unsigned num_queries, expr* const* qs, std::ostream& out) { 1123 ast_manager& m = get_manager(); 1124 ast_pp_util visitor(m); 1125 func_decl_set rels; 1126 unsigned num_axioms = m_background.size(); 1127 expr* const* axioms = m_background.c_ptr(); 1128 expr_ref fml(m); 1129 expr_ref_vector rules(m), queries(m); 1130 svector<symbol> names; 1131 bool use_fixedpoint_extensions = m_params->print_fixedpoint_extensions(); 1132 bool print_low_level = m_params->print_low_level_smt2(); 1133 bool do_declare_vars = m_params->print_with_variable_declarations(); 1134 1135 #define PP(_e_) if (print_low_level) out << mk_smt_pp(_e_, m); else ast_smt2_pp(out, _e_, env); 1136 1137 get_rules_as_formulas(rules, queries, names); 1138 queries.append(num_queries, qs); 1139 1140 smt2_pp_environment_dbg env(m); 1141 mk_fresh_name fresh_names; 1142 collect_free_funcs(num_axioms, axioms, visitor, fresh_names); 1143 collect_free_funcs(rules.size(), rules.c_ptr(), visitor, fresh_names); 1144 collect_free_funcs(queries.size(), queries.c_ptr(), visitor, fresh_names); 1145 func_decl_set funcs; 1146 unsigned sz = visitor.coll.get_num_decls(); 1147 for (unsigned i = 0; i < sz; ++i) { 1148 func_decl* f = visitor.coll.get_func_decls()[i]; 1149 if (f->get_family_id() != null_family_id) { 1150 // 1151 } 1152 else if (is_predicate(f) && use_fixedpoint_extensions) { 1153 rels.insert(f); 1154 } 1155 else { 1156 funcs.insert(f); 1157 } 1158 } 1159 1160 if (!use_fixedpoint_extensions) { 1161 out << "(set-logic HORN)\n"; 1162 } 1163 for (func_decl * f : rels) 1164 visitor.remove_decl(f); 1165 1166 visitor.display_decls(out); 1167 1168 for (func_decl * f : rels) 1169 display_rel_decl(out, f); 1170 1171 if (use_fixedpoint_extensions && do_declare_vars) { 1172 declare_vars(rules, fresh_names, out); 1173 } 1174 1175 if (num_axioms > 0 && !use_fixedpoint_extensions) { 1176 throw default_exception("Background axioms cannot be used with SMT-LIB2 HORN format"); 1177 } 1178 1179 for (unsigned i = 0; i < num_axioms; ++i) { 1180 out << "(assert "; 1181 PP(axioms[i]); 1182 out << ")\n"; 1183 } 1184 for (unsigned i = 0; i < rules.size(); ++i) { 1185 out << (use_fixedpoint_extensions?"(rule ":"(assert "); 1186 expr* r = rules[i].get(); 1187 symbol nm = names[i]; 1188 if (symbol::null != nm) { 1189 out << "(! "; 1190 } 1191 PP(r); 1192 if (symbol::null != nm) { 1193 out << " :named "; 1194 while (fresh_names.contains(nm)) { 1195 std::ostringstream s; 1196 s << nm << '!'; 1197 nm = symbol(s.str()); 1198 } 1199 fresh_names.add(nm); 1200 display_symbol(out, nm) << ')'; 1201 } 1202 out << ")\n"; 1203 } 1204 if (use_fixedpoint_extensions) { 1205 for (unsigned i = 0; i < queries.size(); ++i) { 1206 expr* q = queries[i].get(); 1207 func_decl_ref fn(m); 1208 if (is_query(q)) { 1209 fn = to_app(q)->get_decl(); 1210 } 1211 else { 1212 m_free_vars(q); 1213 m_free_vars.set_default_sort(m.mk_bool_sort()); 1214 sort* const* domain = m_free_vars.c_ptr(); 1215 expr_ref qfn(m); 1216 expr_ref_vector args(m); 1217 fn = m.mk_fresh_func_decl(symbol("q"), symbol(""), m_free_vars.size(), domain, m.mk_bool_sort()); 1218 display_rel_decl(out, fn); 1219 for (unsigned j = 0; j < m_free_vars.size(); ++j) { 1220 args.push_back(m.mk_var(j, m_free_vars[j])); 1221 } 1222 qfn = m.mk_implies(q, m.mk_app(fn, args.size(), args.c_ptr())); 1223 1224 out << "(assert "; 1225 PP(qfn); 1226 out << ")\n"; 1227 } 1228 out << "(query "; 1229 display_symbol(out, fn->get_name()) << ")\n"; 1230 } 1231 } 1232 else { 1233 for (unsigned i = 0; i < queries.size(); ++i) { 1234 if (queries.size() > 1) out << "(push 1)\n"; 1235 out << "(assert "; 1236 expr_ref q(m); 1237 q = m.mk_not(queries[i].get()); 1238 PP(q); 1239 out << ")\n"; 1240 out << "(check-sat)\n"; 1241 if (queries.size() > 1) out << "(pop 1)\n"; 1242 } 1243 } 1244 } 1245 display_rel_decl(std::ostream & out,func_decl * f)1246 void context::display_rel_decl(std::ostream& out, func_decl* f) { 1247 smt2_pp_environment_dbg env(m); 1248 out << "(declare-rel "; 1249 display_symbol(out, f->get_name()) << " ("; 1250 for (unsigned i = 0; i < f->get_arity(); ++i) { 1251 ast_smt2_pp(out, f->get_domain(i), env); 1252 if (i + 1 < f->get_arity()) { 1253 out << " "; 1254 } 1255 } 1256 out << "))\n"; 1257 } 1258 is_query(expr * q)1259 bool context::is_query(expr* q) { 1260 if (!is_app(q) || !is_predicate(to_app(q)->get_decl())) { 1261 return false; 1262 } 1263 app* a = to_app(q); 1264 for (unsigned i = 0; i < a->get_num_args(); ++i) { 1265 if (!is_var(a->get_arg(i))) { 1266 return false; 1267 } 1268 var* v = to_var(a->get_arg(i)); 1269 if (v->get_idx() != i) { 1270 return false; 1271 } 1272 } 1273 return true; 1274 } 1275 1276 declare_vars(expr_ref_vector & rules,mk_fresh_name & fresh_names,std::ostream & out)1277 void context::declare_vars(expr_ref_vector& rules, mk_fresh_name& fresh_names, std::ostream& out) { 1278 // 1279 // replace bound variables in rules by 'var declarations' 1280 // First remove quantifiers, then replace bound variables 1281 // by fresh constants. 1282 // 1283 smt2_pp_environment_dbg env(m); 1284 var_subst vsubst(m, false); 1285 1286 expr_ref_vector fresh_vars(m), subst(m); 1287 expr_ref res(m); 1288 obj_map<sort, unsigned_vector> var_idxs; 1289 obj_map<sort, unsigned> max_vars; 1290 for (unsigned i = 0; i < rules.size(); ++i) { 1291 expr* r = rules[i].get(); 1292 if (!is_forall(r)) { 1293 continue; 1294 } 1295 quantifier* q = to_quantifier(r); 1296 if (has_quantifiers(q->get_expr())) { 1297 continue; 1298 } 1299 max_vars.reset(); 1300 subst.reset(); 1301 unsigned max_var = 0; 1302 unsigned num_vars = q->get_num_decls(); 1303 for (unsigned j = 0; j < num_vars; ++j) { 1304 sort* s = q->get_decl_sort(num_vars-1-j); 1305 // maximal var for the given sort. 1306 if (!max_vars.find(s, max_var)) { 1307 max_var = 0; 1308 } 1309 else { 1310 ++max_var; 1311 } 1312 max_vars.insert(s, max_var); 1313 1314 // index into fresh variable array. 1315 // unsigned fresh_var_idx = 0; 1316 unsigned_vector& vars = var_idxs.insert_if_not_there(s, unsigned_vector()); 1317 if (max_var >= vars.size()) { 1318 SASSERT(vars.size() == max_var); 1319 vars.push_back(fresh_vars.size()); 1320 symbol name = fresh_names.next(); 1321 fresh_vars.push_back(m.mk_const(name, s)); 1322 out << "(declare-var " << name << " "; 1323 ast_smt2_pp(out, s, env); 1324 out << ")\n"; 1325 } 1326 subst.push_back(fresh_vars[vars[max_var]].get()); 1327 } 1328 1329 res = vsubst(q->get_expr(), subst.size(), subst.c_ptr()); 1330 rules[i] = res.get(); 1331 } 1332 } 1333 1334 1335 }; 1336