3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 10:25:18 +00:00

fix #2468, adding assignment phase heuristic

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2019-08-10 15:24:42 -07:00
parent 42e21458ba
commit 9fa9aa09ff
19 changed files with 268 additions and 79 deletions

View file

@ -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, &param, 1, &v);
@ -251,6 +255,14 @@ public:
parameter param(f);
return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, &param, 0, nullptr, nullptr);
}
sort* get_array_range_rec(sort* s) {
while (is_array(s)) {
s = get_array_range(s);
}
return s;
}
};

View file

@ -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<func_decl> 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";);

View file

@ -210,13 +210,14 @@ namespace datatype {
unsigned m_id_counter;
svector<symbol> 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<app> & 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);

View file

@ -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 {

View file

@ -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'),

View file

@ -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;
}

View file

@ -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:

View file

@ -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<model_value_proc> procs;
svector<source> sources;
buffer<model_value_dependency> 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);
}
}

View file

@ -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<extra_fresh_value> 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<enode, app *> 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);
}
}
};

View file

@ -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
*/

View file

@ -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<theory_array, enode *, false>(d->m_parent_selects));
for (enode* n : d->m_stores) {
instantiate_axiom2a(s, n);

View file

@ -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<enode> const& parent_selects(enode* n) { return m_var_data[find(n->get_root()->get_th_var(get_id()))]->m_parent_selects; }
};
};

View file

@ -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<expr> args1, args2;
ptr_buffer<expr> args1, args2;
vector<ptr_vector<expr> > args2l;
args1.push_back(map);
for (unsigned j = 0; j < num_arrays; ++j) {
for (expr* ar : *map) {
ptr_vector<expr> 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<expr> 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);

View file

@ -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<enode> const& theory_datatype::get_array_args(enode* n) {
m_array_args.reset();
context& ctx = get_context();
theory_array* th = dynamic_cast<theory_array*>(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++;

View file

@ -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<var_data> 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<enode> m_array_args;
ptr_vector<enode> const& get_array_args(enode* n);
// class for managing state of final_check
class final_check_st {

View file

@ -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);
}

View file

@ -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;

View file

@ -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:

View file

@ -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);