diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 2900aea85..6f229b30d 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -210,6 +210,10 @@ public: return r; } + app * mk_default(expr * a) { + return m_manager.mk_app(m_fid, OP_ARRAY_DEFAULT, 0, nullptr, 1, &a); + } + app * mk_const_array(sort * s, expr * v) { parameter param(s); return m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶m, 1, &v); @@ -251,6 +255,14 @@ public: parameter param(f); return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, nullptr, nullptr); } + + sort* get_array_range_rec(sort* s) { + while (is_array(s)) { + s = get_array_range(s); + } + return s; + } + }; diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 6ce31755a..1089e0159 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -450,6 +450,19 @@ namespace datatype { m_manager->raise_exception("datatype is not co-variant"); } + array_util autil(m); + for (sort* s : sorts) { + for (constructor const* c : get_def(s)) { + for (accessor const* a : *c) { + if (autil.is_array(a->range())) { + if (sorts.contains(get_array_range(a->range()))) { + m_has_nested_arrays = true; + } + } + } + } + } + u().compute_datatype_size_functions(m_def_block); for (symbol const& s : m_def_block) { sort_ref_vector ps(m); @@ -892,10 +905,13 @@ namespace datatype { for (unsigned i = 0; i < n; ++i) { get_subsorts(get_array_domain(s, i), subsorts); } + if (!is_datatype(get_array_range(s))) { + get_subsorts(get_array_range(s), subsorts); + } for (sort* r : subsorts) { if (mark.is_marked(r)) return false; } - return is_covariant(mark, subsorts, get_array_range(s)); + return true; } def const& util::get_def(sort* s) const { @@ -1115,6 +1131,7 @@ namespace datatype { ptr_vector const& constructors = *get_datatype_constructors(ty); unsigned sz = constructors.size(); + array_util autil(m); TRACE("util_bug", tout << "get-non-rec constructor: " << sort_ref(ty, m) << "\n"; tout << "forbidden: "; for (sort* s : forbidden_set) tout << sort_ref(s, m) << " "; @@ -1129,7 +1146,7 @@ namespace datatype { TRACE("util_bug", tout << "checking " << sort_ref(ty, m) << ": " << func_decl_ref(c, m) << "\n";); unsigned num_args = c->get_arity(); unsigned i = 0; - for (; i < num_args && !is_datatype(c->get_domain(i)); i++); + for (; i < num_args && !is_datatype(autil.get_array_range_rec(c->get_domain(i))); i++); if (i == num_args) { TRACE("util_bug", tout << "found non-rec " << func_decl_ref(c, m) << "\n";); return c; @@ -1142,7 +1159,7 @@ namespace datatype { unsigned num_args = c->get_arity(); unsigned i = 0; for (; i < num_args; i++) { - sort * T_i = c->get_domain(i); + sort * T_i = autil.get_array_range_rec(c->get_domain(i)); TRACE("util_bug", tout << "c: " << i << " " << sort_ref(T_i, m) << "\n";); if (!is_datatype(T_i)) { TRACE("util_bug", tout << sort_ref(T_i, m) << " is not a datatype\n";); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 748688804..c478daa7c 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -210,13 +210,14 @@ namespace datatype { unsigned m_id_counter; svector m_def_block; unsigned m_class_id; + mutable bool m_has_nested_arrays; void inherit(decl_plugin* other_p, ast_translation& tr) override; void log_axiom_definitions(symbol const& s, sort * new_sort); public: - plugin(): m_id_counter(0), m_class_id(0) {} + plugin(): m_id_counter(0), m_class_id(0), m_has_nested_arrays(false) {} ~plugin() override; void finalize() override; @@ -254,6 +255,8 @@ namespace datatype { unsigned get_axiom_base_id(symbol const& s) { return m_axiom_bases[s]; } util & u() const; + bool has_nested_arrays() const { return m_has_nested_arrays; } + private: bool is_value_visit(expr * arg, ptr_buffer & todo) const; @@ -353,6 +356,7 @@ namespace datatype { func_decl * get_accessor_constructor(func_decl * accessor); func_decl * get_recognizer_constructor(func_decl * recognizer) const; func_decl * get_update_accessor(func_decl * update) const; + bool has_nested_arrays() const { return m_plugin->has_nested_arrays(); } family_id get_family_id() const { return m_family_id; } bool are_siblings(sort * s1, sort * s2); bool is_func_decl(op_kind k, unsigned num_params, parameter const* params, func_decl* f); diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 9c2cb26e3..9462ebb0c 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -39,7 +39,8 @@ enum phase_selection { PS_CACHING_CONSERVATIVE, PS_CACHING_CONSERVATIVE2, // similar to the previous one, but alternated default config from time to time. PS_RANDOM, - PS_OCCURRENCE + PS_OCCURRENCE, + PS_THEORY }; enum restart_strategy { diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index f81cbfa44..6986bb0f4 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -10,7 +10,7 @@ def_module_params(module_name='smt', ('quasi_macros', BOOL, False, 'try to find universally quantified formulas that are quasi-macros'), ('restricted_quasi_macros', BOOL, False, 'try to find universally quantified formulas that are restricted quasi-macros'), ('ematching', BOOL, True, 'E-Matching based quantifier instantiation'), - ('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'), + ('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences, 7 - theory'), ('restart_strategy', UINT, 1, '0 - geometric, 1 - inner-outer-geometric, 2 - luby, 3 - fixed, 4 - arithmetic'), ('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the current restart threshold'), ('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal, 6 - activity-based case split with theory-aware branching activity'), diff --git a/src/smt/smt_arith_value.cpp b/src/smt/smt_arith_value.cpp index 8dfca3ebb..abf7161da 100644 --- a/src/smt/smt_arith_value.cpp +++ b/src/smt/smt_arith_value.cpp @@ -17,6 +17,7 @@ Revision History: --*/ +#include "ast/ast_pp.h" #include "smt/smt_arith_value.h" namespace smt { @@ -50,6 +51,7 @@ namespace smt { next = next->get_next(); } while (n != next); + CTRACE("arith_value", !found, tout << "value not found for " << mk_pp(e, m_ctx->get_manager()) << "\n";); return found; } @@ -69,6 +71,7 @@ namespace smt { next = next->get_next(); } while (n != next); + CTRACE("arith_value", !found, tout << "value not found for " << mk_pp(e, m_ctx->get_manager()) << "\n";); return found; } @@ -79,6 +82,7 @@ namespace smt { if (m_tha) return m_tha->get_upper(n, up, is_strict); if (m_thi) return m_thi->get_upper(n, up, is_strict); if (m_thr) return m_thr->get_upper(n, up, is_strict); + TRACE("arith_value", tout << "value not found for " << mk_pp(e, m_ctx->get_manager()) << "\n";); return false; } @@ -89,6 +93,7 @@ namespace smt { if (m_tha) return m_tha->get_lower(n, up, is_strict); if (m_thi) return m_thi->get_lower(n, up, is_strict); if (m_thr) return m_thr->get_lower(n, up, is_strict); + TRACE("arith_value", tout << "value not found for " << mk_pp(e, m_ctx->get_manager()) << "\n";); return false; } @@ -99,6 +104,7 @@ namespace smt { if (m_tha && m_tha->get_value(n, _val) && a.is_numeral(_val, val)) return true; if (m_thi && m_thi->get_value(n, _val) && a.is_numeral(_val, val)) return true; if (m_thr && m_thr->get_value(n, val)) return true; + TRACE("arith_value", tout << "value not found for " << mk_pp(e, m_ctx->get_manager()) << "\n";); return false; } @@ -115,6 +121,7 @@ namespace smt { next = next->get_next(); } while (next != n); + TRACE("arith_value", tout << "value not found for " << mk_pp(e, m_ctx->get_manager()) << "\n";); return false; } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3e1b165b4..3e4caa65b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1849,6 +1849,16 @@ namespace smt { } else { switch (m_fparams.m_phase_selection) { + case PS_THEORY: + if (d.is_theory_atom()) { + theory * th = m_theories.get_plugin(d.get_theory()); + lbool ph = th->get_phase(var); + if (ph != l_undef) { + is_pos = ph == l_true; + break; + } + } + Z3_fallthrough; case PS_CACHING: case PS_CACHING_CONSERVATIVE: case PS_CACHING_CONSERVATIVE2: diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 4b2dcaec2..63b7f20a9 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -21,6 +21,7 @@ Revision History: #include "ast/for_each_expr.h" #include "ast/ast_pp.h" #include "ast/ast_smt2_pp.h" +#include "ast/array_decl_plugin.h" #include "smt/smt_context.h" #include "smt/smt_model_generator.h" #include "smt/proto_model/proto_model.h" @@ -38,15 +39,15 @@ namespace smt { } model_generator::model_generator(ast_manager & m): - m_manager(m), + m(m), m_context(nullptr), m_fresh_idx(1), - m_asts(m_manager), + m_asts(m), m_model(nullptr) { } model_generator::~model_generator() { - dec_ref_collection_values(m_manager, m_hidden_ufs); + dec_ref_collection_values(m, m_hidden_ufs); } void model_generator::reset() { @@ -60,7 +61,7 @@ namespace smt { void model_generator::init_model() { SASSERT(!m_model); // PARAM-TODO smt_params ---> params_ref - m_model = alloc(proto_model, m_manager); // , m_context->get_fparams()); + m_model = alloc(proto_model, m); // , m_context->get_fparams()); for (theory* th : m_context->theories()) { TRACE("model_generator_bug", tout << "init_model for theory: " << th->get_name() << "\n";); th->init_model(*this); @@ -75,10 +76,10 @@ namespace smt { for (unsigned i = 0; i < sz; i++) { expr * p = m_context->get_b_internalized(i); if (is_uninterp_const(p) && m_context->is_relevant(p)) { - SASSERT(m_manager.is_bool(p)); + SASSERT(m.is_bool(p)); func_decl * d = to_app(p)->get_decl(); lbool val = m_context->get_assignment(p); - expr * v = val == l_true ? m_manager.mk_true() : m_manager.mk_false(); + expr * v = val == l_true ? m.mk_true() : m.mk_false(); m_model->register_decl(d, v); } } @@ -93,16 +94,16 @@ namespace smt { for (enode * r : m_context->enodes()) { if (r == r->get_root() && m_context->is_relevant(r)) { roots.push_back(r); - sort * s = m_manager.get_sort(r->get_owner()); + sort * s = m.get_sort(r->get_owner()); model_value_proc * proc = nullptr; - if (m_manager.is_bool(s)) { + if (m.is_bool(s)) { CTRACE("model", m_context->get_assignment(r) == l_undef, - tout << mk_pp(r->get_owner(), m_manager) << "\n";); + tout << mk_pp(r->get_owner(), m) << "\n";); SASSERT(m_context->get_assignment(r) != l_undef); if (m_context->get_assignment(r) == l_true) - proc = alloc(expr_wrapper_proc, m_manager.mk_true()); + proc = alloc(expr_wrapper_proc, m.mk_true()); else - proc = alloc(expr_wrapper_proc, m_manager.mk_false()); + proc = alloc(expr_wrapper_proc, m.mk_false()); } else { family_id fid = s->get_family_id(); @@ -114,7 +115,7 @@ namespace smt { } else { TRACE("model", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); - proc = alloc(fresh_value_proc, mk_extra_fresh_value(m_manager.get_sort(r->get_owner()))); + proc = alloc(fresh_value_proc, mk_extra_fresh_value(m.get_sort(r->get_owner()))); } } else { @@ -132,11 +133,11 @@ namespace smt { model_value_proc* model_generator::mk_model_value(enode* r) { SASSERT(r == r->get_root()); expr * n = r->get_owner(); - if (!m_manager.is_model_value(n)) { - sort * s = m_manager.get_sort(r->get_owner()); + if (!m.is_model_value(n)) { + sort * s = m.get_sort(r->get_owner()); n = m_model->get_fresh_value(s); CTRACE("model", n == 0, - tout << mk_pp(r->get_owner(), m_manager) << "\nsort:\n" << mk_pp(s, m_manager) << "\n"; + tout << mk_pp(r->get_owner(), m) << "\nsort:\n" << mk_pp(s, m) << "\n"; tout << "is_finite: " << m_model->is_finite(s) << "\n";); } return alloc(expr_wrapper_proc, to_app(n)); @@ -175,20 +176,17 @@ namespace smt { // there is an implicit dependency between a fresh value stub of // sort S and the root enodes of sort S that are not associated with fresh values. // - sort * s = src.get_value()->get_sort(); + sort * s = src.get_value()->get_sort(); if (already_traversed.contains(s)) return true; bool visited = true; for (enode * r : roots) { - if (m_manager.get_sort(r->get_owner()) != s) + if (m.get_sort(r->get_owner()) != s) continue; SASSERT(r == r->get_root()); - model_value_proc * proc = root2proc[r]; - SASSERT(proc); - if (proc->is_fresh()) + if (root2proc[r]->is_fresh()) continue; // r is associated with a fresh value... - SASSERT(r == r->get_root()); - TRACE("mg_top_sort", tout << "fresh!" << src.get_value()->get_idx() << " -> #" << r->get_owner_id() << " " << mk_pp(m_manager.get_sort(r->get_owner()), m_manager) << "\n";); + TRACE("mg_top_sort", tout << "fresh!" << src.get_value()->get_idx() << " -> #" << r->get_owner_id() << " " << mk_pp(m.get_sort(r->get_owner()), m) << "\n";); visit_child(source(r), colors, todo, visited); TRACE("mg_top_sort", tout << "visited: " << visited << ", todo.size(): " << todo.size() << "\n";); } @@ -206,8 +204,14 @@ namespace smt { proc->get_dependencies(dependencies); for (model_value_dependency const& dep : dependencies) { visit_child(dep, colors, todo, visited); - TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " -> " << dep << " already visited: " << visited << "\n";); } + TRACE("mg_top_sort", + tout << "src: " << src << " "; + tout << mk_pp(n->get_owner(), m) << "\n"; + for (model_value_dependency const& dep : dependencies) { + tout << "#" << n->get_owner_id() << " -> " << dep << " already visited: " << visited << "\n"; + } + ); return visited; } @@ -273,11 +277,9 @@ namespace smt { // traverse all enodes that are associated with fresh values... for (enode* r : roots) { - model_value_proc * proc = root2proc[r]; - SASSERT(proc); - if (!proc->is_fresh()) - continue; - process_source(source(r), roots, root2proc, colors, already_traversed, todo, sorted_sources); + if (root2proc[r]->is_fresh()) { + process_source(source(r), roots, root2proc, colors, already_traversed, todo, sorted_sources); + } } for (enode * r : roots) { @@ -291,29 +293,32 @@ namespace smt { ptr_vector procs; svector sources; buffer dependencies; - expr_ref_vector dependency_values(m_manager); + expr_ref_vector dependency_values(m); mk_value_procs(root2proc, roots, procs); top_sort_sources(roots, root2proc, sources); TRACE("sorted_sources", for (source const& curr : sources) { if (curr.is_fresh_value()) { - tout << curr << " " << mk_pp(curr.get_value()->get_sort(), m_manager) << "\n"; + tout << curr << " " << mk_pp(curr.get_value()->get_sort(), m) << "\n"; } else { enode * n = curr.get_enode(); SASSERT(n->get_root() == n); - sort * s = m_manager.get_sort(n->get_owner()); - tout << curr << " " << mk_pp(s, m_manager); + tout << mk_pp(n->get_owner(), m) << "\n"; + sort * s = m.get_sort(n->get_owner()); + tout << curr << " " << mk_pp(s, m); tout << " is_fresh: " << root2proc[n]->is_fresh() << "\n"; } - }); + } + m_context->display(tout); + ); scoped_reset _scoped_reset(*this, procs); for (source const& curr : sources) { if (curr.is_fresh_value()) { sort * s = curr.get_value()->get_sort(); - TRACE("model_fresh_bug", tout << curr << " : " << mk_pp(s, m_manager) << "\n";); + TRACE("model_fresh_bug", tout << curr << " : " << mk_pp(s, m) << "\n";); expr * val = m_model->get_fresh_value(s); TRACE("model_fresh_bug", tout << curr << " := #" << (val == nullptr ? UINT_MAX : val->get_id()) << "\n";); m_asts.push_back(val); @@ -331,13 +336,14 @@ namespace smt { for (model_value_dependency const& d : dependencies) { if (d.is_fresh_value()) { CTRACE("mg_top_sort", !d.get_value()->get_value(), - tout << "#" << n->get_owner_id() << " -> " << d << "\n";); + tout << "#" << n->get_owner_id() << " " << mk_pp(n->get_owner(), m) << " -> " << d << "\n";); SASSERT(d.get_value()->get_value()); dependency_values.push_back(d.get_value()->get_value()); } else { enode * child = d.get_enode(); - TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " (" << mk_pp(n->get_owner(), m_manager) << "): " << mk_pp(child->get_owner(), m_manager) << " " << mk_pp(child->get_root()->get_owner(), m_manager) << "\n";); + TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " (" << mk_pp(n->get_owner(), m) << "): " + << mk_pp(child->get_owner(), m) << " " << mk_pp(child->get_root()->get_owner(), m) << "\n";); child = child->get_root(); dependency_values.push_back(m_root2value[child]); } @@ -379,7 +385,7 @@ namespace smt { bool model_generator::include_func_interp(func_decl * f) const { family_id fid = f->get_family_id(); if (fid == null_family_id) return !m_hidden_ufs.contains(f); - if (fid == m_manager.get_basic_family_id()) return false; + if (fid == m.get_basic_family_id()) return false; theory * th = m_context->get_theory(fid); if (!th) return true; return th->include_func_interp(f); @@ -412,19 +418,19 @@ namespace smt { } func_interp * fi = m_model->get_func_interp(f); if (fi == nullptr) { - fi = alloc(func_interp, m_manager, f->get_arity()); + fi = alloc(func_interp, m, f->get_arity()); m_model->register_decl(f, fi); } SASSERT(m_model->has_interpretation(f)); SASSERT(m_model->get_func_interp(f) == fi); // The entry must be new because n->get_cg() == n TRACE("model", - tout << "insert new entry for:\n" << mk_ismt2_pp(n->get_owner(), m_manager) << "\nargs: "; + tout << "insert new entry for:\n" << mk_ismt2_pp(n->get_owner(), m) << "\nargs: "; for (unsigned i = 0; i < num_args; i++) { tout << "#" << n->get_arg(i)->get_owner_id() << " "; } tout << "\n"; - tout << "value: #" << n->get_owner_id() << "\n" << mk_ismt2_pp(result, m_manager) << "\n";); + tout << "value: #" << n->get_owner_id() << "\n" << mk_ismt2_pp(result, m) << "\n";); if (fi->get_entry(args.c_ptr()) == nullptr) fi->insert_new_entry(args.c_ptr(), result); } @@ -457,7 +463,7 @@ namespace smt { for (enode * r : m_context->enodes()) { if (r == r->get_root() && m_context->is_relevant(r)) { expr * n = r->get_owner(); - if (m_manager.is_model_value(n)) { + if (m.is_model_value(n)) { register_value(n); } } @@ -471,12 +477,12 @@ namespace smt { void model_generator::register_macros() { unsigned num = m_context->get_num_macros(); TRACE("model", tout << "num. macros: " << num << "\n";); - expr_ref v(m_manager); + expr_ref v(m); for (unsigned i = 0; i < num; i++) { func_decl * f = m_context->get_macro_interpretation(i, v); - func_interp * fi = alloc(func_interp, m_manager, f->get_arity()); + func_interp * fi = alloc(func_interp, m, f->get_arity()); fi->set_else(v); - TRACE("model", tout << f->get_name() << "\n" << mk_pp(v, m_manager) << "\n";); + TRACE("model", tout << f->get_name() << "\n" << mk_pp(v, m) << "\n";); m_model->register_decl(f, fi); } } diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index ba0d5634c..18aec5101 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -84,7 +84,7 @@ namespace smt { extra_fresh_value(sort * s, unsigned idx):m_sort(s), m_idx(idx), m_value(nullptr) {} sort * get_sort() const { return m_sort; } unsigned get_idx() const { return m_idx; } - void set_value(expr * n) { SASSERT(m_value == 0); m_value = n; } + void set_value(expr * n) { SASSERT(!m_value); m_value = n; } expr * get_value() const { return m_value; } }; @@ -178,7 +178,7 @@ namespace smt { \brief Auxiliary class used during model generation. */ class model_generator { - ast_manager & m_manager; + ast_manager & m; context * m_context; ptr_vector m_extra_fresh_values; unsigned m_fresh_idx; @@ -226,7 +226,7 @@ namespace smt { expr * get_some_value(sort * s); proto_model & get_model() { SASSERT(m_model); return *m_model; } void register_value(expr * val); - ast_manager & get_manager() { return m_manager; } + ast_manager & get_manager() { return m; } proto_model* mk_model(); obj_map const & get_root2value() const { return m_root2value; } @@ -235,7 +235,7 @@ namespace smt { void hide(func_decl * f) { if (!m_hidden_ufs.contains(f)) { m_hidden_ufs.insert(f); - m_manager.inc_ref(f); + m.inc_ref(f); } } }; diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index e5798f6c3..bdb69e87c 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -143,6 +143,13 @@ namespace smt { virtual void assign_eh(bool_var v, bool is_true) { } + /** + \brief use the theory to determine phase of the variable. + */ + virtual lbool get_phase(bool_var v) { + return l_undef; + } + /** \brief Equality propagation (v1 = v2): Core -> Theory */ diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index c1d6cac27..23cc45e54 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -95,7 +95,7 @@ namespace smt { v = find(v); var_data * d = m_var_data[v]; d->m_parent_selects.push_back(s); - TRACE("array", tout << mk_pp(s->get_owner(), get_manager()) << " " << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n";); + TRACE("array", tout << v << " " << mk_pp(s->get_owner(), get_manager()) << " " << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n";); m_trail_stack.push(push_back_trail(d->m_parent_selects)); for (enode* n : d->m_stores) { instantiate_axiom2a(s, n); diff --git a/src/smt/theory_array.h b/src/smt/theory_array.h index 187978012..33a0a5735 100644 --- a/src/smt/theory_array.h +++ b/src/smt/theory_array.h @@ -110,6 +110,8 @@ namespace smt { virtual void merge_eh(theory_var v1, theory_var v2, theory_var, theory_var); static void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {} void unmerge_eh(theory_var v1, theory_var v2); + + ptr_vector const& parent_selects(enode* n) { return m_var_data[find(n->get_root()->get_th_var(get_id()))]->m_parent_selects; } }; }; diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 2a583f16e..56806d6c4 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -140,8 +140,8 @@ namespace smt { set_prop_upward(n->get_arg(0)->get_th_var(get_id())); } else if (is_map(n)) { - for (unsigned i = 0; i < n->get_num_args(); ++i) { - set_prop_upward(n->get_arg(i)->get_th_var(get_id())); + for (enode* arg : enode::args(n)) { + set_prop_upward(arg->get_th_var(get_id())); } } } @@ -481,12 +481,12 @@ namespace smt { tout << mk_bounded_pp(sl->get_owner(), get_manager()) << "\n";); unsigned num_args = select->get_num_args(); unsigned num_arrays = map->get_num_args(); - ptr_buffer args1, args2; + ptr_buffer args1, args2; vector > args2l; args1.push_back(map); - for (unsigned j = 0; j < num_arrays; ++j) { + for (expr* ar : *map) { ptr_vector arg; - arg.push_back(map->get_arg(j)); + arg.push_back(ar); args2l.push_back(arg); } for (unsigned i = 1; i < num_args; ++i) { @@ -537,8 +537,8 @@ namespace smt { func_decl* f = to_func_decl(map->get_decl()->get_parameter(0).get_ast()); SASSERT(map->get_num_args() == f->get_arity()); ptr_buffer args2; - for (unsigned i = 0; i < map->get_num_args(); ++i) { - args2.push_back(mk_default(map->get_arg(i))); + for (expr* arg : *map) { + args2.push_back(mk_default(arg)); } expr_ref def2(m.mk_app(f, args2.size(), args2.c_ptr()), m); diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 3b26ab059..959ce6f14 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast/ast_smt2_pp.h" #include "smt/smt_context.h" #include "smt/theory_datatype.h" +#include "smt/theory_array.h" #include "smt/smt_model_generator.h" namespace smt { @@ -332,6 +333,13 @@ namespace smt { for (unsigned i = 0; i < num_args; i++) { enode * arg = e->get_arg(i); sort * s = get_manager().get_sort(arg->get_owner()); + if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) { + app_ref def(m_autil.mk_default(arg->get_owner()), get_manager()); + if (!ctx.e_internalized(def)) { + ctx.internalize(def, false); + } + arg = ctx.get_enode(def); + } if (!m_util.is_datatype(s)) continue; if (is_attached_to_var(arg)) @@ -371,15 +379,18 @@ namespace smt { // (assert (> (len a) 1) // // If the theory variable is not created for 'a', then a wrong model will be generated. - TRACE("datatype", tout << "apply_sort_cnstr: #" << n->get_owner_id() << "\n";); - TRACE("datatype_bug", - tout << "apply_sort_cnstr:\n" << mk_pp(n->get_owner(), get_manager()) << " "; - tout << m_util.is_datatype(s) << " "; - if (m_util.is_datatype(s)) tout << "is-infinite: " << s->is_infinite() << " "; - if (m_util.is_datatype(s)) tout << "attached: " << is_attached_to_var(n) << " "; - tout << "\n"; - ); - if ((get_context().has_quantifiers() || (m_util.is_datatype(s) && !s->is_infinite())) && !is_attached_to_var(n)) { + TRACE("datatype", tout << "apply_sort_cnstr: #" << n->get_owner_id() << " " << mk_pp(n->get_owner(), get_manager()) << "\n";); + TRACE("datatype_bug", + tout << "apply_sort_cnstr:\n" << mk_pp(n->get_owner(), get_manager()) << " "; + tout << m_util.is_datatype(s) << " "; + if (m_util.is_datatype(s)) tout << "is-infinite: " << s->is_infinite() << " "; + if (m_util.is_datatype(s)) tout << "attached: " << is_attached_to_var(n) << " "; + tout << "\n";); + + if (!is_attached_to_var(n) && + (get_context().has_quantifiers() || + (m_util.is_datatype(s) && m_util.has_nested_arrays()) || + (m_util.is_datatype(s) && !s->is_infinite()))) { mk_var(n); } } @@ -500,6 +511,7 @@ namespace smt { // collect equalities on all children that may have been used. bool found = false; + ast_manager& m = get_manager(); for (enode * arg : enode::args(parentc)) { // found an argument which is equal to root if (arg->get_root() == child->get_root()) { @@ -508,6 +520,17 @@ namespace smt { } found = true; } + sort * s = m.get_sort(arg->get_owner()); + if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) { + for (enode* aarg : get_array_args(arg)) { + if (aarg->get_root() == child->get_root()) { + if (aarg != child) { + m_used_eqs.push_back(enode_pair(aarg, child)); + } + found = true; + } + } + } } VERIFY(found); } @@ -542,6 +565,7 @@ namespace smt { // start exploring subgraph below `app` bool theory_datatype::occurs_check_enter(enode * app) { + context& ctx = get_context(); app = app->get_root(); theory_var v = app->get_th_var(get_id()); if (v == null_theory_var) { @@ -563,15 +587,44 @@ namespace smt { occurs_check_explain(parent, arg); return true; } - // explore `arg` (with paren) - if (m_util.is_datatype(get_manager().get_sort(arg->get_owner()))) { + // explore `arg` (with parent) + expr* earg = arg->get_owner(); + sort* s = get_manager().get_sort(earg); + if (m_util.is_datatype(s)) { m_parent.insert(arg->get_root(), parent); oc_push_stack(arg); } + else if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) { + for (enode* aarg : get_array_args(arg)) { + if (oc_cycle_free(aarg)) { + continue; + } + if (oc_on_stack(aarg)) { + occurs_check_explain(parent, aarg); + return true; + } + if (m_util.is_datatype(get_manager().get_sort(aarg->get_owner()))) { + m_parent.insert(aarg->get_root(), parent); + oc_push_stack(aarg); + } + } + } } return false; } + ptr_vector const& theory_datatype::get_array_args(enode* n) { + m_array_args.reset(); + context& ctx = get_context(); + theory_array* th = dynamic_cast(ctx.get_theory(m_autil.get_family_id())); + for (enode* p : th->parent_selects(n)) { + m_array_args.push_back(p); + } + app_ref def(m_autil.mk_default(n->get_owner()), get_manager()); + m_array_args.push_back(ctx.get_enode(def)); + return m_array_args; + } + /** \brief Check if n can be reached starting from n and following equalities and constructors. For example, occur_check(a1) returns true in the following set of equalities: @@ -637,6 +690,7 @@ namespace smt { theory(m.mk_family_id("datatype")), m_params(p), m_util(m), + m_autil(m), m_find(*this), m_trail_stack(*this) { } @@ -673,7 +727,7 @@ namespace smt { } bool theory_datatype::include_func_interp(func_decl* f) { - return false; // return m_util.is_accessor(f); + return false; } void theory_datatype::init_model(model_generator & m) { @@ -706,8 +760,15 @@ namespace smt { func_decl * c_decl = d->m_constructor->get_decl(); datatype_value_proc * result = alloc(datatype_value_proc, c_decl); unsigned num = d->m_constructor->get_num_args(); - for (unsigned i = 0; i < num; i++) - result->add_dependency(d->m_constructor->get_arg(i)); + for (enode* arg : enode::args(d->m_constructor)) { + result->add_dependency(arg); + } + TRACE("datatype", + tout << mk_pp(n->get_owner(), get_manager()) << "\n"; + tout << "depends on\n"; + for (enode* arg : enode::args(d->m_constructor)) { + tout << " " << mk_pp(arg->get_owner(), get_manager()) << "\n"; + }); return result; } @@ -882,7 +943,7 @@ namespace smt { TRACE("datatype_bug", tout << "non_rec_c: " << non_rec_c->get_name() << "\n";); unsigned non_rec_idx = m_util.get_constructor_idx(non_rec_c); var_data * d = m_var_data[v]; - SASSERT(d->m_constructor == 0); + SASSERT(d->m_constructor == nullptr); func_decl * r = nullptr; m_stats.m_splits++; diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 67cf5cfee..e5b9b9909 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -19,10 +19,11 @@ Revision History: #ifndef THEORY_DATATYPE_H_ #define THEORY_DATATYPE_H_ -#include "smt/smt_theory.h" #include "util/union_find.h" -#include "smt/params/theory_datatype_params.h" +#include "ast/array_decl_plugin.h" #include "ast/datatype_decl_plugin.h" +#include "smt/smt_theory.h" +#include "smt/params/theory_datatype_params.h" #include "smt/proto_model/datatype_factory.h" namespace smt { @@ -48,6 +49,7 @@ namespace smt { theory_datatype_params & m_params; datatype_util m_util; + array_util m_autil; ptr_vector m_var_data; th_union_find m_find; th_trail_stack m_trail_stack; @@ -89,6 +91,8 @@ namespace smt { bool oc_cycle_free(enode * n) const { return n->get_root()->is_marked2(); } void oc_push_stack(enode * n); + ptr_vector m_array_args; + ptr_vector const& get_array_args(enode* n); // class for managing state of final_check class final_check_st { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index a283fa99c..6fc9d9497 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -939,6 +939,29 @@ public: m_asserted_atoms.push_back(delayed_atom(v, is_true)); } + lbool get_phase(bool_var v) { + lp_api::bound* b; + if (!m_bool_var2bound.find(v, b)) { + return l_undef; + } + scoped_internalize_state st(*this); + st.vars().push_back(b->get_var()); + st.coeffs().push_back(rational::one()); + init_left_side(st); + lp::lconstraint_kind k = lp::EQ; + switch (b->get_bound_kind()) { + case lp_api::lower_t: + k = lp::GE; + break; + case lp_api::upper_t: + k = lp::LE; + break; + } + auto vi = get_var_index(b->get_var()); + rational bound = b->get_value(); + return m_solver->compare_values(vi, k, bound) ? l_true : l_false; + } + void new_eq_eh(theory_var v1, theory_var v2) { // or internalize_eq(v1, v2); m_arith_eq_adapter.new_eq_eh(v1, v2); @@ -3565,6 +3588,9 @@ void theory_lra::internalize_eq_eh(app * atom, bool_var v) { void theory_lra::assign_eh(bool_var v, bool is_true) { m_imp->assign_eh(v, is_true); } +lbool theory_lra::get_phase(bool_var v) { + return m_imp->get_phase(v); +} void theory_lra::new_eq_eh(theory_var v1, theory_var v2) { m_imp->new_eq_eh(v1, v2); } diff --git a/src/smt/theory_lra.h b/src/smt/theory_lra.h index 23adaa557..584591248 100644 --- a/src/smt/theory_lra.h +++ b/src/smt/theory_lra.h @@ -43,6 +43,8 @@ namespace smt { void assign_eh(bool_var v, bool is_true) override; + lbool get_phase(bool_var v) override; + void new_eq_eh(theory_var v1, theory_var v2) override; bool use_diseqs() const override; diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index f4fe52a19..c71f7a9ae 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1777,6 +1777,32 @@ constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, c return ci; } +bool lar_solver::compare_values(var_index j, lconstraint_kind k, const mpq & rhs) { + if (is_term(j)) { // j is a term + impq lhs = 0; + for (auto const& cv : get_term(j)) { + lhs += cv.coeff() * get_column_value(cv.var()); + } + return compare_values(lhs, k, rhs); + } + else { + return compare_values(get_column_value(j), k, rhs); + } +} + +bool lar_solver::compare_values(impq const& lhs, lconstraint_kind k, const mpq & rhs) { + switch (k) { + case LT: return lhs < rhs; + case LE: return lhs <= rhs; + case GT: return lhs > rhs; + case GE: return lhs >= rhs; + case EQ: return lhs == rhs; + default: + UNREACHABLE(); + return true; + } +} + void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { switch (m_mpq_lar_core_solver.m_column_types[j]) { case column_type::free_column: diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 2b506abd0..f3aab29b2 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -178,6 +178,10 @@ public: constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) ; + bool compare_values(var_index j, lconstraint_kind kind, const mpq & right_side); + + bool compare_values(impq const& lhs, lconstraint_kind k, const mpq & rhs); + void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index); void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci);