3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-12-08 21:03:23 +00:00

remove set cardinality operators from array theory. Make final-check use priority levels

Issue #7502 shows that running nlsat eagerly during final check can block quantifier instantiation.
To give space for quantifier instances we introduce two levels for final check such that nlsat is only applied in the second and final level.
This commit is contained in:
Nikolaj Bjorner 2025-11-26 15:35:19 -08:00
parent 28dc71c75e
commit 62b3668beb
59 changed files with 94 additions and 843 deletions

View file

@ -35,9 +35,7 @@ array_decl_plugin::array_decl_plugin():
m_set_complement_sym("complement"),
m_set_subset_sym("subset"),
m_array_ext_sym("array-ext"),
m_as_array_sym("as-array"),
m_set_has_size_sym("set-has-size"),
m_set_card_sym("card") {
m_as_array_sym("as-array") {
}
#define ARRAY_SORT_STR "Array"
@ -442,40 +440,6 @@ func_decl * array_decl_plugin::mk_set_subset(unsigned arity, sort * const * doma
func_decl_info(m_family_id, OP_SET_SUBSET));
}
func_decl * array_decl_plugin::mk_set_card(unsigned arity, sort * const* domain) {
if (arity != 1) {
m_manager->raise_exception("card takes only one argument");
return nullptr;
}
arith_util arith(*m_manager);
if (!is_array_sort(domain[0]) || !m_manager->is_bool(get_array_range(domain[0]))) {
m_manager->raise_exception("card expects an array of Booleans");
}
sort * int_sort = arith.mk_int();
return m_manager->mk_func_decl(m_set_card_sym, arity, domain, int_sort,
func_decl_info(m_family_id, OP_SET_CARD));
}
func_decl * array_decl_plugin::mk_set_has_size(unsigned arity, sort * const* domain) {
if (arity != 2) {
m_manager->raise_exception("set-has-size takes two arguments");
return nullptr;
}
m_manager->raise_exception("set-has-size is not supported");
// domain[0] is a Boolean array,
// domain[1] is Int
arith_util arith(*m_manager);
if (!arith.is_int(domain[1])) {
m_manager->raise_exception("set-has-size expects second argument to be an integer");
}
if (!is_array_sort(domain[0]) || !m_manager->is_bool(get_array_range(domain[0]))) {
m_manager->raise_exception("set-has-size expects first argument to be an array of Booleans");
}
sort * bool_sort = m_manager->mk_bool_sort();
return m_manager->mk_func_decl(m_set_has_size_sym, arity, domain, bool_sort,
func_decl_info(m_family_id, OP_SET_HAS_SIZE));
}
func_decl * array_decl_plugin::mk_as_array(func_decl * f) {
vector<parameter> parameters;
@ -541,10 +505,6 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
return mk_set_complement(arity, domain);
case OP_SET_SUBSET:
return mk_set_subset(arity, domain);
case OP_SET_HAS_SIZE:
return mk_set_has_size(arity, domain);
case OP_SET_CARD:
return mk_set_card(arity, domain);
case OP_AS_ARRAY: {
if (num_parameters != 1 ||
!parameters[0].is_ast() ||

View file

@ -62,8 +62,6 @@ enum array_op_kind {
OP_SET_DIFFERENCE,
OP_SET_COMPLEMENT,
OP_SET_SUBSET,
OP_SET_HAS_SIZE,
OP_SET_CARD,
OP_AS_ARRAY, // used for model construction
LAST_ARRAY_OP
};
@ -81,8 +79,6 @@ class array_decl_plugin : public decl_plugin {
symbol m_set_subset_sym;
symbol m_array_ext_sym;
symbol m_as_array_sym;
symbol m_set_has_size_sym;
symbol m_set_card_sym;
bool check_set_arguments(unsigned arity, sort * const * domain);
@ -110,10 +106,6 @@ class array_decl_plugin : public decl_plugin {
func_decl * mk_as_array(func_decl * f);
func_decl* mk_set_has_size(unsigned arity, sort * const* domain);
func_decl* mk_set_card(unsigned arity, sort * const* domain);
bool is_array_sort(sort* s) const;
public:
array_decl_plugin();
@ -173,8 +165,6 @@ public:
bool is_complement(expr* n) const { return is_app_of(n, m_fid, OP_SET_COMPLEMENT); }
bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); }
bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); }
bool is_set_has_size(expr* e) const { return is_app_of(e, m_fid, OP_SET_HAS_SIZE); }
bool is_set_card(expr* e) const { return is_app_of(e, m_fid, OP_SET_CARD); }
bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); }
bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); }
bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
@ -182,8 +172,6 @@ public:
bool is_union(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_UNION); }
bool is_intersect(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_INTERSECT); }
bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); }
bool is_set_has_size(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_HAS_SIZE); }
bool is_set_card(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_CARD); }
bool is_default(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_DEFAULT); }
bool is_default(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_DEFAULT); }
bool is_subset(expr const* n) const { return is_app_of(n, m_fid, OP_SET_SUBSET); }
@ -307,14 +295,6 @@ public:
return m_manager.mk_app(m_fid, OP_SET_UNION, s1, s2);
}
app* mk_has_size(expr* set, expr* n) {
return m_manager.mk_app(m_fid, OP_SET_HAS_SIZE, set, n);
}
app* mk_card(expr* set) {
return m_manager.mk_app(m_fid, OP_SET_CARD, set);
}
func_decl * mk_array_ext(sort* domain, unsigned i);
sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); }

View file

@ -1282,7 +1282,7 @@ void core::add_bounds() {
}
}
lbool core::check() {
lbool core::check(unsigned level) {
lp_settings().stats().m_nla_calls++;
TRACE(nla_solver, tout << "calls = " << lp_settings().stats().m_nla_calls << "\n";);
lra.get_rid_of_inf_eps();
@ -1363,7 +1363,7 @@ lbool core::check() {
ret = bounded_nlsat();
}
if (no_effect() && params().arith_nl_nra()) {
if (no_effect() && params().arith_nl_nra() && level >= 2) {
scoped_limits sl(m_reslim);
sl.push_child(&m_nra_lim);
params_ref p;
@ -1432,7 +1432,7 @@ bool core::no_lemmas_hold() const {
lbool core::test_check() {
lra.set_status(lp::lp_status::OPTIMAL);
return check();
return check(2);
}
std::unordered_set<lpvar> core::get_vars_of_expr_with_opening_terms(const nex *e ) {

View file

@ -394,7 +394,7 @@ public:
bool conflict_found() const;
lbool check();
lbool check(unsigned level);
lbool check_power(lpvar r, lpvar x, lpvar y);
void check_bounded_divisions();

View file

@ -46,8 +46,8 @@ namespace nla {
bool solver::need_check() { return m_core->has_relevant_monomial(); }
lbool solver::check() {
return m_core->check();
lbool solver::check(unsigned level) {
return m_core->check(level);
}
void solver::propagate() {

View file

@ -37,7 +37,7 @@ namespace nla {
void push();
void pop(unsigned scopes);
bool need_check();
lbool check();
lbool check(unsigned level);
void propagate();
void simplify() { m_core->simplify(); }
lbool check_power(lpvar r, lpvar x, lpvar y);

View file

@ -1000,6 +1000,7 @@ namespace arith {
}
sat::check_result solver::check() {
unsigned level = 2;
force_push();
m_model_is_initialized = false;
IF_VERBOSE(12, verbose_stream() << "final-check " << lp().get_status() << "\n");
@ -1042,7 +1043,7 @@ namespace arith {
if (!check_delayed_eqs())
return sat::check_result::CR_CONTINUE;
switch (check_nla()) {
switch (check_nla(level)) {
case l_true:
m_use_nra_model = true;
break;
@ -1498,7 +1499,7 @@ namespace arith {
}
lbool solver::check_nla() {
lbool solver::check_nla(unsigned level) {
if (!m.inc()) {
TRACE(arith, tout << "canceled\n";);
return l_undef;
@ -1509,7 +1510,7 @@ namespace arith {
if (!m_nla->need_check())
return l_true;
lbool r = m_nla->check();
lbool r = m_nla->check(level);
switch (r) {
case l_false:
add_lemmas();

View file

@ -407,7 +407,7 @@ namespace arith {
lbool make_feasible();
bool check_delayed_eqs();
lbool check_lia();
lbool check_nla();
lbool check_nla(unsigned level);
bool check_bv_terms();
bool check_bv_term(app* n);
void add_lemmas();

View file

@ -137,10 +137,6 @@ namespace array {
add_equiv(eq, sub);
break;
}
case OP_SET_HAS_SIZE:
case OP_SET_CARD:
ctx.unhandled_function(n->get_decl());
break;
default:
UNREACHABLE();
break;
@ -184,10 +180,6 @@ namespace array {
break;
case OP_SET_SUBSET:
break;
case OP_SET_HAS_SIZE:
case OP_SET_CARD:
ctx.unhandled_function(n->get_decl());
break;
default:
UNREACHABLE();
break;

View file

@ -644,6 +644,8 @@ namespace euf {
return m_egraph.find(m.mk_false());
}
// NB. revisit this for interleaving qsolver with theory solvers based on priorities of
// activities such as calling nlsat as a final check.
sat::check_result solver::check() {
++m_stats.m_final_checks;
TRACE(euf, s().display(tout););

View file

@ -49,7 +49,6 @@ z3_add_component(smt
smt_value_sort.cpp
smt2_extra_cmds.cpp
theory_arith.cpp
theory_array_bapa.cpp
theory_array_base.cpp
theory_array.cpp
theory_array_full.cpp

View file

@ -157,10 +157,10 @@ namespace smt {
return expr_ref(e, m);
}
final_check_status arith_value::final_check() {
final_check_status arith_value::final_check(unsigned level) {
family_id afid = a.get_family_id();
theory * th = m_ctx->get_theory(afid);
return th->final_check_eh();
return th->final_check_eh(level);
}
};

View file

@ -47,6 +47,6 @@ namespace smt {
expr_ref get_lo(expr* e) const;
expr_ref get_up(expr* e) const;
expr_ref get_fixed(expr* e) const;
final_check_status final_check();
final_check_status final_check(unsigned );
};
};

View file

@ -4122,16 +4122,18 @@ namespace smt {
unsigned old_idx = m_final_check_idx;
unsigned num_th = m_theory_set.size();
unsigned range = num_th + 1;
unsigned level = 1, max_level = 1;
final_check_status result = FC_DONE;
failure f = OK;
do {
while (true) {
TRACE(final_check_step, tout << "processing: " << m_final_check_idx << ", result: " << result << "\n";);
final_check_status ok;
if (m_final_check_idx < num_th) {
theory * th = m_theory_set[m_final_check_idx];
IF_VERBOSE(100, verbose_stream() << "(smt.final-check \"" << th->get_name() << "\")\n";);
ok = th->final_check_eh();
ok = th->final_check_eh(level);
max_level = std::max(max_level, th->num_final_check_levels());
TRACE(final_check_step, tout << "final check '" << th->get_name() << " ok: " << ok << " inconsistent " << inconsistent() << "\n";);
if (get_cancel_flag()) {
f = CANCELED;
@ -4160,8 +4162,12 @@ namespace smt {
return FC_CONTINUE;
break;
}
if (m_final_check_idx == old_idx) {
if (level >= max_level)
break;
++level;
}
}
while (m_final_check_idx != old_idx);
TRACE(final_check_step, tout << "result: " << result << "\n";);

View file

@ -315,10 +315,21 @@ namespace smt {
a truth value to all boolean variables and no inconsistency was
detected.
*/
virtual final_check_status final_check_eh() {
virtual final_check_status final_check_eh(unsigned level) {
return FC_DONE;
}
/**
* \brief This method signals the number of priority levels a theory supports for final checks.
* The first level are for the cheapest final check invocations.
* The levels after that are for more expensive final checks.
* This approach emulates a priority queue of actions taken at final check where the expensive
* checks are deferred.
*/
virtual unsigned num_final_check_levels() const {
return 1;
}
/**
\brief Parametric theories (e.g. Arrays) should implement this method.
See example in context::is_shared

View file

@ -679,7 +679,7 @@ namespace smt {
*/
bool m_liberal_final_check = true;
final_check_status final_check_core();
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
bool can_propagate() override;
void propagate() override;

View file

@ -1535,7 +1535,7 @@ namespace smt {
}
template<typename Ext>
final_check_status theory_arith<Ext>::final_check_eh() {
final_check_status theory_arith<Ext>::final_check_eh(unsigned level) {
TRACE(arith_eq_adapter_info, m_arith_eq_adapter.display_already_processed(tout););
TRACE(arith, display(tout););

View file

@ -359,7 +359,7 @@ namespace smt {
SASSERT(m_find.get_num_vars() == get_num_vars());
}
final_check_status theory_array::final_check_eh() {
final_check_status theory_array::final_check_eh(unsigned) {
m_final_check_idx++;
final_check_status r = FC_DONE;
if (m_params.m_array_lazy_ieq) {

View file

@ -62,7 +62,7 @@ namespace smt {
void relevant_eh(app * n) override;
void push_scope_eh() override;
void pop_scope_eh(unsigned num_scopes) override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void reset_eh() override;
void init_search_eh() override;

View file

@ -1,644 +0,0 @@
/*++
Copyright (c) 2019 Microsoft Corporation
Module Name:
theory_array_bapa.cpp
Abstract:
Saturation procedure for BAPA predicates.
Assume there is a predicate
Size(S, n) for S : Array(T, Bool) and n : Int
The predicate is true if S is a set of size n.
Size(S, n), Size(T, m)
S, T are intersecting. n != m or S != T
D ---------------------------------------------------------
Size(S, n) => Size(S\T, k1), Size(S n T, k2), n = k1 + k2
Size(T, m) => Size(T\S, k3), SIze(S n T, k2), m = k2 + k3
Size(S, n)
P --------------------
Size(S, n) => n >= 0
Size(S, n), is infinite domain
B ------------------------------
Size(S, n) => default(S) = false
Size(S, n), Size(S, m)
F --------------------------------
Size(S, n), Size(S, m) => n = m
Fixing values during final check:
Size(S, n)
V -------------------
assume value(n) = n
Size(S, n), S[i1], ..., S[ik]
O -------------------------------
~distinct(i1, ... ik) or n >= k
Size(S,n)
Ak --------------------------------------------------
S[i1] & .. & S[ik] & distinct(i1, .., ik) or n < k
Q: Is this sufficient? Axiom A1 could be adjusted to add new elements i' until there are k witnesses for Size(S, k).
This is quite bad when k is very large. Instead rely on stably infiniteness or other domain properties of the theories.
When A is finite domain, or there are quantifiers there could be constraints that force domain sizes so domain sizes may have
to be enforced. A succinct way would be through domain comprehension assertions.
Finite domains:
Size(S, n), is finite domain
----------------------------
S <= |A|
Size(S, n), !S[i1], .... !S[ik], S is finite domain
----------------------------------------------------------
default(S) = false or ~distinct(i1,..,ik) or |A| - k <= n
~Size(S, m) is negative on all occurrences, S is finite domain
---------------------------------------------------------------
Size(S, n) n fresh.
Model construction for infinite domains when all Size(S, m) are negative for S.
Author:
Nikolaj Bjorner 2019-04-13
Revision History:
*/
#include "ast/ast_util.h"
#include "ast/ast_pp.h"
#include "ast/rewriter/array_rewriter.h"
#include "smt/smt_context.h"
#include "smt/smt_arith_value.h"
#include "smt/theory_array_full.h"
#include "smt/theory_array_bapa.h"
#if 0
- set of native select terms that are true
- set of auxiliary select terms.
- n1, n2, n3, n4.
- a1, a2, a3, a4, a5.
-
- add select terms, such that first
#endif
namespace smt {
class theory_array_bapa::imp {
struct sz_info {
bool m_is_leaf = true; // has it been split into disjoint subsets already?
rational m_size = rational::minus_one(); // set to >= integer if fixed in final check, otherwise -1
obj_map<enode, expr*> m_selects;
};
typedef std::pair<func_decl*, func_decl*> func_decls;
ast_manager& m;
theory_array_full& th;
arith_util m_arith;
array_util m_autil;
th_rewriter m_rw;
arith_value m_arith_value;
ast_ref_vector m_pinned;
obj_map<app, sz_info*> m_sizeof;
obj_map<expr, rational> m_size_limit;
obj_map<sort, func_decls> m_index_skolems;
obj_map<sort, func_decl*> m_size_limit_sort2skolems;
unsigned m_max_set_enumeration;
context& ctx() { return th.get_context(); }
void reset() {
for (auto& kv : m_sizeof) {
dealloc(kv.m_value);
}
}
bool is_true(expr* e) { return is_true(ctx().get_literal(e)); }
bool is_true(enode* e) { return is_true(e->get_expr()); }
bool is_true(literal l) { return ctx().is_relevant(l) && ctx().get_assignment(l) == l_true; }
bool is_leaf(sz_info& i) const { return i.m_is_leaf; }
bool is_leaf(sz_info* i) const { return is_leaf(*i); }
enode* get_root(expr* e) { return ctx().get_enode(e)->get_root(); }
bool is_select(enode* n) { return th.is_select(n); }
app_ref mk_select(expr* a, expr* i) { expr* args[2] = { a, i }; return app_ref(m_autil.mk_select(2, args), m); }
literal get_literal(expr* e) { return ctx().get_literal(e); }
literal mk_literal(expr* e) { expr_ref _e(e, m); if (!ctx().e_internalized(e)) ctx().internalize(e, false); literal lit = get_literal(e); ctx().mark_as_relevant(lit); return lit; }
literal mk_eq(expr* a, expr* b) {
expr_ref _a(a, m), _b(b, m);
literal lit = th.mk_eq(a, b, false);
ctx().mark_as_relevant(lit);
return lit;
}
void mk_th_axiom(literal l1, literal l2) {
literal lits[2] = { l1, l2 };
mk_th_axiom(2, lits);
}
void mk_th_axiom(literal l1, literal l2, literal l3) {
literal lits[3] = { l1, l2, l3 };
mk_th_axiom(3, lits);
}
void mk_th_axiom(unsigned n, literal* lits) {
TRACE(card, ctx().display_literals_verbose(tout, n, lits) << "\n";);
IF_VERBOSE(10, ctx().display_literals_verbose(verbose_stream(), n, lits) << "\n");
ctx().mk_th_axiom(th.get_id(), n, lits);
}
void update_indices() {
for (auto const& kv : m_sizeof) {
app* k = kv.m_key;
sz_info& v = *kv.m_value;
v.m_selects.reset();
if (is_true(k) && is_leaf(v)) {
enode* set = get_root(k->get_arg(0));
for (enode* parent : enode::parents(set)) {
if (is_select(parent) && parent->get_arg(0)->get_root() == set) {
if (is_true(parent)) {
v.m_selects.insert(parent->get_arg(1)->get_root(), parent->get_expr());
}
}
}
}
}
}
/**
F: Size(S, k1) & Size(S, k2) => k1 = k2
*/
lbool ensure_functional() {
lbool result = l_true;
obj_map<enode, app*> parents;
for (auto const& kv : m_sizeof) {
app* sz1 = kv.m_key;
if (!is_true(sz1)) {
continue;
}
enode* r = get_root(sz1->get_arg(0));
app* sz2 = nullptr;
if (parents.find(r, sz2)) {
expr* k1 = sz1->get_arg(1);
expr* k2 = sz2->get_arg(1);
if (get_root(k1) != get_root(k2)) {
mk_th_axiom(~get_literal(sz1), ~get_literal(sz2), mk_eq(k1, k2));
result = l_false;
}
}
else {
parents.insert(r, sz1);
}
}
return result;
}
/**
Enforce D
*/
lbool ensure_disjoint() {
auto i = m_sizeof.begin(), end = m_sizeof.end();
for (; i != end; ++i) {
auto& kv = *i;
if (!kv.m_value->m_is_leaf) {
continue;
}
for (auto j = i; ++j != end; ) {
if (j->m_value->m_is_leaf && !ensure_disjoint(i->m_key, j->m_key)) {
return l_false;
}
}
}
return l_true;
}
bool ensure_disjoint(app* sz1, app* sz2) {
sz_info& i1 = *m_sizeof[sz1];
sz_info& i2 = *m_sizeof[sz2];
SASSERT(i1.m_is_leaf);
SASSERT(i2.m_is_leaf);
expr* s = sz1->get_arg(0);
expr* t = sz2->get_arg(0);
if (s->get_sort() != t->get_sort()) {
return true;
}
enode* r1 = get_root(s);
enode* r2 = get_root(t);
if (r1 == r2) {
return true;
}
if (!ctx().is_diseq(r1, r2) && ctx().assume_eq(r1, r2)) {
return false;
}
if (do_intersect(i1.m_selects, i2.m_selects)) {
add_disjoint(sz1, sz2);
return false;
}
return true;
}
bool do_intersect(obj_map<enode, expr*> const& s, obj_map<enode, expr*> const& t) const {
if (s.size() > t.size()) {
return do_intersect(t, s);
}
for (auto const& idx : s)
if (t.contains(idx.m_key))
return true;
return false;
}
void add_disjoint(app* sz1, app* sz2) {
sz_info& i1 = *m_sizeof[sz1];
sz_info& i2 = *m_sizeof[sz2];
SASSERT(i1.m_is_leaf);
SASSERT(i2.m_is_leaf);
expr* t = sz1->get_arg(0);
expr* s = sz2->get_arg(0);
expr_ref tms = mk_subtract(t, s);
expr_ref smt = mk_subtract(s, t);
expr_ref tns = mk_intersect(t, s);
#if 0
std::cout << tms << "\n";
std::cout << smt << "\n";
std::cout << tns << "\n";
#endif
#if 0
if (tns == sz1) {
std::cout << "SEEN " << tms << "\n";
}
if (tns == sz2) {
std::cout << "SEEN " << smt << "\n";
}
#endif
ctx().push_trail(value_trail<bool>(i1.m_is_leaf, false));
ctx().push_trail(value_trail<bool>(i2.m_is_leaf, false));
expr_ref k1(m), k2(m), k3(m);
expr_ref sz_tms(m), sz_tns(m), sz_smt(m);
k1 = m_autil.mk_card(tms);
k2 = m_autil.mk_card(tns);
k3 = m_autil.mk_card(smt);
sz_tms = m_autil.mk_has_size(tms, k1);
sz_tns = m_autil.mk_has_size(tns, k2);
sz_smt = m_autil.mk_has_size(smt, k3);
propagate(sz1, sz_tms);
propagate(sz1, sz_tns);
propagate(sz2, sz_smt);
propagate(sz2, sz_tns);
propagate(sz1, mk_eq(k1 + k2, sz1->get_arg(1)));
propagate(sz2, mk_eq(k3 + k2, sz2->get_arg(1)));
}
expr_ref mk_subtract(expr* t, expr* s) {
expr_ref d(m_autil.mk_setminus(t, s), m);
m_rw(d);
return d;
}
expr_ref mk_intersect(expr* t, expr* s) {
expr_ref i(m_autil.mk_intersection(t, s), m);
m_rw(i);
return i;
}
void propagate(expr* assumption, expr* conseq) {
propagate(assumption, mk_literal(conseq));
}
void propagate(expr* assumption, literal conseq) {
mk_th_axiom(~mk_literal(assumption), conseq);
}
/**
Enforce V
*/
lbool ensure_values_assigned() {
lbool result = l_true;
for (auto const& kv : m_sizeof) {
app* k = kv.m_key;
sz_info& i = *kv.m_value;
if (is_leaf(&i)) {
rational value;
expr* sz = k->get_arg(1);
if (!m_arith_value.get_value(sz, value)) {
return l_undef;
}
literal lit = mk_eq(sz, m_arith.mk_int(value));
if (lit != true_literal && is_true(lit)) {
ctx().push_trail(value_trail<rational>(i.m_size, value));
continue;
}
ctx().set_true_first_flag(lit.var());
result = l_false;
}
}
return result;
}
/**
Enforce Ak,
*/
lbool ensure_non_empty() {
for (auto const& kv : m_sizeof) {
sz_info& i = *kv.m_value;
app* set_sz = kv.m_key;
if (is_true(set_sz) && is_leaf(i) && i.m_selects.size() < i.m_size) {
expr* set = set_sz->get_arg(0);
expr_ref le(m_arith.mk_le(set_sz->get_arg(1), m_arith.mk_int(0)), m);
literal le_lit = mk_literal(le);
literal sz_lit = mk_literal(set_sz);
for (unsigned k = i.m_selects.size(); rational(k) < i.m_size; ++k) {
expr_ref idx = mk_index_skolem(set_sz, set, k);
app_ref sel(mk_select(set, idx), m);
mk_th_axiom(~sz_lit, le_lit, mk_literal(sel));
TRACE(card, tout << idx << " " << sel << " " << i.m_size << "\n";);
}
return l_false;
}
}
return l_true;
}
// create skolem function that is injective on integers (ensures uniqueness).
expr_ref mk_index_skolem(app* sz, expr* a, unsigned n) {
func_decls fg;
sort* s = a->get_sort();
if (!m_index_skolems.find(s, fg)) {
sort* idx_sort = get_array_domain(s, 0);
sort* dom1[2] = { s, m_arith.mk_int() };
sort* dom2[1] = { idx_sort };
func_decl* f = m.mk_fresh_func_decl("to-index", "", 2, dom1, idx_sort);
func_decl* g = m.mk_fresh_func_decl("from-index", "", 1, dom2, m_arith.mk_int());
fg = std::make_pair(f, g);
m_index_skolems.insert(s, fg);
m_pinned.push_back(f);
m_pinned.push_back(g);
m_pinned.push_back(s);
}
expr_ref nV(m_arith.mk_int(n), m);
expr_ref result(m.mk_app(fg.first, a, nV), m);
expr_ref le(m_arith.mk_le(sz->get_arg(1), nV), m);
expr_ref fr(m.mk_app(fg.second, result), m);
// set-has-size(a, k) => k <= n or g(f(a,n)) = n
mk_th_axiom(~mk_literal(sz), mk_literal(le), mk_eq(nV, fr));
return result;
}
/**
Enforce O
*/
lbool ensure_no_overflow() {
for (auto const& kv : m_sizeof) {
if (is_true(kv.m_key) && is_leaf(kv.m_value)) {
lbool r = ensure_no_overflow(kv.m_key, *kv.m_value);
if (r != l_true) return r;
}
}
return l_true;
}
lbool ensure_no_overflow(app* sz, sz_info& info) {
SASSERT(!info.m_size.is_neg());
if (info.m_size < info.m_selects.size()) {
for (auto i = info.m_selects.begin(), e = info.m_selects.end(); i != e; ++i) {
for (auto j = i; ++j != e; ) {
if (ctx().assume_eq(i->m_key, j->m_key)) {
return l_false;
}
}
}
// if all is exhausted, then add axiom: set-has-size(s, n) & s[indices] & all-diff(indices) => n >= |indices|
literal_vector lits;
lits.push_back(~mk_literal(sz));
for (auto const& kv : info.m_selects) {
lits.push_back(~mk_literal(kv.m_value));
}
if (info.m_selects.size() > 1) {
ptr_vector<expr> args;
for (auto const& kv : info.m_selects) {
args.push_back(kv.m_key->get_expr());
}
if (info.m_selects.size() == 2) {
lits.push_back(mk_eq(args[0], args[1]));
}
else {
expr_ref diff(m.mk_distinct_expanded(args.size(), args.data()), m);
lits.push_back(~mk_literal(diff));
}
}
expr_ref ge(m_arith.mk_ge(sz->get_arg(1), m_arith.mk_int(info.m_selects.size())), m);
lits.push_back(mk_literal(ge));
mk_th_axiom(lits.size(), lits.data());
return l_false;
}
return l_true;
}
class remove_sz : public trail {
ast_manager& m;
obj_map<app, sz_info*> & m_table;
app* m_obj;
public:
remove_sz(ast_manager& m, obj_map<app, sz_info*>& tab, app* t): m(m), m_table(tab), m_obj(t) { }
void undo() override { m.dec_ref(m_obj); dealloc(m_table[m_obj]); m_table.remove(m_obj); }
};
std::ostream& display(std::ostream& out) {
for (auto const& kv : m_sizeof) {
display(out << mk_pp(kv.m_key, m) << ": ", *kv.m_value);
}
return out;
}
std::ostream& display(std::ostream& out, sz_info& sz) {
return out << (sz.m_is_leaf ? "leaf": "") << " size: " << sz.m_size << " selects: " << sz.m_selects.size() << "\n";
}
public:
imp(theory_array_full& th):
m(th.get_manager()),
th(th),
m_arith(m),
m_autil(m),
m_rw(m),
m_arith_value(m),
m_pinned(m)
{
context& ctx = th.get_context();
m_arith_value.init(&ctx);
m_max_set_enumeration = 4;
}
~imp() {
reset();
}
void internalize_term(app* term) {
if (th.is_set_has_size(term)) {
internalize_size(term);
}
else if (th.is_set_card(term)) {
internalize_card(term);
}
}
/**
* Size(S, n) => n >= 0, default(S) = false
*/
void internalize_size(app* term) {
SASSERT(ctx().e_internalized(term));
literal lit = mk_literal(term);
expr* s = term->get_arg(0);
expr* n = term->get_arg(1);
mk_th_axiom(~lit, mk_literal(m_arith.mk_ge(n, m_arith.mk_int(0))));
sort_size const& sz = s->get_sort()->get_num_elements();
if (sz.is_infinite()) {
mk_th_axiom(~lit, mk_eq(th.mk_default(s), m.mk_false()));
}
else {
warning_msg("correct handling of finite domains is TBD");
// add upper bound on size of set.
// add case where default(S) = true, and add negative elements.
}
m_sizeof.insert(term, alloc(sz_info));
m_size_limit.insert(s, rational(2));
assert_size_limit(s, n);
m.inc_ref(term);
ctx().push_trail(remove_sz(m, m_sizeof, term));
}
/**
\brief whenever there is a cardinality function, it includes an axiom
that entails the set is finite.
*/
void internalize_card(app* term) {
SASSERT(ctx().e_internalized(term));
app_ref has_size(m_autil.mk_has_size(term->get_arg(0), term), m);
literal lit = mk_literal(has_size);
ctx().assign(lit, nullptr);
}
lbool trace_call(char const* msg, lbool r) {
if (r != l_true) {
IF_VERBOSE(2, verbose_stream() << msg << "\n");
}
return r;
}
final_check_status final_check() {
final_check_status st = m_arith_value.final_check();
if (st != FC_DONE) return st;
lbool r = trace_call("ensure_functional", ensure_functional());
if (r == l_true) update_indices();
if (r == l_true) r = trace_call("ensure_disjoint", ensure_disjoint());
if (r == l_true) r = trace_call("ensure_values_assigned", ensure_values_assigned());
if (r == l_true) r = trace_call("ensure_non_empty", ensure_non_empty());
if (r == l_true) r = trace_call("ensure_no_overflow", ensure_no_overflow());
CTRACE(card, r != l_true, display(tout););
switch (r) {
case l_true:
return FC_DONE;
case l_false:
return FC_CONTINUE;
case l_undef:
return FC_GIVEUP;
}
return FC_GIVEUP;
}
void init_model() {
for (auto const& kv : m_sizeof) {
sz_info& i = *kv.m_value;
app* sz = kv.m_key;
if (is_true(sz) && is_leaf(i) && rational(i.m_selects.size()) != i.m_size) {
warning_msg("models for BAPA is TBD");
break;
}
}
}
bool should_research(expr_ref_vector & unsat_core) {
expr* set, *sz;
for (auto & e : unsat_core) {
if (is_app(e) && is_size_limit(to_app(e), set, sz)) {
inc_size_limit(set, sz);
return true;
}
}
return false;
}
void inc_size_limit(expr* set, expr* sz) {
IF_VERBOSE(2, verbose_stream() << "inc value " << mk_pp(set, m) << "\n");
m_size_limit[set] *= rational(2);
assert_size_limit(set, sz);
}
bool is_size_limit(app* e, expr*& set, expr*& sz) {
func_decl* d = nullptr;
if (e->get_num_args() > 0 && m_size_limit_sort2skolems.find(e->get_arg(0)->get_sort(), d) && d == e->get_decl()) {
set = e->get_arg(0);
sz = e->get_arg(1);
return true;
}
else {
return false;
}
}
// has-size(s,n) & size-limit(s, n, k) => n <= k
app_ref mk_size_limit(expr* set, expr* sz) {
func_decl* sk = nullptr;
sort* s = set->get_sort();
if (!m_size_limit_sort2skolems.find(s, sk)) {
sort* dom[3] = { s, m_arith.mk_int(), m_arith.mk_int() };
sk = m.mk_fresh_func_decl("value-limit", "", 3, dom, m.mk_bool_sort());
m_pinned.push_back(sk);
m_size_limit_sort2skolems.insert(s, sk);
}
return app_ref(m.mk_app(sk, set, sz, m_arith.mk_int(m_size_limit[set])), m);
}
void assert_size_limit(expr* set, expr* sz) {
app_ref set_sz(m_autil.mk_has_size(set, sz), m);
app_ref lim(m_arith.mk_int(m_size_limit[set]), m);
app_ref size_limit = mk_size_limit(set, sz);
mk_th_axiom(~mk_literal(set_sz), ~mk_literal(size_limit), mk_literal(m_arith.mk_le(sz, lim)));
}
void add_theory_assumptions(expr_ref_vector & assumptions) {
for (auto const& kv : m_sizeof) {
expr* set = kv.m_key->get_arg(0);
expr* sz = kv.m_key->get_arg(1);
assumptions.push_back(mk_size_limit(set, sz));
}
TRACE(card, tout << "ASSUMPTIONS: " << assumptions << "\n";);
}
};
theory_array_bapa::theory_array_bapa(theory_array_full& th) { m_imp = alloc(imp, th); }
theory_array_bapa::~theory_array_bapa() { dealloc(m_imp); }
void theory_array_bapa::internalize_term(app* term) { m_imp->internalize_term(term); }
final_check_status theory_array_bapa::final_check() { return m_imp->final_check(); }
void theory_array_bapa::init_model() { m_imp->init_model(); }
bool theory_array_bapa::should_research(expr_ref_vector & unsat_core) { return m_imp->should_research(unsat_core); }
void theory_array_bapa::add_theory_assumptions(expr_ref_vector & assumptions) { m_imp->add_theory_assumptions(assumptions); }
}

View file

@ -1,43 +0,0 @@
/*++
Copyright (c) 2019 Microsoft Corporation
Module Name:
theory_array_bapa.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner 2019-04-13
Revision History:
--*/
#pragma once
#include "ast/ast.h"
#include "smt/smt_theory.h"
namespace smt {
class theory_array_full;
class theory_array_bapa {
class imp;
imp* m_imp;
public:
theory_array_bapa(theory_array_full& th);
~theory_array_bapa();
void internalize_term(app* term);
final_check_status final_check();
void init_model();
bool should_research(expr_ref_vector & unsat_core);
void add_theory_assumptions(expr_ref_vector & assumptions);
};
};

View file

@ -681,7 +681,6 @@ namespace smt {
collect_defaults();
collect_selects();
propagate_selects();
if (m_bapa) m_bapa->init_model();
}
/**
@ -699,7 +698,7 @@ namespace smt {
if (!ctx.is_relevant(n))
continue;
if (is_store(n) || is_const(n) || is_default(n) || is_set_has_size(n))
if (is_store(n) || is_const(n) || is_default(n))
return false;
}
return true;

View file

@ -19,14 +19,12 @@ Revision History:
#pragma once
#include "smt/smt_theory.h"
#include "smt/theory_array_bapa.h"
#include "ast/array_decl_plugin.h"
#include "model/array_factory.h"
namespace smt {
class theory_array_base : public theory {
friend class theory_array_bapa;
protected:
bool m_found_unsupported_op;
unsigned m_array_weak_head;
@ -47,8 +45,6 @@ namespace smt {
bool is_as_array(app const * n) const { return n->is_app_of(get_id(), OP_AS_ARRAY); }
bool is_array_sort(sort const* s) const { return s->is_sort_of(get_id(), ARRAY_SORT); }
bool is_array_sort(app const* n) const { return is_array_sort(n->get_sort()); }
bool is_set_has_size(app const* n) const { return n->is_app_of(get_id(), OP_SET_HAS_SIZE); }
bool is_set_card(app const* n) const { return n->is_app_of(get_id(), OP_SET_CARD); }
bool is_store(enode const * n) const { return is_store(n->get_expr()); }
bool is_map(enode const* n) const { return is_map(n->get_expr()); }
@ -57,8 +53,6 @@ namespace smt {
bool is_as_array(enode const * n) const { return is_as_array(n->get_expr()); }
bool is_default(enode const* n) const { return is_default(n->get_expr()); }
bool is_array_sort(enode const* n) const { return is_array_sort(n->get_expr()); }
bool is_set_has_size(enode const* n) const { return is_set_has_size(n->get_expr()); }
bool is_set_carde(enode const* n) const { return is_set_card(n->get_expr()); }
bool is_select_arg(enode* r);
app * mk_select(unsigned num_args, expr * const * args);
@ -74,7 +68,6 @@ namespace smt {
enode_pair_vector m_axiom2_todo;
enode_pair_vector m_extensionality_todo;
enode_pair_vector m_congruent_todo;
scoped_ptr<theory_array_bapa> m_bapa;
void assert_axiom(unsigned num_lits, literal * lits);
void assert_axiom(literal l1, literal l2);

View file

@ -271,7 +271,7 @@ namespace smt {
return theory_array::internalize_term(n);
}
if (!is_const(n) && !is_default(n) && !is_map(n) && !is_as_array(n) && !is_set_has_size(n) && !is_set_card(n)) {
if (!is_const(n) && !is_default(n) && !is_map(n) && !is_as_array(n)) {
if (!is_array_ext(n))
found_unsupported_op(n);
return false;
@ -295,12 +295,6 @@ namespace smt {
mk_var(arg0);
}
}
else if (is_set_has_size(n) || is_set_card(n)) {
if (!m_bapa) {
m_bapa = alloc(theory_array_bapa, *this);
}
m_bapa->internalize_term(n);
}
enode* node = ctx.get_enode(n);
if (!is_attached_to_var(node)) {
@ -449,11 +443,10 @@ namespace smt {
}
bool theory_array_full::should_research(expr_ref_vector & unsat_core) {
return m_bapa && m_bapa->should_research(unsat_core);
return false;
}
void theory_array_full::add_theory_assumptions(expr_ref_vector & assumptions) {
if (m_bapa) m_bapa->add_theory_assumptions(assumptions);
}
//
@ -814,9 +807,6 @@ namespace smt {
}
}
}
if (r == FC_DONE && m_bapa) {
r = m_bapa->final_check();
}
bool should_giveup = m_found_unsupported_op || has_propagate_up_trail() || has_non_beta_as_array();
if (r == FC_DONE && should_giveup)
r = FC_GIVEUP;

View file

@ -1450,7 +1450,7 @@ namespace smt {
<< num_scopes << " = " << (ctx.get_scope_level() - num_scopes) << "\n"););
}
final_check_status theory_bv::final_check_eh() {
final_check_status theory_bv::final_check_eh(unsigned level) {
SASSERT(check_invariant());
if (m_approximates_large_bvs) {
return FC_GIVEUP;

View file

@ -244,7 +244,7 @@ namespace smt {
void relevant_eh(app * n) override;
void push_scope_eh() override;
void pop_scope_eh(unsigned num_scopes) override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void reset_eh() override;
bool include_func_interp(func_decl* f) override;
svector<theory_var> m_merge_aux[2]; //!< auxiliary vector used in merge_zero_one_bits

View file

@ -75,7 +75,7 @@ namespace smt {
bool internalize_atom(app * atom, bool gate_ctx) override;
bool internalize_term(app * term) override;
void display(std::ostream& out) const override {}
final_check_status final_check_eh() override { return final_check() ? FC_DONE : FC_CONTINUE; }
final_check_status final_check_eh(unsigned) override { return final_check() ? FC_DONE : FC_CONTINUE; }
void init_model(model_generator & mg) override;
model_value_proc * mk_value(enode * n, model_generator & mg) override;
void collect_statistics(::statistics& st) const override;

View file

@ -476,7 +476,7 @@ namespace smt {
SASSERT(m_find.get_num_vars() == get_num_vars());
}
final_check_status theory_datatype::final_check_eh() {
final_check_status theory_datatype::final_check_eh(unsigned level) {
force_push();
int num_vars = get_num_vars();
final_check_status r = FC_DONE;

View file

@ -126,7 +126,7 @@ namespace smt {
void relevant_eh(app * n) override;
void push_scope_eh() override;
void pop_scope_eh(unsigned num_scopes) override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void reset_eh() override;
void restart_eh() override { m_util.reset(); }
bool is_shared(theory_var v) const override;

View file

@ -230,7 +230,7 @@ namespace smt {
void restart_eh() override;
void init_search_eh() override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
bool can_propagate() override;
void propagate() override;

View file

@ -387,7 +387,7 @@ namespace smt {
}
template<typename Ext>
final_check_status theory_dense_diff_logic<Ext>::final_check_eh() {
final_check_status theory_dense_diff_logic<Ext>::final_check_eh(unsigned level) {
init_model();
if (assume_eqs(m_var_value_table))
return FC_CONTINUE;

View file

@ -269,7 +269,7 @@ namespace smt {
m_arith_eq_adapter.init_search_eh();
}
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
bool is_shared(theory_var v) const override {
return false;

View file

@ -368,7 +368,7 @@ void theory_diff_logic<Ext>::pop_scope_eh(unsigned num_scopes) {
}
template<typename Ext>
final_check_status theory_diff_logic<Ext>::final_check_eh() {
final_check_status theory_diff_logic<Ext>::final_check_eh(unsigned level) {
if (can_propagate()) {
propagate_core();

View file

@ -62,7 +62,7 @@ namespace smt {
theory::reset_eh();
}
final_check_status theory_dummy::final_check_eh() {
final_check_status theory_dummy::final_check_eh(unsigned) {
return m_theory_exprs ? FC_GIVEUP : FC_DONE;
}

View file

@ -38,7 +38,7 @@ namespace smt {
bool use_diseqs() const override;
void new_diseq_eh(theory_var v1, theory_var v2) override;
void reset_eh() override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
bool build_models() const override {
return false;
}

View file

@ -501,7 +501,7 @@ namespace smt {
theory::reset_eh();
}
final_check_status theory_fpa::final_check_eh() {
final_check_status theory_fpa::final_check_eh(unsigned level) {
TRACE(t_fpa, tout << "final_check_eh\n";);
SASSERT(m_converter.m_extra_assertions.empty());
return FC_DONE;

View file

@ -89,7 +89,7 @@ namespace smt {
bool m_is_initialized;
obj_hashtable<func_decl> m_is_added_to_model;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
bool internalize_atom(app * atom, bool gate_ctx) override;
bool internalize_term(app * term) override;
void apply_sort_cnstr(enode * n, sort * s) override;

View file

@ -38,7 +38,7 @@ namespace smt {
theory_intblast::~theory_intblast() {}
final_check_status theory_intblast::final_check_eh() {
final_check_status theory_intblast::final_check_eh(unsigned) {
for (auto e : m_translator.bv2int()) {
auto* n = ctx.get_enode(e);
auto* r1 = n->get_arg(0)->get_root();

View file

@ -54,7 +54,7 @@ namespace smt {
char const* get_name() const override { return "bv-intblast"; }
smt::theory* mk_fresh(context* new_ctx) override { return alloc(theory_intblast, *new_ctx); }
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void display(std::ostream& out) const override {}
bool can_propagate() override;
void propagate() override;

View file

@ -1630,7 +1630,7 @@ public:
return FC_GIVEUP;
}
final_check_status final_check_eh() {
final_check_status final_check_eh(unsigned level) {
if (propagate_core())
return FC_CONTINUE;
m_model_is_initialized = false;
@ -1658,7 +1658,7 @@ public:
break;
}
switch (check_nla()) {
switch (check_nla(level)) {
case FC_DONE:
break;
case FC_CONTINUE:
@ -2047,11 +2047,11 @@ public:
ctx().set_true_first_flag(lit.var());
}
final_check_status check_nla_continue() {
final_check_status check_nla_continue(unsigned level) {
#if Z3DEBUG
flet f(lp().validate_blocker(), true);
#endif
lbool r = m_nla->check();
lbool r = m_nla->check(level);
switch (r) {
case l_false:
add_lemmas();
@ -2063,7 +2063,7 @@ public:
}
}
final_check_status check_nla() {
final_check_status check_nla(unsigned level) {
// TODO - enable or remove if found useful internals are corrected:
// lp::lar_solver::scoped_auxiliary _sa(lp()); // new atoms are auxilairy and are not used in nra_solver
if (!m.inc()) {
@ -2075,7 +2075,7 @@ public:
return FC_DONE;
if (!m_nla->need_check())
return FC_DONE;
return check_nla_continue();
return check_nla_continue(level);
}
/**
@ -3900,6 +3900,7 @@ public:
}
theory_lra::inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) {
unsigned level = 2;
lp::impq term_max;
lp::lp_status st;
lpvar vi = 0;
@ -3926,7 +3927,7 @@ public:
lp().restore_x();
}
if (m_nla && (st == lp::lp_status::OPTIMAL || st == lp::lp_status::UNBOUNDED)) {
switch (check_nla()) {
switch (check_nla(level)) {
case FC_DONE:
st = lp::lp_status::FEASIBLE;
break;
@ -4286,8 +4287,8 @@ void theory_lra::relevant_eh(app* e) {
void theory_lra::init_search_eh() {
m_imp->init_search_eh();
}
final_check_status theory_lra::final_check_eh() {
return m_imp->final_check_eh();
final_check_status theory_lra::final_check_eh(unsigned level) {
return m_imp->final_check_eh(level);
}
bool theory_lra::is_shared(theory_var v) const {
return m_imp->is_shared(v);

View file

@ -63,7 +63,11 @@ namespace smt {
void init_search_eh() override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
unsigned num_final_check_levels() const override {
return 2;
}
bool is_shared(theory_var v) const override;

View file

@ -985,7 +985,7 @@ namespace smt {
UNREACHABLE();
}
final_check_status theory_pb::final_check_eh() {
final_check_status theory_pb::final_check_eh(unsigned level) {
TRACE(pb, display(tout););
DEBUG_CODE(validate_final_check(););
return FC_DONE;

View file

@ -417,7 +417,7 @@ namespace smt {
void new_diseq_eh(theory_var v1, theory_var v2) override { }
bool use_diseqs() const override { return false; }
bool build_models() const override { return false; }
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void reset_eh() override;
void assign_eh(bool_var v, bool is_true) override;
void init_search_eh() override;

View file

@ -66,7 +66,7 @@ namespace smt {
ctx.internalize_assertions();
}
final_check_status final_check_eh() override {
final_check_status final_check_eh(unsigned) override {
if (m_inst.pending())
ctx.assign(~mk_literal(m_assumption), nullptr);
return FC_DONE;

View file

@ -405,7 +405,7 @@ namespace smt {
ctx.mk_th_axiom(get_id(), clause);
}
final_check_status theory_recfun::final_check_eh() {
final_check_status theory_recfun::final_check_eh(unsigned level) {
if (can_propagate()) {
TRACEFN("final\n");
propagate();

View file

@ -92,7 +92,7 @@ namespace smt {
void reset_eh() override;
void relevant_eh(app * n) override;
char const * get_name() const override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void assign_eh(bool_var v, bool is_true) override;
void push_scope_eh() override;
void pop_scope_eh(unsigned num_scopes) override;

View file

@ -318,7 +318,7 @@ struct scoped_enable_trace {
}
};
final_check_status theory_seq::final_check_eh() {
final_check_status theory_seq::final_check_eh(unsigned level) {
if (!m_has_seq) {
return FC_DONE;
}

View file

@ -379,7 +379,7 @@ namespace smt {
obj_hashtable<expr> m_fixed; // string variables that are fixed length.
obj_hashtable<expr> m_is_digit; // expressions that have been constrained to be digits
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
bool internalize_atom(app* atom, bool) override;
bool internalize_term(app*) override;
void internalize_eq_eh(app * atom, bool_var v) override;

View file

@ -27,7 +27,7 @@ namespace smt {
class theory_seq_empty : public theory {
bool m_used;
final_check_status final_check_eh() override { return m_used?FC_GIVEUP:FC_DONE; }
final_check_status final_check_eh(unsigned) override { return m_used?FC_GIVEUP:FC_DONE; }
bool internalize_atom(app*, bool) override { if (!m_used) { get_context().push_trail(value_trail<bool>(m_used)); m_used = true; } return false; }
bool internalize_term(app*) override { return internalize_atom(nullptr,false); }
void new_eq_eh(theory_var, theory_var) override { }

View file

@ -241,7 +241,7 @@ namespace smt {
}
}
final_check_status theory_sls::final_check_eh() {
final_check_status theory_sls::final_check_eh(unsigned) {
if (!m_smt_plugin)
return FC_DONE;
++m_after_resolve_decide_count;

View file

@ -118,7 +118,7 @@ namespace smt {
void new_eq_eh(theory_var v1, theory_var v2) override {}
void new_diseq_eh(theory_var v1, theory_var v2) override {}
void restart_eh() override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
// sls::smt_context interface
ast_manager& get_manager() override { return m; }

View file

@ -186,7 +186,7 @@ namespace smt {
}
}
final_check_status theory_special_relations::final_check_eh() {
final_check_status theory_special_relations::final_check_eh(unsigned) {
TRACE(special_relations, tout << "\n";);
for (auto const& kv : m_relations) {
lbool r = final_check(*kv.m_value);

View file

@ -187,7 +187,7 @@ namespace smt {
void new_diseq_eh(theory_var v1, theory_var v2) override {}
bool use_diseqs() const override { return false; }
bool build_models() const override { return true; }
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void reset_eh() override;
void assign_eh(bool_var v, bool is_true) override;
void init_search_eh() override {}

View file

@ -157,7 +157,7 @@ theory * theory_user_propagator::mk_fresh(context * new_ctx) {
return th;
}
final_check_status theory_user_propagator::final_check_eh() {
final_check_status theory_user_propagator::final_check_eh(unsigned level) {
if (!(bool)m_final_eh)
return FC_DONE;
force_push();

View file

@ -152,7 +152,7 @@ namespace smt {
void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) force_push(), m_diseq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); }
bool use_diseqs() const override { return ((bool)m_diseq_eh); }
bool build_models() const override { return false; }
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned) override;
void reset_eh() override {}
void assign_eh(bool_var v, bool is_true) override { }
void init_search_eh() override {}

View file

@ -245,7 +245,7 @@ namespace smt {
m_arith_eq_adapter.init_search_eh();
}
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned level) override;
bool is_shared(th_var v) const override {
return false;

View file

@ -394,7 +394,7 @@ namespace smt {
}
template<typename Ext>
final_check_status theory_utvpi<Ext>::final_check_eh() {
final_check_status theory_utvpi<Ext>::final_check_eh(unsigned level) {
SASSERT(is_consistent());
if (can_propagate()) {
propagate();

View file

@ -176,7 +176,7 @@ namespace smt {
}
}
final_check_status theory_wmaxsat::final_check_eh() {
final_check_status theory_wmaxsat::final_check_eh(unsigned level) {
if (m_normalize) normalize();
TRACE(opt, tout << "cost: " << m_zcost << " min cost: " << m_zmin_cost << "\n";);
return FC_DONE;

View file

@ -83,7 +83,7 @@ namespace smt {
void init_search_eh() override;
void assign_eh(bool_var v, bool is_true) override;
final_check_status final_check_eh() override;
final_check_status final_check_eh(unsigned level) override;
bool use_diseqs() const override {
return false;
}