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