3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +00:00

Merge branch 'master' into polysat

This commit is contained in:
Jakob Rath 2023-05-26 15:58:09 +02:00
commit f54f33551e
308 changed files with 6606 additions and 18485 deletions

View file

@ -3958,7 +3958,7 @@ namespace {
void relevant_eh(enode * n, bool lazy) override {
TRACE("trigger_bug", tout << "relevant_eh:\n" << mk_ismt2_pp(n->get_expr(), m) << "\n";
tout << "mam: " << this << "\n";);
TRACE("mam", tout << "relevant_eh: #" << n->get_owner_id() << "\n";);
TRACE("mam", tout << "relevant_eh: #" << enode_pp(n, m_context) << "\n";);
if (n->has_lbl_hash())
update_lbls(n, n->get_lbl_hash());

View file

@ -30,6 +30,7 @@ void preprocessor_params::updt_local_params(params_ref const & _p) {
m_elim_unconstrained = p.elim_unconstrained();
m_solve_eqs = p.solve_eqs();
m_ng_lift_ite = static_cast<lift_ite_kind>(p.q_lift_ite());
m_bound_simplifier = p.bound_simplifier();
}
void preprocessor_params::updt_params(params_ref const & p) {
@ -63,4 +64,5 @@ void preprocessor_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_max_bv_sharing);
DISPLAY_PARAM(m_pre_simplifier);
DISPLAY_PARAM(m_nlquant_elim);
DISPLAY_PARAM(m_bound_simplifier);
}

View file

@ -49,6 +49,7 @@ struct preprocessor_params : public pattern_inference_params,
bool m_max_bv_sharing = true;
bool m_pre_simplifier = true;
bool m_nlquant_elim = false;
bool m_bound_simplifier = true;
public:
preprocessor_params(params_ref const & p = params_ref()):

View file

@ -21,6 +21,7 @@ def_module_params(module_name='smt',
('elim_unconstrained', BOOL, True, 'pre-processing: eliminate unconstrained subterms'),
('solve_eqs', BOOL, True, 'pre-processing: solve equalities'),
('propagate_values', BOOL, True, 'pre-processing: propagate values'),
('bound_simplifier', BOOL, True, 'apply bounds simplification during pre-processing'),
('pull_nested_quantifiers', BOOL, False, 'pre-processing: pull nested quantifiers'),
('refine_inj_axioms', BOOL, True, 'pre-processing: refine injectivity axioms'),
('candidate_models', BOOL, False, 'create candidate models even when quantifier or theory reasoning is incomplete'),

View file

@ -32,7 +32,7 @@ proto_model::proto_model(ast_manager & m, params_ref const & p):
model_core(m),
m_eval(*this),
m_rewrite(m) {
register_factory(alloc(basic_factory, m));
register_factory(alloc(basic_factory, m, m.get_num_asts()));
m_user_sort_factory = alloc(user_sort_factory, m);
register_factory(m_user_sort_factory);
m_model_partial = model_params(p).partial();
@ -288,42 +288,33 @@ bool proto_model::is_finite(sort * s) const {
}
expr * proto_model::get_some_value(sort * s) {
if (m.is_uninterp(s)) {
return m_user_sort_factory->get_some_value(s);
}
else if (value_factory * f = get_factory(s->get_family_id())) {
return f->get_some_value(s);
}
else {
if (m.is_uninterp(s))
return m_user_sort_factory->get_some_value(s);
else if (value_factory * f = get_factory(s->get_family_id()))
return f->get_some_value(s);
else
// there is no factory for the family id, then assume s is uninterpreted.
return m_user_sort_factory->get_some_value(s);
}
return m_user_sort_factory->get_some_value(s);
}
bool proto_model::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
if (m.is_uninterp(s)) {
return m_user_sort_factory->get_some_values(s, v1, v2);
}
else if (value_factory * f = get_factory(s->get_family_id())) {
return f->get_some_values(s, v1, v2);
}
else {
return false;
}
if (m.is_uninterp(s))
return m_user_sort_factory->get_some_values(s, v1, v2);
else if (value_factory * f = get_factory(s->get_family_id()))
return f->get_some_values(s, v1, v2);
else
return false;
}
expr * proto_model::get_fresh_value(sort * s) {
if (m.is_uninterp(s)) {
return m_user_sort_factory->get_fresh_value(s);
}
else if (value_factory * f = get_factory(s->get_family_id())) {
return f->get_fresh_value(s);
}
else {
if (m.is_uninterp(s))
return m_user_sort_factory->get_fresh_value(s);
else if (value_factory * f = get_factory(s->get_family_id()))
return f->get_fresh_value(s);
else
// Use user_sort_factory if the theory has no support for model construnction.
// This is needed when dummy theories are used for arithmetic or arrays.
return m_user_sort_factory->get_fresh_value(s);
}
return m_user_sort_factory->get_fresh_value(s);
}
void proto_model::register_value(expr * n) {

View file

@ -964,7 +964,7 @@ namespace {
}
void display(std::ostream & out) override {
if (m_queue.empty() && m_queue2.empty())
if (m_queue.empty())
return;
out << "case-splits:\n";
display_core(out, m_queue, m_head, 1);

View file

@ -233,7 +233,7 @@ namespace smt {
TRACE("context", tout << "get-proof " << ctx.get_fparams().m_clause_proof << "\n";);
if (!ctx.get_fparams().m_clause_proof)
return proof_ref(m);
proof_ref_vector ps(m);
expr_ref_vector ps(m);
for (auto& info : m_trail) {
expr_ref fact = mk_or(info.m_clause);
proof* pr = info.m_proof;

View file

@ -3024,7 +3024,8 @@ namespace smt {
SASSERT(is_well_sorted(m, e));
TRACE("begin_assert_expr", tout << mk_pp(e, m) << " " << mk_pp(pr, m) << "\n";);
TRACE("begin_assert_expr_ll", tout << mk_ll_pp(e, m) << "\n";);
pop_to_base_lvl();
if (!m_searching)
pop_to_base_lvl();
if (pr == nullptr)
m_asserted_formulas.assert_expr(e);
else

View file

@ -704,14 +704,20 @@ namespace smt {
for (clause* cp : m_lemmas)
if (cp->get_num_literals() == 2)
++bin_lemmas;
auto num_units = [&]() {
if (m_scopes.empty())
return m_assigned_literals.size();
else
return m_scopes[0].m_assigned_literals_lim;
};
std::stringstream strm;
strm << "(smt.stats "
<< std::setw(4) << m_stats.m_num_restarts << " "
<< std::setw(6) << m_stats.m_num_conflicts << " "
<< std::setw(6) << m_stats.m_num_decisions << " "
<< std::setw(6) << m_stats.m_num_propagations << " "
<< std::setw(5) << (m_aux_clauses.size() + bin_clauses) << "/" << bin_clauses << " "
<< std::setw(5) << m_lemmas.size(); if (bin_lemmas > 0) strm << "/" << bin_lemmas << " ";
<< std::setw(5) << (m_aux_clauses.size() + bin_clauses) << "/" << bin_clauses << "/" << num_units()
<< std::setw(7) << m_lemmas.size(); if (bin_lemmas > 0) strm << "/" << bin_lemmas << " ";
strm << std::setw(5) << m_stats.m_num_simplifications << " "
<< std::setw(4) << m_stats.m_num_del_clauses << " "
<< std::setw(7) << mem_stat() << ")\n";
@ -739,8 +745,8 @@ namespace smt {
m_last_position_log = m_stats.m_num_restarts;
// restarts decisions clauses simplifications memory
// conflicts propagations lemmas deletions
int adjust[9] = { -3, -3, -3, -3, -3, -3, -4, -4, -1 };
char const* tag[9] = { ":restarts ", ":conflicts ", ":decisions ", ":propagations ", ":clauses/bin ", ":lemmas ", ":simplify ", ":deletions", ":memory" };
int adjust[9] = { -3, -3, -3, -3, -3, -4, -4, -4, -1 };
char const* tag[9] = { ":restarts ", ":conflicts ", ":decisions ", ":propagations ", ":clauses/bin/units ", ":lemmas ", ":simplify ", ":deletions", ":memory" };
std::stringstream l1, l2;
l1 << "(smt.stats ";

View file

@ -1536,7 +1536,7 @@ namespace smt {
fml = mk_or(fmls);
m_lemma_visitor.collect(fml);
m_lemma_visitor.display_skolem_decls(std::cout);
m_lemma_visitor.display_assert(std::cout, fml.get(), true);
m_lemma_visitor.display_assert(std::cout, fml.get(), false);
}
}

View file

@ -28,6 +28,7 @@ Revision History:
#include "ast/rewriter/rewriter_def.h"
#include "ast/ast_pp.h"
#include "ast/array_decl_plugin.h"
#include "ast/special_relations_decl_plugin.h"
#include "ast/ast_smt2_pp.h"
#include "smt/smt_model_checker.h"
#include "smt/smt_context.h"
@ -358,7 +359,7 @@ namespace smt {
TRACE("model_checker", tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";);
if (r != l_true) {
return r == l_false; // quantifier is satisfied by m_curr_model
return is_safe_for_mbqi(q) && r == l_false; // quantifier is satisfied by m_curr_model
}
model_ref complete_cex;
@ -398,6 +399,26 @@ namespace smt {
return false;
}
bool model_checker::is_safe_for_mbqi(quantifier * q) const {
special_relations_util sp(m);
if (!sp.has_special_relation())
return true;
ast_fast_mark1 visited;
struct proc {
special_relations_util& sp;
bool found = false;
proc(special_relations_util& sp):sp(sp) {}
void operator()(app* f) {
found |= sp.is_special_relation(f);
}
void operator()(expr* e) {}
};
proc p(sp);
quick_for_each_expr(p, visited, q);
return !p.found;
}
void model_checker::init_aux_context() {
if (!m_fparams) {
m_fparams = alloc(smt_params, m_context->get_fparams());

View file

@ -87,6 +87,7 @@ namespace smt {
expr_mark m_visited;
bool contains_model_value(expr * e);
void add_instance(quantifier * q, expr_ref_vector const & bindings, unsigned max_generation, expr * def);
bool is_safe_for_mbqi(quantifier * q) const;
public:
model_checker(ast_manager & m, qi_params const & p, model_finder & mf);

View file

@ -802,7 +802,7 @@ namespace smt {
setup_dl();
setup_seq_str(st);
setup_fpa();
if (st.m_has_sr) setup_special_relations();
setup_special_relations();
}
void setup::setup_unknown(static_features & st) {
@ -818,7 +818,7 @@ namespace smt {
setup_seq_str(st);
setup_fpa();
setup_recfuns();
if (st.m_has_sr) setup_special_relations();
setup_special_relations();
return;
}

View file

@ -41,7 +41,7 @@ Revision History:
namespace smt {
struct theory_arith_stats {
unsigned m_conflicts, m_add_rows, m_pivots, m_diseq_cs, m_gomory_cuts, m_branches, m_gcd_tests, m_patches, m_patches_succ;
unsigned m_conflicts, m_add_rows, m_pivots, m_diseq_cs, m_gomory_cuts, m_branches, m_gcd_tests, m_gcd_conflicts, m_patches, m_patches_succ;
unsigned m_assert_lower, m_assert_upper, m_assert_diseq, m_core2th_eqs, m_core2th_diseqs;
unsigned m_th2core_eqs, m_th2core_diseqs, m_bound_props, m_offset_eqs, m_fixed_eqs, m_offline_eqs;
unsigned m_max_min;
@ -452,18 +452,18 @@ namespace smt {
svector<int> m_var_pos; // temporary array used in add_rows
atoms m_atoms; // set of theory atoms
ptr_vector<bound> m_asserted_bounds; // set of asserted bounds
unsigned m_asserted_qhead;
unsigned m_asserted_qhead = 0;
ptr_vector<atom> m_new_atoms; // new bound atoms that have yet to be internalized.
svector<theory_var> m_nl_monomials; // non linear monomials
svector<theory_var> m_nl_propagated; // non linear monomials that became linear
v_dependency_manager m_dep_manager; // for tracking bounds during non-linear reasoning
vector<uint_set> m_row_vars; // variables in a given row. Used during internalization to detect repeated variables.
unsigned m_row_vars_top;
unsigned m_row_vars_top = 0;
var_heap m_to_patch; // heap containing all variables v s.t. m_value[v] does not satisfy bounds of v.
nat_set m_left_basis; // temporary: set of variables that already left the basis in make_feasible
bool m_blands_rule;
bool m_blands_rule = false;
svector<unsigned> m_update_trail_stack; // temporary trail stack used to restore the last feasible assignment.
nat_set m_in_update_trail_stack; // set of variables in m_update_trail_stack
@ -473,11 +473,11 @@ namespace smt {
inf_numeral m_tmp;
random_gen m_random;
unsigned m_num_conflicts;
unsigned m_num_conflicts = 0;
unsigned m_branch_cut_counter;
unsigned m_branch_cut_counter = 0;
bool m_eager_gcd; // true if gcd should be applied at every add_row
unsigned m_final_check_idx;
unsigned m_final_check_idx = 0;
// backtracking
@ -676,7 +676,7 @@ namespace smt {
See also m_changed_assignment flag.
*/
bool m_liberal_final_check;
bool m_liberal_final_check = true;
final_check_status final_check_core();
final_check_status final_check_eh() override;
@ -734,7 +734,7 @@ namespace smt {
// Assignment management
//
// -----------------------------------
bool m_changed_assignment; //!< auxiliary variable set to true when the assignment is changed.
bool m_changed_assignment = false; //!< auxiliary variable set to true when the assignment is changed.
void save_value(theory_var v);
void discard_update_trail();
void restore_assignment();
@ -790,11 +790,11 @@ namespace smt {
void mark_row_for_bound_prop(unsigned r1);
void mark_rows_for_bound_prop(theory_var v);
void is_row_useful_for_bound_prop(row const & r, int & lower_idx, int & upper_idx) const;
void imply_bound_for_monomial(row const & r, int idx, bool lower);
void imply_bound_for_all_monomials(row const & r, bool lower);
unsigned imply_bound_for_monomial(row const & r, int idx, bool lower);
unsigned imply_bound_for_all_monomials(row const & r, bool lower);
void explain_bound(row const & r, int idx, bool lower, inf_numeral & delta,
antecedents & antecedents);
void mk_implied_bound(row const & r, unsigned idx, bool lower, theory_var v, bound_kind kind, inf_numeral const & k);
unsigned mk_implied_bound(row const & r, unsigned idx, bool lower, theory_var v, bound_kind kind, inf_numeral const & k);
void assign_bound_literal(literal l, row const & r, unsigned idx, bool lower, inf_numeral & delta);
void propagate_bounds();
@ -821,7 +821,7 @@ namespace smt {
var_set m_tmp_var_set;
var_set m_tmp_var_set2;
svector<std::pair<theory_var, theory_var> > m_assume_eq_candidates;
unsigned m_assume_eq_head;
unsigned m_assume_eq_head = 0;
bool random_update(theory_var v);
void mutate_assignment();
bool assume_eqs_core();
@ -953,10 +953,10 @@ namespace smt {
//
// -----------------------------------
typedef int_hashtable<int_hash, default_eq<int> > row_set;
bool m_model_depends_on_computed_epsilon;
unsigned m_nl_rounds;
bool m_nl_gb_exhausted;
unsigned m_nl_strategy_idx; // for fairness
bool m_model_depends_on_computed_epsilon = false;
unsigned m_nl_rounds = 0;
bool m_nl_gb_exhausted = false;
unsigned m_nl_strategy_idx = 0; // for fairness
expr_ref_vector m_nl_new_exprs;
typedef obj_map<expr, unsigned> var2num_occs;
var2num_occs m_var2num_occs;

View file

@ -47,11 +47,15 @@ namespace smt {
else if (m_util.is_idiv(n)) {
e = m_util.mk_idiv0(n->get_arg(0), n->get_arg(1));
}
else if (m_util.is_rem(n)) {
e = m_util.mk_rem0(n->get_arg(0), n->get_arg(1));
else if (m_util.is_rem(n)) {
expr* z = m_util.mk_int(0);
e = m_util.mk_rem0(n->get_arg(0), z);
n = m_util.mk_rem(n->get_arg(0), z);
}
else if (m_util.is_mod(n)) {
e = m_util.mk_mod0(n->get_arg(0), n->get_arg(1));
else if (m_util.is_mod(n)) {
expr* z = m_util.mk_int(0);
e = m_util.mk_mod0(n->get_arg(0), z);
n = m_util.mk_mod(n->get_arg(0), z);
}
else if (m_util.is_power(n)) {
e = m_util.mk_power0(n->get_arg(0), n->get_arg(1));
@ -154,7 +158,6 @@ namespace smt {
case OP_MOD:
case OP_DIV0:
case OP_IDIV0:
case OP_REM0:
case OP_MOD0:
return true;
default:
@ -1732,23 +1735,11 @@ namespace smt {
m_util(m),
m_arith_eq_solver(m),
m_arith_eq_adapter(*this, m_util),
m_asserted_qhead(0),
m_row_vars_top(0),
m_to_patch(1024),
m_blands_rule(false),
m_random(ctx.get_fparams().m_arith_random_seed),
m_num_conflicts(0),
m_branch_cut_counter(0),
m_eager_gcd(m_params.m_arith_eager_gcd),
m_final_check_idx(0),
m_antecedents_index(0),
m_var_value_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)),
m_liberal_final_check(true),
m_changed_assignment(false),
m_assume_eq_head(0),
m_model_depends_on_computed_epsilon(false),
m_nl_rounds(0),
m_nl_gb_exhausted(false),
m_nl_new_exprs(m),
m_bound_watch(null_bool_var) {
}
@ -2700,8 +2691,9 @@ namespace smt {
Then this bound is used to produce a bound for the monomial variable.
*/
template<typename Ext>
void theory_arith<Ext>::imply_bound_for_monomial(row const & r, int idx, bool is_lower) {
unsigned theory_arith<Ext>::imply_bound_for_monomial(row const & r, int idx, bool is_lower) {
row_entry const & entry = r[idx];
unsigned count = 0;
if (m_unassigned_atoms[entry.m_var] > 0) {
inf_numeral implied_k;
typename vector<row_entry>::const_iterator it = r.begin_entries();
@ -2723,7 +2715,7 @@ namespace smt {
tout << "implying lower bound for v" << entry.m_var << " " << implied_k << " using row:\n";
display_row_info(tout, r);
display_var(tout, entry.m_var););
mk_implied_bound(r, idx, is_lower, entry.m_var, B_LOWER, implied_k);
count += mk_implied_bound(r, idx, is_lower, entry.m_var, B_LOWER, implied_k);
}
}
else {
@ -2734,10 +2726,11 @@ namespace smt {
tout << "implying upper bound for v" << entry.m_var << " " << implied_k << " using row:\n";
display_row_info(tout, r);
display_var(tout, entry.m_var););
mk_implied_bound(r, idx, is_lower, entry.m_var, B_UPPER, implied_k);
count += mk_implied_bound(r, idx, is_lower, entry.m_var, B_UPPER, implied_k);
}
}
}
return count;
}
/**
@ -2748,7 +2741,7 @@ namespace smt {
for the monomial variables.
*/
template<typename Ext>
void theory_arith<Ext>::imply_bound_for_all_monomials(row const & r, bool is_lower) {
unsigned theory_arith<Ext>::imply_bound_for_all_monomials(row const & r, bool is_lower) {
// Traverse the row once and compute
// bb = (Sum_{a_i < 0} -a_i*lower(x_i)) + (Sum_{a_j > 0} -a_j * upper(x_j)) If is_lower = true
// bb = (Sum_{a_i > 0} -a_i*lower(x_i)) + (Sum_{a_j < 0} -a_j * upper(x_j)) If is_lower = false
@ -2761,6 +2754,7 @@ namespace smt {
}
}
unsigned count = 0;
inf_numeral implied_k;
typename vector<row_entry>::const_iterator it = r.begin();
typename vector<row_entry>::const_iterator end = r.end();
@ -2784,7 +2778,7 @@ namespace smt {
tout << "implying lower bound for v" << it->m_var << " " << implied_k << " using row:\n";
display_row_info(tout, r);
display_var(tout, it->m_var););
mk_implied_bound(r, idx, is_lower, it->m_var, B_LOWER, implied_k);
count += mk_implied_bound(r, idx, is_lower, it->m_var, B_LOWER, implied_k);
}
}
else {
@ -2796,11 +2790,12 @@ namespace smt {
tout << "implying upper bound for v" << it->m_var << " " << implied_k << " using row:\n";
display_row_info(tout, r);
display_var(tout, it->m_var););
mk_implied_bound(r, idx, is_lower, it->m_var, B_UPPER, implied_k);
count += mk_implied_bound(r, idx, is_lower, it->m_var, B_UPPER, implied_k);
}
}
}
}
return count;
}
/**
@ -2922,10 +2917,11 @@ namespace smt {
}
template<typename Ext>
void theory_arith<Ext>::mk_implied_bound(row const & r, unsigned idx, bool is_lower, theory_var v, bound_kind kind, inf_numeral const & k) {
unsigned theory_arith<Ext>::mk_implied_bound(row const & r, unsigned idx, bool is_lower, theory_var v, bound_kind kind, inf_numeral const & k) {
atoms const & as = m_var_occs[v];
inf_numeral const & epsilon = get_epsilon(v);
inf_numeral delta;
unsigned count = 0;
for (atom* a : as) {
bool_var bv = a->get_bool_var();
literal l(bv);
@ -2942,6 +2938,7 @@ namespace smt {
TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", v" << v << " >= " << k2 << ", delta: " << delta << "\n";
display_row(tout, r););
assign_bound_literal(l, r, idx, is_lower, delta);
++count;
}
// v <= k k < k2 |- v < k2 |- not v >= k2
if (kind == B_UPPER && k < k2) {
@ -2958,6 +2955,7 @@ namespace smt {
TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", not v" << v << " >= " << k2 << ", delta: " << delta << "\n";
display_row(tout, r););
assign_bound_literal(~l, r, idx, is_lower, delta);
++count;
}
}
}
@ -2973,6 +2971,7 @@ namespace smt {
TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", not v" << v << " <= " << k2 << ", delta: " << delta << "\n";
display_row(tout, r););
assign_bound_literal(~l, r, idx, is_lower, delta);
++count;
}
}
// v <= k k <= k2 |- v <= k2
@ -2984,10 +2983,12 @@ namespace smt {
TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", v" << v << " <= " << k2 << ", delta: " << delta << "\n";
display_row(tout, r););
assign_bound_literal(l, r, idx, is_lower, delta);
++count;
}
}
}
}
return count;
}
@ -2998,11 +2999,17 @@ namespace smt {
antecedents ante(*this);
explain_bound(r, idx, is_lower, delta, ante);
TRACE("propagate_bounds",
ante.display(tout) << " --> ";
ctx.display_detailed_literal(tout, l);
tout << "\n";);
TRACE("arith", tout << ctx.get_scope_level() << "\n";
ctx.display_detailed_literal(tout, l) << "\n");
if (ante.lits().size() < small_lemma_size() && ante.eqs().empty()) {
literal_vector & lits = m_tmp_literal_vector2;
lits.reset();
@ -3031,6 +3038,7 @@ namespace smt {
template<typename Ext>
void theory_arith<Ext>::propagate_bounds() {
TRACE("propagate_bounds_detail", display(tout););
unsigned num_prop = 0, count = 0;
for (unsigned r_idx : m_to_check) {
row & r = m_rows[r_idx];
if (r.get_base_var() != null_theory_var) {
@ -3039,15 +3047,21 @@ namespace smt {
int upper_idx;
is_row_useful_for_bound_prop(r, lower_idx, upper_idx);
++num_prop;
if (lower_idx >= 0)
imply_bound_for_monomial(r, lower_idx, true);
count += imply_bound_for_monomial(r, lower_idx, true);
else if (lower_idx == -1)
imply_bound_for_all_monomials(r, true);
count += imply_bound_for_all_monomials(r, true);
else
--num_prop;
++num_prop;
if (upper_idx >= 0)
imply_bound_for_monomial(r, upper_idx, false);
count += imply_bound_for_monomial(r, upper_idx, false);
else if (upper_idx == -1)
imply_bound_for_all_monomials(r, false);
count += imply_bound_for_all_monomials(r, false);
else
--num_prop;
// sneaking cheap eq detection in this loop
propagate_cheap_eq(r_idx);
@ -3063,6 +3077,7 @@ namespace smt {
#endif
}
}
TRACE("arith_eq", tout << "done\n";);
m_to_check.reset();
m_in_to_check.reset();
@ -3377,7 +3392,7 @@ namespace smt {
}
template<typename Ext>
void theory_arith<Ext>::pop_scope_eh(unsigned num_scopes) {
void theory_arith<Ext>::pop_scope_eh(unsigned num_scopes) {
CASSERT("arith", wf_rows());
CASSERT("arith", wf_columns());
CASSERT("arith", valid_row_assignment());
@ -3397,7 +3412,6 @@ namespace smt {
restore_unassigned_atoms(s.m_unassigned_atoms_trail_lim);
m_asserted_bounds.shrink(s.m_asserted_bounds_lim);
m_asserted_qhead = s.m_asserted_qhead_old;
TRACE("arith_pop_scope_bug", tout << "num_vars: " << get_num_vars() << ", num_old_vars: " << get_old_num_vars(num_scopes) << "\n";);
restore_nl_propagated_flag(s.m_nl_propagated_lim);
m_nl_monomials.shrink(s.m_nl_monomials_lim);
del_atoms(s.m_atoms_lim);

View file

@ -514,9 +514,11 @@ namespace smt {
// SASSERT(m_value[x_i].is_rational()); // infinitesimals are not used for integer variables
SASSERT(!m_value[x_i].is_int()); // the base variable is not assigned to an integer value.
if (constrain_free_vars(r) || !is_gomory_cut_target(r)) {
bool cfv = constrain_free_vars(r);
if (cfv || !is_gomory_cut_target(r)) {
TRACE("gomory_cut", tout << "failed to apply gomory cut:\n";
tout << "constrain_free_vars(r): " << constrain_free_vars(r) << "\n";);
tout << "constrain_free_vars(r): " << cfv << "\n";);
return false;
}
@ -752,6 +754,7 @@ namespace smt {
if (!(consts / gcds).is_int()) {
TRACE("gcd_test", tout << "row failed the GCD test:\n"; display_row_info(tout, r););
antecedents ante(*this);
m_stats.m_gcd_conflicts++;
collect_fixed_var_justifications(r, ante);
context & ctx = get_context();
ctx.set_conflict(
@ -831,6 +834,7 @@ namespace smt {
numeral u1 = floor(u/gcds);
if (u1 < l1) {
m_stats.m_gcd_conflicts++;
TRACE("gcd_test", tout << "row failed the extended GCD test:\n"; display_row_info(tout, r););
collect_fixed_var_justifications(r, ante);
context & ctx = get_context();

View file

@ -892,6 +892,7 @@ bool theory_arith<Ext>::propagate_linear_monomial(theory_var v) {
}
tout << "\n";);
return true;
}
@ -2264,8 +2265,10 @@ typename theory_arith<Ext>::gb_result theory_arith<Ext>::compute_grobner(svector
return GB_FAIL;
if (get_gb_eqs_and_look_for_conflict(eqs, gb))
return GB_PROGRESS;
if (scan_for_linear(eqs, gb))
return GB_NEW_EQ;
}
while(scan_for_linear(eqs, gb) && m_params.m_nl_arith_gb_perturbate &&
while(m_params.m_nl_arith_gb_perturbate &&
(!m_nl_gb_exhausted) && try_to_modify_eqs(eqs, gb, next_weight));
return GB_FAIL;
}

View file

@ -37,6 +37,7 @@ namespace smt {
st.update("arith assume eqs", m_stats.m_assume_eqs);
st.update("arith offset eqs", m_stats.m_offset_eqs);
st.update("arith gcd tests", m_stats.m_gcd_tests);
st.update("arith gcd conflicts", m_stats.m_gcd_conflicts);
st.update("arith ineq splits", m_stats.m_branches);
st.update("arith gomory cuts", m_stats.m_gomory_cuts);
st.update("arith branch int", m_stats.m_branch_infeasible_int);
@ -82,8 +83,9 @@ namespace smt {
template<typename Ext>
void theory_arith<Ext>::display_row(std::ostream & out, row const & r, bool compact) const {
out << "(v" << r.get_base_var() << ") : ";
column const & c = m_columns[r.get_base_var()];
out << "(v" << r.get_base_var() << " r" << c[0].m_row_id << ") : ";
bool first = true;
for (auto const& e : r) {
if (!e.is_dead()) {

View file

@ -252,6 +252,8 @@ namespace smt {
else if (m.is_lambda_def(n->get_decl())) {
instantiate_default_lambda_def_axiom(n);
d->m_lambdas.push_back(n);
m_lambdas.push_back(n);
ctx.push_trail(push_back_vector(m_lambdas));
}
return r;
}
@ -830,6 +832,12 @@ namespace smt {
return true;
}
}
for (enode* n : m_lambdas)
for (enode* p : n->get_parents())
if (!is_default(p) && !ctx.is_beta_redex(p, n)) {
TRACE("array", tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n");
return true;
}
return false;
}

View file

@ -86,6 +86,7 @@ namespace smt {
bool has_unitary_domain(app* array_term);
std::pair<app*,func_decl*> mk_epsilon(sort* s);
enode_vector m_as_array;
enode_vector m_lambdas;
bool has_non_beta_as_array();
bool instantiate_select_const_axiom(enode* select, enode* cnst);

View file

@ -811,6 +811,7 @@ namespace smt {
init_bits(e, bits);
}
MK_UNARY(internalize_neg, mk_neg);
MK_UNARY(internalize_not, mk_not);
MK_UNARY(internalize_redand, mk_redand);
MK_UNARY(internalize_redor, mk_redor);
@ -895,6 +896,7 @@ namespace smt {
}
switch (term->get_decl_kind()) {
case OP_BV_NUM: internalize_num(term); return true;
case OP_BNEG: internalize_neg(term); return true;
case OP_BADD: internalize_add(term); return true;
case OP_BSUB: internalize_sub(term); return true;
case OP_BMUL: internalize_mul(term); return true;
@ -944,6 +946,9 @@ namespace smt {
internalize_bv2int(term);
}
return params().m_bv_enable_int2bv2int;
case OP_BSREM: return false;
case OP_BUREM: return false;
case OP_BSMOD: return false;
default:
TRACE("bv_op", tout << "unsupported operator: " << mk_ll_pp(term, m) << "\n";);
UNREACHABLE();

View file

@ -196,6 +196,7 @@ namespace smt {
void internalize_ext_rotate_right(app * n);
void internalize_and(app * n);
void internalize_or(app * n);
void internalize_neg(app * n);
void internalize_not(app * n);
void internalize_nand(app * n);
void internalize_nor(app * n);

View file

@ -19,9 +19,6 @@
--*/
#include "util/stopwatch.h"
#include "math/lp/lp_solver.h"
#include "math/lp/lp_primal_simplex.h"
#include "math/lp/lp_dual_simplex.h"
#include "math/lp/indexed_value.h"
#include "math/lp/lar_solver.h"
#include "math/lp/nla_solver.h"
@ -48,6 +45,7 @@
#include "ast/ast_ll_pp.h"
#include "util/cancel_eh.h"
#include "util/scoped_timer.h"
#include "util/distribution.h"
typedef lp::var_index lpvar;
@ -318,11 +316,13 @@ class theory_lra::imp {
else if (a.is_idiv(n, x, y)) {
e = a.mk_idiv0(x, y);
}
else if (a.is_rem(n, x, y)) {
e = a.mk_rem0(x, y);
else if (a.is_rem(n, x, y)) {
n = a.mk_rem(x, a.mk_int(0));
e = a.mk_rem0(x, a.mk_int(0));
}
else if (a.is_mod(n, x, y)) {
e = a.mk_mod0(x, y);
n = a.mk_mod(x, a.mk_int(0));
e = a.mk_mod0(x, a.mk_int(0));
}
else if (a.is_power(n, x, y)) {
e = a.mk_power0(x, y);
@ -439,6 +439,9 @@ class theory_lra::imp {
if (ctx().relevancy()) ctx().add_relevancy_dependency(n, mod);
if (m_nla && !a.is_numeral(n2)) {
// shortcut to create non-linear division axioms.
internalize_term(to_app(n));
internalize_term(to_app(n1));
internalize_term(to_app(n2));
theory_var q = mk_var(n);
theory_var x = mk_var(n1);
theory_var y = mk_var(n2);
@ -446,6 +449,9 @@ class theory_lra::imp {
}
if (a.is_numeral(n2) && a.is_bounded(n1)) {
ensure_nla();
internalize_term(to_app(n));
internalize_term(to_app(n1));
internalize_term(to_app(n2));
theory_var q = mk_var(n);
theory_var x = mk_var(n1);
theory_var y = mk_var(n2);
@ -466,7 +472,7 @@ class theory_lra::imp {
st.to_ensure_var().push_back(n1);
st.to_ensure_var().push_back(n2);
}
else if (a.is_idiv0(n, n1, n2) || a.is_mod0(n, n1, n2) || a.is_rem0(n, n1, n2)) {
else if (a.is_idiv0(n, n1, n2) || a.is_mod0(n, n1, n2)) {
st.to_ensure_var().push_back(n1);
st.to_ensure_var().push_back(n2);
}
@ -814,12 +820,13 @@ class theory_lra::imp {
}
lpvar get_lpvar(expr* e) {
return get_lpvar(get_enode(e));
theory_var v = mk_var(e);
m_solver->register_existing_terms();
return register_theory_var_in_lar_solver(v);
}
lpvar get_lpvar(enode* n) {
ensure_column(n);
return n ? get_lpvar(n->get_th_var(get_id())) : lp::null_lpvar;
return get_lpvar(n->get_expr());
}
lpvar get_lpvar(theory_var v) const {
@ -1134,6 +1141,17 @@ public:
expr_ref zero(a.mk_real(0), m);
mk_axiom(~mk_literal(a.mk_le(p, zero)));
}
bool can_be_underspecified = false;
if (a.is_numeral(x, r) && r == 0 && (!a.is_numeral(y, r) || r == 0))
can_be_underspecified = true;
if (!a.is_extended_numeral(x, r) &&
!a.is_extended_numeral(y, r))
can_be_underspecified = true;
if (can_be_underspecified) {
literal lit = th.mk_eq(p, a.mk_power0(x, y), false);
ctx().mark_as_relevant(lit);
ctx().assign(lit, nullptr);
}
}
// n < 0 || rem(a, n) = mod(a, n)
@ -1299,7 +1317,6 @@ public:
expr_ref abs_q(m.mk_ite(a.mk_ge(q, zero), q, a.mk_uminus(q)), m);
expr_ref mone(a.mk_int(-1), m);
expr_ref modmq(a.mk_sub(mod, abs_q), m);
ctx().get_rewriter()(modmq);
literal eqz = mk_literal(m.mk_eq(q, zero));
literal mod_ge_0 = mk_literal(a.mk_ge(mod, zero));
literal mod_lt_q = mk_literal(a.mk_le(modmq, mone));
@ -1514,21 +1531,23 @@ public:
}
}
TRACE("arith",
for (theory_var v = 0; v < sz; ++v) {
if (th.is_relevant_and_shared(get_enode(v))) {
for (theory_var v = 0; v < sz; ++v)
if (th.is_relevant_and_shared(get_enode(v)))
tout << "v" << v << " ";
}
}
tout << "\n"; );
if (!vars.empty()) {
lp().random_update(vars.size(), vars.data());
}
}
bool assume_eqs() {
bool assume_eqs() {
if (delayed_assume_eqs())
return true;
TRACE("arith", display(tout););
random_update();
m_model_eqs.reset();
theory_var sz = static_cast<theory_var>(th.get_num_vars());
unsigned old_sz = m_assume_eq_candidates.size();
unsigned num_candidates = 0;
@ -1577,8 +1596,10 @@ public:
CTRACE("arith",
is_eq(v1, v2) && n1->get_root() != n2->get_root(),
tout << "assuming eq: v" << v1 << " = v" << v2 << "\n";);
if (is_eq(v1, v2) && n1->get_root() != n2->get_root() && th.assume_eq(n1, n2))
if (is_eq(v1, v2) && n1->get_root() != n2->get_root() && th.assume_eq(n1, n2)) {
++m_stats.m_assume_eqs;
return true;
}
}
return false;
}
@ -1596,8 +1617,12 @@ public:
final_check_status eval_power(expr* e) {
expr* x, * y;
rational r;
VERIFY(a.is_power(e, x, y));
if (a.is_numeral(x, r) && r == 0 && a.is_numeral(y, r) && r == 0)
return FC_DONE;
if (!m_nla)
return FC_GIVEUP;
switch (m_nla->check_power(get_lpvar(e), get_lpvar(x), get_lpvar(y), m_nla_lemma_vector)) {
case l_true:
return FC_DONE;
@ -1616,9 +1641,14 @@ public:
final_check_status eval_unsupported(expr* e) {
if (a.is_power(e))
return eval_power(e);
if (a.is_power0(e))
return FC_DONE;
return FC_GIVEUP;
}
unsigned m_final_check_idx = 0;
distribution m_dist { 0 };
final_check_status final_check_eh() {
if (propagate_core())
return FC_CONTINUE;
@ -1629,53 +1659,95 @@ public:
if (!lp().is_feasible() || lp().has_changed_columns()) {
is_sat = make_feasible();
}
bool giveup = false;
final_check_status st = FC_DONE;
m_final_check_idx = 0; // remove to experiment.
unsigned old_idx = m_final_check_idx;
switch (is_sat) {
case l_true:
TRACE("arith", display(tout));
switch (check_lia()) {
case l_true:
break;
case l_false:
return FC_CONTINUE;
case l_undef:
TRACE("arith", tout << "check-lia giveup\n";);
if (ctx().get_fparams().m_arith_ignore_int)
// if (lp().has_fixed_at_bound()) // explain and propagate.
#if 0
m_dist.reset();
m_dist.push(0, 1);
m_dist.push(1, 1);
m_dist.push(2, 1);
for (auto idx : m_dist) {
if (!m.inc())
return FC_GIVEUP;
st = FC_CONTINUE;
break;
switch (idx) {
case 0:
if (assume_eqs())
st = FC_CONTINUE;
break;
case 1:
st = check_nla();
break;
case 2:
st = check_lia();
break;
default:
UNREACHABLE();
break;
}
switch (st) {
case FC_DONE:
break;
case FC_CONTINUE:
return st;
case FC_GIVEUP:
giveup = true;
break;
}
}
switch (check_nla()) {
case l_true:
break;
case l_false:
return FC_CONTINUE;
case l_undef:
TRACE("arith", tout << "check-nra giveup\n";);
st = FC_GIVEUP;
break;
}
#else
if (delayed_assume_eqs()) {
++m_stats.m_assume_eqs;
return FC_CONTINUE;
}
if (assume_eqs()) {
++m_stats.m_assume_eqs;
return FC_CONTINUE;
do {
if (!m.inc())
return FC_GIVEUP;
switch (m_final_check_idx) {
case 0:
if (assume_eqs())
st = FC_CONTINUE;
break;
case 1:
st = check_lia();
break;
case 2:
st = check_nla();
break;
}
m_final_check_idx = (m_final_check_idx + 1) % 3;
switch (st) {
case FC_DONE:
break;
case FC_CONTINUE:
return st;
case FC_GIVEUP:
giveup = true;
break;
}
}
while (old_idx != m_final_check_idx);
#endif
if (giveup)
return FC_GIVEUP;
for (expr* e : m_not_handled) {
if (!ctx().is_relevant(e))
continue;
st = FC_DONE;
switch (eval_unsupported(e)) {
case FC_CONTINUE:
st = FC_CONTINUE;
break;
case FC_GIVEUP:
TRACE("arith", tout << "give up " << mk_pp(e, m) << "\n");
if (st != FC_CONTINUE)
st = FC_GIVEUP;
break;
@ -1894,21 +1966,19 @@ public:
visitor.display_asserts(out, fmls, true);
out << "(check-sat)\n";
}
lbool check_lia() {
final_check_status check_lia() {
TRACE("arith",);
if (!m.inc()) {
TRACE("arith", tout << "canceled\n";);
return l_undef;
return FC_CONTINUE;
}
lbool lia_check = l_undef;
auto cr = m_lia->check(&m_explanation);
if (cr != lp::lia_move::sat && ctx().get_fparams().m_arith_ignore_int)
return l_undef;
return FC_GIVEUP;
switch (cr) {
case lp::lia_move::sat:
lia_check = l_true;
break;
case lp::lia_move::branch: {
@ -1931,13 +2001,12 @@ public:
// TBD: ctx().force_phase(ctx().get_literal(b));
// at this point we have a new unassigned atom that the
// SAT core assigns a value to
lia_check = l_false;
++m_stats.m_branch;
break;
return FC_CONTINUE;
}
case lp::lia_move::cut: {
if (ctx().get_fparams().m_arith_ignore_int)
return l_undef;
return FC_GIVEUP;
TRACE("arith", tout << "cut\n";);
++m_stats.m_gomory_cuts;
// m_explanation implies term <= k
@ -1959,28 +2028,28 @@ public:
ctx().display_lemma_as_smt_problem(tout << "new cut:\n", m_core.size(), m_core.data(), m_eqs.size(), m_eqs.data(), lit);
display(tout););
assign(lit, m_core, m_eqs, m_params);
lia_check = l_false;
break;
return FC_CONTINUE;
}
case lp::lia_move::conflict:
TRACE("arith", tout << "conflict\n";);
// ex contains unsat core
set_conflict();
return l_false;
return FC_CONTINUE;
case lp::lia_move::undef:
TRACE("arith", tout << "lia undef\n";);
lia_check = l_undef;
break;
return FC_CONTINUE;
case lp::lia_move::continue_with_check:
lia_check = l_undef;
break;
return FC_CONTINUE;
default:
UNREACHABLE();
}
if (lia_check != l_false && !check_idiv_bounds())
return l_false;
if (!check_idiv_bounds())
return FC_CONTINUE;
return lia_check;
if (assume_eqs())
return FC_CONTINUE;
return FC_DONE;
}
nla::lemma m_lemma;
@ -2017,36 +2086,31 @@ public:
set_conflict_or_lemma(core, false);
}
lbool check_nla_continue() {
final_check_status check_nla_continue() {
m_a1 = nullptr; m_a2 = nullptr;
lbool r = m_nla->check(m_nla_lemma_vector);
switch (r) {
case l_false: {
case l_false:
for (const nla::lemma & l : m_nla_lemma_vector)
false_case_of_check_nla(l);
break;
}
false_case_of_check_nla(l);
return FC_CONTINUE;
case l_true:
if (assume_eqs()) {
return l_false;
}
break;
case l_undef:
break;
return assume_eqs()? FC_CONTINUE: FC_DONE;
default:
return FC_GIVEUP;
}
return r;
}
lbool check_nla() {
final_check_status check_nla() {
if (!m.inc()) {
TRACE("arith", tout << "canceled\n";);
return l_undef;
return FC_GIVEUP;
}
CTRACE("arith",!m_nla, tout << "no nla\n";);
if (!m_nla)
return l_true;
return FC_DONE;
if (!m_nla->need_check())
return l_true;
return FC_DONE;
return check_nla_continue();
}
@ -2168,7 +2232,6 @@ public:
set_evidence(j, m_core, m_eqs);
m_explanation.add_pair(j, v);
}
void propagate_bounds_with_lp_solver() {
if (!should_propagate())
@ -2182,13 +2245,16 @@ public:
if (is_infeasible()) {
get_infeasibility_explanation_and_set_conflict();
// verbose_stream() << "unsat\n";
}
else {
unsigned count = 0, prop = 0;
for (auto& ib : m_bp.ibounds()) {
m.inc();
if (ctx().inconsistent())
break;
propagate_lp_solver_bound(ib);
++prop;
count += propagate_lp_solver_bound(ib);
}
}
}
@ -2209,12 +2275,14 @@ public:
return false;
}
void propagate_lp_solver_bound(const lp::implied_bound& be) {
#if 0
unsigned propagate_lp_solver_bound_dry_run(const lp::implied_bound& be) {
lpvar vi = be.m_j;
theory_var v = lp().local_to_external(vi);
if (v == null_theory_var)
return;
return 0;
TRACE("arith", tout << "v" << v << " " << be.kind() << " " << be.m_bound << "\n";);
@ -2222,20 +2290,58 @@ public:
if (m_unassigned_bounds[v] == 0 && !should_refine_bounds()) {
TRACE("arith", tout << "return\n";);
return;
return 0;
}
lp_bounds const& bounds = m_bounds[v];
bool first = true;
unsigned count = 0;
for (unsigned i = 0; i < bounds.size(); ++i) {
api_bound* b = bounds[i];
if (ctx().get_assignment(b->get_lit()) != l_undef) {
if (ctx().get_assignment(b->get_lit()) != l_undef)
continue;
}
literal lit = is_bound_implied(be.kind(), be.m_bound, *b);
if (lit == null_literal) {
if (lit == null_literal)
continue;
}
TRACE("arith", tout << lit << " bound: " << *b << " first: " << first << "\n";);
ctx().display_literal_verbose(verbose_stream() << "miss ", lit) << "\n";
display(verbose_stream());
TRACE("arith", ctx().display_literal_verbose(tout << "miss ", lit) << "\n");
exit(0);
++count;
}
return count;
}
#endif
unsigned propagate_lp_solver_bound(const lp::implied_bound& be) {
lpvar vi = be.m_j;
theory_var v = lp().local_to_external(vi);
if (v == null_theory_var)
return 0;
TRACE("arith", tout << "v" << v << " " << be.kind() << " " << be.m_bound << "\n";);
reserve_bounds(v);
if (m_unassigned_bounds[v] == 0 && !should_refine_bounds()) {
TRACE("arith", tout << "return\n";);
return 0;
}
lp_bounds const& bounds = m_bounds[v];
bool first = true;
unsigned count = 0;
for (unsigned i = 0; i < bounds.size(); ++i) {
api_bound* b = bounds[i];
if (ctx().get_assignment(b->get_lit()) != l_undef)
continue;
literal lit = is_bound_implied(be.kind(), be.m_bound, *b);
if (lit == null_literal)
continue;
TRACE("arith", tout << lit << " bound: " << *b << " first: " << first << "\n";);
++count;
lp().settings().stats().m_num_of_implied_bounds ++;
if (first) {
@ -2254,6 +2360,8 @@ public:
display_evidence(tout, m_explanation);
lp().print_implied_bound(be, tout);
);
DEBUG_CODE(
for (auto& lit : m_core) {
VERIFY(ctx().get_assignment(lit) == l_true);
@ -2263,7 +2371,9 @@ public:
}
if (should_refine_bounds() && first)
refine_bound(v, be);
refine_bound(v, be);
return count;
}
void refine_bound(theory_var v, const lp::implied_bound& be) {
@ -2887,7 +2997,7 @@ public:
propagate_eqs(b.tv(), ci, k, b, value.get_rational());
}
#if 0
if (propagation_mode() != BP_NONE)
if (should_propagate())
lp().mark_rows_for_bound_prop(b.tv().id());
#endif
}
@ -3125,7 +3235,7 @@ public:
return l_false;
TRACE("arith", tout << "status treated as inconclusive: " << status << "\n";);
// TENTATIVE_UNBOUNDED, UNBOUNDED, TENTATIVE_DUAL_UNBOUNDED, DUAL_UNBOUNDED,
// FLOATING_POINT_ERROR, TIME_EXAUSTED, EMPTY, UNSTABLE
// TIME_EXAUSTED, EMPTY, UNSTABLE
return l_undef;
}
@ -3908,5 +4018,6 @@ void theory_lra::setup() {
}
template class lp::lp_bound_propagator<smt::theory_lra::imp>;
template void lp::lar_solver::propagate_bounds_for_touched_rows<smt::theory_lra::imp>(lp::lp_bound_propagator<smt::theory_lra::imp>&);
template void lp::lar_solver::check_missed_propagations<smt::theory_lra::imp>(lp::lp_bound_propagator<smt::theory_lra::imp>&);
template void lp::lar_solver::explain_implied_bound<smt::theory_lra::imp>(const lp::implied_bound&, lp::lp_bound_propagator<smt::theory_lra::imp>&);
template void lp::lar_solver::calculate_implied_bounds_for_row<smt::theory_lra::imp>(unsigned int, lp::lp_bound_propagator<smt::theory_lra::imp>&);
template unsigned lp::lar_solver::calculate_implied_bounds_for_row<smt::theory_lra::imp>(unsigned int, lp::lp_bound_propagator<smt::theory_lra::imp>&);

View file

@ -1604,7 +1604,7 @@ namespace smt {
std::cout << B << "\n";
}
#endif
SASSERT(is_sat != l_true);
VERIFY(is_sat != l_true);
return true;
}

View file

@ -71,7 +71,7 @@ namespace smt {
ensure_var(v1);
ensure_var(v2);
literal_vector ls;
ls.push_back(l);
ls.push_back(l);
return m_graph.add_non_strict_edge(v1, v2, ls) && m_graph.add_non_strict_edge(v2, v1, ls);
}
@ -130,6 +130,7 @@ namespace smt {
}
bool theory_special_relations::internalize_term(app * term) {
verbose_stream() << mk_pp(term, m) << "\n";
return false;
}
@ -156,9 +157,8 @@ namespace smt {
}
theory_var theory_special_relations::mk_var(expr* e) {
if (!ctx.e_internalized(e)) {
if (!ctx.e_internalized(e))
ctx.internalize(e, false);
}
enode * n = ctx.get_enode(e);
theory_var v = n->get_th_var(get_id());
if (null_theory_var == v) {
@ -405,6 +405,12 @@ namespace smt {
TRACE("special_relations", tout << "already: " << a.v2() << " <= " << a.v1() << "\n";);
continue;
}
if (a.v1() == a.v2()) {
r.m_explanation.reset();
r.m_explanation.push_back(a.explanation());
set_conflict(r);
return l_false;
}
// the nodes visited from v1 become target for v2
if (r.m_graph.reachable(a.v2(), visited, target, w)) {
//
@ -582,18 +588,18 @@ namespace smt {
lbool theory_special_relations::final_check_po(relation& r) {
for (atom* ap : r.m_asserted_atoms) {
atom& a = *ap;
if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) {
// v1 !-> v2
// find v1 -> v3 -> v4 -> v2 path
r.m_explanation.reset();
unsigned timestamp = r.m_graph.get_timestamp();
bool found_path = r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r);
if (found_path) {
TRACE("special_relations", tout << "check po conflict\n";);
r.m_explanation.push_back(a.explanation());
set_conflict(r);
return l_false;
}
if (a.phase())
continue;
// v1 !-> v2
// find v1 -> v3 -> v4 -> v2 path
r.m_explanation.reset();
unsigned timestamp = r.m_graph.get_timestamp();
bool found_path = a.v1() == a.v2() || r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r);
if (found_path) {
TRACE("special_relations", tout << "check po conflict\n";);
r.m_explanation.push_back(a.explanation());
set_conflict(r);
return l_false;
}
}
return l_true;
@ -601,9 +607,8 @@ namespace smt {
void theory_special_relations::propagate() {
if (m_can_propagate) {
for (auto const& kv : m_relations) {
for (auto const& kv : m_relations)
propagate(*kv.m_value);
}
m_can_propagate = false;
}
}
@ -1124,12 +1129,12 @@ namespace smt {
}
void theory_special_relations::display(std::ostream & out) const {
if (m_relations.empty()) return;
if (m_relations.empty())
return;
out << "Theory Special Relations\n";
display_var2enode(out);
for (auto const& kv : m_relations) {
for (auto const& kv : m_relations)
kv.m_value->display(*this, out);
}
}
void theory_special_relations::collect_asserted_po_atoms(vector<std::pair<bool_var, bool>>& atoms) const {

View file

@ -92,6 +92,9 @@ void theory_user_propagator::propagate_cb(
expr_ref _conseq(conseq, m);
ctx.get_rewriter()(conseq, _conseq);
if (!ctx.get_manager().is_true(_conseq) && !ctx.get_manager().is_false(_conseq))
ctx.mark_as_relevant((expr*)_conseq);
if (ctx.lit_internalized(_conseq) && ctx.get_assignment(ctx.get_literal(_conseq)) == l_true)
return;
m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, _conseq));