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:
commit
f54f33551e
308 changed files with 6606 additions and 18485 deletions
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()):
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>&);
|
||||
|
|
|
@ -1604,7 +1604,7 @@ namespace smt {
|
|||
std::cout << B << "\n";
|
||||
}
|
||||
#endif
|
||||
SASSERT(is_sat != l_true);
|
||||
VERIFY(is_sat != l_true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue