mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
Merge branch 'upstream-master' into release-1.0
Conflicts: src/cmd_context/check_logic.cpp src/cmd_context/cmd_context.cpp src/cmd_context/cmd_context.h src/smt/params/smt_params_helper.pyg src/smt/smt_context.cpp
This commit is contained in:
commit
235ea79043
588 changed files with 21784 additions and 15202 deletions
|
@ -264,7 +264,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
void arith_eq_adapter::collect_statistics(::statistics & st) const {
|
||||
st.update("eq adapter", m_stats.m_num_eq_axioms);
|
||||
st.update("arith eq adapter", m_stats.m_num_eq_axioms);
|
||||
}
|
||||
|
||||
void arith_eq_adapter::display_already_processed(std::ostream & out) const {
|
||||
|
|
|
@ -113,6 +113,8 @@ unsigned arith_eq_solver::find_abs_min(vector<numeral>& values) {
|
|||
return index;
|
||||
}
|
||||
|
||||
#ifdef _TRACE
|
||||
|
||||
static void print_row(std::ostream& out, vector<rational> const& row) {
|
||||
for(unsigned i = 0; i < row.size(); ++i) {
|
||||
out << row[i] << " ";
|
||||
|
@ -125,6 +127,7 @@ static void print_rows(std::ostream& out, vector<vector<rational> > const& rows)
|
|||
print_row(out, rows[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// The gcd of the coefficients to variables have to divide the
|
||||
|
|
|
@ -184,13 +184,13 @@ void asserted_formulas::get_assertions(ptr_vector<expr> & result) {
|
|||
}
|
||||
|
||||
void asserted_formulas::push_scope() {
|
||||
SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size());
|
||||
SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size() || m_manager.canceled());
|
||||
TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout););
|
||||
m_scopes.push_back(scope());
|
||||
m_macro_manager.push_scope();
|
||||
scope & s = m_scopes.back();
|
||||
s.m_asserted_formulas_lim = m_asserted_formulas.size();
|
||||
SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead);
|
||||
SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead || m_manager.canceled());
|
||||
s.m_inconsistent_old = m_inconsistent;
|
||||
m_defined_names.push();
|
||||
m_bv_sharing.push_scope();
|
||||
|
@ -543,8 +543,12 @@ void asserted_formulas::infer_patterns() {
|
|||
}
|
||||
|
||||
void asserted_formulas::commit() {
|
||||
m_macro_manager.mark_forbidden(m_asserted_formulas.size() - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead);
|
||||
m_asserted_qhead = m_asserted_formulas.size();
|
||||
commit(m_asserted_formulas.size());
|
||||
}
|
||||
|
||||
void asserted_formulas::commit(unsigned new_qhead) {
|
||||
m_macro_manager.mark_forbidden(new_qhead - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead);
|
||||
m_asserted_qhead = new_qhead;
|
||||
}
|
||||
|
||||
void asserted_formulas::eliminate_term_ite() {
|
||||
|
|
|
@ -113,6 +113,7 @@ public:
|
|||
unsigned get_formulas_last_level() const;
|
||||
unsigned get_qhead() const { return m_asserted_qhead; }
|
||||
void commit();
|
||||
void commit(unsigned new_qhead);
|
||||
expr * get_formula(unsigned idx) const { return m_asserted_formulas.get(idx); }
|
||||
proof * get_formula_proof(unsigned idx) const { return m_manager.proofs_enabled() ? m_asserted_formula_prs.get(idx) : 0; }
|
||||
expr * const * get_formulas() const { return m_asserted_formulas.c_ptr(); }
|
||||
|
|
|
@ -424,7 +424,7 @@ namespace smt {
|
|||
out << *curr;
|
||||
curr = curr->m_next;
|
||||
while (curr != 0 && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) {
|
||||
out << " ";
|
||||
out << "\n";
|
||||
out << *curr;
|
||||
curr = curr->m_next;
|
||||
}
|
||||
|
@ -490,6 +490,7 @@ namespace smt {
|
|||
#ifdef _PROFILE_MAM
|
||||
m_counter = 0;
|
||||
#endif
|
||||
(void)m_lbl_hasher;
|
||||
}
|
||||
|
||||
#ifdef _PROFILE_MAM
|
||||
|
@ -795,7 +796,8 @@ namespace smt {
|
|||
code_tree * m_tree;
|
||||
unsigned m_num_choices;
|
||||
bool m_is_tmp_tree;
|
||||
svector<unsigned> m_mp_already_processed;
|
||||
svector<bool> m_mp_already_processed;
|
||||
obj_map<expr, unsigned> m_matched_exprs;
|
||||
|
||||
struct pcheck_checked {
|
||||
func_decl * m_label;
|
||||
|
@ -879,6 +881,9 @@ namespace smt {
|
|||
*/
|
||||
void get_stats_core(app * n, unsigned & sz, unsigned & num_unbound_vars) {
|
||||
sz++;
|
||||
if (n->is_ground()) {
|
||||
return;
|
||||
}
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = n->get_arg(i);
|
||||
|
@ -901,7 +906,7 @@ namespace smt {
|
|||
void get_stats(app * n, unsigned & sz, unsigned & num_unbound_vars) {
|
||||
sz = 0;
|
||||
num_unbound_vars = 0;
|
||||
return get_stats_core(n, sz, num_unbound_vars);
|
||||
get_stats_core(n, sz, num_unbound_vars);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -948,7 +953,15 @@ namespace smt {
|
|||
set_check_mark(reg, NOT_CHECKED); // reset mark, register was fully processed.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
unsigned matched_reg;
|
||||
if (m_matched_exprs.find(p, matched_reg) && reg != matched_reg) {
|
||||
m_seq.push_back(m_ct_manager.mk_compare(matched_reg, reg));
|
||||
set_check_mark(reg, NOT_CHECKED); // reset mark, register was fully processed.
|
||||
continue;
|
||||
}
|
||||
m_matched_exprs.insert(p, reg);
|
||||
|
||||
if (m_use_filters && get_check_mark(reg) != CHECK_SINGLETON) {
|
||||
func_decl * lbl = to_app(p)->get_decl();
|
||||
approx_set s(m_lbl_hasher(lbl));
|
||||
|
@ -1032,6 +1045,9 @@ namespace smt {
|
|||
*/
|
||||
unsigned get_num_bound_vars_core(app * n, bool & has_unbound_vars) {
|
||||
unsigned r = 0;
|
||||
if (n->is_ground()) {
|
||||
return 0;
|
||||
}
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = n->get_arg(i);
|
||||
|
@ -1100,7 +1116,7 @@ namespace smt {
|
|||
unsigned best_j = 0;
|
||||
bool found_bounded_mp = false;
|
||||
for (unsigned j = 0; j < m_mp->get_num_args(); j++) {
|
||||
if (std::find(m_mp_already_processed.begin(), m_mp_already_processed.end(), j) != m_mp_already_processed.end())
|
||||
if (m_mp_already_processed[j])
|
||||
continue;
|
||||
app * p = to_app(m_mp->get_arg(j));
|
||||
bool has_unbound_vars = false;
|
||||
|
@ -1117,7 +1133,7 @@ namespace smt {
|
|||
best_j = j;
|
||||
}
|
||||
}
|
||||
m_mp_already_processed.push_back(best_j);
|
||||
m_mp_already_processed[best_j] = true;
|
||||
SASSERT(best != 0);
|
||||
app * p = best;
|
||||
func_decl * lbl = p->get_decl();
|
||||
|
@ -1210,13 +1226,16 @@ namespace smt {
|
|||
*/
|
||||
void linearise(instruction * head, unsigned first_idx) {
|
||||
m_seq.reset();
|
||||
m_mp_already_processed.reset();
|
||||
m_mp_already_processed.push_back(first_idx);
|
||||
m_matched_exprs.reset();
|
||||
while (!m_todo.empty())
|
||||
linearise_core();
|
||||
|
||||
if (m_mp->get_num_args() > 1)
|
||||
if (m_mp->get_num_args() > 1) {
|
||||
m_mp_already_processed.reset();
|
||||
m_mp_already_processed.resize(m_mp->get_num_args());
|
||||
m_mp_already_processed[first_idx] = true;
|
||||
linearise_multi_pattern(first_idx);
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
for (unsigned i = 0; i < m_qa->get_num_decls(); i++) {
|
||||
|
@ -1305,9 +1324,6 @@ namespace smt {
|
|||
unsigned reg2 = instr->m_reg2;
|
||||
return
|
||||
m_registers[reg1] != 0 &&
|
||||
m_registers[reg2] != 0 &&
|
||||
is_var(m_registers[reg1]) &&
|
||||
is_var(m_registers[reg2]) &&
|
||||
m_registers[reg1] == m_registers[reg2];
|
||||
}
|
||||
|
||||
|
@ -1565,12 +1581,13 @@ namespace smt {
|
|||
unsigned reg1 = static_cast<compare*>(curr)->m_reg1;
|
||||
unsigned reg2 = static_cast<compare*>(curr)->m_reg2;
|
||||
SASSERT(m_todo.contains(reg2));
|
||||
m_todo.erase(reg1);
|
||||
m_todo.erase(reg2);
|
||||
SASSERT(is_var(m_registers[reg1]));
|
||||
unsigned var_id = to_var(m_registers[reg1])->get_idx();
|
||||
if (m_vars[var_id] == -1)
|
||||
m_vars[var_id] = reg1;
|
||||
if (is_var(m_registers[reg1])) {
|
||||
m_todo.erase(reg1);
|
||||
unsigned var_id = to_var(m_registers[reg1])->get_idx();
|
||||
if (m_vars[var_id] == -1)
|
||||
m_vars[var_id] = reg1;
|
||||
}
|
||||
m_compatible.push_back(curr);
|
||||
}
|
||||
else {
|
||||
|
@ -2147,7 +2164,7 @@ namespace smt {
|
|||
enode_vector * best_v = 0;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
enode * bare = c->m_joints[i];
|
||||
enode_vector * curr_v;
|
||||
enode_vector * curr_v = 0;
|
||||
switch (GET_TAG(bare)) {
|
||||
case NULL_TAG:
|
||||
curr_v = 0;
|
||||
|
@ -2865,6 +2882,7 @@ namespace smt {
|
|||
- first_idx: index to be used as head of the multi-pattern mp
|
||||
*/
|
||||
void add_pattern(quantifier * qa, app * mp, unsigned first_idx) {
|
||||
(void)m_ast_manager;
|
||||
SASSERT(m_ast_manager.is_pattern(mp));
|
||||
SASSERT(first_idx < mp->get_num_args());
|
||||
app * p = to_app(mp->get_arg(first_idx));
|
||||
|
|
|
@ -28,3 +28,14 @@ void dyn_ack_params::updt_params(params_ref const & _p) {
|
|||
m_dack_gc = p.dack_gc();
|
||||
m_dack_gc_inv_decay = p.dack_gc_inv_decay();
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void dyn_ack_params::display(std::ostream & out) const {
|
||||
DISPLAY_PARAM(m_dack);
|
||||
DISPLAY_PARAM(m_dack_eq);
|
||||
DISPLAY_PARAM(m_dack_factor);
|
||||
DISPLAY_PARAM(m_dack_threshold);
|
||||
DISPLAY_PARAM(m_dack_gc);
|
||||
DISPLAY_PARAM(m_dack_gc_inv_decay);
|
||||
}
|
|
@ -47,6 +47,8 @@ public:
|
|||
}
|
||||
|
||||
void updt_params(params_ref const & _p);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -32,3 +32,33 @@ void preprocessor_params::updt_params(params_ref const & p) {
|
|||
arith_simplifier_params::updt_params(p);
|
||||
updt_local_params(p);
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void preprocessor_params::display(std::ostream & out) const {
|
||||
pattern_inference_params::display(out);
|
||||
bit_blaster_params::display(out);
|
||||
bv_simplifier_params::display(out);
|
||||
arith_simplifier_params::display(out);
|
||||
|
||||
DISPLAY_PARAM(m_lift_ite);
|
||||
DISPLAY_PARAM(m_ng_lift_ite);
|
||||
DISPLAY_PARAM(m_pull_cheap_ite_trees);
|
||||
DISPLAY_PARAM(m_pull_nested_quantifiers);
|
||||
DISPLAY_PARAM(m_eliminate_term_ite);
|
||||
DISPLAY_PARAM(m_eliminate_and);
|
||||
DISPLAY_PARAM(m_macro_finder);
|
||||
DISPLAY_PARAM(m_propagate_values);
|
||||
DISPLAY_PARAM(m_propagate_booleans);
|
||||
DISPLAY_PARAM(m_refine_inj_axiom);
|
||||
DISPLAY_PARAM(m_eliminate_bounds);
|
||||
DISPLAY_PARAM(m_simplify_bit2int);
|
||||
DISPLAY_PARAM(m_nnf_cnf);
|
||||
DISPLAY_PARAM(m_distribute_forall);
|
||||
DISPLAY_PARAM(m_reduce_args);
|
||||
DISPLAY_PARAM(m_quasi_macros);
|
||||
DISPLAY_PARAM(m_restricted_quasi_macros);
|
||||
DISPLAY_PARAM(m_max_bv_sharing);
|
||||
DISPLAY_PARAM(m_pre_simplifier);
|
||||
DISPLAY_PARAM(m_nlquant_elim);
|
||||
}
|
||||
|
|
|
@ -83,6 +83,8 @@ public:
|
|||
void updt_local_params(params_ref const & p);
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
#endif /* PREPROCESSOR_PARAMS_H_ */
|
||||
|
|
|
@ -36,3 +36,30 @@ void qi_params::updt_params(params_ref const & _p) {
|
|||
m_qi_cost = p.qi_cost();
|
||||
m_qi_max_eager_multipatterns = p.qi_max_multi_patterns();
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void qi_params::display(std::ostream & out) const {
|
||||
DISPLAY_PARAM(m_qi_ematching);
|
||||
DISPLAY_PARAM(m_qi_cost);
|
||||
DISPLAY_PARAM(m_qi_new_gen);
|
||||
DISPLAY_PARAM(m_qi_eager_threshold);
|
||||
DISPLAY_PARAM(m_qi_lazy_threshold);
|
||||
DISPLAY_PARAM(m_qi_max_eager_multipatterns);
|
||||
DISPLAY_PARAM(m_qi_max_lazy_multipattern_matching);
|
||||
DISPLAY_PARAM(m_qi_profile);
|
||||
DISPLAY_PARAM(m_qi_profile_freq);
|
||||
DISPLAY_PARAM(m_qi_quick_checker);
|
||||
DISPLAY_PARAM(m_qi_lazy_quick_checker);
|
||||
DISPLAY_PARAM(m_qi_promote_unsat);
|
||||
DISPLAY_PARAM(m_qi_max_instances);
|
||||
DISPLAY_PARAM(m_qi_lazy_instantiation);
|
||||
DISPLAY_PARAM(m_qi_conservative_final_check);
|
||||
DISPLAY_PARAM(m_mbqi);
|
||||
DISPLAY_PARAM(m_mbqi_max_cexs);
|
||||
DISPLAY_PARAM(m_mbqi_max_cexs_incr);
|
||||
DISPLAY_PARAM(m_mbqi_max_iterations);
|
||||
DISPLAY_PARAM(m_mbqi_trace);
|
||||
DISPLAY_PARAM(m_mbqi_force_template);
|
||||
DISPLAY_PARAM(m_mbqi_id);
|
||||
}
|
||||
|
|
|
@ -98,13 +98,15 @@ struct qi_params {
|
|||
m_mbqi_max_cexs_incr(1),
|
||||
m_mbqi_max_iterations(1000),
|
||||
m_mbqi_trace(false),
|
||||
m_mbqi_force_template(10),
|
||||
m_mbqi_force_template(10),
|
||||
m_mbqi_id(0)
|
||||
{
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
#endif /* QI_PARAMS_H_ */
|
||||
|
|
|
@ -65,3 +65,96 @@ void smt_params::updt_params(context_params const & p) {
|
|||
m_auto_config = p.m_auto_config;
|
||||
m_model = p.m_model;
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void smt_params::display(std::ostream & out) const {
|
||||
preprocessor_params::display(out);
|
||||
dyn_ack_params::display(out);
|
||||
qi_params::display(out);
|
||||
theory_arith_params::display(out);
|
||||
theory_array_params::display(out);
|
||||
theory_bv_params::display(out);
|
||||
theory_pb_params::display(out);
|
||||
theory_datatype_params::display(out);
|
||||
|
||||
DISPLAY_PARAM(m_display_proof);
|
||||
DISPLAY_PARAM(m_display_dot_proof);
|
||||
DISPLAY_PARAM(m_display_unsat_core);
|
||||
DISPLAY_PARAM(m_check_proof);
|
||||
DISPLAY_PARAM(m_eq_propagation);
|
||||
DISPLAY_PARAM(m_binary_clause_opt);
|
||||
DISPLAY_PARAM(m_relevancy_lvl);
|
||||
DISPLAY_PARAM(m_relevancy_lemma);
|
||||
DISPLAY_PARAM(m_random_seed);
|
||||
DISPLAY_PARAM(m_random_var_freq);
|
||||
DISPLAY_PARAM(m_inv_decay);
|
||||
DISPLAY_PARAM(m_clause_decay);
|
||||
DISPLAY_PARAM(m_random_initial_activity);
|
||||
DISPLAY_PARAM(m_phase_selection);
|
||||
DISPLAY_PARAM(m_phase_caching_on);
|
||||
DISPLAY_PARAM(m_phase_caching_off);
|
||||
DISPLAY_PARAM(m_minimize_lemmas);
|
||||
DISPLAY_PARAM(m_max_conflicts);
|
||||
DISPLAY_PARAM(m_simplify_clauses);
|
||||
DISPLAY_PARAM(m_tick);
|
||||
DISPLAY_PARAM(m_display_features);
|
||||
DISPLAY_PARAM(m_new_core2th_eq);
|
||||
DISPLAY_PARAM(m_ematching);
|
||||
|
||||
DISPLAY_PARAM(m_case_split_strategy);
|
||||
DISPLAY_PARAM(m_rel_case_split_order);
|
||||
DISPLAY_PARAM(m_lookahead_diseq);
|
||||
|
||||
DISPLAY_PARAM(m_delay_units);
|
||||
DISPLAY_PARAM(m_delay_units_threshold);
|
||||
|
||||
DISPLAY_PARAM(m_theory_resolve);
|
||||
|
||||
DISPLAY_PARAM(m_restart_strategy);
|
||||
DISPLAY_PARAM(m_restart_initial);
|
||||
DISPLAY_PARAM(m_restart_factor);
|
||||
DISPLAY_PARAM(m_restart_adaptive);
|
||||
DISPLAY_PARAM(m_agility_factor);
|
||||
DISPLAY_PARAM(m_restart_agility_threshold);
|
||||
|
||||
DISPLAY_PARAM(m_lemma_gc_strategy);
|
||||
DISPLAY_PARAM(m_lemma_gc_half);
|
||||
DISPLAY_PARAM(m_recent_lemmas_size);
|
||||
DISPLAY_PARAM(m_lemma_gc_initial);
|
||||
DISPLAY_PARAM(m_lemma_gc_factor);
|
||||
DISPLAY_PARAM(m_new_old_ratio);
|
||||
DISPLAY_PARAM(m_new_clause_activity);
|
||||
DISPLAY_PARAM(m_old_clause_activity);
|
||||
DISPLAY_PARAM(m_new_clause_relevancy);
|
||||
DISPLAY_PARAM(m_old_clause_relevancy);
|
||||
DISPLAY_PARAM(m_inv_clause_decay);
|
||||
|
||||
DISPLAY_PARAM(m_smtlib_dump_lemmas);
|
||||
DISPLAY_PARAM(m_logic);
|
||||
|
||||
DISPLAY_PARAM(m_profile_res_sub);
|
||||
DISPLAY_PARAM(m_display_bool_var2expr);
|
||||
DISPLAY_PARAM(m_display_ll_bool_var2expr);
|
||||
DISPLAY_PARAM(m_abort_after_preproc);
|
||||
|
||||
DISPLAY_PARAM(m_model);
|
||||
DISPLAY_PARAM(m_model_compact);
|
||||
DISPLAY_PARAM(m_model_on_timeout);
|
||||
DISPLAY_PARAM(m_model_on_final_check);
|
||||
|
||||
DISPLAY_PARAM(m_progress_sampling_freq);
|
||||
|
||||
DISPLAY_PARAM(m_display_installed_theories);
|
||||
DISPLAY_PARAM(m_core_validate);
|
||||
|
||||
DISPLAY_PARAM(m_preprocess);
|
||||
DISPLAY_PARAM(m_user_theory_preprocess_axioms);
|
||||
DISPLAY_PARAM(m_user_theory_persist_axioms);
|
||||
DISPLAY_PARAM(m_timeout);
|
||||
DISPLAY_PARAM(m_rlimit);
|
||||
DISPLAY_PARAM(m_at_labels_cex);
|
||||
DISPLAY_PARAM(m_check_at_labels);
|
||||
DISPLAY_PARAM(m_dump_goal_as_smt);
|
||||
DISPLAY_PARAM(m_auto_config);
|
||||
}
|
|
@ -295,6 +295,8 @@ struct smt_params : public preprocessor_params,
|
|||
void updt_params(params_ref const & p);
|
||||
|
||||
void updt_params(context_params const & p);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
#endif /* SMT_PARAMS_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
def_module_params(module_name='smt',
|
||||
def_module_params(module_name='smt',
|
||||
class_name='smt_params_helper',
|
||||
description='smt solver based on lazy smt',
|
||||
export=True,
|
||||
|
@ -13,11 +13,11 @@ def_module_params(module_name='smt',
|
|||
('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the currect restart threshold'),
|
||||
('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal'),
|
||||
('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'),
|
||||
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ingored if delay_units is false'),
|
||||
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'),
|
||||
('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'),
|
||||
('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'),
|
||||
('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (0 means immediate timeout)'),
|
||||
('rlimit', UINT, 0, 'resource limit (0 means no limit)'),
|
||||
('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'),
|
||||
('rlimit', UINT, 0, 'resource limit (0 means no limit)'),
|
||||
('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts before giving up.'),
|
||||
('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'),
|
||||
('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'),
|
||||
|
@ -74,5 +74,8 @@ def_module_params(module_name='smt',
|
|||
('theory_case_split', BOOL, False, 'Allow the context to use heuristics involving theory case splits, which are a set of literals of which exactly one can be assigned True. If this option is false, the context will generate extra axioms to enforce this instead.'),
|
||||
('theory_aware_branching', BOOL, False, 'Allow the context to use extra information from theory solvers regarding literal branching prioritization.'),
|
||||
('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'),
|
||||
('str.overlap_priority', DOUBLE, -0.1, 'theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true')
|
||||
('str.overlap_priority', DOUBLE, -0.1, 'theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true'),
|
||||
('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'),
|
||||
('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'),
|
||||
('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core')
|
||||
))
|
||||
|
|
|
@ -38,3 +38,51 @@ void theory_arith_params::updt_params(params_ref const & _p) {
|
|||
}
|
||||
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void theory_arith_params::display(std::ostream & out) const {
|
||||
DISPLAY_PARAM(m_arith_mode);
|
||||
DISPLAY_PARAM(m_arith_auto_config_simplex); //!< force simplex solver in auto_config
|
||||
DISPLAY_PARAM(m_arith_blands_rule_threshold);
|
||||
DISPLAY_PARAM(m_arith_propagate_eqs);
|
||||
DISPLAY_PARAM(m_arith_bound_prop);
|
||||
DISPLAY_PARAM(m_arith_stronger_lemmas);
|
||||
DISPLAY_PARAM(m_arith_skip_rows_with_big_coeffs);
|
||||
DISPLAY_PARAM(m_arith_max_lemma_size);
|
||||
DISPLAY_PARAM(m_arith_small_lemma_size);
|
||||
DISPLAY_PARAM(m_arith_reflect);
|
||||
DISPLAY_PARAM(m_arith_ignore_int);
|
||||
DISPLAY_PARAM(m_arith_lazy_pivoting_lvl);
|
||||
DISPLAY_PARAM(m_arith_random_seed);
|
||||
DISPLAY_PARAM(m_arith_random_initial_value);
|
||||
DISPLAY_PARAM(m_arith_random_lower);
|
||||
DISPLAY_PARAM(m_arith_random_upper);
|
||||
DISPLAY_PARAM(m_arith_adaptive);
|
||||
DISPLAY_PARAM(m_arith_adaptive_assertion_threshold);
|
||||
DISPLAY_PARAM(m_arith_adaptive_propagation_threshold);
|
||||
DISPLAY_PARAM(m_arith_dump_lemmas);
|
||||
DISPLAY_PARAM(m_arith_eager_eq_axioms);
|
||||
DISPLAY_PARAM(m_arith_branch_cut_ratio);
|
||||
DISPLAY_PARAM(m_arith_int_eq_branching);
|
||||
DISPLAY_PARAM(m_arith_enum_const_mod);
|
||||
DISPLAY_PARAM(m_arith_gcd_test);
|
||||
DISPLAY_PARAM(m_arith_eager_gcd);
|
||||
DISPLAY_PARAM(m_arith_adaptive_gcd);
|
||||
DISPLAY_PARAM(m_arith_propagation_threshold);
|
||||
DISPLAY_PARAM(m_arith_pivot_strategy);
|
||||
DISPLAY_PARAM(m_arith_add_binary_bounds);
|
||||
DISPLAY_PARAM(m_arith_propagation_strategy);
|
||||
DISPLAY_PARAM(m_arith_eq_bounds);
|
||||
DISPLAY_PARAM(m_arith_lazy_adapter);
|
||||
DISPLAY_PARAM(m_arith_fixnum);
|
||||
DISPLAY_PARAM(m_arith_int_only);
|
||||
DISPLAY_PARAM(m_nl_arith);
|
||||
DISPLAY_PARAM(m_nl_arith_gb);
|
||||
DISPLAY_PARAM(m_nl_arith_gb_threshold);
|
||||
DISPLAY_PARAM(m_nl_arith_gb_eqs);
|
||||
DISPLAY_PARAM(m_nl_arith_gb_perturbate);
|
||||
DISPLAY_PARAM(m_nl_arith_max_degree);
|
||||
DISPLAY_PARAM(m_nl_arith_branching);
|
||||
DISPLAY_PARAM(m_nl_arith_rounds);
|
||||
DISPLAY_PARAM(m_arith_euclidean_solver);
|
||||
}
|
|
@ -156,6 +156,8 @@ struct theory_arith_params {
|
|||
}
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
#endif /* THEORY_ARITH_PARAMS_H_ */
|
||||
|
|
|
@ -25,4 +25,16 @@ void theory_array_params::updt_params(params_ref const & _p) {
|
|||
m_array_extensional = p.array_extensional();
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void theory_array_params::display(std::ostream & out) const {
|
||||
DISPLAY_PARAM(m_array_mode);
|
||||
DISPLAY_PARAM(m_array_weak);
|
||||
DISPLAY_PARAM(m_array_extensional);
|
||||
DISPLAY_PARAM(m_array_laziness);
|
||||
DISPLAY_PARAM(m_array_delay_exp_axiom);
|
||||
DISPLAY_PARAM(m_array_cg);
|
||||
DISPLAY_PARAM(m_array_always_prop_upward);
|
||||
DISPLAY_PARAM(m_array_lazy_ieq);
|
||||
DISPLAY_PARAM(m_array_lazy_ieq_delay);
|
||||
}
|
|
@ -71,6 +71,7 @@ struct theory_array_params : public array_simplifier_params {
|
|||
}
|
||||
#endif
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -24,3 +24,14 @@ void theory_bv_params::updt_params(params_ref const & _p) {
|
|||
m_bv_reflect = p.bv_reflect();
|
||||
m_bv_enable_int2bv2int = p.bv_enable_int2bv();
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void theory_bv_params::display(std::ostream & out) const {
|
||||
DISPLAY_PARAM(m_bv_mode);
|
||||
DISPLAY_PARAM(m_bv_reflect);
|
||||
DISPLAY_PARAM(m_bv_lazy_le);
|
||||
DISPLAY_PARAM(m_bv_cc);
|
||||
DISPLAY_PARAM(m_bv_blast_max_size);
|
||||
DISPLAY_PARAM(m_bv_enable_int2bv2int);
|
||||
}
|
|
@ -44,6 +44,8 @@ struct theory_bv_params {
|
|||
}
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
#endif /* THEORY_BV_PARAMS_H_ */
|
||||
|
|
|
@ -31,6 +31,8 @@ struct theory_datatype_params {
|
|||
p.register_unsigned_param("dt_lazy_splits", m_dt_lazy_splits, "How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy");
|
||||
}
|
||||
#endif
|
||||
|
||||
void display(std::ostream & out) const { out << "m_dt_lazy_splits=" << m_dt_lazy_splits << std::endl; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -26,3 +26,12 @@ void theory_pb_params::updt_params(params_ref const & _p) {
|
|||
m_pb_enable_compilation = p.pb_enable_compilation();
|
||||
m_pb_enable_simplex = p.pb_enable_simplex();
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
||||
void theory_pb_params::display(std::ostream & out) const {
|
||||
DISPLAY_PARAM(m_pb_conflict_frequency);
|
||||
DISPLAY_PARAM(m_pb_learn_complements);
|
||||
DISPLAY_PARAM(m_pb_enable_compilation);
|
||||
DISPLAY_PARAM(m_pb_enable_simplex);
|
||||
}
|
|
@ -35,6 +35,8 @@ struct theory_pb_params {
|
|||
{}
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
|
||||
#endif /* THEORY_PB_PARAMS_H_ */
|
||||
|
|
|
@ -31,7 +31,7 @@ arith_factory::arith_factory(ast_manager & m):
|
|||
arith_factory::~arith_factory() {
|
||||
}
|
||||
|
||||
app * arith_factory::mk_value(rational const & val, bool is_int) {
|
||||
app * arith_factory::mk_num_value(rational const & val, bool is_int) {
|
||||
return numeral_factory::mk_value(val, is_int ? m_util.mk_int() : m_util.mk_real());
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,6 @@ app * bv_factory::mk_value_core(rational const & val, sort * s) {
|
|||
return m_util.mk_numeral(val, s);
|
||||
}
|
||||
|
||||
app * bv_factory::mk_value(rational const & val, unsigned bv_size) {
|
||||
app * bv_factory::mk_num_value(rational const & val, unsigned bv_size) {
|
||||
return numeral_factory::mk_value(val, m_util.mk_sort(bv_size));
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
arith_factory(ast_manager & m);
|
||||
virtual ~arith_factory();
|
||||
|
||||
app * mk_value(rational const & val, bool is_int);
|
||||
app * mk_num_value(rational const & val, bool is_int);
|
||||
};
|
||||
|
||||
class bv_factory : public numeral_factory {
|
||||
|
@ -50,7 +50,7 @@ public:
|
|||
bv_factory(ast_manager & m);
|
||||
virtual ~bv_factory();
|
||||
|
||||
app * mk_value(rational const & val, unsigned bv_size);
|
||||
app * mk_num_value(rational const & val, unsigned bv_size);
|
||||
};
|
||||
|
||||
#endif /* NUMERAL_FACTORY_H_ */
|
||||
|
|
|
@ -183,7 +183,7 @@ public:
|
|||
sort_info* s_info = s->get_info();
|
||||
sort_size const* sz = s_info?&s_info->get_num_elements():0;
|
||||
bool has_max = false;
|
||||
Number max_size;
|
||||
Number max_size(0);
|
||||
if (sz && sz->is_finite() && sz->size() < UINT_MAX) {
|
||||
unsigned usz = static_cast<unsigned>(sz->size());
|
||||
max_size = Number(usz);
|
||||
|
|
|
@ -363,7 +363,7 @@ namespace smt {
|
|||
<< ", scope_level: " << m_context.get_scope_level() << "\n";);
|
||||
if (m_params.m_qi_conservative_final_check) {
|
||||
bool init = false;
|
||||
float min_cost;
|
||||
float min_cost = 0.0;
|
||||
unsigned sz = m_delayed_entries.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
entry & e = m_delayed_entries[i];
|
||||
|
|
47
src/smt/smt2_extra_cmds.cpp
Normal file
47
src/smt/smt2_extra_cmds.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt2_extra_cmds.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Additional SMT-specific commands.
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2017-01-16
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"cmd_context.h"
|
||||
#include"smt2parser.h"
|
||||
#include"smt2_extra_cmds.h"
|
||||
|
||||
class include_cmd : public cmd {
|
||||
char const * m_filename;
|
||||
public:
|
||||
include_cmd() : cmd("include"), m_filename(0) {}
|
||||
virtual char const * get_usage() const { return "<string>"; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "include a file"; }
|
||||
virtual unsigned get_arity() const { return 1; }
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_STRING; }
|
||||
virtual void set_next_arg(cmd_context & ctx, char const * val) { m_filename = val; }
|
||||
virtual void failure_cleanup(cmd_context & ctx) {}
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
std::ifstream is(m_filename);
|
||||
if (is.bad() || is.fail())
|
||||
throw cmd_exception(std::string("failed to open file '") + m_filename + "'");
|
||||
parse_smt2_commands(ctx, is, false, params_ref(), m_filename);
|
||||
is.close();
|
||||
}
|
||||
virtual void prepare(cmd_context & ctx) { reset(ctx); }
|
||||
virtual void reset(cmd_context & ctx) { m_filename = 0; }
|
||||
virtual void finalize(cmd_context & ctx) { reset(ctx); }
|
||||
};
|
||||
|
||||
void install_smt2_extra_cmds(cmd_context & ctx) {
|
||||
ctx.insert(alloc(include_cmd));
|
||||
}
|
26
src/smt/smt2_extra_cmds.h
Normal file
26
src/smt/smt2_extra_cmds.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt2_extra_cmds.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Additional SMT-specific commands.
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2017-01-16
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef SMT2_EXTRA_CMDS_H_
|
||||
#define SMT2_EXTRA_CMDS_H_
|
||||
|
||||
class cmd_context;
|
||||
|
||||
void install_smt2_extra_cmds(cmd_context & ctx);
|
||||
|
||||
#endif /* SMT2_EXTRA_CMDS_H_ */
|
|
@ -24,7 +24,9 @@ Revision History:
|
|||
namespace smt {
|
||||
|
||||
struct bool_var_data {
|
||||
private:
|
||||
b_justification m_justification;
|
||||
public:
|
||||
unsigned m_scope_lvl:24; //!< scope level of when the variable was assigned.
|
||||
unsigned m_mark:1;
|
||||
unsigned m_assumption:1;
|
||||
|
@ -45,6 +47,14 @@ namespace smt {
|
|||
public:
|
||||
|
||||
unsigned get_intern_level() const { return m_iscope_lvl; }
|
||||
|
||||
b_justification justification() const { return m_justification; }
|
||||
|
||||
void set_axiom() { m_justification = b_justification::mk_axiom(); }
|
||||
|
||||
void set_null_justification() { m_justification = null_b_justification; }
|
||||
|
||||
void set_justification(b_justification const& j) { m_justification = j; }
|
||||
|
||||
bool is_atom() const { return m_atom; }
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@ Revision History:
|
|||
#include"ast_ll_pp.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
||||
// ---------------------------
|
||||
//
|
||||
// Base class
|
||||
//
|
||||
// ---------------------------
|
||||
|
||||
|
||||
conflict_resolution::conflict_resolution(ast_manager & m,
|
||||
context & ctx,
|
||||
dyn_ack_manager & dyn_ack_manager,
|
||||
|
@ -42,7 +42,7 @@ namespace smt {
|
|||
m_dyn_ack_manager(dyn_ack_manager),
|
||||
m_assigned_literals(assigned_literals),
|
||||
m_lemma_atoms(m),
|
||||
m_todo_js_qhead(0),
|
||||
m_todo_js_qhead(0),
|
||||
m_antecedents(0),
|
||||
m_watches(watches),
|
||||
m_new_proofs(m),
|
||||
|
@ -67,7 +67,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
/**
|
||||
\brief Find a common ancestor (anc) of n1 and n2 in the 'proof' tree.
|
||||
\brief Find a common ancestor (anc) of n1 and n2 in the 'proof' tree.
|
||||
The common ancestor is used to produce irredundant transitivity proofs.
|
||||
|
||||
n1 = a1 = ... = ai = ANC = ... = root
|
||||
|
@ -100,7 +100,7 @@ namespace smt {
|
|||
*/
|
||||
void conflict_resolution::eq_justification2literals(enode * lhs, enode * rhs, eq_justification js) {
|
||||
SASSERT(m_antecedents);
|
||||
TRACE("conflict_detail",
|
||||
TRACE("conflict_detail",
|
||||
ast_manager& m = get_manager();
|
||||
tout << mk_pp(lhs->get_owner(), m) << " = " << mk_pp(rhs->get_owner(), m);
|
||||
switch (js.get_kind()) {
|
||||
|
@ -133,7 +133,7 @@ namespace smt {
|
|||
mark_eq(lhs->get_arg(1), rhs->get_arg(0));
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
mark_eq(lhs->get_arg(i), rhs->get_arg(i));
|
||||
}
|
||||
break;
|
||||
|
@ -146,9 +146,9 @@ namespace smt {
|
|||
/**
|
||||
\brief Process the transitivity 'proof' from n1 and n2, where
|
||||
n1 and n2 are in the same branch
|
||||
|
||||
|
||||
n1 -> ... -> n2
|
||||
|
||||
|
||||
This method may update m_antecedents, m_todo_js and m_todo_eqs.
|
||||
|
||||
The resultant set of literals is stored in m_antecedents.
|
||||
|
@ -163,7 +163,7 @@ namespace smt {
|
|||
|
||||
/**
|
||||
\brief Process the justification of n1 = n2.
|
||||
|
||||
|
||||
This method may update m_antecedents, m_todo_js and m_todo_eqs.
|
||||
|
||||
The resultant set of literals is stored in m_antecedents.
|
||||
|
@ -180,13 +180,17 @@ namespace smt {
|
|||
|
||||
The result is stored in result.
|
||||
|
||||
\remark This method does not reset the vectors m_antecedents, m_todo_js, m_todo_eqs, nor reset the
|
||||
marks in the justification objects.
|
||||
\remark This method does not reset the vectors m_antecedents, m_todo_js, m_todo_eqs, nor reset the
|
||||
marks in the justification objects.
|
||||
*/
|
||||
void conflict_resolution::justification2literals_core(justification * js, literal_vector & result) {
|
||||
SASSERT(m_todo_js_qhead <= m_todo_js.size());
|
||||
m_antecedents = &result;
|
||||
mark_justification(js);
|
||||
process_justifications();
|
||||
}
|
||||
|
||||
void conflict_resolution::process_justifications() {
|
||||
while (true) {
|
||||
unsigned sz = m_todo_js.size();
|
||||
while (m_todo_js_qhead < sz) {
|
||||
|
@ -234,6 +238,17 @@ namespace smt {
|
|||
SASSERT(m_todo_eqs.empty());
|
||||
}
|
||||
|
||||
void conflict_resolution::eq2literals(enode* n1, enode* n2, literal_vector & result) {
|
||||
SASSERT(m_todo_js.empty());
|
||||
SASSERT(m_todo_js_qhead == 0);
|
||||
SASSERT(m_todo_eqs.empty());
|
||||
m_antecedents = &result;
|
||||
m_todo_eqs.push_back(enode_pair(n1, n2));
|
||||
process_justifications();
|
||||
unmark_justifications(0);
|
||||
SASSERT(m_todo_eqs.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return maximum scope level of an antecedent literal of js.
|
||||
*/
|
||||
|
@ -279,13 +294,13 @@ namespace smt {
|
|||
if (js)
|
||||
r = std::max(r, get_justification_max_lvl(js));
|
||||
break;
|
||||
}
|
||||
}
|
||||
case b_justification::BIN_CLAUSE:
|
||||
r = std::max(r, m_ctx.get_assign_level(js.get_literal()));
|
||||
break;
|
||||
case b_justification::AXIOM:
|
||||
break;
|
||||
case b_justification::JUSTIFICATION:
|
||||
case b_justification::JUSTIFICATION:
|
||||
r = std::max(r, get_justification_max_lvl(js.get_justification()));
|
||||
break;
|
||||
default:
|
||||
|
@ -298,8 +313,8 @@ namespace smt {
|
|||
bool_var var = antecedent.var();
|
||||
unsigned lvl = m_ctx.get_assign_level(var);
|
||||
SASSERT(var < static_cast<int>(m_ctx.get_num_bool_vars()));
|
||||
TRACE("conflict", tout << "processing antecedent (level " << lvl << "):";
|
||||
m_ctx.display_literal(tout, antecedent);
|
||||
TRACE("conflict", tout << "processing antecedent (level " << lvl << "):";
|
||||
m_ctx.display_literal(tout, antecedent);
|
||||
m_ctx.display_detailed_literal(tout << " ", antecedent); tout << "\n";);
|
||||
|
||||
if (!m_ctx.is_marked(var) && lvl > m_ctx.get_base_level()) {
|
||||
|
@ -371,24 +386,23 @@ namespace smt {
|
|||
consequent = false_literal;
|
||||
if (not_l != null_literal)
|
||||
consequent = ~not_l;
|
||||
|
||||
|
||||
m_conflict_lvl = get_max_lvl(consequent, js);
|
||||
|
||||
TRACE("conflict_bug",
|
||||
tout << "conflict_lvl: " << m_conflict_lvl << " scope_lvl: " << m_ctx.get_scope_level() << " base_lvl: " << m_ctx.get_base_level()
|
||||
TRACE("conflict_bug",
|
||||
tout << "conflict_lvl: " << m_conflict_lvl << " scope_lvl: " << m_ctx.get_scope_level() << " base_lvl: " << m_ctx.get_base_level()
|
||||
<< " search_lvl: " << m_ctx.get_search_level() << "\n";
|
||||
tout << "js.kind: " << js.get_kind() << "\n";
|
||||
tout << "consequent: " << consequent << ": ";
|
||||
m_ctx.display_literal_verbose(tout, consequent); tout << "\n";
|
||||
m_ctx.display(tout, js); tout << "\n";
|
||||
);
|
||||
);
|
||||
|
||||
// m_conflict_lvl can be smaller than m_ctx.get_search_level() when:
|
||||
// there are user level scopes created using the Z3 API, and
|
||||
// the previous levels were already inconsistent, or the inconsistency was
|
||||
// triggered by an axiom or justification proof wrapper, this two kinds
|
||||
// of justification are considered level zero.
|
||||
|
||||
if (m_conflict_lvl <= m_ctx.get_search_level()) {
|
||||
TRACE("conflict", tout << "problem is unsat\n";);
|
||||
if (m_manager.proofs_enabled())
|
||||
|
@ -399,7 +413,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
TRACE("conflict", tout << "conflict_lvl: " << m_conflict_lvl << "\n";);
|
||||
|
||||
|
||||
SASSERT(!m_assigned_literals.empty());
|
||||
|
||||
SASSERT(m_todo_js.empty());
|
||||
|
@ -411,32 +425,32 @@ namespace smt {
|
|||
/**
|
||||
\brief Cleanup datastructures used during resolve(), minimize lemma (when minimization is enabled),
|
||||
compute m_new_scope_lvl and m_lemma_iscope_lvl, generate proof if needed.
|
||||
|
||||
|
||||
This method assumes that the lemma is stored in m_lemma (and the associated atoms in m_lemma_atoms).
|
||||
|
||||
|
||||
\warning This method assumes the literals in m_lemma[1] ... m_lemma[m_lemma.size() - 1] are marked.
|
||||
*/
|
||||
void conflict_resolution::finalize_resolve(b_justification conflict, literal not_l) {
|
||||
unmark_justifications(0);
|
||||
|
||||
|
||||
TRACE("conflict",
|
||||
tout << "before minimization:\n";
|
||||
m_ctx.display_literals(tout, m_lemma);
|
||||
tout << "\n";);
|
||||
|
||||
|
||||
TRACE("conflict_verbose",
|
||||
tout << "before minimization:\n";
|
||||
m_ctx.display_literals_verbose(tout, m_lemma);
|
||||
tout << "\n";);
|
||||
|
||||
|
||||
if (m_params.m_minimize_lemmas)
|
||||
minimize_lemma();
|
||||
|
||||
|
||||
TRACE("conflict",
|
||||
tout << "after minimization:\n";
|
||||
m_ctx.display_literals(tout, m_lemma);
|
||||
tout << "\n";);
|
||||
|
||||
|
||||
TRACE("conflict_verbose",
|
||||
tout << "after minimization:\n";
|
||||
m_ctx.display_literals_verbose(tout, m_lemma);
|
||||
|
@ -445,7 +459,7 @@ namespace smt {
|
|||
TRACE("conflict_bug",
|
||||
m_ctx.display_literals_verbose(tout, m_lemma);
|
||||
tout << "\n";);
|
||||
|
||||
|
||||
literal_vector::iterator it = m_lemma.begin();
|
||||
literal_vector::iterator end = m_lemma.end();
|
||||
m_new_scope_lvl = m_ctx.get_search_level();
|
||||
|
@ -464,11 +478,11 @@ namespace smt {
|
|||
m_lemma_iscope_lvl = lvl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TRACE("conflict",
|
||||
tout << "new scope level: " << m_new_scope_lvl << "\n";
|
||||
tout << "intern. scope level: " << m_lemma_iscope_lvl << "\n";);
|
||||
|
||||
|
||||
if (m_manager.proofs_enabled())
|
||||
mk_conflict_proof(conflict, not_l);
|
||||
}
|
||||
|
@ -482,16 +496,18 @@ namespace smt {
|
|||
|
||||
unsigned idx = skip_literals_above_conflict_level();
|
||||
|
||||
TRACE("conflict", m_ctx.display_literal_verbose(tout, not_l); m_ctx.display(tout << " ", conflict););
|
||||
|
||||
// save space for first uip
|
||||
m_lemma.push_back(null_literal);
|
||||
m_lemma_atoms.push_back(0);
|
||||
|
||||
unsigned num_marks = 0;
|
||||
if (not_l != null_literal) {
|
||||
TRACE("conflict", tout << "not_l: "; m_ctx.display_literal(tout, not_l); tout << "\n";);
|
||||
TRACE("conflict", tout << "not_l: "; m_ctx.display_literal_verbose(tout, not_l); tout << "\n";);
|
||||
process_antecedent(not_l, num_marks);
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
|
||||
if (get_manager().has_trace_stream()) {
|
||||
|
@ -500,7 +516,7 @@ namespace smt {
|
|||
get_manager().trace_stream() << "\n";
|
||||
}
|
||||
|
||||
TRACE("conflict", tout << "processing consequent: "; m_ctx.display_literal(tout, consequent); tout << "\n";
|
||||
TRACE("conflict", tout << "processing consequent: "; m_ctx.display_literal_verbose(tout, consequent); tout << "\n";
|
||||
tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << "\n";);
|
||||
SASSERT(js != null_b_justification);
|
||||
switch (js.get_kind()) {
|
||||
|
@ -528,7 +544,7 @@ namespace smt {
|
|||
process_antecedent(~l, num_marks);
|
||||
}
|
||||
justification * js = cls->get_justification();
|
||||
if (js)
|
||||
if (js)
|
||||
process_justification(js, num_marks);
|
||||
break;
|
||||
}
|
||||
|
@ -544,13 +560,13 @@ namespace smt {
|
|||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
while (true) {
|
||||
literal l = m_assigned_literals[idx];
|
||||
if (m_ctx.is_marked(l.var()))
|
||||
if (m_ctx.is_marked(l.var()))
|
||||
break;
|
||||
CTRACE("conflict", m_ctx.get_assign_level(l) != m_conflict_lvl && m_ctx.get_assign_level(l) != m_ctx.get_base_level(),
|
||||
tout << "assign_level(l): " << m_ctx.get_assign_level(l) << ", conflict_lvl: " << m_conflict_lvl << ", l: "; m_ctx.display_literal(tout, l);
|
||||
tout << "assign_level(l): " << m_ctx.get_assign_level(l) << ", conflict_lvl: " << m_conflict_lvl << ", l: "; m_ctx.display_literal(tout, l);
|
||||
tout << "\n";);
|
||||
SASSERT(m_ctx.get_assign_level(l) == m_conflict_lvl ||
|
||||
// it may also be an (out-of-order) asserted literal
|
||||
|
@ -566,7 +582,7 @@ namespace smt {
|
|||
idx--;
|
||||
num_marks--;
|
||||
m_ctx.unset_mark(c_var);
|
||||
}
|
||||
}
|
||||
while (num_marks > 0);
|
||||
|
||||
TRACE("conflict", tout << "FUIP: "; m_ctx.display_literal(tout, consequent); tout << "\n";);
|
||||
|
@ -575,8 +591,8 @@ namespace smt {
|
|||
m_lemma_atoms.set(0, m_ctx.bool_var2expr(consequent.var()));
|
||||
|
||||
// TODO:
|
||||
//
|
||||
// equality optimization should go here.
|
||||
//
|
||||
// equality optimization should go here.
|
||||
//
|
||||
|
||||
finalize_resolve(conflict, not_l);
|
||||
|
@ -586,7 +602,7 @@ namespace smt {
|
|||
|
||||
/**
|
||||
\brief Return an approximation for the set of scope levels where the literals in m_lemma
|
||||
were assigned.
|
||||
were assigned.
|
||||
*/
|
||||
level_approx_set conflict_resolution::get_lemma_approx_level_set() {
|
||||
level_approx_set result;
|
||||
|
@ -626,7 +642,7 @@ namespace smt {
|
|||
unsigned lvl = m_ctx.get_assign_level(var);
|
||||
if (!m_ctx.is_marked(var) && lvl > m_ctx.get_base_level()) {
|
||||
if (m_lvl_set.may_contain(lvl)) {
|
||||
m_ctx.set_mark(var);
|
||||
m_ctx.set_mark(var);
|
||||
m_unmark.push_back(var);
|
||||
m_lemma_min_stack.push_back(var);
|
||||
}
|
||||
|
@ -653,18 +669,18 @@ namespace smt {
|
|||
}
|
||||
|
||||
/**
|
||||
\brief Return true if lit is implied by other marked literals
|
||||
and/or literals assigned at the base level.
|
||||
The set lvl_set is used as an optimization.
|
||||
\brief Return true if lit is implied by other marked literals
|
||||
and/or literals assigned at the base level.
|
||||
The set lvl_set is used as an optimization.
|
||||
The idea is to stop the recursive search with a failure
|
||||
as soon as we find a literal assigned in a level that is not in lvl_set.
|
||||
as soon as we find a literal assigned in a level that is not in lvl_set.
|
||||
*/
|
||||
bool conflict_resolution::implied_by_marked(literal lit) {
|
||||
m_lemma_min_stack.reset(); // avoid recursive function
|
||||
m_lemma_min_stack.push_back(lit.var());
|
||||
unsigned old_size = m_unmark.size();
|
||||
unsigned old_js_qhead = m_todo_js_qhead;
|
||||
|
||||
|
||||
while (!m_lemma_min_stack.empty()) {
|
||||
bool_var var = m_lemma_min_stack.back();
|
||||
m_lemma_min_stack.pop_back();
|
||||
|
@ -725,7 +741,7 @@ namespace smt {
|
|||
m_unmark.reset();
|
||||
|
||||
m_lvl_set = get_lemma_approx_level_set();
|
||||
|
||||
|
||||
unsigned sz = m_lemma.size();
|
||||
unsigned i = 1; // the first literal is the FUIP
|
||||
unsigned j = 1;
|
||||
|
@ -742,7 +758,7 @@ namespace smt {
|
|||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
reset_unmark_and_justifications(0, 0);
|
||||
m_lemma .shrink(j);
|
||||
m_lemma_atoms.shrink(j);
|
||||
|
@ -796,7 +812,7 @@ namespace smt {
|
|||
}
|
||||
if (m_manager.coarse_grain_proofs())
|
||||
return pr;
|
||||
TRACE("norm_eq_proof",
|
||||
TRACE("norm_eq_proof",
|
||||
tout << "#" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";
|
||||
tout << mk_ll_pp(pr, m_manager, true, false););
|
||||
SASSERT(m_manager.is_eq(fact) || m_manager.is_iff(fact));
|
||||
|
@ -892,7 +908,7 @@ namespace smt {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Return the proof object associated with the given literal if it already
|
||||
exists. Otherwise, return 0 and add l to the todo-list.
|
||||
|
@ -925,16 +941,16 @@ namespace smt {
|
|||
// p1: is a proof of "A"
|
||||
// p2: is a proof of "not A"
|
||||
// [unit-resolution p1 p2]: false
|
||||
//
|
||||
//
|
||||
// Let us assume that "A" was assigned first during propagation.
|
||||
// Then, the "resolve" method will never select "not A" as a hypothesis.
|
||||
// "not_A" will be the not_l argument in this method.
|
||||
// "not_A" will be the not_l argument in this method.
|
||||
// Since we are assuming that "A" was assigned first", m_ctx.get_justification("A") will be
|
||||
// p1.
|
||||
//
|
||||
//
|
||||
// So, the test "m_ctx.get_justification(l.var()) == js" is used to check
|
||||
// if l was assigned before ~l.
|
||||
if (m_ctx.is_marked(l.var()) && m_ctx.get_justification(l.var()) == js) {
|
||||
if ((m_ctx.is_marked(l.var()) && m_ctx.get_justification(l.var()) == js) || (js.get_kind() == b_justification::AXIOM)) {
|
||||
expr_ref l_expr(m_manager);
|
||||
m_ctx.literal2expr(l, l_expr);
|
||||
proof * pr = m_manager.mk_hypothesis(l_expr.get());
|
||||
|
@ -1008,11 +1024,11 @@ namespace smt {
|
|||
tout << mk_pp(m_manager.get_fact(prs[i]), m_manager) << "\n";
|
||||
}
|
||||
tout << "consequent:\n" << mk_pp(l_exr, m_manager) << "\n";);
|
||||
TRACE("get_proof",
|
||||
TRACE("get_proof",
|
||||
tout << l.index() << " " << true_literal.index() << " " << false_literal.index() << " ";
|
||||
m_ctx.display_literal(tout, l); tout << " --->\n";
|
||||
tout << mk_ll_pp(l_exr, m_manager););
|
||||
CTRACE("get_proof_bug_after",
|
||||
CTRACE("get_proof_bug_after",
|
||||
invocation_counter >= DUMP_AFTER_NUM_INVOCATIONS,
|
||||
tout << l.index() << " " << true_literal.index() << " " << false_literal.index() << " ";
|
||||
m_ctx.display_literal(tout, l); tout << " --->\n";
|
||||
|
@ -1026,7 +1042,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Return the proof object associated with the given justification
|
||||
if it already exists. Otherwise, return 0 and add js to the todo-list.
|
||||
|
@ -1051,7 +1067,7 @@ namespace smt {
|
|||
m_js2proof.reset();
|
||||
literal_vector::iterator it = m_lemma.begin();
|
||||
literal_vector::iterator end = m_lemma.end();
|
||||
for (; it != end; ++it)
|
||||
for (; it != end; ++it)
|
||||
m_ctx.set_mark((*it).var());
|
||||
}
|
||||
|
||||
|
@ -1062,6 +1078,9 @@ namespace smt {
|
|||
return true;
|
||||
SASSERT(js.get_kind() != b_justification::BIN_CLAUSE);
|
||||
CTRACE("visit_b_justification_bug", js.get_kind() == b_justification::AXIOM, tout << "l: " << l << "\n"; m_ctx.display(tout););
|
||||
|
||||
if (js.get_kind() == b_justification::AXIOM)
|
||||
return true;
|
||||
SASSERT(js.get_kind() != b_justification::AXIOM);
|
||||
if (js.get_kind() == b_justification::CLAUSE) {
|
||||
clause * cls = js.get_clause();
|
||||
|
@ -1073,14 +1092,17 @@ namespace smt {
|
|||
i = 1;
|
||||
}
|
||||
else {
|
||||
SASSERT(cls->get_literal(1) == l);
|
||||
if (get_proof(~cls->get_literal(0)) == 0)
|
||||
visited = false;
|
||||
i = 2;
|
||||
}
|
||||
}
|
||||
for (; i < num_lits; i++)
|
||||
for (; i < num_lits; i++) {
|
||||
SASSERT(cls->get_literal(i) != l);
|
||||
if (get_proof(~cls->get_literal(i)) == 0)
|
||||
visited = false;
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
else
|
||||
|
@ -1093,7 +1115,7 @@ namespace smt {
|
|||
SASSERT(pr);
|
||||
TRACE("proof_gen_bug", tout << "lit2pr_saved: #" << l << "\n";);
|
||||
m_lit2proof.insert(l, pr);
|
||||
TRACE("mk_proof",
|
||||
TRACE("mk_proof",
|
||||
tout << mk_bounded_pp(m_ctx.bool_var2expr(l.var()), m_manager, 10) << "\n";
|
||||
tout << "storing proof for: "; m_ctx.display_literal(tout, l); tout << "\n";
|
||||
tout << mk_ll_pp(pr, m_manager););
|
||||
|
@ -1102,7 +1124,7 @@ namespace smt {
|
|||
/**
|
||||
\brief Given that lhs = ... = rhs, and lhs reaches rhs in the 'proof' tree branch.
|
||||
Then, return true if all proof objects needed to create the proof steps are already
|
||||
available. Otherwise return false and update m_todo_pr with info about the proof
|
||||
available. Otherwise return false and update m_todo_pr with info about the proof
|
||||
objects that need to be created.
|
||||
*/
|
||||
bool conflict_resolution::visit_trans_proof(enode * lhs, enode * rhs) {
|
||||
|
@ -1158,7 +1180,7 @@ namespace smt {
|
|||
|
||||
/**
|
||||
\brief Return true if all proof objects that are used to build the proof that lhs = rhs were
|
||||
already built. If the result is false, then m_todo_pr is updated with info about the proof
|
||||
already built. If the result is false, then m_todo_pr is updated with info about the proof
|
||||
objects that need to be created.
|
||||
*/
|
||||
bool conflict_resolution::visit_eq_justications(enode * lhs, enode * rhs) {
|
||||
|
@ -1210,7 +1232,7 @@ namespace smt {
|
|||
if (prs1.size() == 1)
|
||||
pr = prs1[0];
|
||||
else {
|
||||
TRACE("mk_transitivity",
|
||||
TRACE("mk_transitivity",
|
||||
unsigned sz = prs1.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
tout << mk_ll_pp(prs1[i], m_manager) << "\n";
|
||||
|
@ -1235,14 +1257,19 @@ namespace smt {
|
|||
}
|
||||
tout << "\n";);
|
||||
init_mk_proof();
|
||||
literal consequent = false_literal;
|
||||
if (not_l != null_literal)
|
||||
consequent = ~not_l;
|
||||
visit_b_justification(consequent, conflict);
|
||||
if (not_l != null_literal)
|
||||
literal consequent;
|
||||
if (not_l == null_literal) {
|
||||
consequent = false_literal;
|
||||
}
|
||||
else {
|
||||
consequent = ~not_l;
|
||||
m_todo_pr.push_back(tp_elem(not_l));
|
||||
}
|
||||
visit_b_justification(consequent, conflict);
|
||||
|
||||
while (!m_todo_pr.empty()) {
|
||||
tp_elem & elem = m_todo_pr.back();
|
||||
|
||||
switch (elem.m_kind) {
|
||||
case tp_elem::EQUALITY: {
|
||||
enode * lhs = elem.m_lhs;
|
||||
|
@ -1272,7 +1299,7 @@ namespace smt {
|
|||
}
|
||||
case tp_elem::LITERAL: {
|
||||
literal l = to_literal(elem.m_lidx);
|
||||
if (m_lit2proof.contains(l))
|
||||
if (m_lit2proof.contains(l))
|
||||
m_todo_pr.pop_back();
|
||||
else {
|
||||
b_justification js = m_ctx.get_justification(l.var());
|
||||
|
@ -1326,19 +1353,20 @@ namespace smt {
|
|||
|
||||
void conflict_resolution::process_antecedent_for_unsat_core(literal antecedent) {
|
||||
bool_var var = antecedent.var();
|
||||
TRACE("conflict", tout << "processing antecedent: ";
|
||||
m_ctx.display_literal_info(tout << antecedent << " ", antecedent);
|
||||
tout << (m_ctx.is_marked(var)?"marked":"not marked");
|
||||
tout << "\n";);
|
||||
|
||||
TRACE("conflict", tout << "processing antecedent: ";
|
||||
m_ctx.display_literal_info(tout << antecedent << " ", antecedent);
|
||||
tout << (m_ctx.is_marked(var)?"marked":"not marked");
|
||||
tout << "\n";);
|
||||
|
||||
if (!m_ctx.is_marked(var)) {
|
||||
m_ctx.set_mark(var);
|
||||
m_unmark.push_back(var);
|
||||
if (m_ctx.is_assumption(var))
|
||||
m_assumptions.push_back(antecedent);
|
||||
}
|
||||
if (m_ctx.is_assumption(var)) {
|
||||
m_assumptions.push_back(antecedent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void conflict_resolution::process_justification_for_unsat_core(justification * js) {
|
||||
literal_vector & antecedents = m_tmp_literal_vector;
|
||||
antecedents.reset();
|
||||
|
@ -1353,7 +1381,7 @@ namespace smt {
|
|||
SASSERT(m_ctx.tracking_assumptions());
|
||||
m_assumptions.reset();
|
||||
m_unmark.reset();
|
||||
|
||||
|
||||
SASSERT(m_conflict_lvl <= m_ctx.get_search_level());
|
||||
unsigned search_lvl = m_ctx.get_search_level();
|
||||
|
||||
|
@ -1361,19 +1389,19 @@ namespace smt {
|
|||
literal consequent = false_literal;
|
||||
if (not_l != null_literal) {
|
||||
consequent = ~not_l;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int idx = skip_literals_above_conflict_level();
|
||||
|
||||
|
||||
if (not_l != null_literal)
|
||||
process_antecedent_for_unsat_core(consequent);
|
||||
|
||||
|
||||
if (m_assigned_literals.empty()) {
|
||||
goto end_unsat_core;
|
||||
}
|
||||
|
||||
|
||||
while (true) {
|
||||
TRACE("unsat_core_bug", tout << "js.get_kind(): " << js.get_kind() << ", idx: " << idx << "\n";);
|
||||
TRACE("unsat_core_bug", tout << consequent << " js.get_kind(): " << js.get_kind() << ", idx: " << idx << "\n";);
|
||||
switch (js.get_kind()) {
|
||||
case b_justification::CLAUSE: {
|
||||
clause * cls = js.get_clause();
|
||||
|
@ -1394,7 +1422,7 @@ namespace smt {
|
|||
process_antecedent_for_unsat_core(~l);
|
||||
}
|
||||
justification * js = cls->get_justification();
|
||||
if (js)
|
||||
if (js)
|
||||
process_justification_for_unsat_core(js);
|
||||
break;
|
||||
}
|
||||
|
@ -1410,18 +1438,22 @@ namespace smt {
|
|||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (idx < 0)
|
||||
goto end_unsat_core;
|
||||
|
||||
if (m_ctx.is_assumption(consequent.var())) {
|
||||
m_assumptions.push_back(consequent);
|
||||
}
|
||||
while (idx >= 0) {
|
||||
literal l = m_assigned_literals[idx];
|
||||
TRACE("unsat_core_bug", tout << "l: " << l << ", get_assign_level(l): " << m_ctx.get_assign_level(l) << ", is_marked(l): " << m_ctx.is_marked(l.var()) << "\n";);
|
||||
if (m_ctx.get_assign_level(l) < search_lvl || idx == 0)
|
||||
if (m_ctx.get_assign_level(l) < search_lvl)
|
||||
goto end_unsat_core;
|
||||
if (m_ctx.is_marked(l.var()))
|
||||
if (m_ctx.is_marked(l.var()))
|
||||
break;
|
||||
idx--;
|
||||
}
|
||||
if (idx < 0) {
|
||||
goto end_unsat_core;
|
||||
}
|
||||
|
||||
SASSERT(idx >= 0);
|
||||
consequent = m_assigned_literals[idx];
|
||||
|
@ -1435,12 +1467,12 @@ namespace smt {
|
|||
TRACE("unsat_core", tout << "assumptions:\n"; m_ctx.display_literals(tout, m_assumptions); tout << "\n";);
|
||||
reset_unmark_and_justifications(0, 0);
|
||||
}
|
||||
|
||||
conflict_resolution * mk_conflict_resolution(ast_manager & m,
|
||||
|
||||
conflict_resolution * mk_conflict_resolution(ast_manager & m,
|
||||
context & ctx,
|
||||
dyn_ack_manager & dack_manager,
|
||||
smt_params const & params,
|
||||
literal_vector const & assigned_literals,
|
||||
literal_vector const & assigned_literals,
|
||||
vector<watch_list> & watches) {
|
||||
return alloc(conflict_resolution, m, ctx, dack_manager, params, assigned_literals, watches);
|
||||
}
|
||||
|
|
|
@ -168,6 +168,7 @@ namespace smt {
|
|||
void eq_branch2literals(enode * n1, enode * n2);
|
||||
void eq2literals(enode * n1, enode * n2);
|
||||
void justification2literals_core(justification * js, literal_vector & result) ;
|
||||
void process_justifications();
|
||||
void unmark_justifications(unsigned old_js_qhead);
|
||||
|
||||
literal_vector m_tmp_literal_vector;
|
||||
|
@ -257,6 +258,8 @@ namespace smt {
|
|||
|
||||
void justification2literals(justification * js, literal_vector & result);
|
||||
|
||||
void eq2literals(enode * n1, enode * n2, literal_vector & result);
|
||||
|
||||
};
|
||||
|
||||
inline void mark_literals(conflict_resolution & cr, unsigned sz, literal const * ls) {
|
||||
|
|
595
src/smt/smt_consequences.cpp
Normal file
595
src/smt/smt_consequences.cpp
Normal file
|
@ -0,0 +1,595 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_consequences.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tuned consequence finding for smt_context.
|
||||
|
||||
Author:
|
||||
|
||||
nbjorner 2016-07-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "smt_context.h"
|
||||
#include "ast_util.h"
|
||||
#include "datatype_decl_plugin.h"
|
||||
#include "model_pp.h"
|
||||
#include "max_cliques.h"
|
||||
#include "stopwatch.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
expr_ref context::antecedent2fml(index_set const& vars) {
|
||||
expr_ref_vector premises(m_manager);
|
||||
index_set::iterator it = vars.begin(), end = vars.end();
|
||||
for (; it != end; ++it) {
|
||||
expr* e = bool_var2expr(*it);
|
||||
premises.push_back(get_assignment(*it) != l_false ? e : m_manager.mk_not(e));
|
||||
}
|
||||
return mk_and(premises);
|
||||
}
|
||||
|
||||
//
|
||||
// The literal lit is assigned at the search level, so it follows from the assumptions.
|
||||
// We retrieve the set of assumptions it depends on in the set 's'.
|
||||
// The map m_antecedents contains the association from these literals to the assumptions they depend on.
|
||||
// We then examine the contents of the literal lit and augment the set of consequences in one of the following cases:
|
||||
// - e is a propositional atom and it is one of the variables that is to be fixed.
|
||||
// - e is an equality between a variable and value that is to be fixed.
|
||||
// - e is a data-type recognizer of a variable that is to be fixed.
|
||||
//
|
||||
void context::extract_fixed_consequences(literal lit, obj_map<expr, expr*>& vars, index_set const& assumptions, expr_ref_vector& conseq) {
|
||||
ast_manager& m = m_manager;
|
||||
datatype_util dt(m);
|
||||
expr* e1, *e2;
|
||||
expr_ref fml(m);
|
||||
if (lit == true_literal) return;
|
||||
expr* e = bool_var2expr(lit.var());
|
||||
index_set s;
|
||||
if (assumptions.contains(lit.var())) {
|
||||
s.insert(lit.var());
|
||||
}
|
||||
else {
|
||||
justify(lit, s);
|
||||
}
|
||||
m_antecedents.insert(lit.var(), s);
|
||||
TRACE("context", display_literal_verbose(tout, lit);
|
||||
for (index_set::iterator it = s.begin(), end = s.end(); it != end; ++it) {
|
||||
tout << " " << *it;
|
||||
}
|
||||
tout << "\n";);
|
||||
bool found = false;
|
||||
if (vars.contains(e)) {
|
||||
found = true;
|
||||
fml = lit.sign() ? m.mk_not(e) : e;
|
||||
vars.erase(e);
|
||||
}
|
||||
else if (!lit.sign() && m.is_eq(e, e1, e2)) {
|
||||
if (vars.contains(e2)) {
|
||||
std::swap(e1, e2);
|
||||
}
|
||||
if (vars.contains(e1) && m.is_value(e2)) {
|
||||
found = true;
|
||||
fml = e;
|
||||
vars.erase(e1);
|
||||
}
|
||||
}
|
||||
else if (!lit.sign() && is_app(e) && dt.is_recognizer(to_app(e)->get_decl())) {
|
||||
if (vars.contains(to_app(e)->get_arg(0))) {
|
||||
found = true;
|
||||
fml = m.mk_eq(to_app(e)->get_arg(0), m.mk_const(dt.get_recognizer_constructor(to_app(e)->get_decl())));
|
||||
vars.erase(to_app(e)->get_arg(0));
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
fml = m.mk_implies(antecedent2fml(s), fml);
|
||||
conseq.push_back(fml);
|
||||
}
|
||||
}
|
||||
|
||||
void context::justify(literal lit, index_set& s) {
|
||||
b_justification js = get_justification(lit.var());
|
||||
switch (js.get_kind()) {
|
||||
case b_justification::CLAUSE: {
|
||||
clause * cls = js.get_clause();
|
||||
if (!cls) break;
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned j = 0; j < num_lits; ++j) {
|
||||
literal lit2 = cls->get_literal(j);
|
||||
if (lit2.var() != lit.var()) {
|
||||
s |= m_antecedents.find(lit2.var());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case b_justification::BIN_CLAUSE: {
|
||||
s |= m_antecedents.find(js.get_literal().var());
|
||||
break;
|
||||
}
|
||||
case b_justification::AXIOM: {
|
||||
break;
|
||||
}
|
||||
case b_justification::JUSTIFICATION: {
|
||||
literal_vector literals;
|
||||
m_conflict_resolution->justification2literals(js.get_justification(), literals);
|
||||
for (unsigned j = 0; j < literals.size(); ++j) {
|
||||
s |= m_antecedents.find(literals[j].var());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void context::extract_fixed_consequences(unsigned& start, obj_map<expr, expr*>& vars, index_set const& assumptions, expr_ref_vector& conseq) {
|
||||
pop_to_search_lvl();
|
||||
SASSERT(!inconsistent());
|
||||
literal_vector const& lits = assigned_literals();
|
||||
unsigned sz = lits.size();
|
||||
for (unsigned i = start; i < sz; ++i) {
|
||||
extract_fixed_consequences(lits[i], vars, assumptions, conseq);
|
||||
}
|
||||
start = sz;
|
||||
SASSERT(!inconsistent());
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The assignment stack is assumed consistent.
|
||||
// For each Boolean variable, we check if there is a literal assigned to the
|
||||
// opposite value of the reference model, and for non-Boolean variables we
|
||||
// check if the current state forces the variable to be distinct from the reference value.
|
||||
//
|
||||
// For yet to be determined Boolean variables we furthermore force the phase to be opposite
|
||||
// to the reference value in the attempt to let the sat engine emerge with a model that
|
||||
// rules out as many non-fixed variables as possible.
|
||||
//
|
||||
|
||||
unsigned context::delete_unfixed(obj_map<expr, expr*>& var2val, expr_ref_vector& unfixed) {
|
||||
ast_manager& m = m_manager;
|
||||
ptr_vector<expr> to_delete;
|
||||
obj_map<expr,expr*>::iterator it = var2val.begin(), end = var2val.end();
|
||||
for (; it != end; ++it) {
|
||||
expr* k = it->m_key;
|
||||
expr* v = it->m_value;
|
||||
if (m.is_bool(k)) {
|
||||
literal lit = get_literal(k);
|
||||
switch (get_assignment(lit)) {
|
||||
case l_true:
|
||||
if (m.is_false(v)) {
|
||||
to_delete.push_back(k);
|
||||
}
|
||||
else {
|
||||
force_phase(lit.var(), false);
|
||||
}
|
||||
break;
|
||||
case l_false:
|
||||
if (m.is_true(v)) {
|
||||
to_delete.push_back(k);
|
||||
}
|
||||
else {
|
||||
force_phase(lit.var(), true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
to_delete.push_back(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (e_internalized(k) && m.are_distinct(v, get_enode(k)->get_root()->get_owner())) {
|
||||
to_delete.push_back(k);
|
||||
}
|
||||
else if (get_assignment(mk_diseq(k, v)) == l_true) {
|
||||
to_delete.push_back(k);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < to_delete.size(); ++i) {
|
||||
var2val.remove(to_delete[i]);
|
||||
unfixed.push_back(to_delete[i]);
|
||||
}
|
||||
return to_delete.size();
|
||||
}
|
||||
|
||||
#define are_equal(v, k) (e_internalized(k) && e_internalized(v) && get_enode(k)->get_root() == get_enode(v)->get_root())
|
||||
|
||||
//
|
||||
// Extract equalities that are congruent at the search level.
|
||||
// Add a clause to short-circuit the congruence justifications for
|
||||
// next rounds.
|
||||
//
|
||||
unsigned context::extract_fixed_eqs(obj_map<expr, expr*>& var2val, expr_ref_vector& conseq) {
|
||||
TRACE("context", tout << "extract fixed consequences\n";);
|
||||
ast_manager& m = m_manager;
|
||||
ptr_vector<expr> to_delete;
|
||||
expr_ref fml(m), eq(m);
|
||||
obj_map<expr,expr*>::iterator it = var2val.begin(), end = var2val.end();
|
||||
for (; it != end; ++it) {
|
||||
expr* k = it->m_key;
|
||||
expr* v = it->m_value;
|
||||
if (!m.is_bool(k) && are_equal(k, v)) {
|
||||
literal_vector literals;
|
||||
m_conflict_resolution->eq2literals(get_enode(v), get_enode(k), literals);
|
||||
index_set s;
|
||||
for (unsigned i = 0; i < literals.size(); ++i) {
|
||||
SASSERT(get_assign_level(literals[i]) <= get_search_level());
|
||||
s |= m_antecedents.find(literals[i].var());
|
||||
}
|
||||
|
||||
fml = m.mk_eq(k, v);
|
||||
fml = m.mk_implies(antecedent2fml(s), fml);
|
||||
conseq.push_back(fml);
|
||||
to_delete.push_back(k);
|
||||
|
||||
for (unsigned i = 0; i < literals.size(); ++i) {
|
||||
literals[i].neg();
|
||||
}
|
||||
literal lit = mk_diseq(k, v);
|
||||
literals.push_back(lit);
|
||||
mk_clause(literals.size(), literals.c_ptr(), 0);
|
||||
TRACE("context", display_literals_verbose(tout, literals.size(), literals.c_ptr()););
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < to_delete.size(); ++i) {
|
||||
var2val.remove(to_delete[i]);
|
||||
}
|
||||
return to_delete.size();
|
||||
}
|
||||
|
||||
literal context::mk_diseq(expr* e, expr* val) {
|
||||
ast_manager& m = m_manager;
|
||||
if (m.is_bool(e)) {
|
||||
return literal(get_bool_var(e), m.is_true(val));
|
||||
}
|
||||
else {
|
||||
expr_ref eq(mk_eq_atom(e, val), m);
|
||||
internalize_formula(eq, false);
|
||||
return literal(get_bool_var(eq), true);
|
||||
}
|
||||
}
|
||||
|
||||
lbool context::get_consequences(expr_ref_vector const& assumptions,
|
||||
expr_ref_vector const& vars,
|
||||
expr_ref_vector& conseq,
|
||||
expr_ref_vector& unfixed) {
|
||||
|
||||
m_antecedents.reset();
|
||||
pop_to_base_lvl();
|
||||
lbool is_sat = check(assumptions.size(), assumptions.c_ptr());
|
||||
if (is_sat != l_true) {
|
||||
TRACE("context", tout << is_sat << "\n";);
|
||||
return is_sat;
|
||||
}
|
||||
|
||||
obj_map<expr, expr*> var2val;
|
||||
index_set _assumptions;
|
||||
for (unsigned i = 0; i < assumptions.size(); ++i) {
|
||||
_assumptions.insert(get_literal(assumptions[i]).var());
|
||||
}
|
||||
model_ref mdl;
|
||||
get_model(mdl);
|
||||
ast_manager& m = m_manager;
|
||||
expr_ref_vector trail(m);
|
||||
model_evaluator eval(*mdl.get());
|
||||
expr_ref val(m);
|
||||
TRACE("context", model_pp(tout, *mdl););
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
eval(vars[i], val);
|
||||
if (m.is_value(val)) {
|
||||
trail.push_back(val);
|
||||
var2val.insert(vars[i], val);
|
||||
}
|
||||
else {
|
||||
unfixed.push_back(vars[i]);
|
||||
}
|
||||
}
|
||||
unsigned num_units = 0;
|
||||
extract_fixed_consequences(num_units, var2val, _assumptions, conseq);
|
||||
app_ref eq(m);
|
||||
TRACE("context",
|
||||
tout << "vars: " << vars.size() << "\n";
|
||||
tout << "lits: " << num_units << "\n";);
|
||||
m_case_split_queue->init_search_eh();
|
||||
unsigned num_iterations = 0;
|
||||
unsigned num_fixed_eqs = 0;
|
||||
unsigned chunk_size = 100;
|
||||
|
||||
while (!var2val.empty()) {
|
||||
obj_map<expr,expr*>::iterator it = var2val.begin(), end = var2val.end();
|
||||
unsigned num_vars = 0;
|
||||
for (; it != end && num_vars < chunk_size; ++it) {
|
||||
if (get_cancel_flag()) {
|
||||
return l_undef;
|
||||
}
|
||||
expr* e = it->m_key;
|
||||
expr* val = it->m_value;
|
||||
literal lit = mk_diseq(e, val);
|
||||
mark_as_relevant(lit);
|
||||
if (get_assignment(lit) != l_undef) {
|
||||
continue;
|
||||
}
|
||||
++num_vars;
|
||||
push_scope();
|
||||
assign(lit, b_justification::mk_axiom(), true);
|
||||
if (!propagate()) {
|
||||
if (!resolve_conflict() || inconsistent()) {
|
||||
TRACE("context", tout << "inconsistent\n";);
|
||||
SASSERT(inconsistent());
|
||||
m_conflict = null_b_justification;
|
||||
m_not_l = null_literal;
|
||||
SASSERT(m_search_lvl == get_search_level());
|
||||
}
|
||||
}
|
||||
}
|
||||
SASSERT(!inconsistent());
|
||||
++num_iterations;
|
||||
|
||||
lbool is_sat = l_undef;
|
||||
while (true) {
|
||||
is_sat = bounded_search();
|
||||
if (is_sat != l_true && m_last_search_failure != OK) {
|
||||
return is_sat;
|
||||
}
|
||||
if (is_sat == l_undef) {
|
||||
IF_VERBOSE(1, verbose_stream() << "(get-consequences inc-limits)\n";);
|
||||
inc_limits();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (is_sat == l_false) {
|
||||
SASSERT(inconsistent());
|
||||
m_conflict = null_b_justification;
|
||||
m_not_l = null_literal;
|
||||
}
|
||||
if (is_sat == l_true) {
|
||||
delete_unfixed(var2val, unfixed);
|
||||
}
|
||||
extract_fixed_consequences(num_units, var2val, _assumptions, conseq);
|
||||
num_fixed_eqs += extract_fixed_eqs(var2val, conseq);
|
||||
IF_VERBOSE(1, display_consequence_progress(verbose_stream(), num_iterations, var2val.size(), conseq.size(),
|
||||
unfixed.size(), num_fixed_eqs););
|
||||
TRACE("context", display_consequence_progress(tout, num_iterations, var2val.size(), conseq.size(),
|
||||
unfixed.size(), num_fixed_eqs););
|
||||
}
|
||||
|
||||
end_search();
|
||||
DEBUG_CODE(validate_consequences(assumptions, vars, conseq, unfixed););
|
||||
return l_true;
|
||||
}
|
||||
|
||||
|
||||
void context::display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq) {
|
||||
out << "(get-consequences"
|
||||
<< " iterations: " << it
|
||||
<< " variables: " << nv
|
||||
<< " fixed: " << fixed
|
||||
<< " unfixed: " << unfixed
|
||||
<< " fixed-eqs: " << eq
|
||||
<< ")\n";
|
||||
}
|
||||
|
||||
void context::extract_cores(expr_ref_vector const& asms, vector<expr_ref_vector>& cores, unsigned& min_core_size) {
|
||||
index_set _asms, _nasms;
|
||||
u_map<expr*> var2expr;
|
||||
for (unsigned i = 0; i < asms.size(); ++i) {
|
||||
literal lit = get_literal(asms[i]);
|
||||
_asms.insert(lit.index());
|
||||
_nasms.insert((~lit).index());
|
||||
var2expr.insert(lit.var(), asms[i]);
|
||||
}
|
||||
|
||||
m_antecedents.reset();
|
||||
literal_vector const& lits = assigned_literals();
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
literal lit = lits[i];
|
||||
index_set s;
|
||||
if (_asms.contains(lit.index())) {
|
||||
s.insert(lit.var());
|
||||
}
|
||||
else {
|
||||
justify(lit, s);
|
||||
}
|
||||
m_antecedents.insert(lit.var(), s);
|
||||
if (_nasms.contains(lit.index())) {
|
||||
expr_ref_vector core(m_manager);
|
||||
index_set::iterator it = s.begin(), end = s.end();
|
||||
for (; it != end; ++it) {
|
||||
core.push_back(var2expr[*it]);
|
||||
}
|
||||
core.push_back(var2expr[lit.var()]);
|
||||
cores.push_back(core);
|
||||
min_core_size = std::min(min_core_size, core.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void context::preferred_sat(literal_vector& lits) {
|
||||
bool retry = true;
|
||||
while (retry) {
|
||||
retry = false;
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
literal lit = lits[i];
|
||||
if (lit == null_literal || get_assignment(lit) != l_undef) {
|
||||
continue;
|
||||
}
|
||||
push_scope();
|
||||
assign(lit, b_justification::mk_axiom(), true);
|
||||
while (!propagate()) {
|
||||
lits[i] = null_literal;
|
||||
retry = true;
|
||||
if (!resolve_conflict() || inconsistent()) {
|
||||
SASSERT(inconsistent());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void context::display_partial_assignment(std::ostream& out, expr_ref_vector const& asms, unsigned min_core_size) {
|
||||
unsigned num_true = 0, num_false = 0, num_undef = 0;
|
||||
for (unsigned i = 0; i < asms.size(); ++i) {
|
||||
literal lit = get_literal(asms[i]);
|
||||
if (get_assignment(lit) == l_false) {
|
||||
++num_false;
|
||||
}
|
||||
if (get_assignment(lit) == l_true) {
|
||||
++num_true;
|
||||
}
|
||||
if (get_assignment(lit) == l_undef) {
|
||||
++num_undef;
|
||||
}
|
||||
}
|
||||
out << "(smt.preferred-sat true: " << num_true << " false: " << num_false << " undef: " << num_undef << " min core: " << min_core_size << ")\n";
|
||||
}
|
||||
|
||||
lbool context::preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores) {
|
||||
pop_to_base_lvl();
|
||||
cores.reset();
|
||||
setup_context(false);
|
||||
internalize_assertions();
|
||||
if (m_asserted_formulas.inconsistent() || inconsistent()) {
|
||||
return l_false;
|
||||
}
|
||||
scoped_mk_model smk(*this);
|
||||
init_search();
|
||||
flet<bool> l(m_searching, true);
|
||||
unsigned level = m_scope_lvl;
|
||||
unsigned min_core_size = UINT_MAX;
|
||||
lbool is_sat = l_true;
|
||||
unsigned num_restarts = 0;
|
||||
|
||||
while (true) {
|
||||
if (m_manager.canceled()) {
|
||||
is_sat = l_undef;
|
||||
break;
|
||||
}
|
||||
literal_vector lits;
|
||||
for (unsigned i = 0; i < asms.size(); ++i) {
|
||||
lits.push_back(get_literal(asms[i]));
|
||||
}
|
||||
preferred_sat(lits);
|
||||
if (inconsistent()) {
|
||||
SASSERT(m_scope_lvl == level);
|
||||
is_sat = l_false;
|
||||
break;
|
||||
}
|
||||
extract_cores(asms, cores, min_core_size);
|
||||
IF_VERBOSE(1, display_partial_assignment(verbose_stream(), asms, min_core_size););
|
||||
|
||||
if (min_core_size <= 10) {
|
||||
is_sat = l_undef;
|
||||
break;
|
||||
}
|
||||
|
||||
is_sat = bounded_search();
|
||||
if (!restart(is_sat, level)) {
|
||||
break;
|
||||
}
|
||||
++num_restarts;
|
||||
if (num_restarts >= min_core_size) {
|
||||
is_sat = l_undef;
|
||||
while (num_restarts <= 10*min_core_size) {
|
||||
is_sat = bounded_search();
|
||||
if (!restart(is_sat, level)) {
|
||||
break;
|
||||
}
|
||||
++num_restarts;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_search();
|
||||
|
||||
return check_finalize(is_sat);
|
||||
}
|
||||
|
||||
struct neg_literal {
|
||||
unsigned negate(unsigned i) {
|
||||
return (~to_literal(i)).index();
|
||||
}
|
||||
};
|
||||
|
||||
lbool context::find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
|
||||
unsigned_vector ps;
|
||||
max_cliques<neg_literal> mc;
|
||||
expr_ref lit(m_manager);
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
expr* n = vars[i];
|
||||
bool neg = m_manager.is_not(n, n);
|
||||
if (b_internalized(n)) {
|
||||
ps.push_back(literal(get_bool_var(n), neg).index());
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < m_watches.size(); ++i) {
|
||||
watch_list & w = m_watches[i];
|
||||
for (literal const* it = w.begin_literals(), *end = w.end_literals(); it != end; ++it) {
|
||||
unsigned idx1 = (~to_literal(i)).index();
|
||||
unsigned idx2 = it->index();
|
||||
if (idx1 < idx2) {
|
||||
mc.add_edge(idx1, idx2);
|
||||
}
|
||||
}
|
||||
}
|
||||
vector<unsigned_vector> _mutexes;
|
||||
mc.cliques(ps, _mutexes);
|
||||
for (unsigned i = 0; i < _mutexes.size(); ++i) {
|
||||
expr_ref_vector lits(m_manager);
|
||||
for (unsigned j = 0; j < _mutexes[i].size(); ++j) {
|
||||
literal2expr(to_literal(_mutexes[i][j]), lit);
|
||||
lits.push_back(lit);
|
||||
}
|
||||
mutexes.push_back(lits);
|
||||
}
|
||||
return l_true;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate, in a slow pass, that the current consequences are correctly
|
||||
// extracted.
|
||||
//
|
||||
void context::validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars,
|
||||
expr_ref_vector const& conseq, expr_ref_vector const& unfixed) {
|
||||
ast_manager& m = m_manager;
|
||||
expr_ref tmp(m);
|
||||
SASSERT(!inconsistent());
|
||||
for (unsigned i = 0; i < conseq.size(); ++i) {
|
||||
push();
|
||||
for (unsigned j = 0; j < assumptions.size(); ++j) {
|
||||
assert_expr(assumptions[j]);
|
||||
}
|
||||
TRACE("context", tout << "checking: " << mk_pp(conseq[i], m) << "\n";);
|
||||
tmp = m.mk_not(conseq[i]);
|
||||
assert_expr(tmp);
|
||||
VERIFY(check() != l_true);
|
||||
pop(1);
|
||||
}
|
||||
model_ref mdl;
|
||||
for (unsigned i = 0; i < unfixed.size(); ++i) {
|
||||
push();
|
||||
for (unsigned j = 0; j < assumptions.size(); ++j) {
|
||||
assert_expr(assumptions[j]);
|
||||
}
|
||||
TRACE("context", tout << "checking unfixed: " << mk_pp(unfixed[i], m) << "\n";);
|
||||
lbool is_sat = check();
|
||||
SASSERT(is_sat != l_false);
|
||||
if (is_sat == l_true) {
|
||||
get_model(mdl);
|
||||
mdl->eval(unfixed[i], tmp);
|
||||
if (m.is_value(tmp)) {
|
||||
tmp = m.mk_not(m.mk_eq(unfixed[i], tmp));
|
||||
assert_expr(tmp);
|
||||
is_sat = check();
|
||||
SASSERT(is_sat != l_false);
|
||||
}
|
||||
}
|
||||
pop(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -263,10 +263,11 @@ namespace smt {
|
|||
m_assignment[false_literal.index()] = l_false;
|
||||
if (m_manager.proofs_enabled()) {
|
||||
proof * pr = m_manager.mk_true_proof();
|
||||
m_bdata[true_bool_var].m_justification = b_justification(mk_justification(justification_proof_wrapper(*this, pr)));
|
||||
|
||||
set_justification(true_bool_var, m_bdata[true_bool_var], b_justification(mk_justification(justification_proof_wrapper(*this, pr))));
|
||||
}
|
||||
else {
|
||||
m_bdata[true_bool_var].m_justification = b_justification::mk_axiom();
|
||||
m_bdata[true_bool_var].set_axiom();
|
||||
}
|
||||
m_true_enode = mk_enode(t, true, true, false);
|
||||
// internalizer is marking enodes as interpreted whenever the associated ast is a value and a constant.
|
||||
|
@ -294,6 +295,12 @@ namespace smt {
|
|||
std::swap(lhs, rhs);
|
||||
return m_manager.mk_eq(lhs, rhs);
|
||||
}
|
||||
|
||||
void context::set_justification(bool_var v, bool_var_data& d, b_justification const& j) {
|
||||
SASSERT(validate_justification(v, d, j));
|
||||
d.set_justification(j);
|
||||
}
|
||||
|
||||
|
||||
void context::assign_core(literal l, b_justification j, bool decision) {
|
||||
TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " ";
|
||||
|
@ -304,7 +311,7 @@ namespace smt {
|
|||
m_assignment[l.index()] = l_true;
|
||||
m_assignment[(~l).index()] = l_false;
|
||||
bool_var_data & d = get_bdata(l.var());
|
||||
d.m_justification = j;
|
||||
set_justification(l.var(), d, j);
|
||||
d.m_scope_lvl = m_scope_lvl;
|
||||
if (m_fparams.m_restart_adaptive && d.m_phase_available) {
|
||||
m_agility *= m_fparams.m_agility_factor;
|
||||
|
@ -1097,7 +1104,7 @@ namespace smt {
|
|||
\brief This method is invoked when a new disequality is asserted.
|
||||
The disequality is propagated to the theories.
|
||||
*/
|
||||
void context::add_diseq(enode * n1, enode * n2) {
|
||||
bool context::add_diseq(enode * n1, enode * n2) {
|
||||
enode * r1 = n1->get_root();
|
||||
enode * r2 = n2->get_root();
|
||||
TRACE("add_diseq", tout << "assigning: #" << n1->get_owner_id() << " != #" << n2->get_owner_id() << "\n";
|
||||
|
@ -1114,7 +1121,11 @@ namespace smt {
|
|||
|
||||
if (r1 == r2) {
|
||||
TRACE("add_diseq_inconsistent", tout << "add_diseq #" << n1->get_owner_id() << " #" << n2->get_owner_id() << " inconsistency, scope_lvl: " << m_scope_lvl << "\n";);
|
||||
return; // context is inconsistent
|
||||
//return false;
|
||||
|
||||
theory_id t1 = r1->m_th_var_list.get_th_id();
|
||||
if (t1 == null_theory_id) return false;
|
||||
return get_theory(t1)->use_diseqs();
|
||||
}
|
||||
|
||||
// Propagate disequalities to theories
|
||||
|
@ -1148,6 +1159,7 @@ namespace smt {
|
|||
l1 = l1->get_next();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1403,7 +1415,10 @@ namespace smt {
|
|||
}
|
||||
else {
|
||||
TRACE("add_diseq", display_eq_detail(tout, bool_var2enode(v)););
|
||||
add_diseq(get_enode(lhs), get_enode(rhs));
|
||||
if (!add_diseq(get_enode(lhs), get_enode(rhs)) && !inconsistent()) {
|
||||
literal n_eq = literal(l.var(), true);
|
||||
set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), n_eq);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (d.is_theory_atom()) {
|
||||
|
@ -1756,8 +1771,10 @@ namespace smt {
|
|||
return false;
|
||||
if (!propagate_th_case_split())
|
||||
return false;
|
||||
if (get_cancel_flag())
|
||||
if (get_cancel_flag()) {
|
||||
m_qhead = qhead;
|
||||
return true;
|
||||
}
|
||||
SASSERT(!inconsistent());
|
||||
propagate_relevancy(qhead);
|
||||
if (inconsistent())
|
||||
|
@ -1775,8 +1792,10 @@ namespace smt {
|
|||
m_qmanager->propagate();
|
||||
if (inconsistent())
|
||||
return false;
|
||||
if (resource_limits_exceeded())
|
||||
if (resource_limits_exceeded()) {
|
||||
m_qhead = qhead;
|
||||
return true;
|
||||
}
|
||||
if (!can_propagate()) {
|
||||
CASSERT("diseq_bug", inconsistent() || check_missing_diseq_conflict());
|
||||
CASSERT("eqc_bool", check_eqc_bool_assignment());
|
||||
|
@ -1787,6 +1806,7 @@ namespace smt {
|
|||
|
||||
void context::set_conflict(b_justification js, literal not_l) {
|
||||
if (!inconsistent()) {
|
||||
TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout, js); );
|
||||
m_conflict = js;
|
||||
m_not_l = not_l;
|
||||
}
|
||||
|
@ -1841,7 +1861,7 @@ namespace smt {
|
|||
m_stats.m_num_decisions++;
|
||||
|
||||
push_scope();
|
||||
TRACE("context", tout << "splitting, lvl: " << m_scope_lvl << "\n";);
|
||||
TRACE("decide", tout << "splitting, lvl: " << m_scope_lvl << "\n";);
|
||||
|
||||
TRACE("decide_detail", tout << mk_pp(bool_var2expr(var), m_manager) << "\n";);
|
||||
|
||||
|
@ -2022,11 +2042,13 @@ namespace smt {
|
|||
v.shrink(old_size);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void context::mark_as_deleted(clause * cls) {
|
||||
SASSERT(!cls->deleted());
|
||||
remove_cls_occs(cls);
|
||||
cls->mark_as_deleted(m_manager);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Undo variable assignments.
|
||||
|
@ -2042,7 +2064,7 @@ namespace smt {
|
|||
m_assignment[(~l).index()] = l_undef;
|
||||
bool_var v = l.var();
|
||||
bool_var_data & d = get_bdata(v);
|
||||
d.m_justification = null_b_justification;
|
||||
d.set_null_justification();
|
||||
m_case_split_queue->unassign_var_eh(v);
|
||||
}
|
||||
|
||||
|
@ -2480,6 +2502,13 @@ namespace smt {
|
|||
SASSERT(m_scope_lvl == m_base_lvl);
|
||||
}
|
||||
|
||||
void context::pop_to_search_lvl() {
|
||||
unsigned num_levels = m_scope_lvl - get_search_level();
|
||||
if (num_levels > 0) {
|
||||
pop_scope(num_levels);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Simplify the given clause using the assignment. Return
|
||||
true if the clause was already satisfied, and false otherwise.
|
||||
|
@ -2595,10 +2624,10 @@ namespace smt {
|
|||
cls->set_justification(0);
|
||||
m_justifications.push_back(js);
|
||||
}
|
||||
m_bdata[v0].m_justification = b_justification(js);
|
||||
set_justification(v0, m_bdata[v0], b_justification(js));
|
||||
}
|
||||
else
|
||||
m_bdata[v0].m_justification = b_justification::mk_axiom();
|
||||
m_bdata[v0].set_axiom();
|
||||
}
|
||||
}
|
||||
del_clause(cls);
|
||||
|
@ -3085,7 +3114,11 @@ namespace smt {
|
|||
if (!m_asserted_formulas.inconsistent()) {
|
||||
unsigned sz = m_asserted_formulas.get_num_formulas();
|
||||
unsigned qhead = m_asserted_formulas.get_qhead();
|
||||
while (qhead < sz && !m_manager.canceled()) {
|
||||
while (qhead < sz) {
|
||||
if (get_cancel_flag()) {
|
||||
m_asserted_formulas.commit(qhead);
|
||||
return;
|
||||
}
|
||||
expr * f = m_asserted_formulas.get_formula(qhead);
|
||||
proof * pr = m_asserted_formulas.get_formula_proof(qhead);
|
||||
internalize_assertion(f, pr, 0);
|
||||
|
@ -3142,6 +3175,8 @@ namespace smt {
|
|||
// in a consistent context.
|
||||
if (inconsistent())
|
||||
return;
|
||||
if (get_cancel_flag())
|
||||
return;
|
||||
push_scope();
|
||||
for (unsigned i = 0; i < num_assumptions; i++) {
|
||||
expr * curr_assumption = assumptions[i];
|
||||
|
@ -3181,7 +3216,7 @@ namespace smt {
|
|||
SASSERT(m_assumptions.empty());
|
||||
return;
|
||||
}
|
||||
obj_hashtable<expr> already_found_assumptions;
|
||||
uint_set already_found_assumptions;
|
||||
literal_vector::const_iterator it = m_conflict_resolution->begin_unsat_core();
|
||||
literal_vector::const_iterator end = m_conflict_resolution->end_unsat_core();
|
||||
for (; it != end; ++it) {
|
||||
|
@ -3190,10 +3225,9 @@ namespace smt {
|
|||
SASSERT(get_bdata(l.var()).m_assumption);
|
||||
if (!m_literal2assumption.contains(l.index())) l.neg();
|
||||
SASSERT(m_literal2assumption.contains(l.index()));
|
||||
expr * a = m_literal2assumption[l.index()];
|
||||
if (!already_found_assumptions.contains(a)) {
|
||||
already_found_assumptions.insert(a);
|
||||
m_unsat_core.push_back(a);
|
||||
if (!already_found_assumptions.contains(l.index())) {
|
||||
already_found_assumptions.insert(l.index());
|
||||
m_unsat_core.push_back(m_literal2assumption[l.index()]);
|
||||
}
|
||||
}
|
||||
reset_assumptions();
|
||||
|
@ -3438,19 +3472,6 @@ namespace smt {
|
|||
m_num_conflicts_since_restart = 0;
|
||||
}
|
||||
|
||||
struct context::scoped_mk_model {
|
||||
context & m_ctx;
|
||||
scoped_mk_model(context & ctx):m_ctx(ctx) {
|
||||
m_ctx.m_proto_model = 0;
|
||||
m_ctx.m_model = 0;
|
||||
}
|
||||
~scoped_mk_model() {
|
||||
if (m_ctx.m_proto_model.get() != 0) {
|
||||
m_ctx.m_model = m_ctx.m_proto_model->mk_model();
|
||||
m_ctx.m_proto_model = 0; // proto_model is not needed anymore.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
lbool context::search() {
|
||||
#ifndef _EXTERNAL_RELEASE
|
||||
|
@ -3478,78 +3499,10 @@ namespace smt {
|
|||
TRACE("search_bug", tout << "status: " << status << ", inconsistent: " << inconsistent() << "\n";);
|
||||
TRACE("assigned_literals_per_lvl", display_num_assigned_literals_per_lvl(tout);
|
||||
tout << ", num_assigned: " << m_assigned_literals.size() << "\n";);
|
||||
|
||||
if (m_last_search_failure != OK) {
|
||||
if (status != l_false) {
|
||||
// build candidate model before returning
|
||||
mk_proto_model(status);
|
||||
// status = l_undef;
|
||||
}
|
||||
|
||||
if (!restart(status, curr_lvl)) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool force_restart = false;
|
||||
|
||||
if (status == l_false) {
|
||||
break;
|
||||
}
|
||||
else if (status == l_true) {
|
||||
SASSERT(!inconsistent());
|
||||
mk_proto_model(l_true);
|
||||
// possible outcomes DONE l_true, DONE l_undef, CONTINUE
|
||||
quantifier_manager::check_model_result cmr = m_qmanager->check_model(m_proto_model.get(), m_model_generator->get_root2value());
|
||||
if (cmr == quantifier_manager::SAT) {
|
||||
// done
|
||||
break;
|
||||
}
|
||||
if (cmr == quantifier_manager::UNKNOWN) {
|
||||
// giving up
|
||||
m_last_search_failure = QUANTIFIERS;
|
||||
status = l_undef;
|
||||
break;
|
||||
}
|
||||
status = l_undef;
|
||||
force_restart = true;
|
||||
}
|
||||
|
||||
SASSERT(status == l_undef);
|
||||
inc_limits();
|
||||
if (force_restart || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) {
|
||||
SASSERT(!inconsistent());
|
||||
IF_VERBOSE(1, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations
|
||||
<< " :decisions " << m_stats.m_num_decisions
|
||||
<< " :conflicts " << m_stats.m_num_conflicts << " :restart " << m_restart_threshold;
|
||||
if (m_fparams.m_restart_strategy == RS_IN_OUT_GEOMETRIC) {
|
||||
verbose_stream() << " :restart-outer " << m_restart_outer_threshold;
|
||||
}
|
||||
if (m_fparams.m_restart_adaptive) {
|
||||
verbose_stream() << " :agility " << m_agility;
|
||||
}
|
||||
verbose_stream() << ")" << std::endl; verbose_stream().flush(););
|
||||
// execute the restart
|
||||
m_stats.m_num_restarts++;
|
||||
if (m_scope_lvl > curr_lvl) {
|
||||
pop_scope(m_scope_lvl - curr_lvl);
|
||||
SASSERT(at_search_level());
|
||||
}
|
||||
ptr_vector<theory>::iterator it = m_theory_set.begin();
|
||||
ptr_vector<theory>::iterator end = m_theory_set.end();
|
||||
for (; it != end && !inconsistent(); ++it)
|
||||
(*it)->restart_eh();
|
||||
TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";);
|
||||
if (!inconsistent()) {
|
||||
m_qmanager->restart_eh();
|
||||
}
|
||||
if (inconsistent()) {
|
||||
VERIFY(!resolve_conflict());
|
||||
status = l_false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_fparams.m_simplify_clauses)
|
||||
simplify_clauses();
|
||||
if (m_fparams.m_lemma_gc_strategy == LGC_AT_RESTART)
|
||||
del_inactive_lemmas();
|
||||
}
|
||||
|
||||
TRACE("search_lite", tout << "status: " << status << "\n";);
|
||||
|
@ -3563,6 +3516,80 @@ namespace smt {
|
|||
end_search();
|
||||
return status;
|
||||
}
|
||||
|
||||
bool context::restart(lbool& status, unsigned curr_lvl) {
|
||||
|
||||
if (m_last_search_failure != OK) {
|
||||
if (status != l_false) {
|
||||
// build candidate model before returning
|
||||
mk_proto_model(status);
|
||||
// status = l_undef;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status == l_false) {
|
||||
return false;
|
||||
}
|
||||
if (status == l_true) {
|
||||
SASSERT(!inconsistent());
|
||||
mk_proto_model(l_true);
|
||||
// possible outcomes DONE l_true, DONE l_undef, CONTINUE
|
||||
quantifier_manager::check_model_result cmr = m_qmanager->check_model(m_proto_model.get(), m_model_generator->get_root2value());
|
||||
if (cmr == quantifier_manager::SAT) {
|
||||
// done
|
||||
status = l_true;
|
||||
return false;
|
||||
}
|
||||
if (cmr == quantifier_manager::UNKNOWN) {
|
||||
IF_VERBOSE(1, verbose_stream() << "(smt.giveup quantifiers)\n";);
|
||||
// giving up
|
||||
m_last_search_failure = QUANTIFIERS;
|
||||
status = l_undef;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
inc_limits();
|
||||
if (status == l_true || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) {
|
||||
SASSERT(!inconsistent());
|
||||
IF_VERBOSE(1, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations
|
||||
<< " :decisions " << m_stats.m_num_decisions
|
||||
<< " :conflicts " << m_stats.m_num_conflicts << " :restart " << m_restart_threshold;
|
||||
if (m_fparams.m_restart_strategy == RS_IN_OUT_GEOMETRIC) {
|
||||
verbose_stream() << " :restart-outer " << m_restart_outer_threshold;
|
||||
}
|
||||
if (m_fparams.m_restart_adaptive) {
|
||||
verbose_stream() << " :agility " << m_agility;
|
||||
}
|
||||
verbose_stream() << ")" << std::endl; verbose_stream().flush(););
|
||||
// execute the restart
|
||||
m_stats.m_num_restarts++;
|
||||
if (m_scope_lvl > curr_lvl) {
|
||||
pop_scope(m_scope_lvl - curr_lvl);
|
||||
SASSERT(at_search_level());
|
||||
}
|
||||
ptr_vector<theory>::iterator it = m_theory_set.begin();
|
||||
ptr_vector<theory>::iterator end = m_theory_set.end();
|
||||
for (; it != end && !inconsistent(); ++it)
|
||||
(*it)->restart_eh();
|
||||
TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";);
|
||||
if (!inconsistent()) {
|
||||
m_qmanager->restart_eh();
|
||||
}
|
||||
if (inconsistent()) {
|
||||
VERIFY(!resolve_conflict());
|
||||
status = l_false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_fparams.m_simplify_clauses)
|
||||
simplify_clauses();
|
||||
if (m_fparams.m_lemma_gc_strategy == LGC_AT_RESTART)
|
||||
del_inactive_lemmas();
|
||||
|
||||
status = l_undef;
|
||||
return true;
|
||||
}
|
||||
|
||||
void context::tick(unsigned & counter) const {
|
||||
counter++;
|
||||
|
@ -3579,7 +3606,6 @@ namespace smt {
|
|||
}
|
||||
|
||||
lbool context::bounded_search() {
|
||||
SASSERT(!inconsistent());
|
||||
unsigned counter = 0;
|
||||
|
||||
TRACE("bounded_search", tout << "starting bounded search...\n";);
|
||||
|
@ -3653,6 +3679,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
if (resource_limits_exceeded() && !inconsistent()) {
|
||||
m_last_search_failure = RESOURCE_LIMIT;
|
||||
return l_undef;
|
||||
}
|
||||
}
|
||||
|
@ -3923,15 +3950,15 @@ namespace smt {
|
|||
#ifdef Z3DEBUG
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal l = lits[i];
|
||||
if (m_manager.is_not(expr_lits.get(i))) {
|
||||
if (expr_signs[i] != l.sign()) {
|
||||
expr* real_atom;
|
||||
VERIFY(m_manager.is_not(expr_lits.get(i), real_atom));
|
||||
// the sign must have flipped when internalizing
|
||||
expr * real_atom = to_app(expr_lits.get(i))->get_arg(0);
|
||||
CTRACE("resolve_conflict_bug", real_atom != bool_var2expr(l.var()), tout << mk_pp(real_atom, m_manager) << "\n" << mk_pp(bool_var2expr(l.var()), m_manager) << "\n";);
|
||||
SASSERT(real_atom == bool_var2expr(l.var()));
|
||||
SASSERT(expr_signs[i] != l.sign());
|
||||
}
|
||||
else {
|
||||
SASSERT(expr_lits.get(i) == bool_var2expr(l.var()));
|
||||
SASSERT(expr_signs[i] == l.sign());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -4275,7 +4302,7 @@ namespace smt {
|
|||
m_fingerprints.display(tout);
|
||||
);
|
||||
failure fl = get_last_search_failure();
|
||||
if (fl == MEMOUT || fl == CANCELED || fl == TIMEOUT || fl == NUM_CONFLICTS) {
|
||||
if (fl == MEMOUT || fl == CANCELED || fl == TIMEOUT || fl == NUM_CONFLICTS || fl == RESOURCE_LIMIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,9 +50,9 @@ Revision History:
|
|||
#include"statistics.h"
|
||||
#include"progress_callback.h"
|
||||
|
||||
// there is a significant space overhead with allocating 1000+ contexts in
|
||||
// there is a significant space overhead with allocating 1000+ contexts in
|
||||
// the case that each context only references a few expressions.
|
||||
// Using a map instead of a vector for the literals can compress space
|
||||
// Using a map instead of a vector for the literals can compress space
|
||||
// consumption.
|
||||
#ifdef SPARSE_MAP
|
||||
#define USE_BOOL_VAR_VECTOR 0
|
||||
|
@ -98,7 +98,7 @@ namespace smt {
|
|||
// Remark: boolean expressions can also be internalized as
|
||||
// enodes. Examples: boolean expression nested in an
|
||||
// uninterpreted function.
|
||||
expr_ref_vector m_e_internalized_stack; // stack of the expressions already internalized as enodes.
|
||||
expr_ref_vector m_e_internalized_stack; // stack of the expressions already internalized as enodes.
|
||||
|
||||
ptr_vector<justification> m_justifications;
|
||||
|
||||
|
@ -116,7 +116,7 @@ namespace smt {
|
|||
plugin_manager<theory> m_theories; // mapping from theory_id -> theory
|
||||
ptr_vector<theory> m_theory_set; // set of theories for fast traversal
|
||||
vector<enode_vector> m_decl2enodes; // decl -> enode (for decls with arity > 0)
|
||||
cg_table m_cg_table;
|
||||
cg_table m_cg_table;
|
||||
dyn_ack_manager m_dyn_ack_manager;
|
||||
struct new_eq {
|
||||
enode * m_lhs;
|
||||
|
@ -140,7 +140,7 @@ namespace smt {
|
|||
svector<new_th_eq> m_propagated_th_eqs;
|
||||
svector<new_th_eq> m_propagated_th_diseqs;
|
||||
svector<enode_pair> m_diseq_vector;
|
||||
#endif
|
||||
#endif
|
||||
enode * m_is_diseq_tmp; // auxiliary enode used to find congruent equality atoms.
|
||||
|
||||
tmp_enode m_tmp_enode;
|
||||
|
@ -161,8 +161,8 @@ namespace smt {
|
|||
vector<watch_list> m_watches; //!< per literal
|
||||
vector<clause_set> m_lit_occs; //!< index for backward subsumption
|
||||
svector<bool_var_data> m_bdata; //!< mapping bool_var -> data
|
||||
svector<double> m_activity;
|
||||
clause_vector m_aux_clauses;
|
||||
svector<double> m_activity;
|
||||
clause_vector m_aux_clauses;
|
||||
clause_vector m_lemmas;
|
||||
vector<clause_vector> m_clauses_to_reinit;
|
||||
expr_ref_vector m_units_to_reassert;
|
||||
|
@ -176,7 +176,7 @@ namespace smt {
|
|||
bool m_phase_cache_on;
|
||||
unsigned m_phase_counter; //!< auxiliary variable used to decide when to turn on/off phase caching
|
||||
bool m_phase_default; //!< default phase when using phase caching
|
||||
|
||||
|
||||
// A conflict is usually a single justification. That is, a justification
|
||||
// for false. If m_not_l is not null_literal, then m_conflict is a
|
||||
// justification for l, and the conflict is union of m_no_l and m_conflict;
|
||||
|
@ -200,17 +200,30 @@ namespace smt {
|
|||
model_ref m_model;
|
||||
std::string m_unknown;
|
||||
void mk_proto_model(lbool r);
|
||||
struct scoped_mk_model;
|
||||
struct scoped_mk_model {
|
||||
context & m_ctx;
|
||||
scoped_mk_model(context & ctx):m_ctx(ctx) {
|
||||
m_ctx.m_proto_model = 0;
|
||||
m_ctx.m_model = 0;
|
||||
}
|
||||
~scoped_mk_model() {
|
||||
if (m_ctx.m_proto_model.get() != 0) {
|
||||
m_ctx.m_model = m_ctx.m_proto_model->mk_model();
|
||||
m_ctx.m_proto_model = 0; // proto_model is not needed anymore.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Unsat core extraction
|
||||
//
|
||||
// -----------------------------------
|
||||
typedef u_map<expr *> literal2assumption;
|
||||
typedef u_map<expr *> literal2assumption;
|
||||
literal_vector m_assumptions;
|
||||
literal2assumption m_literal2assumption; // maps an expression associated with a literal to the original assumption
|
||||
expr_ref_vector m_unsat_core;
|
||||
expr_ref_vector m_unsat_core;
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
|
@ -245,7 +258,6 @@ namespace smt {
|
|||
return m_params;
|
||||
}
|
||||
|
||||
|
||||
bool get_cancel_flag() { return !m_manager.limit().inc(); }
|
||||
|
||||
region & get_region() {
|
||||
|
@ -260,7 +272,7 @@ namespace smt {
|
|||
SASSERT(e_internalized(n));
|
||||
return m_app2enode[n->get_id()];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Similar to get_enode, but returns 0 if n is to e_internalized.
|
||||
*/
|
||||
|
@ -322,7 +334,7 @@ namespace smt {
|
|||
literal enode2literal(enode const * n) const {
|
||||
SASSERT(n->is_bool());
|
||||
return n == m_false_enode ? false_literal : literal(enode2bool_var(n));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned get_num_bool_vars() const {
|
||||
return m_b_internalized_stack.size();
|
||||
|
@ -335,7 +347,7 @@ namespace smt {
|
|||
bool_var_data const & get_bdata(bool_var v) const {
|
||||
return m_bdata[v];
|
||||
}
|
||||
|
||||
|
||||
lbool get_lit_assignment(unsigned lit_idx) const {
|
||||
return static_cast<lbool>(m_assignment[lit_idx]);
|
||||
}
|
||||
|
@ -348,8 +360,8 @@ namespace smt {
|
|||
return get_assignment(literal(v));
|
||||
}
|
||||
|
||||
literal_vector const & assigned_literals() const {
|
||||
return m_assigned_literals;
|
||||
literal_vector const & assigned_literals() const {
|
||||
return m_assigned_literals;
|
||||
}
|
||||
|
||||
lbool get_assignment(expr * n) const;
|
||||
|
@ -362,9 +374,11 @@ namespace smt {
|
|||
void get_assignments(expr_ref_vector& assignments);
|
||||
|
||||
b_justification get_justification(bool_var v) const {
|
||||
return get_bdata(v).m_justification;
|
||||
return get_bdata(v).justification();
|
||||
}
|
||||
|
||||
void set_justification(bool_var v, bool_var_data& d, b_justification const& j);
|
||||
|
||||
bool has_th_justification(bool_var v, theory_id th_id) const {
|
||||
b_justification js = get_justification(v);
|
||||
return js.get_kind() == b_justification::JUSTIFICATION && js.get_justification()->get_from_theory() == th_id;
|
||||
|
@ -422,7 +436,7 @@ namespace smt {
|
|||
unsigned get_assign_level(literal l) const {
|
||||
return get_assign_level(l.var());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Return the scope level when v was internalized.
|
||||
*/
|
||||
|
@ -433,7 +447,7 @@ namespace smt {
|
|||
theory * get_theory(theory_id th_id) const {
|
||||
return m_theories.get_plugin(th_id);
|
||||
}
|
||||
|
||||
|
||||
ptr_vector<theory>::const_iterator begin_theories() const {
|
||||
return m_theories.begin();
|
||||
}
|
||||
|
@ -447,7 +461,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
unsigned get_base_level() const {
|
||||
return m_base_lvl;
|
||||
return m_base_lvl;
|
||||
}
|
||||
|
||||
bool at_base_level() const {
|
||||
|
@ -467,11 +481,11 @@ namespace smt {
|
|||
}
|
||||
|
||||
expr * bool_var2expr(bool_var v) const {
|
||||
return m_bool_var2expr[v];
|
||||
return m_bool_var2expr[v];
|
||||
}
|
||||
|
||||
|
||||
void literal2expr(literal l, expr_ref & result) const {
|
||||
if (l == true_literal)
|
||||
if (l == true_literal)
|
||||
result = m_manager.mk_true();
|
||||
else if (l == false_literal)
|
||||
result = m_manager.mk_false();
|
||||
|
@ -498,7 +512,7 @@ namespace smt {
|
|||
unsigned id = decl->get_decl_id();
|
||||
return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : 0;
|
||||
}
|
||||
|
||||
|
||||
enode_vector::const_iterator end_enodes_of(func_decl const * decl) const {
|
||||
unsigned id = decl->get_decl_id();
|
||||
return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : 0;
|
||||
|
@ -588,7 +602,7 @@ namespace smt {
|
|||
void push_scope();
|
||||
|
||||
unsigned pop_scope_core(unsigned num_scopes);
|
||||
|
||||
|
||||
void pop_scope(unsigned num_scopes);
|
||||
|
||||
void undo_trail_stack(unsigned old_size);
|
||||
|
@ -614,13 +628,13 @@ namespace smt {
|
|||
bool is_empty_clause(clause const * c) const;
|
||||
|
||||
void cache_generation(unsigned new_scope_lvl);
|
||||
|
||||
|
||||
void cache_generation(clause const * cls, unsigned new_scope_lvl);
|
||||
|
||||
void cache_generation(unsigned num_lits, literal const * lits, unsigned new_scope_lvl);
|
||||
|
||||
void cache_generation(expr * n, unsigned new_scope_lvl);
|
||||
|
||||
|
||||
void reset_cache_generation();
|
||||
|
||||
void reinit_clauses(unsigned num_scopes, unsigned num_bool_vars);
|
||||
|
@ -629,14 +643,14 @@ namespace smt {
|
|||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Internalization
|
||||
// Internalization
|
||||
//
|
||||
// -----------------------------------
|
||||
public:
|
||||
bool b_internalized(expr const * n) const {
|
||||
return get_bool_var_of_id_option(n->get_id()) != null_bool_var;
|
||||
}
|
||||
|
||||
|
||||
bool lit_internalized(expr const * n) const {
|
||||
return m_manager.is_false(n) || (m_manager.is_not(n) ? b_internalized(to_app(n)->get_arg(0)) : b_internalized(n));
|
||||
}
|
||||
|
@ -645,7 +659,7 @@ namespace smt {
|
|||
return m_app2enode.get(n->get_id(), 0) != 0;
|
||||
}
|
||||
|
||||
unsigned get_num_b_internalized() const {
|
||||
unsigned get_num_b_internalized() const {
|
||||
return m_b_internalized_stack.size();
|
||||
}
|
||||
|
||||
|
@ -653,7 +667,7 @@ namespace smt {
|
|||
return m_b_internalized_stack.get(idx);
|
||||
}
|
||||
|
||||
unsigned get_num_e_internalized() const {
|
||||
unsigned get_num_e_internalized() const {
|
||||
return m_e_internalized_stack.size();
|
||||
}
|
||||
|
||||
|
@ -690,9 +704,9 @@ namespace smt {
|
|||
void ts_visit_child(expr * n, bool gate_ctx, svector<int> & tcolors, svector<int> & fcolors, svector<expr_bool_pair> & todo, bool & visited);
|
||||
|
||||
bool ts_visit_children(expr * n, bool gate_ctx, svector<int> & tcolors, svector<int> & fcolors, svector<expr_bool_pair> & todo);
|
||||
|
||||
|
||||
void top_sort_expr(expr * n, svector<expr_bool_pair> & sorted_exprs);
|
||||
|
||||
|
||||
void assert_default(expr * n, proof * pr);
|
||||
|
||||
void assert_distinct(app * n, proof * pr);
|
||||
|
@ -720,7 +734,7 @@ namespace smt {
|
|||
void internalize_term(app * n);
|
||||
|
||||
void internalize_ite_term(app * n);
|
||||
|
||||
|
||||
bool internalize_theory_term(app * n);
|
||||
|
||||
void internalize_uninterpreted(app * n);
|
||||
|
@ -751,7 +765,7 @@ namespace smt {
|
|||
bool simplify_aux_lemma_literals(unsigned & num_lits, literal * lits);
|
||||
|
||||
void mark_for_reinit(clause * cls, unsigned scope_lvl, bool reinternalize_atoms);
|
||||
|
||||
|
||||
unsigned get_max_iscope_lvl(unsigned num_lits, literal const * lits) const;
|
||||
|
||||
bool use_binary_clause_opt(literal l1, literal l2, bool lemma) const;
|
||||
|
@ -783,7 +797,7 @@ namespace smt {
|
|||
void add_and_rel_watches(app * n);
|
||||
|
||||
void add_or_rel_watches(app * n);
|
||||
|
||||
|
||||
void add_ite_rel_watches(app * n);
|
||||
|
||||
void mk_not_cnstr(app * n);
|
||||
|
@ -795,7 +809,7 @@ namespace smt {
|
|||
void mk_iff_cnstr(app * n);
|
||||
|
||||
void mk_ite_cnstr(app * n);
|
||||
|
||||
|
||||
bool lit_occs_enabled() const { return m_fparams.m_phase_selection==PS_OCCURRENCE; }
|
||||
|
||||
void add_lit_occs(clause * cls);
|
||||
|
@ -838,7 +852,7 @@ namespace smt {
|
|||
bool propagate_th_case_split();
|
||||
|
||||
bool_var mk_bool_var(expr * n);
|
||||
|
||||
|
||||
enode * mk_enode(app * n, bool suppress_args, bool merge_tf, bool cgc_enabled);
|
||||
|
||||
void attach_th_var(enode * n, theory * th, theory_var v);
|
||||
|
@ -847,7 +861,7 @@ namespace smt {
|
|||
justification * mk_justification(Justification const & j) {
|
||||
justification * js = new (m_region) Justification(j);
|
||||
SASSERT(js->in_region());
|
||||
if (js->has_del_eh())
|
||||
if (js->has_del_eh())
|
||||
m_justifications.push_back(js);
|
||||
return js;
|
||||
}
|
||||
|
@ -868,10 +882,10 @@ namespace smt {
|
|||
unsigned m_num_conflicts_since_lemma_gc;
|
||||
unsigned m_restart_threshold;
|
||||
unsigned m_restart_outer_threshold;
|
||||
unsigned m_luby_idx;
|
||||
unsigned m_luby_idx;
|
||||
double m_agility;
|
||||
unsigned m_lemma_gc_threshold;
|
||||
|
||||
|
||||
void assign_core(literal l, b_justification j, bool decision = false);
|
||||
void trace_assign(literal l, b_justification j, bool decision) const;
|
||||
|
||||
|
@ -897,7 +911,7 @@ namespace smt {
|
|||
|
||||
friend class set_true_first_trail;
|
||||
void set_true_first_flag(bool_var v);
|
||||
|
||||
|
||||
bool try_true_first(bool_var v) const { return get_bdata(v).try_true_first(); }
|
||||
|
||||
bool assume_eq(enode * lhs, enode * rhs);
|
||||
|
@ -918,13 +932,13 @@ namespace smt {
|
|||
d.m_phase = phase;
|
||||
}
|
||||
|
||||
void force_phase(literal l) {
|
||||
void force_phase(literal l) {
|
||||
force_phase(l.var(), !l.sign());
|
||||
}
|
||||
|
||||
bool contains_instance(quantifier * q, unsigned num_bindings, enode * const * bindings);
|
||||
|
||||
bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation,
|
||||
bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation,
|
||||
unsigned min_top_generation, unsigned max_top_generation, ptr_vector<enode> & used_enodes);
|
||||
|
||||
void set_global_generation(unsigned generation) { m_generation = generation; }
|
||||
|
@ -973,11 +987,11 @@ namespace smt {
|
|||
push_eq(n1, n2, eq_justification::mk_cg(used_commutativity));
|
||||
}
|
||||
|
||||
void add_diseq(enode * n1, enode * n2);
|
||||
bool add_diseq(enode * n1, enode * n2);
|
||||
|
||||
void assign_quantifier(quantifier * q);
|
||||
|
||||
void set_conflict(b_justification js, literal not_l);
|
||||
void set_conflict(b_justification js, literal not_l);
|
||||
|
||||
void set_conflict(b_justification js) {
|
||||
set_conflict(js, null_literal);
|
||||
|
@ -1016,12 +1030,12 @@ namespace smt {
|
|||
#define INV_ACTIVITY_LIMIT 1e-100
|
||||
|
||||
void rescale_bool_var_activity();
|
||||
|
||||
|
||||
public:
|
||||
void inc_bvar_activity(bool_var v) {
|
||||
double & act = m_activity[v];
|
||||
act += m_bvar_inc;
|
||||
if (act > ACTIVITY_LIMIT)
|
||||
if (act > ACTIVITY_LIMIT)
|
||||
rescale_bool_var_activity();
|
||||
m_case_split_queue->activity_increased_eh(v);
|
||||
}
|
||||
|
@ -1050,7 +1064,7 @@ namespace smt {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool can_delete(clause * cls) const {
|
||||
if (cls->in_reinit_stack())
|
||||
return false;
|
||||
|
@ -1072,7 +1086,7 @@ namespace smt {
|
|||
bool validate_assumptions(unsigned num_assumptions, expr * const * assumptions);
|
||||
|
||||
void init_assumptions(unsigned num_assumptions, expr * const * assumptions);
|
||||
|
||||
|
||||
void reset_assumptions();
|
||||
|
||||
void mk_unsat_core();
|
||||
|
@ -1087,12 +1101,14 @@ namespace smt {
|
|||
|
||||
void inc_limits();
|
||||
|
||||
bool restart(lbool& status, unsigned curr_lvl);
|
||||
|
||||
void tick(unsigned & counter) const;
|
||||
|
||||
lbool bounded_search();
|
||||
|
||||
|
||||
final_check_status final_check();
|
||||
|
||||
|
||||
void check_proof(proof * pr);
|
||||
|
||||
void forget_phase_of_vars_in_current_level();
|
||||
|
@ -1119,7 +1135,7 @@ namespace smt {
|
|||
|
||||
public:
|
||||
// event handler for relevancy_propagator class
|
||||
void relevant_eh(expr * n);
|
||||
void relevant_eh(expr * n);
|
||||
|
||||
bool is_relevant(expr * n) const {
|
||||
return !relevancy() || is_relevant_core(n);
|
||||
|
@ -1143,9 +1159,9 @@ namespace smt {
|
|||
void mark_as_relevant(enode * n) { mark_as_relevant(n->get_owner()); }
|
||||
|
||||
void mark_as_relevant(bool_var v) { mark_as_relevant(bool_var2expr(v)); }
|
||||
|
||||
|
||||
void mark_as_relevant(literal l) { mark_as_relevant(l.var()); }
|
||||
|
||||
|
||||
template<typename Eh>
|
||||
relevancy_eh * mk_relevancy_eh(Eh const & eh) {
|
||||
return m_relevancy_propagator->mk_relevancy_eh(eh);
|
||||
|
@ -1166,9 +1182,9 @@ namespace smt {
|
|||
void propagate_th_eqs();
|
||||
|
||||
void propagate_th_diseqs();
|
||||
|
||||
|
||||
bool can_theories_propagate() const;
|
||||
|
||||
|
||||
bool propagate();
|
||||
|
||||
public:
|
||||
|
@ -1184,7 +1200,7 @@ namespace smt {
|
|||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Pretty Printing
|
||||
// Pretty Printing
|
||||
//
|
||||
// -----------------------------------
|
||||
protected:
|
||||
|
@ -1232,7 +1248,7 @@ namespace smt {
|
|||
void display_binary_clauses(std::ostream & out) const;
|
||||
|
||||
void display_assignment(std::ostream & out) const;
|
||||
|
||||
|
||||
void display_eqc(std::ostream & out) const;
|
||||
|
||||
void display_app_enode_map(std::ostream & out) const;
|
||||
|
@ -1252,15 +1268,15 @@ namespace smt {
|
|||
void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const;
|
||||
|
||||
void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const;
|
||||
void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents,
|
||||
unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs,
|
||||
void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents,
|
||||
unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs,
|
||||
literal consequent = false_literal, symbol const& logic = symbol::null) const;
|
||||
|
||||
void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents,
|
||||
unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs,
|
||||
void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents,
|
||||
unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs,
|
||||
literal consequent = false_literal, symbol const& logic = symbol::null) const;
|
||||
|
||||
void display_assignment_as_smtlib2(std::ostream& out, symbol const& logic = symbol::null) const;
|
||||
void display_assignment_as_smtlib2(std::ostream& out, symbol const& logic = symbol::null) const;
|
||||
|
||||
void display_normalized_enodes(std::ostream & out) const;
|
||||
|
||||
|
@ -1306,13 +1322,13 @@ namespace smt {
|
|||
bool check_invariant() const;
|
||||
|
||||
bool check_eqc_bool_assignment() const;
|
||||
|
||||
|
||||
bool check_missing_clause_propagation(clause_vector const & v) const;
|
||||
|
||||
bool check_missing_bin_clause_propagation() const;
|
||||
|
||||
bool check_missing_eq_propagation() const;
|
||||
|
||||
|
||||
bool check_missing_congruence() const;
|
||||
|
||||
bool check_missing_bool_enode_propagation() const;
|
||||
|
@ -1353,6 +1369,7 @@ namespace smt {
|
|||
virtual void setup_context(bool use_static_features);
|
||||
void setup_components(void);
|
||||
void pop_to_base_lvl();
|
||||
void pop_to_search_lvl();
|
||||
#ifdef Z3DEBUG
|
||||
bool already_internalized_theory(theory * th) const;
|
||||
bool already_internalized_theory_core(theory * th, expr_ref_vector const & s) const;
|
||||
|
@ -1374,6 +1391,38 @@ namespace smt {
|
|||
literal lit, context& src_ctx, context& dst_ctx,
|
||||
vector<bool_var> b2v, ast_translation& tr);
|
||||
|
||||
/*
|
||||
\brief Utilities for consequence finding.
|
||||
*/
|
||||
typedef hashtable<unsigned, u_hash, u_eq> index_set;
|
||||
//typedef uint_set index_set;
|
||||
u_map<index_set> m_antecedents;
|
||||
void extract_fixed_consequences(literal lit, obj_map<expr, expr*>& var2val, index_set const& assumptions, expr_ref_vector& conseq);
|
||||
void extract_fixed_consequences(unsigned& idx, obj_map<expr, expr*>& var2val, index_set const& assumptions, expr_ref_vector& conseq);
|
||||
|
||||
void display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq);
|
||||
|
||||
unsigned delete_unfixed(obj_map<expr, expr*>& var2val, expr_ref_vector& unfixed);
|
||||
|
||||
unsigned extract_fixed_eqs(obj_map<expr, expr*>& var2val, expr_ref_vector& conseq);
|
||||
|
||||
expr_ref antecedent2fml(index_set const& ante);
|
||||
|
||||
|
||||
literal mk_diseq(expr* v, expr* val);
|
||||
|
||||
void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars,
|
||||
expr_ref_vector const& conseq, expr_ref_vector const& unfixed);
|
||||
|
||||
bool validate_justification(bool_var v, bool_var_data const& d, b_justification const& j);
|
||||
|
||||
void justify(literal lit, index_set& s);
|
||||
|
||||
void extract_cores(expr_ref_vector const& asms, vector<expr_ref_vector>& cores, unsigned& min_core_size);
|
||||
|
||||
void preferred_sat(literal_vector& literals);
|
||||
|
||||
void display_partial_assignment(std::ostream& out, expr_ref_vector const& asms, unsigned min_core_size);
|
||||
|
||||
public:
|
||||
context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref());
|
||||
|
@ -1412,12 +1461,18 @@ namespace smt {
|
|||
|
||||
void pop(unsigned num_scopes);
|
||||
|
||||
lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true);
|
||||
|
||||
lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true);
|
||||
|
||||
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed);
|
||||
|
||||
lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes);
|
||||
|
||||
lbool preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores);
|
||||
|
||||
lbool setup_and_check(bool reset_cancel = true);
|
||||
|
||||
|
||||
// return 'true' if assertions are inconsistent.
|
||||
bool reduce_assertions();
|
||||
bool reduce_assertions();
|
||||
|
||||
bool resource_limits_exceeded();
|
||||
|
||||
|
@ -1437,22 +1492,20 @@ namespace smt {
|
|||
|
||||
void internalize_instance(expr * body, proof * pr, unsigned generation) {
|
||||
internalize_assertion(body, pr, generation);
|
||||
#ifndef SMTCOMP
|
||||
if (relevancy())
|
||||
m_case_split_queue->internalize_instance_eh(body, generation);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool already_internalized() const { return m_e_internalized_stack.size() > 2 || m_b_internalized_stack.size() > 1; }
|
||||
|
||||
|
||||
unsigned get_unsat_core_size() const {
|
||||
return m_unsat_core.size();
|
||||
}
|
||||
|
||||
|
||||
expr * get_unsat_core_expr(unsigned idx) const {
|
||||
return m_unsat_core.get(idx);
|
||||
}
|
||||
|
||||
|
||||
void get_model(model_ref & m) const;
|
||||
|
||||
bool update_model(bool refinalize);
|
||||
|
@ -1460,17 +1513,17 @@ namespace smt {
|
|||
void get_proto_model(proto_model_ref & m) const;
|
||||
|
||||
bool validate_model();
|
||||
|
||||
|
||||
unsigned get_num_asserted_formulas() const { return m_asserted_formulas.get_num_formulas(); }
|
||||
|
||||
unsigned get_asserted_formulas_last_level() const { return m_asserted_formulas.get_formulas_last_level(); }
|
||||
|
||||
expr * get_asserted_formula(unsigned idx) const { return m_asserted_formulas.get_formula(idx); }
|
||||
|
||||
|
||||
proof * get_asserted_formula_proof(unsigned idx) const { return m_asserted_formulas.get_formula_proof(idx); }
|
||||
|
||||
|
||||
expr * const * get_asserted_formulas() const { return m_asserted_formulas.get_formulas(); }
|
||||
|
||||
|
||||
proof * const * get_asserted_formula_proofs() const { return m_asserted_formulas.get_formula_proofs(); }
|
||||
|
||||
void get_assumptions_core(ptr_vector<expr> & result);
|
||||
|
@ -1482,7 +1535,7 @@ namespace smt {
|
|||
void display_unsat_core(std::ostream & out) const;
|
||||
|
||||
void collect_statistics(::statistics & st) const;
|
||||
|
||||
|
||||
void display_statistics(std::ostream & out) const;
|
||||
void display_istatistics(std::ostream & out) const;
|
||||
|
||||
|
|
|
@ -322,6 +322,9 @@ namespace smt {
|
|||
bool context::check_th_diseq_propagation() const {
|
||||
TRACE("check_th_diseq_propagation", tout << "m_propagated_th_diseqs.size() " << m_propagated_th_diseqs.size() << "\n";);
|
||||
int num = get_num_bool_vars();
|
||||
if (inconsistent()) {
|
||||
return true;
|
||||
}
|
||||
for (bool_var v = 0; v < num; v++) {
|
||||
if (has_enode(v)) {
|
||||
enode * n = bool_var2enode(v);
|
||||
|
@ -399,6 +402,20 @@ namespace smt {
|
|||
|
||||
#endif
|
||||
|
||||
bool context::validate_justification(bool_var v, bool_var_data const& d, b_justification const& j) {
|
||||
if (j.get_kind() == b_justification::CLAUSE && v != true_bool_var) {
|
||||
clause* cls = j.get_clause();
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
literal l = cls->get_literal(0);
|
||||
if (l.var() != v) {
|
||||
l = cls->get_literal(1);
|
||||
}
|
||||
SASSERT(l.var() == v);
|
||||
SASSERT(m_assignment[l.index()] == l_true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool context::validate_model() {
|
||||
if (!m_proto_model) {
|
||||
return true;
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace smt {
|
|||
return out << "CANCELED";
|
||||
case NUM_CONFLICTS:
|
||||
return out << "NUM_CONFLICTS";
|
||||
case RESOURCE_LIMIT:
|
||||
return out << "RESOURCE_LIMIT";
|
||||
case THEORY:
|
||||
if (!m_incomplete_theories.empty()) {
|
||||
ptr_vector<theory>::const_iterator it = m_incomplete_theories.begin();
|
||||
|
@ -78,6 +80,7 @@ namespace smt {
|
|||
r += "))";
|
||||
break;
|
||||
}
|
||||
case RESOURCE_LIMIT: r = "(resource limits reached)"; break;
|
||||
case QUANTIFIERS: r = "(incomplete quantifiers)"; break;
|
||||
case UNKNOWN: r = m_unknown; break;
|
||||
}
|
||||
|
@ -250,7 +253,7 @@ namespace smt {
|
|||
|
||||
void context::display_app_enode_map(std::ostream & out) const {
|
||||
if (!m_e_internalized_stack.empty()) {
|
||||
out << "expresion -> enode:\n";
|
||||
out << "expression -> enode:\n";
|
||||
unsigned sz = m_e_internalized_stack.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * n = m_e_internalized_stack.get(i);
|
||||
|
@ -262,7 +265,7 @@ namespace smt {
|
|||
|
||||
void context::display_expr_bool_var_map(std::ostream & out) const {
|
||||
if (!m_b_internalized_stack.empty()) {
|
||||
out << "expresion -> bool_var:\n";
|
||||
out << "expression -> bool_var:\n";
|
||||
unsigned sz = m_b_internalized_stack.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * n = m_b_internalized_stack.get(i);
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace smt {
|
|||
return static_cast<unsigned>(acc / m_lemmas.size());
|
||||
}
|
||||
|
||||
void acc_num_occs(clause * cls, unsigned_vector & lit2num_occs) {
|
||||
static void acc_num_occs(clause * cls, unsigned_vector & lit2num_occs) {
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal l = cls->get_literal(i);
|
||||
|
@ -40,7 +40,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
void acc_num_occs(clause_vector const & v, unsigned_vector & lit2num_occs) {
|
||||
static void acc_num_occs(clause_vector const & v, unsigned_vector & lit2num_occs) {
|
||||
clause_vector::const_iterator it = v.begin();
|
||||
clause_vector::const_iterator end = v.end();
|
||||
for (; it != end; ++it)
|
||||
|
@ -79,7 +79,7 @@ namespace smt {
|
|||
out << (m_assigned_literals.size() - n) << "]";
|
||||
}
|
||||
|
||||
void acc_var_num_occs(clause * cls, unsigned_vector & var2num_occs) {
|
||||
static void acc_var_num_occs(clause * cls, unsigned_vector & var2num_occs) {
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal l = cls->get_literal(i);
|
||||
|
@ -87,7 +87,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
void acc_var_num_occs(clause_vector const & v, unsigned_vector & var2num_occs) {
|
||||
static void acc_var_num_occs(clause_vector const & v, unsigned_vector & var2num_occs) {
|
||||
clause_vector::const_iterator it = v.begin();
|
||||
clause_vector::const_iterator end = v.end();
|
||||
for (; it != end; ++it)
|
||||
|
@ -114,7 +114,7 @@ namespace smt {
|
|||
out << "\n";
|
||||
}
|
||||
|
||||
void acc_var_num_min_occs(clause * cls, unsigned_vector & var2num_min_occs) {
|
||||
static void acc_var_num_min_occs(clause * cls, unsigned_vector & var2num_min_occs) {
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
bool_var min_var = cls->get_literal(0).var();
|
||||
for (unsigned i = 1; i < num_lits; i++) {
|
||||
|
@ -125,7 +125,7 @@ namespace smt {
|
|||
var2num_min_occs[min_var]++;
|
||||
}
|
||||
|
||||
void acc_var_num_min_occs(clause_vector const & v, unsigned_vector & var2num_min_occs) {
|
||||
static void acc_var_num_min_occs(clause_vector const & v, unsigned_vector & var2num_min_occs) {
|
||||
clause_vector::const_iterator it = v.begin();
|
||||
clause_vector::const_iterator end = v.end();
|
||||
for (; it != end; ++it)
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace smt {
|
|||
CANCELED, //!< External cancel flag was set
|
||||
NUM_CONFLICTS, //!< Maximum number of conflicts was reached
|
||||
THEORY, //!< Theory is incomplete
|
||||
RESOURCE_LIMIT,
|
||||
QUANTIFIERS //!< Logical context contains universal quantifiers.
|
||||
};
|
||||
|
||||
|
|
|
@ -321,10 +321,10 @@ namespace smt {
|
|||
void context::internalize(expr * n, bool gate_ctx) {
|
||||
TRACE("internalize", tout << "internalizing:\n" << mk_pp(n, m_manager) << "\n";);
|
||||
TRACE("internalize_bug", tout << "internalizing:\n" << mk_bounded_pp(n, m_manager) << "\n";);
|
||||
if (is_var(n)) {
|
||||
throw default_exception("Formulas should not contain unbound variables");
|
||||
}
|
||||
if (m_manager.is_bool(n)) {
|
||||
if (is_var(n)) {
|
||||
throw default_exception("Formulas should not contain unbound variables");
|
||||
}
|
||||
SASSERT(is_quantifier(n) || is_app(n));
|
||||
internalize_formula(n, gate_ctx);
|
||||
}
|
||||
|
@ -335,23 +335,6 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
bool find_arg(app * n, expr * t, expr * & other) {
|
||||
SASSERT(n->get_num_args() == 2);
|
||||
if (n->get_arg(0) == t) {
|
||||
other = n->get_arg(1);
|
||||
return true;
|
||||
}
|
||||
else if (n->get_arg(1) == t) {
|
||||
other = n->get_arg(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_args(app * n, expr * t1, expr * t2) {
|
||||
SASSERT(n->get_num_args() == 2);
|
||||
return (n->get_arg(0) == t1 && n->get_arg(1) == t2) || (n->get_arg(1) == t1 && n->get_arg(0) == t2);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Internalize the given formula into the logical context.
|
||||
|
@ -840,7 +823,7 @@ namespace smt {
|
|||
}
|
||||
#endif
|
||||
TRACE("mk_bool_var", tout << "creating boolean variable: " << v << " for:\n" << mk_pp(n, m_manager) << "\n";);
|
||||
TRACE("mk_var_bug", tout << "mk_bool: " << v << "\n";);
|
||||
TRACE("mk_var_bug", tout << "mk_bool: " << v << "\n";);
|
||||
set_bool_var(id, v);
|
||||
m_bdata.reserve(v+1);
|
||||
m_activity.reserve(v+1);
|
||||
|
@ -1045,15 +1028,13 @@ namespace smt {
|
|||
bool context::simplify_aux_clause_literals(unsigned & num_lits, literal * lits, literal_buffer & simp_lits) {
|
||||
std::sort(lits, lits + num_lits);
|
||||
literal prev = null_literal;
|
||||
unsigned i = 0;
|
||||
unsigned j = 0;
|
||||
for (; i < num_lits; i++) {
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal curr = lits[i];
|
||||
lbool val = get_assignment(curr);
|
||||
if (val == l_false)
|
||||
simp_lits.push_back(~curr);
|
||||
switch(val) {
|
||||
case l_false:
|
||||
simp_lits.push_back(~curr);
|
||||
break; // ignore literal
|
||||
case l_undef:
|
||||
if (curr == ~prev)
|
||||
|
@ -1283,10 +1264,9 @@ namespace smt {
|
|||
The deletion event handler is ignored if binary clause optimization is applicable.
|
||||
*/
|
||||
clause * context::mk_clause(unsigned num_lits, literal * lits, justification * j, clause_kind k, clause_del_eh * del_eh) {
|
||||
TRACE("mk_clause", tout << "creating clause:\n"; display_literals(tout, num_lits, lits); tout << "\n";);
|
||||
TRACE("mk_clause", tout << "creating clause:\n"; display_literals_verbose(tout, num_lits, lits); tout << "\n";);
|
||||
switch (k) {
|
||||
case CLS_AUX: {
|
||||
unsigned old_num_lits = num_lits;
|
||||
literal_buffer simp_lits;
|
||||
if (!simplify_aux_clause_literals(num_lits, lits, simp_lits))
|
||||
return 0; // clause is equivalent to true;
|
||||
|
@ -1295,8 +1275,9 @@ namespace smt {
|
|||
SASSERT(get_assignment(simp_lits[i]) == l_true);
|
||||
}
|
||||
});
|
||||
if (old_num_lits != num_lits)
|
||||
if (!simp_lits.empty()) {
|
||||
j = mk_justification(unit_resolution_justification(m_region, j, simp_lits.size(), simp_lits.c_ptr()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLS_AUX_LEMMA: {
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace smt {
|
|||
tout << lits[i] << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
SASSERT(m_num_literals > 0);
|
||||
}
|
||||
|
||||
unit_resolution_justification::unit_resolution_justification(justification * js,
|
||||
|
@ -68,6 +69,7 @@ namespace smt {
|
|||
tout << lits[i] << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
SASSERT(num_lits != 0);
|
||||
}
|
||||
|
||||
unit_resolution_justification::~unit_resolution_justification() {
|
||||
|
|
|
@ -55,6 +55,18 @@ namespace smt {
|
|||
void set_progress_callback(progress_callback * callback) {
|
||||
return m_kernel.set_progress_callback(callback);
|
||||
}
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
// m_kernel.display(out); <<< for external users it is just junk
|
||||
// TODO: it will be replaced with assertion_stack.display
|
||||
unsigned num = m_kernel.get_num_asserted_formulas();
|
||||
expr * const * fms = m_kernel.get_asserted_formulas();
|
||||
out << "(kernel";
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
out << "\n " << mk_ismt2_pp(fms[i], m(), 2);
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
|
||||
void assert_expr(expr * e) {
|
||||
TRACE("smt_kernel", tout << "assert:\n" << mk_ismt2_pp(e, m()) << "\n";);
|
||||
|
@ -98,6 +110,19 @@ namespace smt {
|
|||
lbool check(unsigned num_assumptions, expr * const * assumptions) {
|
||||
return m_kernel.check(num_assumptions, assumptions);
|
||||
}
|
||||
|
||||
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) {
|
||||
return m_kernel.get_consequences(assumptions, vars, conseq, unfixed);
|
||||
}
|
||||
|
||||
lbool preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores) {
|
||||
return m_kernel.preferred_sat(asms, cores);
|
||||
}
|
||||
|
||||
|
||||
lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
|
||||
return m_kernel.find_mutexes(vars, mutexes);
|
||||
}
|
||||
|
||||
void get_model(model_ref & m) const {
|
||||
m_kernel.get_model(m);
|
||||
|
@ -146,18 +171,6 @@ namespace smt {
|
|||
void get_guessed_literals(expr_ref_vector & result) {
|
||||
m_kernel.get_guessed_literals(result);
|
||||
}
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
// m_kernel.display(out); <<< for external users it is just junk
|
||||
// TODO: it will be replaced with assertion_stack.display
|
||||
unsigned num = m_kernel.get_num_asserted_formulas();
|
||||
expr * const * fms = m_kernel.get_asserted_formulas();
|
||||
out << "(kernel";
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
out << "\n " << mk_ismt2_pp(fms[i], m(), 2);
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
|
||||
void collect_statistics(::statistics & st) const {
|
||||
m_kernel.collect_statistics(st);
|
||||
|
@ -214,6 +227,12 @@ namespace smt {
|
|||
m_imp->assert_expr(e);
|
||||
}
|
||||
|
||||
void kernel::assert_expr(expr_ref_vector const& es) {
|
||||
for (unsigned i = 0; i < es.size(); ++i) {
|
||||
m_imp->assert_expr(es[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void kernel::assert_expr(expr * e, proof * pr) {
|
||||
m_imp->assert_expr(e, pr);
|
||||
}
|
||||
|
@ -264,6 +283,18 @@ namespace smt {
|
|||
return r;
|
||||
}
|
||||
|
||||
lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) {
|
||||
return m_imp->get_consequences(assumptions, vars, conseq, unfixed);
|
||||
}
|
||||
|
||||
lbool kernel::preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores) {
|
||||
return m_imp->preferred_sat(asms, cores);
|
||||
}
|
||||
|
||||
lbool kernel::find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
|
||||
return m_imp->find_mutexes(vars, mutexes);
|
||||
}
|
||||
|
||||
void kernel::get_model(model_ref & m) const {
|
||||
m_imp->get_model(m);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,8 @@ namespace smt {
|
|||
This method uses the "asserted" proof as a justification for e.
|
||||
*/
|
||||
void assert_expr(expr * e);
|
||||
|
||||
|
||||
void assert_expr(expr_ref_vector const& es);
|
||||
/**
|
||||
\brief Assert the given assertion with the given proof as a justification.
|
||||
*/
|
||||
|
@ -126,6 +127,22 @@ namespace smt {
|
|||
|
||||
lbool check(app_ref_vector const& asms) { return check(asms.size(), (expr* const*)asms.c_ptr()); }
|
||||
|
||||
/**
|
||||
\brief extract consequences among variables.
|
||||
*/
|
||||
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars,
|
||||
expr_ref_vector& conseq, expr_ref_vector& unfixed);
|
||||
|
||||
/**
|
||||
\brief find mutually exclusive variables.
|
||||
*/
|
||||
lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes);
|
||||
|
||||
/**
|
||||
\brief Preferential SAT.
|
||||
*/
|
||||
lbool preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores);
|
||||
|
||||
/**
|
||||
\brief Return the model associated with the last check command.
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace smt {
|
|||
out << "true";
|
||||
else if (*this == false_literal)
|
||||
out << "false";
|
||||
else if (*this == null_literal)
|
||||
out << "null";
|
||||
else if (sign())
|
||||
out << "(not " << mk_pp(bool_var2expr_map[var()], m) << ")";
|
||||
else
|
||||
|
|
|
@ -112,7 +112,6 @@ namespace smt {
|
|||
if (!m_curr_model->eval(q->get_expr(), tmp, true)) {
|
||||
return;
|
||||
}
|
||||
//std::cout << tmp << "\n";
|
||||
TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";);
|
||||
ptr_buffer<expr> subst_args;
|
||||
unsigned num_decls = q->get_num_decls();
|
||||
|
@ -138,8 +137,10 @@ namespace smt {
|
|||
}
|
||||
|
||||
bool model_checker::add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv) {
|
||||
if (cex == 0)
|
||||
return false; // no model available.
|
||||
if (cex == 0) {
|
||||
TRACE("model_checker", tout << "no model is available\n";);
|
||||
return false;
|
||||
}
|
||||
unsigned num_decls = q->get_num_decls();
|
||||
// Remark: sks were created for the flat version of q.
|
||||
SASSERT(sks.size() >= num_decls);
|
||||
|
@ -153,19 +154,24 @@ namespace smt {
|
|||
sk_value = cex->get_const_interp(sk_d);
|
||||
if (sk_value == 0) {
|
||||
sk_value = cex->get_some_value(sk_d->get_range());
|
||||
if (sk_value == 0)
|
||||
if (sk_value == 0) {
|
||||
TRACE("model_checker", tout << "Could not get value for " << sk_d->get_name() << "\n";);
|
||||
return false; // get_some_value failed... giving up
|
||||
}
|
||||
TRACE("model_checker", tout << "Got some value " << sk_value << "\n";);
|
||||
}
|
||||
if (use_inv) {
|
||||
unsigned sk_term_gen;
|
||||
expr * sk_term = m_model_finder.get_inv(q, i, sk_value, sk_term_gen);
|
||||
if (sk_term != 0) {
|
||||
TRACE("model_checker", tout << "Found inverse " << mk_pp(sk_term, m) << "\n";);
|
||||
SASSERT(!m.is_model_value(sk_term));
|
||||
if (sk_term_gen > max_generation)
|
||||
max_generation = sk_term_gen;
|
||||
sk_value = sk_term;
|
||||
}
|
||||
else {
|
||||
TRACE("model_checker", tout << "no inverse value for " << sk_value << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -175,8 +181,10 @@ namespace smt {
|
|||
sk_value = sk_term;
|
||||
}
|
||||
}
|
||||
if (contains_model_value(sk_value))
|
||||
if (contains_model_value(sk_value)) {
|
||||
TRACE("model_checker", tout << "value is private to model: " << sk_value << "\n";);
|
||||
return false;
|
||||
}
|
||||
bindings.set(num_decls - i - 1, sk_value);
|
||||
}
|
||||
|
||||
|
@ -186,6 +194,7 @@ namespace smt {
|
|||
}
|
||||
tout << "\n";);
|
||||
|
||||
max_generation = std::max(m_qm->get_generation(q), max_generation);
|
||||
add_instance(q, bindings, max_generation);
|
||||
return true;
|
||||
}
|
||||
|
@ -286,18 +295,15 @@ namespace smt {
|
|||
break;
|
||||
model_ref cex;
|
||||
m_aux_context->get_model(cex);
|
||||
if (add_instance(q, cex.get(), sks, true)) {
|
||||
num_new_instances++;
|
||||
if (num_new_instances < m_max_cexs) {
|
||||
if (!add_blocking_clause(cex.get(), sks))
|
||||
break; // add_blocking_clause failed... stop the search for new counter-examples...
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!add_instance(q, cex.get(), sks, true)) {
|
||||
break;
|
||||
}
|
||||
if (num_new_instances >= m_max_cexs)
|
||||
break;
|
||||
num_new_instances++;
|
||||
if (num_new_instances >= m_max_cexs || !add_blocking_clause(cex.get(), sks)) {
|
||||
TRACE("model_checker", tout << "Add blocking clause failed\n";);
|
||||
// add_blocking_clause failed... stop the search for new counter-examples...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_new_instances == 0) {
|
||||
|
@ -357,9 +363,6 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
struct scoped_set_relevancy {
|
||||
};
|
||||
|
||||
bool model_checker::check(proto_model * md, obj_map<enode, app *> const & root2value) {
|
||||
SASSERT(md != 0);
|
||||
m_root2value = &root2value;
|
||||
|
@ -368,8 +371,11 @@ namespace smt {
|
|||
if (it == end)
|
||||
return true;
|
||||
|
||||
if (m_iteration_idx >= m_params.m_mbqi_max_iterations)
|
||||
if (m_iteration_idx >= m_params.m_mbqi_max_iterations) {
|
||||
IF_VERBOSE(1, verbose_stream() << "(smt.mbqi \"max instantiations " << m_iteration_idx << " reached\")\n";);
|
||||
m_context->set_reason_unknown("max mbqi instantiations reached");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_curr_model = md;
|
||||
m_value2expr.reset();
|
||||
|
|
|
@ -315,6 +315,7 @@ namespace smt {
|
|||
|
||||
void mk_instantiation_set(ast_manager & m) {
|
||||
SASSERT(is_root());
|
||||
SASSERT(!m_set);
|
||||
m_set = alloc(instantiation_set, m);
|
||||
}
|
||||
|
||||
|
@ -497,7 +498,7 @@ namespace smt {
|
|||
m_bvsimp = static_cast<bv_simplifier_plugin*>(s.get_plugin(m.mk_family_id("bv")));
|
||||
}
|
||||
|
||||
~auf_solver() {
|
||||
virtual ~auf_solver() {
|
||||
flush_nodes();
|
||||
reset_eval_cache();
|
||||
}
|
||||
|
@ -1001,10 +1002,13 @@ namespace smt {
|
|||
void add_elem_to_empty_inst_sets() {
|
||||
ptr_vector<node>::const_iterator it = m_root_nodes.begin();
|
||||
ptr_vector<node>::const_iterator end = m_root_nodes.end();
|
||||
obj_map<sort, expr*> sort2elems;
|
||||
ptr_vector<node> need_fresh;
|
||||
for (; it != end; ++it) {
|
||||
node * n = *it;
|
||||
SASSERT(n->is_root());
|
||||
instantiation_set const * s = n->get_instantiation_set();
|
||||
TRACE("model_finder", s->display(tout););
|
||||
obj_map<expr, unsigned> const & elems = s->get_elems();
|
||||
if (elems.empty()) {
|
||||
// The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts
|
||||
|
@ -1013,11 +1017,29 @@ namespace smt {
|
|||
// If these module values "leak" inside the logical context, they may affect satisfiability.
|
||||
//
|
||||
sort * ns = n->get_sort();
|
||||
if (m_manager.is_fully_interp(ns))
|
||||
if (m_manager.is_fully_interp(ns)) {
|
||||
n->insert(m_model->get_some_value(ns), 0);
|
||||
else
|
||||
n->insert(m_manager.mk_fresh_const("elem", ns), 0);
|
||||
}
|
||||
else {
|
||||
need_fresh.push_back(n);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sort2elems.insert(n->get_sort(), elems.begin()->m_key);
|
||||
}
|
||||
}
|
||||
expr_ref_vector trail(m_manager);
|
||||
for (unsigned i = 0; i < need_fresh.size(); ++i) {
|
||||
expr * e;
|
||||
node* n = need_fresh[i];
|
||||
sort* s = n->get_sort();
|
||||
if (!sort2elems.find(s, e)) {
|
||||
e = m_manager.mk_fresh_const("elem", s);
|
||||
trail.push_back(e);
|
||||
sort2elems.insert(s, e);
|
||||
}
|
||||
n->insert(e, 0);
|
||||
TRACE("model_finder", tout << "fresh constant: " << mk_pp(e, m_manager) << "\n";);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
|||
#include"smt_context.h"
|
||||
#include"smt_model_generator.h"
|
||||
#include"proto_model.h"
|
||||
#include"ref_util.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_pp.h"
|
||||
|
@ -36,6 +37,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
model_generator::~model_generator() {
|
||||
dec_ref_collection_values(m_manager, m_hidden_ufs);
|
||||
}
|
||||
|
||||
void model_generator::reset() {
|
||||
|
@ -386,6 +388,7 @@ namespace smt {
|
|||
enode * n = *it3;
|
||||
if (is_uninterp_const(n->get_owner()) && m_context->is_relevant(n)) {
|
||||
func_decl * d = n->get_owner()->get_decl();
|
||||
if (m_hidden_ufs.contains(d)) continue;
|
||||
expr * val = get_value(n);
|
||||
m_model->register_decl(d, val);
|
||||
}
|
||||
|
@ -404,9 +407,9 @@ namespace smt {
|
|||
*/
|
||||
bool model_generator::include_func_interp(func_decl * f) const {
|
||||
family_id fid = f->get_family_id();
|
||||
if (fid == null_family_id) return true;
|
||||
if (fid == null_family_id) return !m_hidden_ufs.contains(f);
|
||||
if (fid == m_manager.get_basic_family_id()) return false;
|
||||
theory * th = m_context->get_theory(fid);
|
||||
theory * th = m_context->get_theory(fid);
|
||||
if (!th) return true;
|
||||
return th->include_func_interp(f);
|
||||
}
|
||||
|
|
|
@ -182,6 +182,7 @@ namespace smt {
|
|||
obj_map<enode, app *> m_root2value;
|
||||
ast_ref_vector m_asts;
|
||||
proto_model * m_model;
|
||||
obj_hashtable<func_decl> m_hidden_ufs;
|
||||
|
||||
void init_model();
|
||||
void mk_bool_model();
|
||||
|
@ -220,6 +221,13 @@ namespace smt {
|
|||
|
||||
obj_map<enode, app *> const & get_root2value() const { return m_root2value; }
|
||||
app * get_value(enode * n) const;
|
||||
|
||||
void hide(func_decl * f) {
|
||||
if (!m_hidden_ufs.contains(f)) {
|
||||
m_hidden_ufs.insert(f);
|
||||
m_manager.inc_ref(f);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ Revision History:
|
|||
#include"ast_smt2_pp.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
||||
quantifier_manager_plugin * mk_default_plugin();
|
||||
|
||||
struct quantifier_manager::imp {
|
||||
|
@ -40,7 +40,7 @@ namespace smt {
|
|||
ptr_vector<quantifier> m_quantifiers;
|
||||
scoped_ptr<quantifier_manager_plugin> m_plugin;
|
||||
unsigned m_num_instances;
|
||||
|
||||
|
||||
imp(quantifier_manager & wrapper, context & ctx, smt_params & p, quantifier_manager_plugin * plugin):
|
||||
m_wrapper(wrapper),
|
||||
m_context(ctx),
|
||||
|
@ -85,7 +85,7 @@ namespace smt {
|
|||
out << max_generation << " : " << max_cost << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void del(quantifier * q) {
|
||||
if (m_params.m_qi_profile) {
|
||||
display_stats(verbose_stream(), q);
|
||||
|
@ -99,15 +99,15 @@ namespace smt {
|
|||
}
|
||||
|
||||
bool is_shared(enode * n) const {
|
||||
return m_plugin->is_shared(n);
|
||||
return m_plugin->is_shared(n);
|
||||
}
|
||||
|
||||
bool add_instance(quantifier * q, app * pat,
|
||||
unsigned num_bindings,
|
||||
enode * const * bindings,
|
||||
unsigned max_generation,
|
||||
unsigned min_top_generation,
|
||||
unsigned max_top_generation,
|
||||
bool add_instance(quantifier * q, app * pat,
|
||||
unsigned num_bindings,
|
||||
enode * const * bindings,
|
||||
unsigned max_generation,
|
||||
unsigned min_top_generation,
|
||||
unsigned max_top_generation,
|
||||
ptr_vector<enode> & used_enodes) {
|
||||
max_generation = std::max(max_generation, get_generation(q));
|
||||
if (m_num_instances > m_params.m_qi_max_instances)
|
||||
|
@ -136,7 +136,7 @@ namespace smt {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void init_search_eh() {
|
||||
m_num_instances = 0;
|
||||
ptr_vector<quantifier>::iterator it2 = m_quantifiers.begin();
|
||||
|
@ -147,8 +147,9 @@ namespace smt {
|
|||
}
|
||||
m_qi_queue.init_search_eh();
|
||||
m_plugin->init_search_eh();
|
||||
TRACE("smt_params", m_params.display(tout); );
|
||||
}
|
||||
|
||||
|
||||
void assign_eh(quantifier * q) {
|
||||
m_plugin->assign_eh(q);
|
||||
}
|
||||
|
@ -174,7 +175,7 @@ namespace smt {
|
|||
m_plugin->pop(num_scopes);
|
||||
m_qi_queue.pop_scope(num_scopes);
|
||||
}
|
||||
|
||||
|
||||
bool can_propagate() {
|
||||
return m_qi_queue.has_work() || m_plugin->can_propagate();
|
||||
}
|
||||
|
@ -183,9 +184,9 @@ namespace smt {
|
|||
m_plugin->propagate();
|
||||
m_qi_queue.instantiate();
|
||||
}
|
||||
|
||||
|
||||
bool check_quantifier(quantifier* q) {
|
||||
return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // TBD: && !m_context->get_manager().is_rec_fun_def(q);
|
||||
return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // && !m_context.get_manager().is_rec_fun_def(q);
|
||||
}
|
||||
|
||||
bool quick_check_quantifiers() {
|
||||
|
@ -250,7 +251,7 @@ namespace smt {
|
|||
quantifier_manager::~quantifier_manager() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
|
||||
context & quantifier_manager::get_context() const {
|
||||
return m_imp->m_context;
|
||||
}
|
||||
|
@ -284,16 +285,16 @@ namespace smt {
|
|||
return m_imp->get_generation(q);
|
||||
}
|
||||
|
||||
bool quantifier_manager::add_instance(quantifier * q, app * pat,
|
||||
unsigned num_bindings,
|
||||
enode * const * bindings,
|
||||
unsigned max_generation,
|
||||
unsigned min_top_generation,
|
||||
unsigned max_top_generation,
|
||||
bool quantifier_manager::add_instance(quantifier * q, app * pat,
|
||||
unsigned num_bindings,
|
||||
enode * const * bindings,
|
||||
unsigned max_generation,
|
||||
unsigned min_top_generation,
|
||||
unsigned max_top_generation,
|
||||
ptr_vector<enode> & used_enodes) {
|
||||
return m_imp->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_generation, used_enodes);
|
||||
}
|
||||
|
||||
|
||||
bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation) {
|
||||
ptr_vector<enode> tmp;
|
||||
return add_instance(q, 0, num_bindings, bindings, generation, generation, generation, tmp);
|
||||
|
@ -346,7 +347,7 @@ namespace smt {
|
|||
quantifier_manager::check_model_result quantifier_manager::check_model(proto_model * m, obj_map<enode, app *> const & root2value) {
|
||||
return m_imp->check_model(m, root2value);
|
||||
}
|
||||
|
||||
|
||||
void quantifier_manager::push() {
|
||||
m_imp->push();
|
||||
}
|
||||
|
@ -356,17 +357,14 @@ namespace smt {
|
|||
}
|
||||
|
||||
void quantifier_manager::reset() {
|
||||
#pragma omp critical (quantifier_manager)
|
||||
{
|
||||
context & ctx = m_imp->m_context;
|
||||
smt_params & p = m_imp->m_params;
|
||||
quantifier_manager_plugin * plugin = m_imp->m_plugin->mk_fresh();
|
||||
m_imp->~imp();
|
||||
m_imp = new (m_imp) imp(*this, ctx, p, plugin);
|
||||
plugin->set_manager(*this);
|
||||
}
|
||||
context & ctx = m_imp->m_context;
|
||||
smt_params & p = m_imp->m_params;
|
||||
quantifier_manager_plugin * plugin = m_imp->m_plugin->mk_fresh();
|
||||
m_imp->~imp();
|
||||
m_imp = new (m_imp) imp(*this, ctx, p, plugin);
|
||||
plugin->set_manager(*this);
|
||||
}
|
||||
|
||||
|
||||
void quantifier_manager::display(std::ostream & out) const {
|
||||
}
|
||||
|
||||
|
@ -381,12 +379,12 @@ namespace smt {
|
|||
m_imp->display_stats(out, q);
|
||||
}
|
||||
|
||||
ptr_vector<quantifier>::const_iterator quantifier_manager::begin_quantifiers() const {
|
||||
return m_imp->m_quantifiers.begin();
|
||||
ptr_vector<quantifier>::const_iterator quantifier_manager::begin_quantifiers() const {
|
||||
return m_imp->m_quantifiers.begin();
|
||||
}
|
||||
|
||||
ptr_vector<quantifier>::const_iterator quantifier_manager::end_quantifiers() const {
|
||||
return m_imp->m_quantifiers.end();
|
||||
|
||||
ptr_vector<quantifier>::const_iterator quantifier_manager::end_quantifiers() const {
|
||||
return m_imp->m_quantifiers.end();
|
||||
}
|
||||
|
||||
// The default plugin uses E-matching, MBQI and quick-checker
|
||||
|
@ -403,13 +401,13 @@ namespace smt {
|
|||
bool m_active;
|
||||
public:
|
||||
default_qm_plugin():
|
||||
m_qm(0),
|
||||
m_context(0),
|
||||
m_new_enode_qhead(0),
|
||||
m_qm(0),
|
||||
m_context(0),
|
||||
m_new_enode_qhead(0),
|
||||
m_lazy_matching_idx(0),
|
||||
m_active(false) {
|
||||
}
|
||||
|
||||
|
||||
virtual ~default_qm_plugin() {
|
||||
}
|
||||
|
||||
|
@ -433,20 +431,18 @@ namespace smt {
|
|||
|
||||
virtual bool model_based() const { return m_fparams->m_mbqi; }
|
||||
|
||||
virtual bool mbqi_enabled(quantifier *q) const {
|
||||
if(!m_fparams->m_mbqi_id) return true;
|
||||
virtual bool mbqi_enabled(quantifier *q) const {
|
||||
if (!m_fparams->m_mbqi_id) return true;
|
||||
const symbol &s = q->get_qid();
|
||||
size_t len = strlen(m_fparams->m_mbqi_id);
|
||||
if(s == symbol::null || s.is_numerical())
|
||||
if (s == symbol::null || s.is_numerical())
|
||||
return len == 0;
|
||||
return strncmp(s.bare_str(),m_fparams->m_mbqi_id,len) == 0;
|
||||
}
|
||||
return strncmp(s.bare_str(), m_fparams->m_mbqi_id, len) == 0;
|
||||
}
|
||||
|
||||
/* Quantifier id's must begin with the prefix specified by
|
||||
parameter mbqi.id to be instantiated with MBQI. The default
|
||||
value is the empty string, so all quantifiers are
|
||||
instantiated.
|
||||
*/
|
||||
/* Quantifier id's must begin with the prefix specified by parameter
|
||||
mbqi.id to be instantiated with MBQI. The default value is the
|
||||
empty string, so all quantifiers are instantiated. */
|
||||
virtual void add(quantifier * q) {
|
||||
if (m_fparams->m_mbqi && mbqi_enabled(q)) {
|
||||
m_active = true;
|
||||
|
@ -454,8 +450,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
virtual void del(quantifier * q) {
|
||||
}
|
||||
virtual void del(quantifier * q) { }
|
||||
|
||||
virtual void push() {
|
||||
m_mam->push_scope();
|
||||
|
@ -464,7 +459,7 @@ namespace smt {
|
|||
m_model_finder->push_scope();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void pop(unsigned num_scopes) {
|
||||
m_mam->pop_scope(num_scopes);
|
||||
m_lazy_mam->pop_scope(num_scopes);
|
||||
|
@ -472,7 +467,7 @@ namespace smt {
|
|||
m_model_finder->pop_scope(num_scopes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void init_search_eh() {
|
||||
m_lazy_matching_idx = 0;
|
||||
if (m_fparams->m_mbqi) {
|
||||
|
@ -483,39 +478,43 @@ namespace smt {
|
|||
|
||||
virtual void assign_eh(quantifier * q) {
|
||||
m_active = true;
|
||||
if (m_fparams->m_ematching) {
|
||||
bool has_unary_pattern = false;
|
||||
unsigned num_patterns = q->get_num_patterns();
|
||||
for (unsigned i = 0; i < num_patterns; i++) {
|
||||
app * mp = to_app(q->get_pattern(i));
|
||||
if (mp->get_num_args() == 1) {
|
||||
has_unary_pattern = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unsigned num_eager_multi_patterns = m_fparams->m_qi_max_eager_multipatterns;
|
||||
if (!has_unary_pattern)
|
||||
num_eager_multi_patterns++;
|
||||
for (unsigned i = 0, j = 0; i < num_patterns; i++) {
|
||||
app * mp = to_app(q->get_pattern(i));
|
||||
SASSERT(m_context->get_manager().is_pattern(mp));
|
||||
bool unary = (mp->get_num_args() == 1);
|
||||
if (!unary && j >= num_eager_multi_patterns) {
|
||||
TRACE("assign_quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n"
|
||||
<< "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns
|
||||
<< " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";);
|
||||
m_lazy_mam->add_pattern(q, mp);
|
||||
}
|
||||
else {
|
||||
TRACE("assign_quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";);
|
||||
m_mam->add_pattern(q, mp);
|
||||
}
|
||||
if (!unary)
|
||||
j++;
|
||||
if (!m_fparams->m_ematching) {
|
||||
return;
|
||||
}
|
||||
if (false && m_context->get_manager().is_rec_fun_def(q) && mbqi_enabled(q)) {
|
||||
return;
|
||||
}
|
||||
bool has_unary_pattern = false;
|
||||
unsigned num_patterns = q->get_num_patterns();
|
||||
for (unsigned i = 0; i < num_patterns; i++) {
|
||||
app * mp = to_app(q->get_pattern(i));
|
||||
if (mp->get_num_args() == 1) {
|
||||
has_unary_pattern = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unsigned num_eager_multi_patterns = m_fparams->m_qi_max_eager_multipatterns;
|
||||
if (!has_unary_pattern)
|
||||
num_eager_multi_patterns++;
|
||||
for (unsigned i = 0, j = 0; i < num_patterns; i++) {
|
||||
app * mp = to_app(q->get_pattern(i));
|
||||
SASSERT(m_context->get_manager().is_pattern(mp));
|
||||
bool unary = (mp->get_num_args() == 1);
|
||||
if (!unary && j >= num_eager_multi_patterns) {
|
||||
TRACE("assign_quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n"
|
||||
<< "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns
|
||||
<< " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";);
|
||||
m_lazy_mam->add_pattern(q, mp);
|
||||
}
|
||||
else {
|
||||
TRACE("assign_quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";);
|
||||
m_mam->add_pattern(q, mp);
|
||||
}
|
||||
if (!unary)
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool use_ematching() const {
|
||||
return m_fparams->m_ematching && !m_qm->empty();
|
||||
}
|
||||
|
@ -537,7 +536,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
virtual void restart_eh() {
|
||||
if (m_fparams->m_mbqi) {
|
||||
if (m_fparams->m_mbqi) {
|
||||
m_model_finder->restart_eh();
|
||||
m_model_checker->restart_eh();
|
||||
}
|
||||
|
@ -612,7 +611,7 @@ namespace smt {
|
|||
}
|
||||
return FC_DONE;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
quantifier_manager_plugin * mk_default_plugin() {
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace smt {
|
|||
public:
|
||||
quantifier_manager(context & ctx, smt_params & fp, params_ref const & p);
|
||||
~quantifier_manager();
|
||||
|
||||
|
||||
context & get_context() const;
|
||||
|
||||
void set_plugin(quantifier_manager_plugin * plugin);
|
||||
|
@ -51,12 +51,12 @@ namespace smt {
|
|||
quantifier_stat * get_stat(quantifier * q) const;
|
||||
unsigned get_generation(quantifier * q) const;
|
||||
|
||||
bool add_instance(quantifier * q, app * pat,
|
||||
unsigned num_bindings,
|
||||
enode * const * bindings,
|
||||
unsigned max_generation,
|
||||
unsigned min_top_generation,
|
||||
unsigned max_top_generation,
|
||||
bool add_instance(quantifier * q, app * pat,
|
||||
unsigned num_bindings,
|
||||
enode * const * bindings,
|
||||
unsigned max_generation,
|
||||
unsigned min_top_generation,
|
||||
unsigned max_top_generation,
|
||||
ptr_vector<enode> & used_enodes);
|
||||
bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation = 0);
|
||||
|
||||
|
@ -78,11 +78,11 @@ namespace smt {
|
|||
bool mbqi_enabled(quantifier *q) const; // can mbqi instantiate this quantifier?
|
||||
void adjust_model(proto_model * m);
|
||||
check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value);
|
||||
|
||||
|
||||
void push();
|
||||
void pop(unsigned num_scopes);
|
||||
void reset();
|
||||
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
void display_stats(std::ostream & out, quantifier * q) const;
|
||||
|
||||
|
@ -97,7 +97,7 @@ namespace smt {
|
|||
public:
|
||||
quantifier_manager_plugin() {}
|
||||
virtual ~quantifier_manager_plugin() {}
|
||||
|
||||
|
||||
virtual void set_manager(quantifier_manager & qm) = 0;
|
||||
|
||||
virtual quantifier_manager_plugin * mk_fresh() = 0;
|
||||
|
@ -106,7 +106,7 @@ namespace smt {
|
|||
virtual void del(quantifier * q) = 0;
|
||||
|
||||
virtual bool is_shared(enode * n) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
\brief This method is invoked whenever q is assigned to true.
|
||||
*/
|
||||
|
@ -131,9 +131,9 @@ namespace smt {
|
|||
\brief This method is invoked whenever the solver restarts.
|
||||
*/
|
||||
virtual void restart_eh() = 0;
|
||||
|
||||
|
||||
/**
|
||||
\brief Return true if the quantifier_manager can propagate information
|
||||
\brief Return true if the quantifier_manager can propagate information
|
||||
information back into the core.
|
||||
*/
|
||||
virtual bool can_propagate() const = 0;
|
||||
|
@ -143,11 +143,11 @@ namespace smt {
|
|||
\brief Return true if the plugin is "model based"
|
||||
*/
|
||||
virtual bool model_based() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
\brief Is "model based" instantiate allowed to instantiate this quantifier?
|
||||
*/
|
||||
virtual bool mbqi_enabled(quantifier *q) const {return true;}
|
||||
virtual bool mbqi_enabled(quantifier *q) const {return true;}
|
||||
|
||||
/**
|
||||
\brief Give a change to the plugin to adjust the interpretation of unintepreted functions.
|
||||
|
@ -161,10 +161,10 @@ namespace smt {
|
|||
It also provides a mapping from enodes to their interpretations.
|
||||
*/
|
||||
virtual quantifier_manager::check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value) = 0;
|
||||
|
||||
|
||||
virtual void push() = 0;
|
||||
virtual void pop(unsigned num_scopes) = 0;
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
void check_no_arithmetic(static_features const & st, char const * logic) {
|
||||
static void check_no_arithmetic(static_features const & st, char const * logic) {
|
||||
if (st.m_num_arith_ineqs > 0 || st.m_num_arith_terms > 0 || st.m_num_arith_eqs > 0)
|
||||
throw default_exception("Benchmark constains arithmetic, but specified loging does not support it.");
|
||||
}
|
||||
|
@ -236,21 +236,21 @@ namespace smt {
|
|||
(st.m_num_arith_eqs + st.m_num_arith_ineqs) > st.m_num_uninterpreted_constants * 9;
|
||||
}
|
||||
|
||||
bool is_in_diff_logic(static_features const & st) {
|
||||
static bool is_in_diff_logic(static_features const & st) {
|
||||
return
|
||||
st.m_num_arith_eqs == st.m_num_diff_eqs &&
|
||||
st.m_num_arith_terms == st.m_num_diff_terms &&
|
||||
st.m_num_arith_ineqs == st.m_num_diff_ineqs;
|
||||
}
|
||||
|
||||
bool is_diff_logic(static_features const & st) {
|
||||
static bool is_diff_logic(static_features const & st) {
|
||||
return
|
||||
is_in_diff_logic(st) &&
|
||||
(st.m_num_diff_ineqs > 0 || st.m_num_diff_eqs > 0 || st.m_num_diff_terms > 0)
|
||||
;
|
||||
}
|
||||
|
||||
void check_no_uninterpreted_functions(static_features const & st, char const * logic) {
|
||||
static void check_no_uninterpreted_functions(static_features const & st, char const * logic) {
|
||||
if (st.m_num_uninterpreted_functions != 0)
|
||||
throw default_exception("Benchmark contains uninterpreted function symbols, but specified logic does not support them.");
|
||||
}
|
||||
|
|
|
@ -20,36 +20,67 @@ Notes:
|
|||
#include"smt_kernel.h"
|
||||
#include"reg_decl_plugins.h"
|
||||
#include"smt_params.h"
|
||||
#include"smt_params_helper.hpp"
|
||||
#include"mus.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"func_decl_dependencies.h"
|
||||
#include"dec_ref_util.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
class solver : public solver_na2as {
|
||||
smt_params m_params;
|
||||
smt::kernel m_context;
|
||||
progress_callback * m_callback;
|
||||
symbol m_logic;
|
||||
smt_params m_smt_params;
|
||||
params_ref m_params;
|
||||
smt::kernel m_context;
|
||||
progress_callback * m_callback;
|
||||
symbol m_logic;
|
||||
bool m_minimizing_core;
|
||||
bool m_core_extend_patterns;
|
||||
unsigned m_core_extend_patterns_max_distance;
|
||||
obj_map<expr, expr*> m_name2assertion;
|
||||
|
||||
public:
|
||||
solver(ast_manager & m, params_ref const & p, symbol const & l):
|
||||
solver(ast_manager & m, params_ref const & p, symbol const & l) :
|
||||
solver_na2as(m),
|
||||
m_smt_params(p),
|
||||
m_params(p),
|
||||
m_context(m, m_params) {
|
||||
m_context(m, m_smt_params),
|
||||
m_minimizing_core(false),
|
||||
m_core_extend_patterns(false),
|
||||
m_core_extend_patterns_max_distance(UINT_MAX) {
|
||||
m_logic = l;
|
||||
if (m_logic != symbol::null)
|
||||
m_context.set_logic(m_logic);
|
||||
smt_params_helper smth(p);
|
||||
m_core_extend_patterns = smth.core_extend_patterns();
|
||||
m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance();
|
||||
}
|
||||
|
||||
virtual solver* translate(ast_manager& m, params_ref const& p) {
|
||||
solver* result = alloc(solver, m, p, m_logic);
|
||||
virtual solver * translate(ast_manager & m, params_ref const & p) {
|
||||
solver * result = alloc(solver, m, p, m_logic);
|
||||
smt::kernel::copy(m_context, result->m_context);
|
||||
|
||||
ast_translation translator(get_manager(), m);
|
||||
obj_map<expr, expr*>::iterator it = m_name2assertion.begin();
|
||||
obj_map<expr, expr*>::iterator end = m_name2assertion.end();
|
||||
for (; it != end; it++)
|
||||
result->m_name2assertion.insert(translator(it->m_key),
|
||||
translator(it->m_value));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
virtual ~solver() {
|
||||
dec_ref_values(get_manager(), m_name2assertion);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params.updt_params(p);
|
||||
m_smt_params.updt_params(p);
|
||||
m_params.copy(p);
|
||||
m_context.updt_params(p);
|
||||
smt_params_helper smth(p);
|
||||
m_core_extend_patterns = smth.core_extend_patterns();
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
|
@ -60,15 +91,46 @@ namespace smt {
|
|||
m_context.collect_statistics(st);
|
||||
}
|
||||
|
||||
virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) {
|
||||
expr_ref_vector unfixed(m_context.m());
|
||||
return m_context.get_consequences(assumptions, vars, conseq, unfixed);
|
||||
}
|
||||
|
||||
virtual lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
|
||||
return m_context.find_mutexes(vars, mutexes);
|
||||
}
|
||||
|
||||
virtual void assert_expr(expr * t) {
|
||||
m_context.assert_expr(t);
|
||||
}
|
||||
|
||||
virtual void assert_expr(expr * t, expr * a) {
|
||||
solver_na2as::assert_expr(t, a);
|
||||
SASSERT(!m_name2assertion.contains(a));
|
||||
get_manager().inc_ref(t);
|
||||
m_name2assertion.insert(a, t);
|
||||
}
|
||||
|
||||
virtual void push_core() {
|
||||
m_context.push();
|
||||
}
|
||||
|
||||
virtual void pop_core(unsigned n) {
|
||||
unsigned cur_sz = m_assumptions.size();
|
||||
if (n > 0 && cur_sz > 0) {
|
||||
unsigned lvl = m_scopes.size();
|
||||
SASSERT(n <= lvl);
|
||||
unsigned new_lvl = lvl - n;
|
||||
unsigned old_sz = m_scopes[new_lvl];
|
||||
for (unsigned i = cur_sz; i > old_sz; ) {
|
||||
--i;
|
||||
expr * key = m_assumptions[i].get();
|
||||
SASSERT(m_name2assertion.contains(key));
|
||||
expr * value = m_name2assertion.find(key);
|
||||
m.dec_ref(value);
|
||||
m_name2assertion.erase(key);
|
||||
}
|
||||
}
|
||||
m_context.pop(n);
|
||||
}
|
||||
|
||||
|
@ -77,10 +139,39 @@ namespace smt {
|
|||
return m_context.check(num_assumptions, assumptions);
|
||||
}
|
||||
|
||||
struct scoped_minimize_core {
|
||||
solver& s;
|
||||
expr_ref_vector m_assumptions;
|
||||
scoped_minimize_core(solver& s) : s(s), m_assumptions(s.m_assumptions) {
|
||||
s.m_minimizing_core = true;
|
||||
s.m_assumptions.reset();
|
||||
}
|
||||
|
||||
~scoped_minimize_core() {
|
||||
s.m_minimizing_core = false;
|
||||
s.m_assumptions.append(m_assumptions);
|
||||
}
|
||||
};
|
||||
|
||||
virtual void get_unsat_core(ptr_vector<expr> & r) {
|
||||
unsigned sz = m_context.get_unsat_core_size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
r.push_back(m_context.get_unsat_core_expr(i));
|
||||
}
|
||||
|
||||
if (m_minimizing_core && smt_params_helper(m_params).core_minimize()) {
|
||||
scoped_minimize_core scm(*this);
|
||||
mus mus(*this);
|
||||
mus.add_soft(r.size(), r.c_ptr());
|
||||
ptr_vector<expr> r2;
|
||||
if (l_true == mus.get_mus(r2)) {
|
||||
r.reset();
|
||||
r.append(r2);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_core_extend_patterns)
|
||||
add_pattern_literals_to_core(r);
|
||||
}
|
||||
|
||||
virtual void get_model(model_ref & m) {
|
||||
|
@ -105,8 +196,7 @@ namespace smt {
|
|||
r.append(tmp.size(), tmp.c_ptr());
|
||||
}
|
||||
|
||||
virtual ast_manager& get_manager() { return m_context.m(); }
|
||||
|
||||
virtual ast_manager & get_manager() const { return m_context.m(); }
|
||||
|
||||
virtual void set_progress_callback(progress_callback * callback) {
|
||||
m_callback = callback;
|
||||
|
@ -116,18 +206,118 @@ namespace smt {
|
|||
virtual unsigned get_num_assertions() const {
|
||||
return m_context.size();
|
||||
}
|
||||
|
||||
|
||||
virtual expr * get_assertion(unsigned idx) const {
|
||||
SASSERT(idx < get_num_assertions());
|
||||
return m_context.get_formulas()[idx];
|
||||
}
|
||||
|
||||
virtual void display(std::ostream & out) const {
|
||||
m_context.display(out);
|
||||
}
|
||||
|
||||
};
|
||||
struct collect_fds_proc {
|
||||
ast_manager & m;
|
||||
func_decl_set & m_fds;
|
||||
collect_fds_proc(ast_manager & m, func_decl_set & fds) :
|
||||
m(m), m_fds(fds) {
|
||||
}
|
||||
void operator()(var * n) {}
|
||||
void operator()(app * n) {
|
||||
func_decl * fd = n->get_decl();
|
||||
if (fd->get_family_id() == null_family_id)
|
||||
m_fds.insert_if_not_there(fd);
|
||||
}
|
||||
void operator()(quantifier * n) {}
|
||||
};
|
||||
|
||||
struct collect_pattern_fds_proc {
|
||||
ast_manager & m;
|
||||
expr_fast_mark1 m_visited;
|
||||
func_decl_set & m_fds;
|
||||
collect_pattern_fds_proc(ast_manager & m, func_decl_set & fds) :
|
||||
m(m), m_fds(fds) {
|
||||
m_visited.reset();
|
||||
}
|
||||
void operator()(var * n) {}
|
||||
void operator()(app * n) {}
|
||||
void operator()(quantifier * n) {
|
||||
collect_fds_proc p(m, m_fds);
|
||||
|
||||
unsigned sz = n->get_num_patterns();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
quick_for_each_expr(p, m_visited, n->get_pattern(i));
|
||||
|
||||
sz = n->get_num_no_patterns();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
quick_for_each_expr(p, m_visited, n->get_no_pattern(i));
|
||||
}
|
||||
};
|
||||
|
||||
void collect_pattern_func_decls(expr_ref & e, func_decl_set & fds) {
|
||||
collect_pattern_fds_proc p(get_manager(), fds);
|
||||
expr_mark visited;
|
||||
for_each_expr(p, visited, e);
|
||||
}
|
||||
|
||||
void compute_assrtn_fds(ptr_vector<expr> & core, vector<func_decl_set> & assrtn_fds) {
|
||||
assrtn_fds.resize(m_name2assertion.size());
|
||||
obj_map<expr, expr*>::iterator ait = m_name2assertion.begin();
|
||||
obj_map<expr, expr*>::iterator aend = m_name2assertion.end();
|
||||
for (unsigned i = 0; ait != aend; ait++, i++) {
|
||||
if (core.contains(ait->m_key))
|
||||
continue;
|
||||
collect_fds_proc p(m, assrtn_fds[i]);
|
||||
expr_fast_mark1 visited;
|
||||
quick_for_each_expr(p, visited, ait->m_value);
|
||||
}
|
||||
}
|
||||
|
||||
bool fds_intersect(func_decl_set & pattern_fds, func_decl_set & assrtn_fds) {
|
||||
func_decl_set::iterator it = pattern_fds.begin();
|
||||
func_decl_set::iterator end = pattern_fds.end();
|
||||
for (; it != end; it++) {
|
||||
func_decl * fd = *it;
|
||||
if (assrtn_fds.contains(fd))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void add_pattern_literals_to_core(ptr_vector<expr> & core) {
|
||||
ast_manager & m = get_manager();
|
||||
expr_ref_vector new_core_literals(m);
|
||||
|
||||
func_decl_set pattern_fds;
|
||||
vector<func_decl_set> assrtn_fds;
|
||||
|
||||
for (unsigned d = 0; d < m_core_extend_patterns_max_distance; d++) {
|
||||
new_core_literals.reset();
|
||||
|
||||
unsigned sz = core.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr_ref name(core[i], m);
|
||||
SASSERT(m_name2assertion.contains(name));
|
||||
expr_ref assrtn(m_name2assertion.find(name), m);
|
||||
collect_pattern_func_decls(assrtn, pattern_fds);
|
||||
}
|
||||
|
||||
if (!pattern_fds.empty()) {
|
||||
if (assrtn_fds.empty())
|
||||
compute_assrtn_fds(core, assrtn_fds);
|
||||
|
||||
obj_map<expr, expr*>::iterator ait = m_name2assertion.begin();
|
||||
obj_map<expr, expr*>::iterator aend = m_name2assertion.end();
|
||||
for (unsigned i = 0; ait != aend; ait++, i++) {
|
||||
if (!core.contains(ait->m_key) &&
|
||||
fds_intersect(pattern_fds, assrtn_fds[i]))
|
||||
new_core_literals.push_back(ait->m_key);
|
||||
}
|
||||
}
|
||||
|
||||
core.append(new_core_literals.size(), new_core_literals.c_ptr());
|
||||
|
||||
if (new_core_literals.empty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic) {
|
||||
|
|
|
@ -24,63 +24,10 @@ Notes:
|
|||
#include"rewriter_types.h"
|
||||
#include"filter_model_converter.h"
|
||||
#include"ast_util.h"
|
||||
#include"solver2tactic.h"
|
||||
|
||||
typedef obj_map<expr, expr *> expr2expr_map;
|
||||
|
||||
void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector<expr>& assumptions, expr2expr_map& bool2dep, ref<filter_model_converter>& fmc) {
|
||||
expr2expr_map dep2bool;
|
||||
ptr_vector<expr> deps;
|
||||
ast_manager& m = g->m();
|
||||
expr_ref_vector clause(m);
|
||||
unsigned sz = g->size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * f = g->form(i);
|
||||
expr_dependency * d = g->dep(i);
|
||||
if (d == 0 || !g->unsat_core_enabled()) {
|
||||
clauses.push_back(f);
|
||||
}
|
||||
else {
|
||||
// create clause (not d1 \/ ... \/ not dn \/ f) when the d's are the assumptions/dependencies of f.
|
||||
clause.reset();
|
||||
clause.push_back(f);
|
||||
deps.reset();
|
||||
m.linearize(d, deps);
|
||||
SASSERT(!deps.empty()); // d != 0, then deps must not be empty
|
||||
ptr_vector<expr>::iterator it = deps.begin();
|
||||
ptr_vector<expr>::iterator end = deps.end();
|
||||
for (; it != end; ++it) {
|
||||
expr * d = *it;
|
||||
if (is_uninterp_const(d) && m.is_bool(d)) {
|
||||
// no need to create a fresh boolean variable for d
|
||||
if (!bool2dep.contains(d)) {
|
||||
assumptions.push_back(d);
|
||||
bool2dep.insert(d, d);
|
||||
}
|
||||
clause.push_back(m.mk_not(d));
|
||||
}
|
||||
else {
|
||||
// must normalize assumption
|
||||
expr * b = 0;
|
||||
if (!dep2bool.find(d, b)) {
|
||||
b = m.mk_fresh_const(0, m.mk_bool_sort());
|
||||
dep2bool.insert(d, b);
|
||||
bool2dep.insert(b, d);
|
||||
assumptions.push_back(b);
|
||||
if (!fmc) {
|
||||
fmc = alloc(filter_model_converter, m);
|
||||
}
|
||||
fmc->insert(to_app(b)->get_decl());
|
||||
}
|
||||
clause.push_back(m.mk_not(b));
|
||||
}
|
||||
}
|
||||
SASSERT(clause.size() > 1);
|
||||
expr_ref cls(m);
|
||||
cls = mk_or(m, clause.size(), clause.c_ptr());
|
||||
clauses.push_back(cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class smt_tactic : public tactic {
|
||||
smt_params m_params;
|
||||
|
@ -191,6 +138,7 @@ public:
|
|||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
try {
|
||||
mc = 0; pc = 0; core = 0;
|
||||
SASSERT(in->is_well_sorted());
|
||||
ast_manager & m = in->m();
|
||||
TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " "
|
||||
|
@ -199,6 +147,7 @@ public:
|
|||
tout << "fail-if-inconclusive: " << m_fail_if_inconclusive << "\n";
|
||||
tout << "params_ref: " << m_params_ref << "\n";
|
||||
tout << "nnf: " << fparams().m_nnf_cnf << "\n";);
|
||||
TRACE("smt_tactic_params", m_params.display(tout););
|
||||
TRACE("smt_tactic_detail", in->display(tout););
|
||||
TRACE("smt_tactic_memory", tout << "wasted_size: " << m.get_allocator().get_wasted_size() << "\n";);
|
||||
scoped_init_ctx init(*this, m);
|
||||
|
@ -255,11 +204,11 @@ public:
|
|||
if (in->models_enabled()) {
|
||||
model_ref md;
|
||||
m_ctx->get_model(md);
|
||||
mc = model2model_converter(md.get());
|
||||
buffer<symbol> r;
|
||||
m_ctx->get_relevant_labels(0, r);
|
||||
mc = model_and_labels2model_converter(md.get(), r);
|
||||
mc = concat(fmc.get(), mc.get());
|
||||
}
|
||||
pc = 0;
|
||||
core = 0;
|
||||
return;
|
||||
}
|
||||
case l_false: {
|
||||
|
@ -284,17 +233,17 @@ public:
|
|||
}
|
||||
in->assert_expr(m.mk_false(), pr, lcore);
|
||||
result.push_back(in.get());
|
||||
mc = 0;
|
||||
pc = 0;
|
||||
core = 0;
|
||||
return;
|
||||
}
|
||||
case l_undef:
|
||||
if (m_ctx->canceled()) {
|
||||
throw tactic_exception(Z3_CANCELED_MSG);
|
||||
}
|
||||
if (m_fail_if_inconclusive)
|
||||
throw tactic_exception("smt tactic failed to show goal to be sat/unsat");
|
||||
if (m_fail_if_inconclusive) {
|
||||
std::stringstream strm;
|
||||
strm << "smt tactic failed to show goal to be sat/unsat " << m_ctx->last_failure_as_string();
|
||||
throw tactic_exception(strm.str().c_str());
|
||||
}
|
||||
result.push_back(in.get());
|
||||
if (m_candidate_models) {
|
||||
switch (m_ctx->last_failure()) {
|
||||
|
@ -304,10 +253,10 @@ public:
|
|||
if (in->models_enabled()) {
|
||||
model_ref md;
|
||||
m_ctx->get_model(md);
|
||||
mc = model2model_converter(md.get());
|
||||
buffer<symbol> r;
|
||||
m_ctx->get_relevant_labels(0, r);
|
||||
mc = model_and_labels2model_converter(md.get(), r);
|
||||
}
|
||||
pc = 0;
|
||||
core = 0;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -32,8 +32,6 @@ tactic * mk_smt_tactic(params_ref const & p = params_ref());
|
|||
tactic * mk_smt_tactic_using(bool auto_config = true, params_ref const & p = params_ref());
|
||||
|
||||
|
||||
void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector<expr>& assumptions, obj_map<expr, expr*>& bool2dep, ref<filter_model_converter>& fmc);
|
||||
|
||||
/*
|
||||
ADD_TACTIC("smt", "apply a SAT based SMT solver.", "mk_smt_tactic(p)")
|
||||
*/
|
||||
|
|
|
@ -958,6 +958,7 @@ 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
|
||||
|
@ -1092,7 +1093,7 @@ namespace smt {
|
|||
virtual inf_eps_rational<inf_rational> maximize(theory_var v, expr_ref& blocker, bool& has_shared);
|
||||
virtual inf_eps_rational<inf_rational> value(theory_var v);
|
||||
virtual theory_var add_objective(app* term);
|
||||
virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val);
|
||||
expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val);
|
||||
void enable_record_conflict(expr* bound);
|
||||
void record_conflict(unsigned num_lits, literal const * lits,
|
||||
unsigned num_eqs, enode_pair const * eqs,
|
||||
|
|
|
@ -417,8 +417,8 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
void theory_arith<Ext>::atom::display(theory_arith<Ext> const& th, std::ostream& out) const {
|
||||
literal l(get_bool_var(), !m_is_true);
|
||||
out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << get_k() << " ";
|
||||
out << l << ":";
|
||||
// out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << get_k() << " ";
|
||||
// out << l << ":";
|
||||
th.get_context().display_detailed_literal(out, l);
|
||||
}
|
||||
|
||||
|
@ -1056,6 +1056,11 @@ namespace smt {
|
|||
inf_eps_rational<inf_rational> theory_arith<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shared) {
|
||||
TRACE("bound_bug", display_var(tout, v); display(tout););
|
||||
has_shared = false;
|
||||
if (!m_nl_monomials.empty()) {
|
||||
has_shared = true;
|
||||
blocker = mk_gt(v);
|
||||
return inf_eps_rational<inf_rational>(get_value(v));
|
||||
}
|
||||
max_min_t r = max_min(v, true, true, has_shared);
|
||||
if (r == UNBOUNDED) {
|
||||
has_shared = false;
|
||||
|
@ -1300,6 +1305,7 @@ namespace smt {
|
|||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::pick_var_to_leave(
|
||||
|
@ -1331,7 +1337,7 @@ namespace smt {
|
|||
if (update_gains(inc, s, coeff_ij, min_gain, max_gain) ||
|
||||
(x_i == null_theory_var && !unbounded_gain(max_gain))) {
|
||||
x_i = s;
|
||||
a_ij = coeff_ij;
|
||||
a_ij = coeff_ij;
|
||||
}
|
||||
has_shared |= ctx.is_shared(get_enode(s));
|
||||
}
|
||||
|
@ -1709,7 +1715,7 @@ namespace smt {
|
|||
SASSERT(!maintain_integrality || valid_assignment());
|
||||
SASSERT(satisfy_bounds());
|
||||
}
|
||||
TRACE("opt", display(tout););
|
||||
TRACE("opt_verbose", display(tout););
|
||||
return (best_efforts>0 || ctx.get_cancel_flag())?BEST_EFFORT:result;
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ namespace smt {
|
|||
}
|
||||
rational _val;
|
||||
expr* arg1, *arg2;
|
||||
if (m_util.is_mul(m, arg1, arg2) && m_util.is_numeral(arg1, _val)) {
|
||||
if (m_util.is_mul(m, arg1, arg2) && m_util.is_numeral(arg1, _val) && is_app(arg1) && is_app(arg2)) {
|
||||
SASSERT(m->get_num_args() == 2);
|
||||
numeral val(_val);
|
||||
theory_var v = internalize_term_core(to_app(arg2));
|
||||
|
@ -297,6 +297,11 @@ namespace smt {
|
|||
scoped_row_vars _sc(m_row_vars, m_row_vars_top);
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
if (is_var(n->get_arg(i))) {
|
||||
std::ostringstream strm;
|
||||
strm << mk_pp(n, get_manager()) << " contains a free variable";
|
||||
throw default_exception(strm.str());
|
||||
}
|
||||
internalize_internal_monomial(to_app(n->get_arg(i)), r_id);
|
||||
}
|
||||
enode * e = mk_enode(n);
|
||||
|
@ -356,6 +361,11 @@ namespace smt {
|
|||
SASSERT(!val.is_one());
|
||||
unsigned r_id = mk_row();
|
||||
scoped_row_vars _sc(m_row_vars, m_row_vars_top);
|
||||
if (is_var(m->get_arg(1))) {
|
||||
std::ostringstream strm;
|
||||
strm << mk_pp(m, get_manager()) << " contains a free variable";
|
||||
throw default_exception(strm.str());
|
||||
}
|
||||
if (reflection_enabled())
|
||||
internalize_term_core(to_app(m->get_arg(0)));
|
||||
theory_var v = internalize_mul_core(to_app(m->get_arg(1)));
|
||||
|
@ -455,7 +465,7 @@ namespace smt {
|
|||
tout << s_ante << "\n" << s_conseq << "\n";);
|
||||
|
||||
literal lits[2] = {l_ante, l_conseq};
|
||||
ctx.mk_th_axiom(get_id(), 2, lits);
|
||||
mk_clause(l_ante, l_conseq, 0, 0);
|
||||
if (ctx.relevancy()) {
|
||||
if (l_ante == false_literal) {
|
||||
ctx.mark_as_relevant(l_conseq);
|
||||
|
@ -747,17 +757,25 @@ namespace smt {
|
|||
enode * e = mk_enode(n);
|
||||
return mk_var(e);
|
||||
}
|
||||
else {
|
||||
TRACE("arith_internalize_detail", tout << "before:\n" << mk_pp(n, get_manager()) << "\n";);
|
||||
if (!ctx.e_internalized(n))
|
||||
ctx.internalize(n, false);
|
||||
TRACE("arith_internalize_detail", tout << "after:\n" << mk_pp(n, get_manager()) << "\n";);
|
||||
enode * e = ctx.get_enode(n);
|
||||
if (!is_attached_to_var(e))
|
||||
return mk_var(e);
|
||||
else
|
||||
return e->get_th_var(get_id());
|
||||
if (m_util.get_family_id() == n->get_family_id()) {
|
||||
found_unsupported_op(n);
|
||||
if (ctx.e_internalized(n))
|
||||
return expr2var(n);
|
||||
for (unsigned i = 0; i < n->get_num_args(); ++i) {
|
||||
ctx.internalize(n->get_arg(i), false);
|
||||
}
|
||||
return mk_var(mk_enode(n));
|
||||
}
|
||||
|
||||
TRACE("arith_internalize_detail", tout << "before:\n" << mk_pp(n, get_manager()) << "\n";);
|
||||
if (!ctx.e_internalized(n))
|
||||
ctx.internalize(n, false);
|
||||
TRACE("arith_internalize_detail", tout << "after:\n" << mk_pp(n, get_manager()) << "\n";);
|
||||
enode * e = ctx.get_enode(n);
|
||||
if (!is_attached_to_var(e))
|
||||
return mk_var(e);
|
||||
else
|
||||
return e->get_th_var(get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -916,11 +934,13 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::mk_clause(literal l1, literal l2, unsigned num_params, parameter * params) {
|
||||
TRACE("arith", literal lits[2]; lits[0] = l1; lits[1] = l2; get_context().display_literals_verbose(tout, 2, lits); tout << "\n";);
|
||||
get_context().mk_th_axiom(get_id(), l1, l2, num_params, params);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::mk_clause(literal l1, literal l2, literal l3, unsigned num_params, parameter * params) {
|
||||
TRACE("arith", literal lits[3]; lits[0] = l1; lits[1] = l2; lits[2] = l3; get_context().display_literals_verbose(tout, 3, lits); tout << "\n";);
|
||||
get_context().mk_th_axiom(get_id(), l1, l2, l3, num_params, params);
|
||||
}
|
||||
|
||||
|
@ -1051,7 +1071,7 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::flush_bound_axioms() {
|
||||
CTRACE("arith", !m_new_atoms.empty(), tout << "flush bound axioms\n";);
|
||||
CTRACE("arith_verbose", !m_new_atoms.empty(), tout << "flush bound axioms\n";);
|
||||
|
||||
while (!m_new_atoms.empty()) {
|
||||
ptr_vector<atom> atoms;
|
||||
|
@ -1066,7 +1086,7 @@ namespace smt {
|
|||
--i;
|
||||
}
|
||||
}
|
||||
CTRACE("arith", !atoms.empty(),
|
||||
CTRACE("arith", atoms.size() > 1,
|
||||
for (unsigned i = 0; i < atoms.size(); ++i) {
|
||||
atoms[i]->display(*this, tout); tout << "\n";
|
||||
});
|
||||
|
@ -1196,6 +1216,9 @@ namespace smt {
|
|||
kind = A_UPPER;
|
||||
else
|
||||
kind = A_LOWER;
|
||||
if (!is_app(n->get_arg(0)) || !is_app(n->get_arg(1))) {
|
||||
return false;
|
||||
}
|
||||
app * lhs = to_app(n->get_arg(0));
|
||||
app * rhs = to_app(n->get_arg(1));
|
||||
expr * rhs2;
|
||||
|
@ -1214,6 +1237,14 @@ namespace smt {
|
|||
ctx.set_var_theory(bv, get_id());
|
||||
rational _k;
|
||||
VERIFY(m_util.is_numeral(rhs, _k));
|
||||
if (is_int(v) && !_k.is_int()) {
|
||||
if (kind == A_UPPER) {
|
||||
_k = floor(_k);
|
||||
}
|
||||
else {
|
||||
_k = ceil(_k);
|
||||
}
|
||||
}
|
||||
inf_numeral k(_k);
|
||||
atom * a = alloc(atom, bv, v, k, kind);
|
||||
mk_bound_axioms(a);
|
||||
|
@ -1237,10 +1268,11 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::internalize_eq_eh(app * atom, bool_var v) {
|
||||
if (m_params.m_arith_eager_eq_axioms) {
|
||||
expr* _lhs, *_rhs;
|
||||
if (m_params.m_arith_eager_eq_axioms && get_manager().is_eq(atom, _lhs, _rhs) && is_app(_lhs) && is_app(_rhs)) {
|
||||
context & ctx = get_context();
|
||||
app * lhs = to_app(atom->get_arg(0));
|
||||
app * rhs = to_app(atom->get_arg(1));
|
||||
app * lhs = to_app(_lhs);
|
||||
app * rhs = to_app(_rhs);
|
||||
enode * n1 = ctx.get_enode(lhs);
|
||||
enode * n2 = ctx.get_enode(rhs);
|
||||
// The expression atom may be a theory axiom. In this case, it may not be in simplified form.
|
||||
|
@ -1262,7 +1294,7 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::assign_eh(bool_var v, bool is_true) {
|
||||
TRACE("arith", tout << "p" << v << " := " << (is_true?"true":"false") << "\n";);
|
||||
TRACE("arith_verbose", tout << "p" << v << " := " << (is_true?"true":"false") << "\n";);
|
||||
atom * a = get_bv2a(v);
|
||||
if (!a) return;
|
||||
SASSERT(get_context().get_assignment(a->get_bool_var()) != l_undef);
|
||||
|
@ -1373,26 +1405,27 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
final_check_status theory_arith<Ext>::final_check_core() {
|
||||
m_model_depends_on_computed_epsilon = false;
|
||||
unsigned old_idx = m_final_check_idx;
|
||||
final_check_status result = FC_DONE;
|
||||
final_check_status ok;
|
||||
do {
|
||||
TRACE("final_check_arith", tout << "m_final_check_idx: " << m_final_check_idx << ", result: " << result << "\n";);
|
||||
TRACE("arith", tout << "m_final_check_idx: " << m_final_check_idx << ", result: " << result << "\n";);
|
||||
switch (m_final_check_idx) {
|
||||
case 0:
|
||||
ok = check_int_feasibility();
|
||||
TRACE("final_check_arith", tout << "check_int_feasibility(), ok: " << ok << "\n";);
|
||||
TRACE("arith", tout << "check_int_feasibility(), ok: " << ok << "\n";);
|
||||
break;
|
||||
case 1:
|
||||
if (assume_eqs_core())
|
||||
ok = FC_CONTINUE;
|
||||
else
|
||||
ok = FC_DONE;
|
||||
TRACE("final_check_arith", tout << "assume_eqs(), ok: " << ok << "\n";);
|
||||
TRACE("arith", tout << "assume_eqs(), ok: " << ok << "\n";);
|
||||
break;
|
||||
default:
|
||||
ok = process_non_linear();
|
||||
TRACE("final_check_arith", tout << "non_linear(), ok: " << ok << "\n";);
|
||||
TRACE("arith", tout << "non_linear(), ok: " << ok << "\n";);
|
||||
break;
|
||||
}
|
||||
m_final_check_idx = (m_final_check_idx + 1) % 3;
|
||||
|
@ -1403,7 +1436,7 @@ namespace smt {
|
|||
result = FC_GIVEUP;
|
||||
break;
|
||||
case FC_CONTINUE:
|
||||
TRACE("final_check_arith",
|
||||
TRACE("arith",
|
||||
tout << "continue arith..."
|
||||
<< (get_context().inconsistent()?"inconsistent\n":"\n"););
|
||||
return FC_CONTINUE;
|
||||
|
@ -1420,7 +1453,7 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
final_check_status theory_arith<Ext>::final_check_eh() {
|
||||
TRACE("arith_eq_adapter_info", m_arith_eq_adapter.display_already_processed(tout););
|
||||
TRACE("arith_final_check", display(tout););
|
||||
TRACE("arith", display(tout););
|
||||
|
||||
if (!propagate_core())
|
||||
return FC_CONTINUE;
|
||||
|
@ -1437,7 +1470,7 @@ namespace smt {
|
|||
m_liberal_final_check = false;
|
||||
m_changed_assignment = false;
|
||||
result = final_check_core();
|
||||
TRACE("final_check_arith", tout << "result: " << result << "\n";);
|
||||
TRACE("arith", tout << "result: " << result << "\n";);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1637,6 +1670,7 @@ namespace smt {
|
|||
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),
|
||||
|
@ -2394,6 +2428,7 @@ namespace smt {
|
|||
theory_var v = b->get_var();
|
||||
inf_numeral const & k = b->get_value();
|
||||
|
||||
TRACE("arith", display_bound(tout, b); tout << "v" << v << " <= " << k << "\n";);
|
||||
bound * u = upper(v);
|
||||
bound * l = lower(v);
|
||||
|
||||
|
@ -2434,7 +2469,7 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::assert_bound(bound * b) {
|
||||
TRACE("assert_bound", display_bound(tout, b););
|
||||
TRACE("assert_bound", display_bound(tout, b); display(tout););
|
||||
theory_var v = b->get_var();
|
||||
|
||||
if (b->is_atom()) {
|
||||
|
@ -2456,7 +2491,7 @@ namespace smt {
|
|||
break;
|
||||
}
|
||||
|
||||
TRACE("arith_assert", tout << "result: " << result << "\n"; display(tout););
|
||||
TRACE("arith_bound", tout << "result: " << result << "\n"; display(tout););
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -3012,12 +3047,14 @@ namespace smt {
|
|||
m_stats.m_conflicts++;
|
||||
m_num_conflicts++;
|
||||
TRACE("arith_conflict",
|
||||
tout << "scope: " << ctx.get_scope_level() << "\n";
|
||||
for (unsigned i = 0; i < num_literals; i++) {
|
||||
ctx.display_detailed_literal(tout, lits[i]);
|
||||
tout << " ";
|
||||
if (coeffs_enabled()) {
|
||||
tout << "bound: " << bounds.lit_coeffs()[i] << "\n";
|
||||
}
|
||||
tout << "\n";
|
||||
}
|
||||
for (unsigned i = 0; i < num_eqs; i++) {
|
||||
tout << "#" << eqs[i].first->get_owner_id() << "=#" << eqs[i].second->get_owner_id() << " ";
|
||||
|
@ -3185,7 +3222,9 @@ namespace smt {
|
|||
m_factory = alloc(arith_factory, get_manager());
|
||||
m.register_factory(m_factory);
|
||||
compute_epsilon();
|
||||
refine_epsilon();
|
||||
if (!m_model_depends_on_computed_epsilon) {
|
||||
refine_epsilon();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
|
@ -3198,7 +3237,7 @@ namespace smt {
|
|||
TRACE("arith", tout << "Truncating non-integer value. This is possible for non-linear constraints v" << v << " " << num << "\n";);
|
||||
num = floor(num);
|
||||
}
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, m_util.is_int(var2expr(v))));
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, m_util.is_int(var2expr(v))));
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace smt {
|
|||
SASSERT(lower_bound(v).is_rational());
|
||||
numeral const & val = lower_bound(v).get_rational();
|
||||
value_sort_pair key(val, is_int_src(v));
|
||||
TRACE("arith_eq", tout << mk_pp(get_enode(v)->get_owner(), get_manager()) << " = " << val << "\n";);
|
||||
theory_var v2;
|
||||
if (m_fixed_var_table.find(key, v2)) {
|
||||
if (v2 < static_cast<int>(get_num_vars()) && is_fixed(v2) && lower_bound(v2).get_rational() == val) {
|
||||
|
@ -64,7 +65,7 @@ namespace smt {
|
|||
lower(v2)->push_justification(ante, numeral::zero(), proofs_enabled());
|
||||
upper(v)->push_justification(ante, numeral::zero(), proofs_enabled());
|
||||
|
||||
TRACE("arith_fixed_propagate_eq", tout << "propagate eq: v" << v << " = v" << v2 << "\n";
|
||||
TRACE("arith_eq", tout << "propagate eq: v" << v << " = v" << v2 << "\n";
|
||||
display_var(tout, v);
|
||||
display_var(tout, v2););
|
||||
m_stats.m_fixed_eqs++;
|
||||
|
@ -175,7 +176,7 @@ namespace smt {
|
|||
timer.stop();
|
||||
ok++;
|
||||
if (ok % 100000 == 0) {
|
||||
TRACE("propagate_cheap_eq",
|
||||
TRACE("arith_eq",
|
||||
tout << total << " " << ok << " "
|
||||
<< static_cast<double>(ok)/static_cast<double>(total)
|
||||
<< " " << timer.get_seconds() << "\n";
|
||||
|
@ -216,7 +217,7 @@ namespace smt {
|
|||
void theory_arith<Ext>::propagate_cheap_eq(unsigned rid) {
|
||||
if (!propagate_eqs())
|
||||
return;
|
||||
TRACE("propagate_cheap_eq", tout << "checking if row " << rid << " can propagate equality.\n";
|
||||
TRACE("arith_eq_verbose", tout << "checking if row " << rid << " can propagate equality.\n";
|
||||
display_row_info(tout, rid););
|
||||
row const & r = m_rows[rid];
|
||||
theory_var x;
|
||||
|
@ -247,6 +248,7 @@ namespace smt {
|
|||
//
|
||||
// x1 <= k1 x1 >= k1, x2 <= x1 + k2 x2 >= x1 + k2
|
||||
//
|
||||
TRACE("arith_eq_propagation", tout << "fixed\n";);
|
||||
lower(x2)->push_justification(ante, numeral::zero(), proofs_enabled());
|
||||
upper(x2)->push_justification(ante, numeral::zero(), proofs_enabled());
|
||||
m_stats.m_fixed_eqs++;
|
||||
|
@ -258,7 +260,7 @@ namespace smt {
|
|||
// found equality x = y
|
||||
antecedents ante(*this);
|
||||
collect_fixed_var_justifications(r, ante);
|
||||
TRACE("propagate_cheap_eq", tout << "propagate eq using x-y=0 row:\n"; display_row_info(tout, r););
|
||||
TRACE("arith_eq", tout << "propagate eq using x-y=0 row:\n"; display_row_info(tout, r););
|
||||
m_stats.m_offset_eqs++;
|
||||
propagate_eq_to_core(x, y, ante);
|
||||
}
|
||||
|
@ -299,7 +301,7 @@ namespace smt {
|
|||
antecedents ante(*this);
|
||||
collect_fixed_var_justifications(r, ante);
|
||||
collect_fixed_var_justifications(r2, ante);
|
||||
TRACE("propagate_cheap_eq", tout << "propagate eq two rows:\n";
|
||||
TRACE("arith_eq", tout << "propagate eq two rows:\n";
|
||||
tout << "swapped: " << swapped << "\n";
|
||||
tout << "x : v" << x << "\n";
|
||||
tout << "x2 : v" << x2 << "\n";
|
||||
|
@ -324,28 +326,42 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
void theory_arith<Ext>::propagate_eq_to_core(theory_var x, theory_var y, antecedents& antecedents) {
|
||||
// Ignore equality if variables are already known to be equal.
|
||||
ast_manager& m = get_manager();
|
||||
if (is_equal(x, y))
|
||||
return;
|
||||
// I doesn't make sense to propagate an equality (to the core) of variables of different sort.
|
||||
if (get_manager().get_sort(var2expr(x)) != get_manager().get_sort(var2expr(y))) {
|
||||
TRACE("arith", tout << mk_pp(var2expr(x), get_manager()) << " = " << mk_pp(var2expr(y), get_manager()) << "\n";);
|
||||
if (m.get_sort(var2expr(x)) != m.get_sort(var2expr(y))) {
|
||||
TRACE("arith", tout << mk_pp(var2expr(x), m) << " = " << mk_pp(var2expr(y), m) << "\n";);
|
||||
return;
|
||||
}
|
||||
context & ctx = get_context();
|
||||
region & r = ctx.get_region();
|
||||
enode * _x = get_enode(x);
|
||||
enode * _y = get_enode(y);
|
||||
eq_vector const& eqs = antecedents.eqs();
|
||||
literal_vector const& lits = antecedents.lits();
|
||||
justification * js =
|
||||
ctx.mk_justification(
|
||||
ext_theory_eq_propagation_justification(
|
||||
get_id(), r,
|
||||
antecedents.lits().size(), antecedents.lits().c_ptr(),
|
||||
antecedents.eqs().size(), antecedents.eqs().c_ptr(),
|
||||
lits.size(), lits.c_ptr(),
|
||||
eqs.size(), eqs.c_ptr(),
|
||||
_x, _y,
|
||||
antecedents.num_params(), antecedents.params("eq-propagate")));
|
||||
TRACE("propagate_eq_to_core", tout << "detected equality: #" << _x->get_owner_id() << " = #" << _y->get_owner_id() << "\n";
|
||||
TRACE("arith_eq", tout << "detected equality: #" << _x->get_owner_id() << " = #" << _y->get_owner_id() << "\n";
|
||||
display_var(tout, x);
|
||||
display_var(tout, y););
|
||||
TRACE("arith_eq_propagation",
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
ctx.display_detailed_literal(tout, lits[i]);
|
||||
tout << "\n";
|
||||
}
|
||||
for (unsigned i = 0; i < eqs.size(); ++i) {
|
||||
tout << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m) << "\n";
|
||||
}
|
||||
tout << " ==> ";
|
||||
tout << mk_pp(_x->get_owner(), m) << " = " << mk_pp(_y->get_owner(), m) << "\n";
|
||||
);
|
||||
ctx.assign_eq(_x, _y, eq_justification(js));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1267,11 +1267,11 @@ namespace smt {
|
|||
final_check_status theory_arith<Ext>::check_int_feasibility() {
|
||||
TRACE("arith_int_detail", get_context().display(tout););
|
||||
if (!has_infeasible_int_var()) {
|
||||
TRACE("arith_int_incomp", tout << "FC_DONE 1...\n"; display(tout););
|
||||
TRACE("arith", tout << "FC_DONE 1...\n"; display(tout););
|
||||
return FC_DONE;
|
||||
}
|
||||
|
||||
TRACE("arith_int_fracs",
|
||||
TRACE("arith",
|
||||
int num = get_num_vars();
|
||||
for (theory_var v = 0; v < num; v++) {
|
||||
if (is_int(v) && !get_value(v).is_int()) {
|
||||
|
@ -1385,7 +1385,7 @@ namespace smt {
|
|||
m_branch_cut_counter++;
|
||||
// TODO: add giveup code
|
||||
if (m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) {
|
||||
TRACE("opt", display(tout););
|
||||
TRACE("opt_verbose", display(tout););
|
||||
move_non_base_vars_to_bounds();
|
||||
if (!make_feasible()) {
|
||||
TRACE("arith_int", tout << "failed to move variables to bounds.\n";);
|
||||
|
|
|
@ -23,9 +23,9 @@ Revision History:
|
|||
|
||||
namespace smt {
|
||||
|
||||
template<typename Ext>
|
||||
template<typename Ext>
|
||||
expr * theory_arith<Ext>::mk_nary_mul(unsigned sz, expr * const * args, bool is_int) {
|
||||
if (sz == 0)
|
||||
if (sz == 0)
|
||||
return m_util.mk_numeral(rational(1), is_int);
|
||||
if (sz == 1)
|
||||
return args[0];
|
||||
|
@ -36,21 +36,21 @@ namespace smt {
|
|||
return m_util.mk_mul(sz, args);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
template<typename Ext>
|
||||
expr * theory_arith<Ext>::mk_nary_add(unsigned sz, expr * const * args, bool is_int) {
|
||||
if (sz == 0)
|
||||
if (sz == 0)
|
||||
return m_util.mk_numeral(rational(0), is_int);
|
||||
if (sz == 1)
|
||||
return args[0];
|
||||
return m_util.mk_add(sz, args);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
template<typename Ext>
|
||||
expr * theory_arith<Ext>::mk_nary_add(unsigned sz, expr * const * args) {
|
||||
SASSERT(sz != 0);
|
||||
return mk_nary_add(sz, args, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Insert v into vars and already_found if v is not already in already_found.
|
||||
*/
|
||||
|
@ -92,21 +92,21 @@ namespace smt {
|
|||
theory_var s = r.get_base_var();
|
||||
// ignore quasi base vars... actually they should not be used if the problem is non linear...
|
||||
if (is_quasi_base(s))
|
||||
continue;
|
||||
continue;
|
||||
// If s is a base variable different from v and it is free, then this row can be ignored.
|
||||
// It doesn't need to be part of the non linear cluster. For all purposes, this variable
|
||||
// was eliminated by substitution.
|
||||
if (is_free(s) && s != v)
|
||||
continue;
|
||||
continue;
|
||||
typename vector<row_entry>::const_iterator it2 = r.begin_entries();
|
||||
typename vector<row_entry>::const_iterator end2 = r.end_entries();
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (!it2->is_dead() && !is_fixed(it2->m_var))
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (!it2->is_dead() && !is_fixed(it2->m_var))
|
||||
mark_var(it2->m_var, vars, already_found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Store in vars the variables that are in the non linear cluster of constraints,
|
||||
and are not satisfied by the current assignment.
|
||||
|
@ -123,7 +123,7 @@ namespace smt {
|
|||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
expr * n = var2expr(v);
|
||||
if (ctx.is_relevant(n))
|
||||
if (ctx.is_relevant(n))
|
||||
mark_var(v, vars, already_found);
|
||||
}
|
||||
for (unsigned idx = 0; idx < vars.size(); idx++) {
|
||||
|
@ -134,7 +134,7 @@ namespace smt {
|
|||
svector<theory_var>::const_iterator it = vars.begin();
|
||||
svector<theory_var>::const_iterator end = vars.end();
|
||||
for (; it != end; ++it) tout << "v" << *it << " ";
|
||||
tout << "\n";);
|
||||
tout << "\n";);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,7 +148,7 @@ namespace smt {
|
|||
|
||||
\remark if a variables has an even number of occurrences, then
|
||||
I consider that it has a bound associated with it.
|
||||
|
||||
|
||||
Examples:
|
||||
1) Assume x1, x4 have bounds:
|
||||
analyze_monomial(x1 * x2 * x2 * x3 * x3 * x3 * x4)
|
||||
|
@ -168,24 +168,24 @@ namespace smt {
|
|||
int idx = 0;
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (arg == var) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (power % 2 == 1 && is_free(var)) {
|
||||
c++;
|
||||
free_var_idx = idx;
|
||||
if (c > 1)
|
||||
return std::make_pair(2, free_var_idx);
|
||||
}
|
||||
var = arg;
|
||||
power = 1;
|
||||
idx++;
|
||||
}
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (arg == var) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (power % 2 == 1 && is_free(var)) {
|
||||
c++;
|
||||
free_var_idx = idx;
|
||||
if (c > 1)
|
||||
return std::make_pair(2, free_var_idx);
|
||||
}
|
||||
var = arg;
|
||||
power = 1;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
if (power % 2 == 1 && is_free(var)) {
|
||||
c++;
|
||||
|
@ -257,17 +257,17 @@ namespace smt {
|
|||
unsigned j;
|
||||
for (j = 0; j < to_app(m)->get_num_args(); j++) {
|
||||
expr * arg = to_app(m)->get_arg(j);
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (var == arg) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (curr_idx == i)
|
||||
return var_power_pair(var, power);
|
||||
curr_idx++;
|
||||
if (var == 0) {
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
else if (var == arg) {
|
||||
power++;
|
||||
}
|
||||
else {
|
||||
if (curr_idx == i)
|
||||
return var_power_pair(var, power);
|
||||
curr_idx++;
|
||||
var = arg;
|
||||
power = 1;
|
||||
}
|
||||
|
@ -289,24 +289,24 @@ namespace smt {
|
|||
bound * l = lower(v);
|
||||
bound * u = upper(v);
|
||||
if (l && u) {
|
||||
return interval(m_dep_manager,
|
||||
l->get_value().get_rational().to_rational(),
|
||||
return interval(m_dep_manager,
|
||||
l->get_value().get_rational().to_rational(),
|
||||
!l->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
m_dep_manager.mk_leaf(l),
|
||||
u->get_value().get_rational().to_rational(),
|
||||
u->get_value().get_rational().to_rational(),
|
||||
!u->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
m_dep_manager.mk_leaf(u));
|
||||
}
|
||||
else if (l) {
|
||||
return interval(m_dep_manager,
|
||||
l->get_value().get_rational().to_rational(),
|
||||
l->get_value().get_rational().to_rational(),
|
||||
!l->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
true,
|
||||
m_dep_manager.mk_leaf(l));
|
||||
}
|
||||
else if (u) {
|
||||
return interval(m_dep_manager,
|
||||
u->get_value().get_rational().to_rational(),
|
||||
u->get_value().get_rational().to_rational(),
|
||||
!u->get_value().get_infinitesimal().to_rational().is_zero(),
|
||||
false,
|
||||
m_dep_manager.mk_leaf(u));
|
||||
|
@ -333,12 +333,12 @@ namespace smt {
|
|||
void theory_arith<Ext>::mul_bound_of(expr * var, unsigned power, interval & target) {
|
||||
theory_var v = expr2var(var);
|
||||
interval i = mk_interval_for(v);
|
||||
|
||||
TRACE("non_linear",
|
||||
|
||||
TRACE("non_linear",
|
||||
display_interval(tout << "bound: ",i); tout << i << "\n";
|
||||
tout << mk_pp(var, get_manager()) << "\n";
|
||||
tout << "power " << power << ": " << expt(i, power) << "\n";
|
||||
display_interval(tout << "target before: ", target); tout << "\n";);
|
||||
display_interval(tout << "target before: ", target); tout << "\n";);
|
||||
i.expt(power);
|
||||
target *= i;
|
||||
TRACE("non_linear", display_interval(tout << "target after: ", target); tout << "\n";);
|
||||
|
@ -348,7 +348,7 @@ namespace smt {
|
|||
\brief Evaluate the given expression using interval arithmetic.
|
||||
|
||||
- If a subexpression is internalized, then mk_interval_for is used to
|
||||
compute its interval.
|
||||
compute its interval.
|
||||
|
||||
- Only +, *, and numerals are handled.
|
||||
*/
|
||||
|
@ -382,7 +382,7 @@ namespace smt {
|
|||
interval it = evaluate_as_interval(var);
|
||||
it.expt(power);
|
||||
r *= it;
|
||||
}
|
||||
}
|
||||
TRACE("cross_nested_eval_bug", display_nested_form(tout, n); tout << "\ninterval: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
@ -424,7 +424,7 @@ namespace smt {
|
|||
ptr_vector<void>::const_iterator end = bounds.end();
|
||||
for (; it != end; ++it) {
|
||||
bound * b = static_cast<bound*>(*it);
|
||||
accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,7 +476,7 @@ namespace smt {
|
|||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::update_bounds_using_interval(expr * n, interval const & i) {
|
||||
SASSERT(expr2var(n) != null_theory_var);
|
||||
|
@ -510,7 +510,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
/**
|
||||
\brief Propagate a bound to the i-th variable of the given monomial
|
||||
\brief Propagate a bound to the i-th variable of the given monomial
|
||||
using the bounds of m and other variables in m.
|
||||
|
||||
\remark We do not support roots in interval... so, if the i-th var has power != 1
|
||||
|
@ -523,7 +523,7 @@ namespace smt {
|
|||
var_power_pair p = get_var_and_degree(m, i);
|
||||
expr * v = p.first;
|
||||
unsigned power = p.second;
|
||||
TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) <<
|
||||
TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) <<
|
||||
"\npower: " << power << "\n";);
|
||||
if (power != 1)
|
||||
return false; // TODO: remove, when the n-th root is implemented in interval.
|
||||
|
@ -556,7 +556,7 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
bool theory_arith<Ext>::propagate_nl_bound(expr * m, int i) {
|
||||
TRACE("propagate_nl_bound", tout << "propagate using i: " << i << "\n"; display_monomial(tout, m); tout << "\n";);
|
||||
if (i == -1)
|
||||
if (i == -1)
|
||||
return propagate_nl_upward(m);
|
||||
else
|
||||
return propagate_nl_downward(m, i);
|
||||
|
@ -589,10 +589,8 @@ namespace smt {
|
|||
m_dep_manager.reset();
|
||||
bool propagated = false;
|
||||
context & ctx = get_context();
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
for (unsigned i = 0; i < m_nl_monomials.size(); i++) {
|
||||
theory_var v = m_nl_monomials[i];
|
||||
expr * m = var2expr(v);
|
||||
if (!ctx.is_relevant(m))
|
||||
continue;
|
||||
|
@ -640,6 +638,7 @@ namespace smt {
|
|||
if (!val.get_infinitesimal().is_zero() && !computed_epsilon) {
|
||||
compute_epsilon();
|
||||
computed_epsilon = true;
|
||||
m_model_depends_on_computed_epsilon = true;
|
||||
}
|
||||
return val.get_rational().to_rational() + m_epsilon.to_rational() * val.get_infinitesimal().to_rational();
|
||||
}
|
||||
|
@ -654,16 +653,20 @@ namespace smt {
|
|||
bool theory_arith<Ext>::check_monomial_assignment(theory_var v, bool & computed_epsilon) {
|
||||
SASSERT(is_pure_monomial(var2expr(v)));
|
||||
expr * m = var2expr(v);
|
||||
rational val(1);
|
||||
rational val(1), v_val;
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var curr = expr2var(arg);
|
||||
SASSERT(curr != null_theory_var);
|
||||
val *= get_value(curr, computed_epsilon);
|
||||
theory_var curr = expr2var(arg);
|
||||
SASSERT(curr != null_theory_var);
|
||||
v_val = get_value(curr, computed_epsilon);
|
||||
TRACE("non_linear", tout << mk_pp(arg, get_manager()) << " = " << v_val << "\n";);
|
||||
val *= v_val;
|
||||
}
|
||||
return get_value(v, computed_epsilon) == val;
|
||||
v_val = get_value(v, computed_epsilon);
|
||||
TRACE("non_linear", tout << "v" << v << " := " << v_val << " == " << val << "\n";);
|
||||
return v_val == val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Return true if for every monomial x_1 * ... * x_n,
|
||||
|
@ -691,11 +694,11 @@ namespace smt {
|
|||
/**
|
||||
\brief Try to find an integer variable for performing branching
|
||||
in the non linear cluster.
|
||||
|
||||
|
||||
The idea is select a variable in a monomial with an invalid
|
||||
assignment. I give preference to variables with small ranges.
|
||||
If no variable is bounded, then select a random one.
|
||||
|
||||
|
||||
Free variables are not considered.
|
||||
*/
|
||||
template<typename Ext>
|
||||
|
@ -705,44 +708,42 @@ namespace smt {
|
|||
theory_var target = null_theory_var;
|
||||
bool bounded = false;
|
||||
unsigned n = 0;
|
||||
numeral range;
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
if (is_real(v))
|
||||
numeral range;
|
||||
for (unsigned j = 0; j < m_nl_monomials.size(); ++j) {
|
||||
theory_var v = m_nl_monomials[j];
|
||||
if (is_real(v))
|
||||
continue;
|
||||
bool computed_epsilon = false;
|
||||
bool r = check_monomial_assignment(v, computed_epsilon);
|
||||
bool r = check_monomial_assignment(v, computed_epsilon);
|
||||
SASSERT(!computed_epsilon); // integer variables do not use epsilon
|
||||
if (!r) {
|
||||
expr * m = get_enode(v)->get_owner();
|
||||
SASSERT(is_pure_monomial(m));
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var curr = ctx.get_enode(arg)->get_th_var(get_id());
|
||||
TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";);
|
||||
if (!is_fixed(curr) && is_int(curr)) {
|
||||
if (is_bounded(curr)) {
|
||||
numeral new_range;
|
||||
new_range = upper_bound(curr).get_rational();
|
||||
new_range -= lower_bound(curr).get_rational();
|
||||
if (!bounded || new_range < range) {
|
||||
target = curr;
|
||||
range = new_range;
|
||||
bounded = true;
|
||||
}
|
||||
}
|
||||
else if (!bounded) {
|
||||
n++;
|
||||
TRACE("nl_branching", tout << "n: " << n << "\n";);
|
||||
if (m_random()%n == 0)
|
||||
target = curr;
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
TRACE("nl_branching", tout << "after target: v" << target << "\n";);
|
||||
theory_var curr = ctx.get_enode(arg)->get_th_var(get_id());
|
||||
TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";);
|
||||
if (!is_fixed(curr) && is_int(curr)) {
|
||||
if (is_bounded(curr)) {
|
||||
numeral new_range;
|
||||
new_range = upper_bound(curr).get_rational();
|
||||
new_range -= lower_bound(curr).get_rational();
|
||||
if (!bounded || new_range < range) {
|
||||
target = curr;
|
||||
range = new_range;
|
||||
bounded = true;
|
||||
}
|
||||
}
|
||||
else if (!bounded) {
|
||||
n++;
|
||||
TRACE("nl_branching", tout << "n: " << n << "\n";);
|
||||
if (m_random()%n == 0)
|
||||
target = curr;
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
SASSERT(target != null_theory_var);
|
||||
}
|
||||
TRACE("nl_branching", tout << "after target: v" << target << "\n";);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -762,7 +763,7 @@ namespace smt {
|
|||
m_stats.m_nl_branching++;
|
||||
SASSERT(is_int(v));
|
||||
expr * bound = 0;
|
||||
if (lower(v))
|
||||
if (lower(v))
|
||||
bound = m_util.mk_le(var2expr(v), m_util.mk_numeral(lower_bound(v).get_rational().to_rational(), true));
|
||||
else if (upper(v))
|
||||
bound = m_util.mk_ge(var2expr(v), m_util.mk_numeral(upper_bound(v).get_rational().to_rational(), true));
|
||||
|
@ -787,14 +788,14 @@ namespace smt {
|
|||
unsigned num_nl_vars = 0;
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var)) {
|
||||
num_nl_vars++;
|
||||
}
|
||||
else {
|
||||
if (lower_bound(_var).is_zero())
|
||||
return true;
|
||||
}
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var)) {
|
||||
num_nl_vars++;
|
||||
}
|
||||
else {
|
||||
if (lower_bound(_var).is_zero())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return num_nl_vars <= 1;
|
||||
}
|
||||
|
@ -809,9 +810,9 @@ namespace smt {
|
|||
numeral r(1);
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var))
|
||||
r *= lower_bound(_var).get_rational();
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var))
|
||||
r *= lower_bound(_var).get_rational();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -825,9 +826,9 @@ namespace smt {
|
|||
SASSERT(is_pure_monomial(m));
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var))
|
||||
return arg;
|
||||
theory_var _var = expr2var(arg);
|
||||
if (!is_fixed(_var))
|
||||
return arg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -886,7 +887,7 @@ namespace smt {
|
|||
}
|
||||
else {
|
||||
// One of the x_i variables is zero,
|
||||
// or all of them are assigned.
|
||||
// or all of them are assigned.
|
||||
|
||||
// Assert the equality
|
||||
// (= (* x_1 ... x_n) k)
|
||||
|
@ -908,45 +909,45 @@ namespace smt {
|
|||
|
||||
SASSERT(is_pure_monomial(m));
|
||||
bool found_zero = false;
|
||||
for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var)) {
|
||||
bound * l = lower(_var);
|
||||
bound * u = upper(_var);
|
||||
if (l->get_value().is_zero()) {
|
||||
/* if zero was found, then it is the explanation */
|
||||
SASSERT(k.is_zero());
|
||||
found_zero = true;
|
||||
m_tmp_lit_set.reset();
|
||||
m_tmp_eq_set.reset();
|
||||
new_lower->m_lits.reset();
|
||||
new_lower->m_eqs.reset();
|
||||
}
|
||||
for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
theory_var _var = expr2var(arg);
|
||||
if (is_fixed(_var)) {
|
||||
bound * l = lower(_var);
|
||||
bound * u = upper(_var);
|
||||
if (l->get_value().is_zero()) {
|
||||
/* if zero was found, then it is the explanation */
|
||||
SASSERT(k.is_zero());
|
||||
found_zero = true;
|
||||
m_tmp_lit_set.reset();
|
||||
m_tmp_eq_set.reset();
|
||||
new_lower->m_lits.reset();
|
||||
new_lower->m_eqs.reset();
|
||||
}
|
||||
accumulate_justification(*l, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
|
||||
TRACE("non_linear",
|
||||
|
||||
TRACE("non_linear",
|
||||
for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_lower->m_lits[j]);
|
||||
tout << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
|
||||
|
||||
accumulate_justification(*u, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set);
|
||||
|
||||
TRACE("non_linear",
|
||||
|
||||
TRACE("non_linear",
|
||||
for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_lower->m_lits[j]);
|
||||
tout << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
new_upper->m_lits.append(new_lower->m_lits);
|
||||
new_upper->m_eqs.append(new_lower->m_eqs);
|
||||
|
||||
TRACE("non_linear",
|
||||
TRACE("non_linear",
|
||||
tout << "lower: " << new_lower << " upper: " << new_upper << "\n";
|
||||
for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_upper->m_lits[j]);
|
||||
|
@ -965,10 +966,19 @@ namespace smt {
|
|||
bool theory_arith<Ext>::propagate_linear_monomials() {
|
||||
TRACE("non_linear", tout << "propagating linear monomials...\n";);
|
||||
bool p = false;
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
// CMW: m_nl_monomials is sometimes modified while executing
|
||||
// propagate_linear_monomial(...), invalidating the iterator `it'.
|
||||
// (Via the relevancy propagation that internalizes a new axiom
|
||||
// in mk_div_axiom and possibly others.) I'm replacing the iterator
|
||||
// with an index `i'.
|
||||
|
||||
// Was previously:
|
||||
// svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
// svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
// for (; it != end; ++it) {
|
||||
// theory_var v = *it;
|
||||
for (unsigned i = 0; i < m_nl_monomials.size(); i++) {
|
||||
theory_var v = m_nl_monomials[i];
|
||||
if (propagate_linear_monomial(v))
|
||||
p = true;
|
||||
}
|
||||
|
@ -979,9 +989,9 @@ namespace smt {
|
|||
/*
|
||||
Interval arithmetic does not satisfy distributivity.
|
||||
Actually, it satisfies the sub-distributivity property:
|
||||
|
||||
|
||||
x*(y + z) \subseteq x*y + x*z
|
||||
|
||||
|
||||
The sub-distributivity property only holds if condensation
|
||||
is not used. For example:
|
||||
|
||||
|
@ -995,11 +1005,11 @@ namespace smt {
|
|||
|
||||
x*(x^3+1) = [-7, 14]
|
||||
x^4 + x = [-2, 17]
|
||||
|
||||
|
||||
This weakness of AI is known as the "dependency problem",
|
||||
which comes from the decorrelation of the multiple occurrences
|
||||
of one variable during interval evaluation.
|
||||
|
||||
|
||||
Given a polynomial:
|
||||
p(x) = a_0 + a_1 * x + ... + a_n * x^n
|
||||
The horner extension is:
|
||||
|
@ -1009,13 +1019,13 @@ namespace smt {
|
|||
h_p(x) = x(2 + x^3(1 + x))
|
||||
|
||||
The horner extension evaluates tighter intervals when
|
||||
condensation is not used.
|
||||
condensation is not used.
|
||||
|
||||
Remark: there is no guarantee that horner extension will
|
||||
provide a tighter interval than a sum of monomials when
|
||||
condensation is used.
|
||||
|
||||
For multivariate polynomials nested (or cross nested) forms
|
||||
For multivariate polynomials nested (or cross nested) forms
|
||||
are used. The idea is to select one variable, and pretend the
|
||||
other are parameters. The horner form is computed for the selected
|
||||
variable, and the computation continues for the polynomials on the
|
||||
|
@ -1027,13 +1037,13 @@ namespace smt {
|
|||
|
||||
p(x) = a*x^n + b*x^{n+m} for n >= m
|
||||
is equivalent to
|
||||
|
||||
|
||||
b*x^{n-m}*[(x^{m} + a/(2b))^2 - (a/2b)^2]
|
||||
|
||||
|
||||
This polynomial provides tight bound when n and m have the same parity and:
|
||||
1) a*b > 0 and (lower(x) >= 0 or upper(x)^m <= -a/b)
|
||||
2) a*b < 0 and (upper(x) <= 0 or lower(x)^m >= a/b)
|
||||
|
||||
|
||||
This polynomial also provides tight bounds when n = m,
|
||||
and the polynomial is simplified to, and n and m may have arbitrary parities:
|
||||
|
||||
|
@ -1047,7 +1057,7 @@ namespace smt {
|
|||
If we compute the bounds for x^2 - x we obtain
|
||||
(-oo, oo).
|
||||
|
||||
On the other hand, if we compute the bounds for
|
||||
On the other hand, if we compute the bounds for
|
||||
(x - 1/2)^2 - 1/4
|
||||
we obtain the bounds (0, oo), and the inconsistency
|
||||
is detected.
|
||||
|
@ -1055,8 +1065,8 @@ namespace smt {
|
|||
Remark: In Z3, I condensate multiple occurrences of a variable
|
||||
when evaluating monomials. So, the interval for a monomial is
|
||||
always tight.
|
||||
|
||||
Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3,
|
||||
|
||||
Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3,
|
||||
if intersection(Vars(M1), union(Vars(M2), Vars(M3))) = empty-set,
|
||||
|
||||
Remark: A trivial consequence of Moore's theorem for interval
|
||||
|
@ -1066,7 +1076,7 @@ namespace smt {
|
|||
|
||||
/**
|
||||
\brief Check whether the same variable occurs in two different monomials.
|
||||
|
||||
|
||||
\remark Fixed variables are ignored.
|
||||
|
||||
\remark A trivial consequence of Moore's theorem for interval
|
||||
|
@ -1208,7 +1218,7 @@ namespace smt {
|
|||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the number of occurrences in the result vector.
|
||||
typename var2num_occs::iterator it2 = m_var2num_occs.begin();
|
||||
typename var2num_occs::iterator end2 = m_var2num_occs.end();
|
||||
|
@ -1263,14 +1273,14 @@ namespace smt {
|
|||
m_nl_new_exprs.push_back(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Return true if var only occurs in two monovariate monomials,
|
||||
and return its power and coefficients and these monomials.
|
||||
The arguments i1 and i2 contain the position in p of the two monomials.
|
||||
*/
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::in_monovariate_monomials(sbuffer<coeff_expr> & p, expr * var,
|
||||
bool theory_arith<Ext>::in_monovariate_monomials(sbuffer<coeff_expr> & p, expr * var,
|
||||
unsigned & i1, rational & c1, unsigned & n1, unsigned & i2, rational & c2, unsigned & n2) {
|
||||
int idx = 0;
|
||||
#define SET_RESULT(POWER) { \
|
||||
|
@ -1289,7 +1299,7 @@ namespace smt {
|
|||
else \
|
||||
return false; \
|
||||
}
|
||||
|
||||
|
||||
typename sbuffer<coeff_expr>::const_iterator it = p.begin();
|
||||
typename sbuffer<coeff_expr>::const_iterator end = p.end();
|
||||
for (unsigned i = 0; it != end; ++it, ++i) {
|
||||
|
@ -1396,7 +1406,7 @@ namespace smt {
|
|||
SASSERT(d != UINT_MAX);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Divide m by var^d.
|
||||
*/
|
||||
|
@ -1416,19 +1426,19 @@ namespace smt {
|
|||
ptr_buffer<expr> new_args;
|
||||
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
|
||||
expr * arg = to_app(m)->get_arg(i);
|
||||
if (arg == var) {
|
||||
if (idx < d)
|
||||
idx++;
|
||||
else
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
else {
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
if (arg == var) {
|
||||
if (idx < d)
|
||||
idx++;
|
||||
else
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
else {
|
||||
new_args.push_back(arg);
|
||||
}
|
||||
}
|
||||
SASSERT(idx == d);
|
||||
TRACE("factor_bug", tout << "new_args:\n"; for(unsigned i = 0; i < new_args.size(); i++) tout << mk_pp(new_args[i], get_manager()) << "\n";);
|
||||
expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var));
|
||||
expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var));
|
||||
m_nl_new_exprs.push_back(result);
|
||||
TRACE("factor", tout << "result: " << mk_pp(result, get_manager()) << "\n";);
|
||||
return result;
|
||||
|
@ -1442,7 +1452,7 @@ namespace smt {
|
|||
SASSERT(!p.empty());
|
||||
SASSERT(var != 0);
|
||||
unsigned d = get_min_degree(p, var);
|
||||
TRACE("horner_bug", tout << "poly:\n";
|
||||
TRACE("horner_bug", tout << "poly:\n";
|
||||
for (unsigned i = 0; i < p.size(); i++) { if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); } tout << "\n";
|
||||
tout << "var: " << mk_pp(var, get_manager()) << "\n";
|
||||
tout << "min_degree: " << d << "\n";);
|
||||
|
@ -1467,7 +1477,7 @@ namespace smt {
|
|||
// TODO: improve here
|
||||
s = m_util.mk_add(q, s);
|
||||
}
|
||||
|
||||
|
||||
expr * result = s;
|
||||
if (d != 0) {
|
||||
expr * xd = power(var, d);
|
||||
|
@ -1513,9 +1523,9 @@ namespace smt {
|
|||
unsigned nm = UINT_MAX;
|
||||
if (in_monovariate_monomials(p, var, i1, a, n, i2, b, nm)) {
|
||||
CTRACE("in_monovariate_monomials", n == nm,
|
||||
for (unsigned i = 0; i < p.size(); i++) {
|
||||
if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager());
|
||||
}
|
||||
for (unsigned i = 0; i < p.size(); i++) {
|
||||
if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager());
|
||||
}
|
||||
tout << "\n";
|
||||
tout << "var: " << mk_pp(var, get_manager()) << "\n";
|
||||
tout << "i1: " << i1 << "\n";
|
||||
|
@ -1556,7 +1566,7 @@ namespace smt {
|
|||
sbuffer<coeff_expr> rest;
|
||||
unsigned sz = p.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (i != i1 && i != i2)
|
||||
if (i != i1 && i != i2)
|
||||
rest.push_back(p[i]);
|
||||
}
|
||||
if (rest.empty())
|
||||
|
@ -1620,7 +1630,7 @@ namespace smt {
|
|||
|
||||
/**
|
||||
\brief Check whether the polynomial represented by the current row is
|
||||
consistent with respect to the known bound when converted into a
|
||||
consistent with respect to the known bound when converted into a
|
||||
equivalent cross nested form.
|
||||
*/
|
||||
template<typename Ext>
|
||||
|
@ -1630,17 +1640,17 @@ namespace smt {
|
|||
return true;
|
||||
|
||||
TRACE("cross_nested", tout << "problematic...\n";);
|
||||
|
||||
|
||||
/*
|
||||
The method is_cross_nested converts rows back to expressions.
|
||||
The conversion back to expressions may create sort incorrect expressions.
|
||||
This is in some sense ok, since these expressions are temporary, but
|
||||
This is in some sense ok, since these expressions are temporary, but
|
||||
the sort incorrect expressions may generate assertion violations.
|
||||
|
||||
|
||||
Sort incorrect expressions may be created in the following cases:
|
||||
|
||||
|
||||
1) mixed real int rows.
|
||||
|
||||
|
||||
2) int rows that contain non integer coefficients.
|
||||
|
||||
3) int rows that when converted to cross nested form use non integer coefficients.
|
||||
|
@ -1654,10 +1664,10 @@ namespace smt {
|
|||
c) Disable the assertions temporally. This sounds like a big HACK.
|
||||
|
||||
d) Use a different data-structure to represent polynomials in cross-nested form. Disadvantage: code duplication, the data-structure
|
||||
is essentially identical to the ASTs we are using right now.
|
||||
is essentially identical to the ASTs we are using right now.
|
||||
|
||||
e) Disable the test when we cannot create a well-sorted expression.
|
||||
I'm temporally using this solution.
|
||||
I'm temporally using this solution.
|
||||
I implemented the following logic:
|
||||
1) (mixed real int) Disable the test. Most benchmarks do not contain mixed int real variables.
|
||||
2) (int coeffs) I multiply the row by a constant to force it to have only integer coefficients.
|
||||
|
@ -1696,7 +1706,7 @@ namespace smt {
|
|||
svector<theory_var>::const_iterator end = nl_cluster.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
if (!is_base(v))
|
||||
if (!is_base(v))
|
||||
continue;
|
||||
m_stats.m_nl_cross_nested++;
|
||||
row const & r = m_rows[get_var_row(v)];
|
||||
|
@ -1719,8 +1729,8 @@ namespace smt {
|
|||
/**
|
||||
\brief Initialize variable order for grobner basis computation.
|
||||
Make:
|
||||
"quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" >
|
||||
"variables with lower or upper bounds" > "quoted bounded variables" >
|
||||
"quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" >
|
||||
"variables with lower or upper bounds" > "quoted bounded variables" >
|
||||
"bounded variables" > "quoted fixed variables" > "fixed variables"
|
||||
*/
|
||||
template<typename Ext>
|
||||
|
@ -1801,7 +1811,7 @@ namespace smt {
|
|||
}
|
||||
if (!coeff.is_zero())
|
||||
return gb.mk_monomial(coeff, vars.size(), vars.c_ptr());
|
||||
else
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1918,7 +1928,7 @@ namespace smt {
|
|||
derived_bound b(null_theory_var, inf_numeral(0), B_LOWER);
|
||||
dependency2new_bound(d, b);
|
||||
set_conflict(b, ante, "arith_nl");
|
||||
TRACE("non_linear",
|
||||
TRACE("non_linear",
|
||||
for (unsigned i = 0; i < b.m_lits.size(); ++i) {
|
||||
tout << b.m_lits[i] << " ";
|
||||
});
|
||||
|
@ -2027,7 +2037,7 @@ namespace smt {
|
|||
unsigned num1 = m1_sq->get_degree();
|
||||
unsigned num2 = m2_sq->get_degree();
|
||||
unsigned num12 = m1m2->get_degree();
|
||||
if (num1 + num2 != num12 * 2)
|
||||
if (num1 + num2 != num12 * 2)
|
||||
return false;
|
||||
unsigned i1, i2, i12;
|
||||
i1 = i2 = i12 = 0;
|
||||
|
@ -2072,8 +2082,8 @@ namespace smt {
|
|||
*/
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::is_inconsistent2(grobner::equation const * eq, grobner & gb) {
|
||||
// TODO: a possible improvement: create a quotation for (M1 - M2)^2
|
||||
// instead of trying to find it in a specific equation.
|
||||
// TODO: a possible improvement: create a quotation for (M1 - M2)^2
|
||||
// instead of trying to find it in a specific equation.
|
||||
// This approach is more precise, but more expensive
|
||||
// since a new row must be created.
|
||||
buffer<interval> intervals;
|
||||
|
@ -2117,7 +2127,7 @@ namespace smt {
|
|||
continue;
|
||||
// m1, m2, and m1m2 form a perfect square.
|
||||
// check if [0, oo) provides a better lowerbound than adding the intervals of m1, m2 and m1m2;
|
||||
TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n";
|
||||
TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n";
|
||||
gb.display_monomial(tout, *m1); tout << "\n";
|
||||
gb.display_monomial(tout, *m2); tout << "\n";
|
||||
gb.display_monomial(tout, *m1m2); tout << "\n";);
|
||||
|
@ -2131,7 +2141,7 @@ namespace smt {
|
|||
deleted[i] = true;
|
||||
deleted[j] = true;
|
||||
deleted[k] = true;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k < num)
|
||||
|
@ -2184,7 +2194,7 @@ namespace smt {
|
|||
grobner::monomial const * m = eq->get_monomial(i);
|
||||
if (m->get_degree() == 0)
|
||||
k -= m->get_coeff();
|
||||
else
|
||||
else
|
||||
args.push_back(monomial2expr(eq->get_monomial(i), is_int));
|
||||
}
|
||||
context & ctx = get_context();
|
||||
|
@ -2213,7 +2223,7 @@ namespace smt {
|
|||
TRACE("non_linear", tout << "inserted new equation into the tableau\n"; display_var(tout, v););
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Compute Grobner basis, return true if a conflict or new fixed variables were detected.
|
||||
*/
|
||||
|
@ -2227,7 +2237,7 @@ namespace smt {
|
|||
bool warn = false;
|
||||
unsigned next_weight = MAX_DEFAULT_WEIGHT + 1; // next weight using during perturbation phase.
|
||||
ptr_vector<grobner::equation> eqs;
|
||||
|
||||
|
||||
while (true) {
|
||||
TRACE("non_linear_gb", tout << "before:\n"; gb.display(tout););
|
||||
bool r = false;
|
||||
|
@ -2267,7 +2277,7 @@ namespace smt {
|
|||
if (is_inconsistent2(eq, gb))
|
||||
return GB_PROGRESS;
|
||||
}
|
||||
// Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed,
|
||||
// Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed,
|
||||
// then assert bounds for x, and continue
|
||||
gb_result result = GB_FAIL;
|
||||
if (m_params.m_nl_arith_gb_eqs) {
|
||||
|
@ -2277,7 +2287,7 @@ namespace smt {
|
|||
if (!eq->is_linear_combination()) {
|
||||
TRACE("non_linear", tout << "processing new equality:\n"; gb.display_equation(tout, *eq););
|
||||
TRACE("non_linear_bug", tout << "processing new equality:\n"; gb.display_equation(tout, *eq););
|
||||
if (internalize_gb_eq(eq))
|
||||
if (internalize_gb_eq(eq))
|
||||
result = GB_NEW_EQ;
|
||||
}
|
||||
}
|
||||
|
@ -2331,10 +2341,8 @@ namespace smt {
|
|||
bool theory_arith<Ext>::max_min_nl_vars() {
|
||||
var_set already_found;
|
||||
svector<theory_var> vars;
|
||||
svector<theory_var>::const_iterator it = m_nl_monomials.begin();
|
||||
svector<theory_var>::const_iterator end = m_nl_monomials.end();
|
||||
for (; it != end; ++it) {
|
||||
theory_var v = *it;
|
||||
for (unsigned j = 0; j < m_nl_monomials.size(); ++j) {
|
||||
theory_var v = m_nl_monomials[j];
|
||||
mark_var(v, vars, already_found);
|
||||
expr * n = var2expr(v);
|
||||
SASSERT(is_pure_monomial(n));
|
||||
|
@ -2353,6 +2361,7 @@ namespace smt {
|
|||
*/
|
||||
template<typename Ext>
|
||||
final_check_status theory_arith<Ext>::process_non_linear() {
|
||||
m_model_depends_on_computed_epsilon = false;
|
||||
if (m_nl_monomials.empty())
|
||||
return FC_DONE;
|
||||
|
||||
|
@ -2372,10 +2381,10 @@ namespace smt {
|
|||
IF_VERBOSE(3, verbose_stream() << "Max. non linear arithmetic rounds. Increase threshold using NL_ARITH_ROUNDS=<limit>\n";);
|
||||
return FC_GIVEUP;
|
||||
}
|
||||
|
||||
|
||||
get_context().push_trail(value_trail<context, unsigned>(m_nl_rounds));
|
||||
m_nl_rounds++;
|
||||
|
||||
|
||||
elim_quasi_base_rows();
|
||||
move_non_base_vars_to_bounds();
|
||||
TRACE("non_linear", tout << "processing non linear constraints...\n"; get_context().display(tout););
|
||||
|
@ -2384,8 +2393,8 @@ namespace smt {
|
|||
failed();
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
|
||||
if (!max_min_nl_vars())
|
||||
|
||||
if (!max_min_nl_vars())
|
||||
return FC_CONTINUE;
|
||||
|
||||
if (check_monomial_assignments()) {
|
||||
|
@ -2409,20 +2418,20 @@ namespace smt {
|
|||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!is_cross_nested_consistent(vars))
|
||||
if (!is_cross_nested_consistent(vars))
|
||||
progress = true;
|
||||
break;
|
||||
case 2:
|
||||
if (m_params.m_nl_arith_gb) {
|
||||
switch(compute_grobner(vars)) {
|
||||
case GB_PROGRESS:
|
||||
case GB_PROGRESS:
|
||||
progress = true;
|
||||
break;
|
||||
case GB_NEW_EQ:
|
||||
case GB_NEW_EQ:
|
||||
progress = true;
|
||||
propagate_core();
|
||||
break;
|
||||
case GB_FAIL:
|
||||
case GB_FAIL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,22 +27,22 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
void theory_arith<Ext>::collect_statistics(::statistics & st) const {
|
||||
st.update("arith conflicts", m_stats.m_conflicts);
|
||||
st.update("add rows", m_stats.m_add_rows);
|
||||
st.update("pivots", m_stats.m_pivots);
|
||||
st.update("assert lower", m_stats.m_assert_lower);
|
||||
st.update("assert upper", m_stats.m_assert_upper);
|
||||
st.update("assert diseq", m_stats.m_assert_diseq);
|
||||
st.update("bound prop", m_stats.m_bound_props);
|
||||
st.update("fixed eqs", m_stats.m_fixed_eqs);
|
||||
st.update("offset eqs", m_stats.m_offset_eqs);
|
||||
st.update("gcd tests", m_stats.m_gcd_tests);
|
||||
st.update("ineq splits", m_stats.m_branches);
|
||||
st.update("gomory cuts", m_stats.m_gomory_cuts);
|
||||
st.update("max-min", m_stats.m_max_min);
|
||||
st.update("grobner", m_stats.m_gb_compute_basis);
|
||||
st.update("pseudo nonlinear", m_stats.m_nl_linear);
|
||||
st.update("nonlinear bounds", m_stats.m_nl_bounds);
|
||||
st.update("nonlinear horner", m_stats.m_nl_cross_nested);
|
||||
st.update("arith add rows", m_stats.m_add_rows);
|
||||
st.update("arith pivots", m_stats.m_pivots);
|
||||
st.update("arith assert lower", m_stats.m_assert_lower);
|
||||
st.update("arith assert upper", m_stats.m_assert_upper);
|
||||
st.update("arith assert diseq", m_stats.m_assert_diseq);
|
||||
st.update("arith bound prop", m_stats.m_bound_props);
|
||||
st.update("arith fixed eqs", m_stats.m_fixed_eqs);
|
||||
st.update("arith offset eqs", m_stats.m_offset_eqs);
|
||||
st.update("arith gcd tests", m_stats.m_gcd_tests);
|
||||
st.update("arith ineq splits", m_stats.m_branches);
|
||||
st.update("arith gomory cuts", m_stats.m_gomory_cuts);
|
||||
st.update("arith max-min", m_stats.m_max_min);
|
||||
st.update("arith grobner", m_stats.m_gb_compute_basis);
|
||||
st.update("arith pseudo nonlinear", m_stats.m_nl_linear);
|
||||
st.update("arith nonlinear bounds", m_stats.m_nl_bounds);
|
||||
st.update("arith nonlinear horner", m_stats.m_nl_cross_nested);
|
||||
m_arith_eq_adapter.collect_statistics(st);
|
||||
}
|
||||
|
||||
|
|
|
@ -404,7 +404,7 @@ namespace smt {
|
|||
r = assert_delayed_axioms();
|
||||
}
|
||||
}
|
||||
TRACE("as_array", tout << "m_found_unsupported_op: " << m_found_unsupported_op << " " << r << "\n";);
|
||||
TRACE("array", tout << "m_found_unsupported_op: " << m_found_unsupported_op << " " << r << "\n";);
|
||||
if (r == FC_DONE && m_found_unsupported_op)
|
||||
r = FC_GIVEUP;
|
||||
return r;
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
void theory_array_base::found_unsupported_op(expr * n) {
|
||||
TRACE("theory_array_unsup", tout << mk_ll_pp(n, get_manager()) << "\n";);
|
||||
TRACE("array", tout << mk_ll_pp(n, get_manager()) << "\n";);
|
||||
if (!m_found_unsupported_op) {
|
||||
get_context().push_trail(value_trail<context, bool>(m_found_unsupported_op));
|
||||
m_found_unsupported_op = true;
|
||||
|
|
|
@ -312,6 +312,7 @@ namespace smt {
|
|||
SASSERT(v != null_theory_var);
|
||||
unsigned sz = bits.size();
|
||||
SASSERT(get_bv_size(n) == sz);
|
||||
m_bits[v].reset();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * bit = bits.get(i);
|
||||
expr_ref s_bit(m);
|
||||
|
@ -809,6 +810,7 @@ namespace smt {
|
|||
theory_var v = e->get_th_var(get_id());
|
||||
unsigned num_args = n->get_num_args();
|
||||
unsigned i = num_args;
|
||||
m_bits[v].reset();
|
||||
while (i > 0) {
|
||||
i--;
|
||||
theory_var arg = get_arg_var(e, i);
|
||||
|
@ -830,6 +832,7 @@ namespace smt {
|
|||
unsigned end = n->get_decl()->get_parameter(0).get_int();
|
||||
SASSERT(start <= end);
|
||||
literal_vector & arg_bits = m_bits[arg];
|
||||
m_bits[v].reset();
|
||||
for (unsigned i = start; i <= end; ++i)
|
||||
add_bit(v, arg_bits[i]);
|
||||
find_wpos(v);
|
||||
|
@ -1533,6 +1536,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
void theory_bv::unmerge_eh(theory_var v1, theory_var v2) {
|
||||
|
||||
// v1 was the root of the equivalence class
|
||||
// I must remove the zero_one_bits that are from v2.
|
||||
|
||||
|
@ -1579,7 +1583,7 @@ namespace smt {
|
|||
#endif
|
||||
get_fixed_value(v, val);
|
||||
SASSERT(r);
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(val, get_bv_size(v)));
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_num_value(val, get_bv_size(v)));
|
||||
}
|
||||
|
||||
void theory_bv::display_var(std::ostream & out, theory_var v) const {
|
||||
|
|
|
@ -97,6 +97,7 @@ namespace smt {
|
|||
virtual void pop_scope_eh(unsigned num_scopes);
|
||||
virtual final_check_status final_check_eh();
|
||||
virtual void reset_eh();
|
||||
virtual void restart_eh() { m_util.reset(); }
|
||||
virtual bool is_shared(theory_var v) const;
|
||||
public:
|
||||
theory_datatype(ast_manager & m, theory_datatype_params & p);
|
||||
|
|
|
@ -198,7 +198,7 @@ namespace smt {
|
|||
void del_vars(unsigned old_num_vars);
|
||||
void init_model();
|
||||
bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective);
|
||||
expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict);
|
||||
expr_ref mk_ineq(theory_var v, inf_eps const& val, bool is_strict);
|
||||
#ifdef Z3DEBUG
|
||||
bool check_vector_sizes() const;
|
||||
bool check_matrix() const;
|
||||
|
@ -270,8 +270,8 @@ namespace smt {
|
|||
virtual inf_eps_rational<inf_rational> maximize(theory_var v, expr_ref& blocker, bool& has_shared);
|
||||
virtual inf_eps_rational<inf_rational> value(theory_var v);
|
||||
virtual theory_var add_objective(app* term);
|
||||
virtual expr_ref mk_gt(theory_var v, inf_rational const& val);
|
||||
virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val);
|
||||
virtual expr_ref mk_gt(theory_var v, inf_eps const& val);
|
||||
expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val);
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
|
|
|
@ -828,7 +828,7 @@ namespace smt {
|
|||
SASSERT(v != null_theory_var);
|
||||
numeral const & val = m_assignment[v];
|
||||
rational num = val.get_rational().to_rational() + m_epsilon * val.get_infinitesimal().to_rational();
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int(v)));
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, is_int(v)));
|
||||
}
|
||||
|
||||
// TBD: code is common to both sparse and dense difference logic solvers.
|
||||
|
@ -1002,9 +1002,10 @@ namespace smt {
|
|||
m_assignment[i] = a;
|
||||
// TBD: if epsilon is != 0, then adjust a by some small fraction.
|
||||
}
|
||||
blocker = mk_gt(v, r);
|
||||
inf_eps result(rational(0), r);
|
||||
blocker = mk_gt(v, result);
|
||||
IF_VERBOSE(10, verbose_stream() << blocker << "\n";);
|
||||
return inf_eps(rational(0), r);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
TRACE("opt", tout << "unbounded\n"; );
|
||||
|
@ -1034,18 +1035,18 @@ namespace smt {
|
|||
}
|
||||
|
||||
template<typename Ext>
|
||||
expr_ref theory_dense_diff_logic<Ext>::mk_gt(theory_var v, inf_rational const& val) {
|
||||
expr_ref theory_dense_diff_logic<Ext>::mk_gt(theory_var v, inf_eps const& val) {
|
||||
return mk_ineq(v, val, true);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
expr_ref theory_dense_diff_logic<Ext>::mk_ge(
|
||||
filter_model_converter& fm, theory_var v, inf_rational const& val) {
|
||||
filter_model_converter& fm, theory_var v, inf_eps const& val) {
|
||||
return mk_ineq(v, val, false);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
expr_ref theory_dense_diff_logic<Ext>::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) {
|
||||
expr_ref theory_dense_diff_logic<Ext>::mk_ineq(theory_var v, inf_eps const& val, bool is_strict) {
|
||||
ast_manager& m = get_manager();
|
||||
objective_term const& t = m_objectives[v];
|
||||
expr_ref e(m), f(m), f2(m);
|
||||
|
|
|
@ -324,14 +324,15 @@ namespace smt {
|
|||
virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared);
|
||||
virtual inf_eps value(theory_var v);
|
||||
virtual theory_var add_objective(app* term);
|
||||
virtual expr_ref mk_gt(theory_var v, inf_rational const& val);
|
||||
virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val);
|
||||
expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val);
|
||||
|
||||
bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective);
|
||||
|
||||
private:
|
||||
|
||||
expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict);
|
||||
expr_ref mk_gt(theory_var v, inf_eps const& val);
|
||||
|
||||
expr_ref mk_ineq(theory_var v, inf_eps const& val, bool is_strict);
|
||||
|
||||
virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j);
|
||||
|
||||
|
|
|
@ -905,7 +905,7 @@ model_value_proc * theory_diff_logic<Ext>::mk_value(enode * n, model_generator &
|
|||
numeral val = m_graph.get_assignment(v);
|
||||
rational num = val.get_rational().to_rational() + m_delta * val.get_infinitesimal().to_rational();
|
||||
TRACE("arith", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";);
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, m_util.is_int(n->get_owner())));
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, m_util.is_int(n->get_owner())));
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
|
@ -1242,7 +1242,8 @@ theory_diff_logic<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shar
|
|||
rational r = rational(val.first) + m_delta*rational(val.second);
|
||||
m_graph.set_assignment(i, numeral(r));
|
||||
}
|
||||
blocker = mk_gt(v, r);
|
||||
inf_eps r1(rational(0), r);
|
||||
blocker = mk_gt(v, r1);
|
||||
return inf_eps(rational(0), r + m_objective_consts[v]);
|
||||
}
|
||||
default:
|
||||
|
@ -1273,7 +1274,7 @@ theory_var theory_diff_logic<Ext>::add_objective(app* term) {
|
|||
}
|
||||
|
||||
template<typename Ext>
|
||||
expr_ref theory_diff_logic<Ext>::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) {
|
||||
expr_ref theory_diff_logic<Ext>::mk_ineq(theory_var v, inf_eps const& val, bool is_strict) {
|
||||
ast_manager& m = get_manager();
|
||||
objective_term const& t = m_objectives[v];
|
||||
expr_ref e(m), f(m), f2(m);
|
||||
|
@ -1304,7 +1305,7 @@ expr_ref theory_diff_logic<Ext>::mk_ineq(theory_var v, inf_rational const& val,
|
|||
return f;
|
||||
}
|
||||
|
||||
inf_rational new_val = val; // - inf_rational(m_objective_consts[v]);
|
||||
inf_eps new_val = val; // - inf_rational(m_objective_consts[v]);
|
||||
e = m_util.mk_numeral(new_val.get_rational(), m.get_sort(f));
|
||||
|
||||
if (new_val.get_infinitesimal().is_neg()) {
|
||||
|
@ -1328,12 +1329,12 @@ expr_ref theory_diff_logic<Ext>::mk_ineq(theory_var v, inf_rational const& val,
|
|||
}
|
||||
|
||||
template<typename Ext>
|
||||
expr_ref theory_diff_logic<Ext>::mk_gt(theory_var v, inf_rational const& val) {
|
||||
expr_ref theory_diff_logic<Ext>::mk_gt(theory_var v, inf_eps const& val) {
|
||||
return mk_ineq(v, val, true);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
expr_ref theory_diff_logic<Ext>::mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val) {
|
||||
expr_ref theory_diff_logic<Ext>::mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) {
|
||||
return mk_ineq(v, val, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ Revision History:
|
|||
#include"theory_fpa.h"
|
||||
#include"theory_bv.h"
|
||||
#include"smt_model_generator.h"
|
||||
#include"bv2fpa_converter.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
@ -83,27 +84,6 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
void theory_fpa::fpa2bv_converter_wrapped::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
// Note: this introduces new UFs that should be filtered afterwards.
|
||||
return fpa2bv_converter::mk_function(f, num, args, result);
|
||||
}
|
||||
|
||||
expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_max_unspecified(func_decl * f, expr * x, expr * y) {
|
||||
expr_ref a(m), wrapped(m), wu(m), wu_eq(m);
|
||||
a = m.mk_app(f, x, y);
|
||||
wrapped = m_th.wrap(a);
|
||||
wu = m_th.unwrap(wrapped, f->get_range());
|
||||
wu_eq = m.mk_eq(wu, a);
|
||||
m_extra_assertions.push_back(wu_eq);
|
||||
|
||||
unsigned bv_sz = m_bv_util.get_bv_size(wrapped);
|
||||
expr_ref sc(m);
|
||||
sc = m.mk_eq(m_bv_util.mk_extract(bv_sz-2, 0, wrapped), m_bv_util.mk_numeral(0, bv_sz-1));
|
||||
m_extra_assertions.push_back(sc);
|
||||
|
||||
return wu;
|
||||
}
|
||||
|
||||
theory_fpa::theory_fpa(ast_manager & m) :
|
||||
theory(m.mk_family_id("fpa")),
|
||||
m_converter(m, this),
|
||||
|
@ -137,15 +117,15 @@ namespace smt {
|
|||
|
||||
SASSERT(m_trail_stack.get_num_scopes() == 0);
|
||||
SASSERT(m_conversions.empty());
|
||||
SASSERT(m_is_added_to_model.empty());
|
||||
}
|
||||
SASSERT(m_is_added_to_model.empty());
|
||||
}
|
||||
void theory_fpa::init(context * ctx) {
|
||||
smt::theory::init(ctx);
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector<expr> & values) {
|
||||
TRACE("t_fpa_detail",
|
||||
TRACE("t_fpa_detail",
|
||||
ast_manager & m = m_th.get_manager();
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;);
|
||||
|
@ -222,7 +202,7 @@ namespace smt {
|
|||
app * theory_fpa::fpa_rm_value_proc::mk_value(model_generator & mg, ptr_vector<expr> & values) {
|
||||
SASSERT(values.size() == 1);
|
||||
|
||||
TRACE("t_fpa_detail",
|
||||
TRACE("t_fpa_detail",
|
||||
ast_manager & m = m_th.get_manager();
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;);
|
||||
|
@ -256,12 +236,12 @@ namespace smt {
|
|||
app_ref res(m);
|
||||
|
||||
if (m_fpa_util.is_fp(e)) {
|
||||
expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) };
|
||||
expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) };
|
||||
res = m_bv_util.mk_concat(3, cargs);
|
||||
m_th_rw((expr_ref&)res);
|
||||
}
|
||||
else {
|
||||
sort * es = m.get_sort(e);
|
||||
sort * es = m.get_sort(e);
|
||||
|
||||
sort_ref bv_srt(m);
|
||||
if (m_converter.is_rm(es))
|
||||
|
@ -285,7 +265,7 @@ namespace smt {
|
|||
SASSERT(!m_fpa_util.is_fp(e));
|
||||
SASSERT(m_bv_util.is_bv(e));
|
||||
SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s));
|
||||
ast_manager & m = get_manager();
|
||||
ast_manager & m = get_manager();
|
||||
app_ref res(m);
|
||||
|
||||
unsigned bv_sz = m_bv_util.get_bv_size(e);
|
||||
|
@ -306,7 +286,7 @@ namespace smt {
|
|||
m_bv_util.mk_extract(bv_sz - 2, sbits - 1, e),
|
||||
m_bv_util.mk_extract(sbits - 2, 0, e));
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -328,12 +308,13 @@ namespace smt {
|
|||
|
||||
expr_ref e_conv(m), res(m);
|
||||
proof_ref pr(m);
|
||||
|
||||
m_rw(e, e_conv);
|
||||
|
||||
TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << std::endl;
|
||||
tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << std::endl;);
|
||||
|
||||
if (m_fpa_util.is_rm(e)) {
|
||||
if (m_fpa_util.is_rm(e)) {
|
||||
SASSERT(m_fpa_util.is_bv2rm(e_conv));
|
||||
expr_ref bv_rm(m);
|
||||
m_th_rw(to_app(e_conv)->get_arg(0), bv_rm);
|
||||
|
@ -350,7 +331,7 @@ namespace smt {
|
|||
}
|
||||
else
|
||||
UNREACHABLE();
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -383,7 +364,7 @@ namespace smt {
|
|||
res = convert_atom(e);
|
||||
else if (m_fpa_util.is_float(e) || m_fpa_util.is_rm(e))
|
||||
res = convert_term(e);
|
||||
else
|
||||
else
|
||||
res = convert_conversion_term(e);
|
||||
|
||||
TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl;
|
||||
|
@ -416,6 +397,7 @@ namespace smt {
|
|||
res = m.mk_and(res, t);
|
||||
}
|
||||
m_converter.m_extra_assertions.reset();
|
||||
|
||||
m_th_rw(res);
|
||||
|
||||
CTRACE("t_fpa", !m.is_true(res), tout << "side condition: " << mk_ismt2_pp(res, m) << std::endl;);
|
||||
|
@ -469,7 +451,7 @@ namespace smt {
|
|||
TRACE("t_fpa_internalize", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";);
|
||||
SASSERT(term->get_family_id() == get_family_id());
|
||||
SASSERT(!get_context().e_internalized(term));
|
||||
|
||||
|
||||
ast_manager & m = get_manager();
|
||||
context & ctx = get_context();
|
||||
|
||||
|
@ -515,7 +497,7 @@ namespace smt {
|
|||
SASSERT(n->get_owner()->get_decl()->get_range() == s);
|
||||
|
||||
ast_manager & m = get_manager();
|
||||
context & ctx = get_context();
|
||||
context & ctx = get_context();
|
||||
app_ref owner(n->get_owner(), m);
|
||||
|
||||
if (!is_attached_to_var(n)) {
|
||||
|
@ -531,7 +513,7 @@ namespace smt {
|
|||
assert_cnstr(valid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!ctx.relevancy())
|
||||
relevant_eh(owner);
|
||||
}
|
||||
|
@ -571,6 +553,7 @@ namespace smt {
|
|||
c = m.mk_eq(xc, yc);
|
||||
|
||||
m_th_rw(c);
|
||||
|
||||
expr_ref xe_eq_ye(m), c_eq_iff(m);
|
||||
xe_eq_ye = m.mk_eq(xe, ye);
|
||||
c_eq_iff = m.mk_iff(xe_eq_ye, c);
|
||||
|
@ -621,7 +604,7 @@ namespace smt {
|
|||
xe_eq_ye = m.mk_eq(xe, ye);
|
||||
not_xe_eq_ye = m.mk_not(xe_eq_ye);
|
||||
c_eq_iff = m.mk_iff(not_xe_eq_ye, c);
|
||||
assert_cnstr(c_eq_iff);
|
||||
assert_cnstr(c_eq_iff);
|
||||
assert_cnstr(mk_side_conditions());
|
||||
|
||||
return;
|
||||
|
@ -701,8 +684,15 @@ namespace smt {
|
|||
// These are the conversion functions fp.to_* */
|
||||
SASSERT(!m_fpa_util.is_float(n) && !m_fpa_util.is_rm(n));
|
||||
}
|
||||
else
|
||||
UNREACHABLE();
|
||||
else {
|
||||
/* Theory variables can be merged when (= bv-term (bvwrap fp-term)),
|
||||
in which case context::relevant_eh may call theory_fpa::relevant_eh
|
||||
after theory_bv::relevant_eh, regardless of whether theory_fpa is
|
||||
interested in this term. But, this can only happen because of
|
||||
(bvwrap ...) terms, i.e., `n' must be a bit-vector expression,
|
||||
which we can safely ignore. */
|
||||
SASSERT(m_bv_util.is_bv(n));
|
||||
}
|
||||
}
|
||||
|
||||
void theory_fpa::reset_eh() {
|
||||
|
@ -710,9 +700,12 @@ namespace smt {
|
|||
pop_scope_eh(m_trail_stack.get_num_scopes());
|
||||
m_converter.reset();
|
||||
m_rw.reset();
|
||||
m_th_rw.reset();
|
||||
m_trail_stack.pop_scope(m_trail_stack.get_num_scopes());
|
||||
if (m_factory) dealloc(m_factory); m_factory = 0;
|
||||
m_th_rw.reset();
|
||||
m_trail_stack.pop_scope(m_trail_stack.get_num_scopes());
|
||||
if (m_factory) {
|
||||
dealloc(m_factory);
|
||||
m_factory = 0;
|
||||
}
|
||||
ast_manager & m = get_manager();
|
||||
dec_ref_map_key_values(m, m_conversions);
|
||||
dec_ref_collection_values(m, m_is_added_to_model);
|
||||
|
@ -727,8 +720,9 @@ namespace smt {
|
|||
|
||||
void theory_fpa::init_model(model_generator & mg) {
|
||||
TRACE("t_fpa", tout << "initializing model" << std::endl; display(tout););
|
||||
m_factory = alloc(fpa_value_factory, get_manager(), get_family_id());
|
||||
mg.register_factory(m_factory);
|
||||
ast_manager & m = get_manager();
|
||||
m_factory = alloc(fpa_value_factory, m, get_family_id());
|
||||
mg.register_factory(m_factory);
|
||||
}
|
||||
|
||||
model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) {
|
||||
|
@ -814,7 +808,33 @@ namespace smt {
|
|||
return res;
|
||||
}
|
||||
|
||||
void theory_fpa::finalize_model(model_generator & mg) {}
|
||||
void theory_fpa::finalize_model(model_generator & mg) {
|
||||
ast_manager & m = get_manager();
|
||||
proto_model & mdl = mg.get_model();
|
||||
proto_model new_model(m);
|
||||
|
||||
bv2fpa_converter bv2fp(m, m_converter);
|
||||
|
||||
obj_hashtable<func_decl> seen;
|
||||
bv2fp.convert_min_max_specials(&mdl, &new_model, seen);
|
||||
bv2fp.convert_uf2bvuf(&mdl, &new_model, seen);
|
||||
|
||||
for (obj_hashtable<func_decl>::iterator it = seen.begin();
|
||||
it != seen.end();
|
||||
it++)
|
||||
mdl.unregister_decl(*it);
|
||||
|
||||
for (unsigned i = 0; i < new_model.get_num_constants(); i++) {
|
||||
func_decl * f = new_model.get_constant(i);
|
||||
mdl.register_decl(f, new_model.get_const_interp(f));
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < new_model.get_num_functions(); i++) {
|
||||
func_decl * f = new_model.get_function(i);
|
||||
func_interp * fi = new_model.get_func_interp(f)->copy();
|
||||
mdl.register_decl(f, fi);
|
||||
}
|
||||
}
|
||||
|
||||
void theory_fpa::display(std::ostream & out) const
|
||||
{
|
||||
|
@ -865,8 +885,8 @@ namespace smt {
|
|||
}
|
||||
|
||||
bool theory_fpa::include_func_interp(func_decl * f) {
|
||||
TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;);
|
||||
|
||||
TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;);
|
||||
|
||||
if (f->get_family_id() == get_family_id()) {
|
||||
bool include =
|
||||
m_fpa_util.is_min_unspecified(f) ||
|
||||
|
@ -882,8 +902,6 @@ namespace smt {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
else if (m_converter.is_uf2bvuf(f) || m_converter.is_special(f))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -83,9 +83,6 @@ namespace smt {
|
|||
virtual ~fpa2bv_converter_wrapped() {}
|
||||
virtual void mk_const(func_decl * f, expr_ref & result);
|
||||
virtual void mk_rm_const(func_decl * f, expr_ref & result);
|
||||
virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y);
|
||||
};
|
||||
|
||||
class fpa_value_proc : public model_value_proc {
|
||||
|
@ -123,7 +120,7 @@ namespace smt {
|
|||
|
||||
public:
|
||||
fpa_rm_value_proc(theory_fpa * th) :
|
||||
m_th(*th), m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util) {}
|
||||
m_th(*th), m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util) { (void) m_th; }
|
||||
|
||||
void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); }
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace smt {
|
|||
virtual inf_eps value(theory_var) = 0;
|
||||
virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) = 0;
|
||||
virtual theory_var add_objective(app* term) = 0;
|
||||
virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return expr_ref(*((ast_manager*)0)); }
|
||||
bool is_linear(ast_manager& m, expr* term);
|
||||
bool is_numeral(arith_util& a, expr* term);
|
||||
};
|
||||
|
|
|
@ -321,7 +321,8 @@ namespace smt {
|
|||
if (m_simplex.upper_valid(v)) {
|
||||
m_simplex.get_upper(v, last_bound);
|
||||
if (m_mpq_inf_mgr.gt(bound, last_bound)) {
|
||||
literal lit = m_explain_upper.get(v, null_literal);
|
||||
literal lit = m_explain_upper.get(v, null_literal);
|
||||
TRACE("pb", tout << ~lit << " " << ~explain << "\n";);
|
||||
get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain));
|
||||
return false;
|
||||
}
|
||||
|
@ -342,6 +343,7 @@ namespace smt {
|
|||
m_simplex.get_lower(v, last_bound);
|
||||
if (m_mpq_inf_mgr.gt(last_bound, bound)) {
|
||||
literal lit = m_explain_lower.get(v, null_literal);
|
||||
TRACE("pb", tout << ~lit << " " << ~explain << "\n";);
|
||||
get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain));
|
||||
return false;
|
||||
}
|
||||
|
@ -405,6 +407,7 @@ namespace smt {
|
|||
if (proofs_enabled()) {
|
||||
js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr());
|
||||
}
|
||||
TRACE("pb", tout << lits << "\n";);
|
||||
ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0);
|
||||
|
||||
return false;
|
||||
|
@ -515,16 +518,17 @@ namespace smt {
|
|||
++log;
|
||||
n *= 2;
|
||||
}
|
||||
unsigned th = args.size()*log; // 10*
|
||||
unsigned th = args.size()*log*log;
|
||||
c->m_compilation_threshold = th;
|
||||
IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threhshold to " << th << ")\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threshold to " << th << ")\n";);
|
||||
TRACE("pb", tout << "compilation threshold: " << th << "\n";);
|
||||
}
|
||||
else {
|
||||
c->m_compilation_threshold = UINT_MAX;
|
||||
}
|
||||
init_watch_var(*c);
|
||||
m_ineqs.insert(abv, c);
|
||||
init_watch(abv);
|
||||
m_var_infos[abv].m_ineq = c;
|
||||
m_ineqs_trail.push_back(abv);
|
||||
|
||||
if (m_enable_simplex) {
|
||||
|
@ -684,35 +688,43 @@ namespace smt {
|
|||
watch_literal(lit, &c);
|
||||
}
|
||||
|
||||
void theory_pb::init_watch(bool_var v) {
|
||||
if (m_var_infos.size() <= static_cast<unsigned>(v)) {
|
||||
m_var_infos.resize(static_cast<unsigned>(v)+100);
|
||||
}
|
||||
}
|
||||
|
||||
void theory_pb::watch_literal(literal lit, ineq* c) {
|
||||
ptr_vector<ineq>* ineqs;
|
||||
if (!m_lwatch.find(lit.index(), ineqs)) {
|
||||
init_watch(lit.var());
|
||||
ptr_vector<ineq>* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()];
|
||||
if (ineqs == 0) {
|
||||
ineqs = alloc(ptr_vector<ineq>);
|
||||
m_lwatch.insert(lit.index(), ineqs);
|
||||
m_var_infos[lit.var()].m_lit_watch[lit.sign()] = ineqs;
|
||||
}
|
||||
ineqs->push_back(c);
|
||||
}
|
||||
|
||||
void theory_pb::watch_var(bool_var v, ineq* c) {
|
||||
ptr_vector<ineq>* ineqs;
|
||||
if (!m_vwatch.find(v, ineqs)) {
|
||||
init_watch(v);
|
||||
ptr_vector<ineq>* ineqs = m_var_infos[v].m_var_watch;
|
||||
if (ineqs == 0) {
|
||||
ineqs = alloc(ptr_vector<ineq>);
|
||||
m_vwatch.insert(v, ineqs);
|
||||
m_var_infos[v].m_var_watch = ineqs;
|
||||
}
|
||||
ineqs->push_back(c);
|
||||
}
|
||||
|
||||
void theory_pb::unwatch_var(bool_var v, ineq* c) {
|
||||
ptr_vector<ineq>* ineqs = 0;
|
||||
if (m_vwatch.find(v, ineqs)) {
|
||||
ptr_vector<ineq>* ineqs = m_var_infos[v].m_var_watch;
|
||||
if (ineqs) {
|
||||
remove(*ineqs, c);
|
||||
}
|
||||
}
|
||||
|
||||
void theory_pb::unwatch_literal(literal w, ineq* c) {
|
||||
ptr_vector<ineq>* ineqs = 0;
|
||||
if (m_lwatch.find(w.index(), ineqs)) {
|
||||
remove(*ineqs, c);
|
||||
void theory_pb::unwatch_literal(literal lit, ineq* c) {
|
||||
ptr_vector<ineq>* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()];
|
||||
if (ineqs) {
|
||||
remove(*ineqs, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -738,22 +750,9 @@ namespace smt {
|
|||
|
||||
void theory_pb::reset_eh() {
|
||||
|
||||
// m_watch;
|
||||
u_map<ptr_vector<ineq>*>::iterator it = m_lwatch.begin(), end = m_lwatch.end();
|
||||
for (; it != end; ++it) {
|
||||
dealloc(it->m_value);
|
||||
for (unsigned i = 0; i < m_var_infos.size(); ++i) {
|
||||
m_var_infos[i].reset();
|
||||
}
|
||||
it = m_vwatch.begin(), end = m_vwatch.end();
|
||||
for (; it != end; ++it) {
|
||||
dealloc(it->m_value);
|
||||
}
|
||||
u_map<ineq*>::iterator itc = m_ineqs.begin(), endc = m_ineqs.end();
|
||||
for (; itc != endc; ++itc) {
|
||||
dealloc(itc->m_value);
|
||||
}
|
||||
m_lwatch.reset();
|
||||
m_vwatch.reset();
|
||||
m_ineqs.reset();
|
||||
m_ineqs_trail.reset();
|
||||
m_ineqs_lim.reset();
|
||||
m_stats.reset();
|
||||
|
@ -773,8 +772,10 @@ namespace smt {
|
|||
void theory_pb::assign_eh(bool_var v, bool is_true) {
|
||||
ptr_vector<ineq>* ineqs = 0;
|
||||
literal nlit(v, is_true);
|
||||
init_watch(v);
|
||||
TRACE("pb", tout << "assign: " << ~nlit << "\n";);
|
||||
if (m_lwatch.find(nlit.index(), ineqs)) {
|
||||
ineqs = m_var_infos[v].m_lit_watch[nlit.sign()];
|
||||
if (ineqs != 0) {
|
||||
if (m_enable_simplex) {
|
||||
mpq_inf num(mpq(is_true?1:0),mpq(0));
|
||||
if (!update_bound(v, ~nlit, is_true, num)) {
|
||||
|
@ -794,14 +795,15 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (m_vwatch.find(v, ineqs)) {
|
||||
ineqs = m_var_infos[v].m_var_watch;
|
||||
if (ineqs != 0) {
|
||||
for (unsigned i = 0; i < ineqs->size(); ++i) {
|
||||
ineq* c = (*ineqs)[i];
|
||||
assign_watch(v, is_true, *c);
|
||||
}
|
||||
}
|
||||
ineq* c = 0;
|
||||
if (m_ineqs.find(v, c)) {
|
||||
ineq* c = m_var_infos[v].m_ineq;
|
||||
if (c != 0) {
|
||||
if (m_enable_simplex) {
|
||||
row_info const& info = m_ineq_row_info.find(v);
|
||||
scoped_eps_numeral coeff(m_mpq_inf_mgr);
|
||||
|
@ -1216,7 +1218,7 @@ namespace smt {
|
|||
|
||||
void theory_pb::inc_propagations(ineq& c) {
|
||||
++c.m_num_propagations;
|
||||
if (c.m_compiled == l_false && c.m_num_propagations > c.m_compilation_threshold) {
|
||||
if (c.m_compiled == l_false && c.m_num_propagations >= c.m_compilation_threshold) {
|
||||
c.m_compiled = l_undef;
|
||||
m_to_compile.push_back(&c);
|
||||
}
|
||||
|
@ -1246,9 +1248,9 @@ namespace smt {
|
|||
literal_vector in;
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
rational n = c.coeff(i);
|
||||
lbool val = ctx.get_assignment(c.lit());
|
||||
if (val != l_undef &&
|
||||
ctx.get_assign_level(thl) == ctx.get_base_level()) {
|
||||
literal lit = c.lit(i);
|
||||
lbool val = ctx.get_assignment(lit);
|
||||
if (val != l_undef && ctx.get_assign_level(lit) == ctx.get_base_level()) {
|
||||
if (val == l_true) {
|
||||
unsigned m = n.get_unsigned();
|
||||
if (k < m) {
|
||||
|
@ -1263,31 +1265,35 @@ namespace smt {
|
|||
n -= rational::one();
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("pb", tout << in << " >= " << k << "\n";);
|
||||
|
||||
|
||||
psort_expr ps(ctx, *this);
|
||||
psort_nw<psort_expr> sortnw(ps);
|
||||
sortnw.m_stats.reset();
|
||||
|
||||
if (ctx.get_assignment(thl) == l_true &&
|
||||
ctx.get_assign_level(thl) == ctx.get_base_level()) {
|
||||
psort_expr ps(ctx, *this);
|
||||
psort_nw<psort_expr> sortnw(ps);
|
||||
sortnw.m_stats.reset();
|
||||
at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr());
|
||||
at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr());
|
||||
TRACE("pb", tout << ~thl << " " << at_least_k << "\n";);
|
||||
ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k));
|
||||
m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars;
|
||||
m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses;
|
||||
}
|
||||
else {
|
||||
psort_expr ps(ctx, *this);
|
||||
psort_nw<psort_expr> sortnw(ps);
|
||||
sortnw.m_stats.reset();
|
||||
literal at_least_k = sortnw.ge(true, k, in.size(), in.c_ptr());
|
||||
TRACE("pb", tout << ~thl << " " << at_least_k << "\n";);
|
||||
ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k));
|
||||
ctx.mk_clause(~at_least_k, thl, justify(thl, ~at_least_k));
|
||||
m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars;
|
||||
m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses;
|
||||
}
|
||||
IF_VERBOSE(1, verbose_stream()
|
||||
<< "(smt.pb compile sorting network bound: "
|
||||
<< k << " literals: " << in.size() << ")\n";);
|
||||
m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars;
|
||||
m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses;
|
||||
|
||||
IF_VERBOSE(2, verbose_stream()
|
||||
<< "(smt.pb compile sorting network bound: "
|
||||
<< k << " literals: " << in.size()
|
||||
<< " clauses: " << sortnw.m_stats.m_num_compiled_clauses
|
||||
<< " vars: " << sortnw.m_stats.m_num_compiled_vars << ")\n";);
|
||||
|
||||
TRACE("pb", tout << thl << "\n";);
|
||||
// auxiliary clauses get removed when popping scopes.
|
||||
// we have to recompile the circuit after back-tracking.
|
||||
c.m_compiled = l_false;
|
||||
|
@ -1297,7 +1303,6 @@ namespace smt {
|
|||
|
||||
|
||||
void theory_pb::init_search_eh() {
|
||||
m_to_compile.reset();
|
||||
}
|
||||
|
||||
void theory_pb::push_scope_eh() {
|
||||
|
@ -1311,10 +1316,9 @@ namespace smt {
|
|||
unsigned sz = m_ineqs_lim[new_lim];
|
||||
while (m_ineqs_trail.size() > sz) {
|
||||
bool_var v = m_ineqs_trail.back();
|
||||
ineq* c = 0;
|
||||
VERIFY(m_ineqs.find(v, c));
|
||||
ineq* c = m_var_infos[v].m_ineq;
|
||||
clear_watch(*c);
|
||||
m_ineqs.remove(v);
|
||||
m_var_infos[v].m_ineq = 0;
|
||||
m_ineqs_trail.pop_back();
|
||||
if (m_enable_simplex) {
|
||||
row_info r_info;
|
||||
|
@ -1326,6 +1330,7 @@ namespace smt {
|
|||
m_ineq_rep.erase(r_info.m_rep);
|
||||
}
|
||||
}
|
||||
m_to_compile.erase(c);
|
||||
dealloc(c);
|
||||
}
|
||||
m_ineqs_lim.resize(new_lim);
|
||||
|
@ -1451,6 +1456,7 @@ namespace smt {
|
|||
if (proofs_enabled()) {
|
||||
js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr());
|
||||
}
|
||||
TRACE("pb", tout << lits << "\n";);
|
||||
ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0);
|
||||
}
|
||||
|
||||
|
@ -1746,7 +1752,7 @@ namespace smt {
|
|||
// verbose_stream() << "(pb.conflict min size: " << l_size << ")\n";
|
||||
// s_min_l_size = l_size;
|
||||
//}
|
||||
//IF_VERBOSE(1, verbose_stream() << "(pb.conflict " << m_ineq_literals.size() << " " << m_lemma.size() << "\n";);
|
||||
IF_VERBOSE(1, verbose_stream() << "(pb.conflict " << m_ineq_literals.size() << " " << m_lemma.size() << ")\n";);
|
||||
switch(is_true) {
|
||||
case l_true:
|
||||
UNREACHABLE();
|
||||
|
@ -1757,6 +1763,7 @@ namespace smt {
|
|||
for (unsigned i = 0; i < m_ineq_literals.size(); ++i) {
|
||||
m_ineq_literals[i].neg();
|
||||
}
|
||||
TRACE("pb", tout << m_ineq_literals << "\n";);
|
||||
ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), justify(m_ineq_literals), CLS_AUX_LEMMA, 0);
|
||||
break;
|
||||
default: {
|
||||
|
@ -1857,9 +1864,11 @@ namespace smt {
|
|||
}
|
||||
|
||||
void theory_pb::validate_final_check() {
|
||||
u_map<ineq*>::iterator itc = m_ineqs.begin(), endc = m_ineqs.end();
|
||||
for (; itc != endc; ++itc) {
|
||||
validate_final_check(*itc->m_value);
|
||||
for (unsigned i = 0; i < m_var_infos.size(); ++i) {
|
||||
ineq* c = m_var_infos[i].m_ineq;
|
||||
if (c) {
|
||||
validate_final_check(*c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2067,29 +2076,37 @@ namespace smt {
|
|||
return p;
|
||||
}
|
||||
|
||||
void theory_pb::display_watch(std::ostream& out, bool_var v, bool sign) const {
|
||||
watch_list const* w = m_var_infos[v].m_lit_watch[sign];
|
||||
if (!w) return;
|
||||
watch_list const& wl = *w;
|
||||
out << "watch: " << literal(v, sign) << " |-> ";
|
||||
for (unsigned i = 0; i < wl.size(); ++i) {
|
||||
out << wl[i]->lit() << " ";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
void theory_pb::display(std::ostream& out) const {
|
||||
u_map<ptr_vector<ineq>*>::iterator it = m_lwatch.begin(), end = m_lwatch.end();
|
||||
for (; it != end; ++it) {
|
||||
out << "watch: " << to_literal(it->m_key) << " |-> ";
|
||||
watch_list const& wl = *it->m_value;
|
||||
for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) {
|
||||
display_watch(out, vi, false);
|
||||
display_watch(out, vi, true);
|
||||
}
|
||||
for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) {
|
||||
watch_list const* w = m_var_infos[vi].m_var_watch;
|
||||
if (!w) continue;
|
||||
out << "watch (v): " << literal(vi) << " |-> ";
|
||||
watch_list const& wl = *w;
|
||||
for (unsigned i = 0; i < wl.size(); ++i) {
|
||||
out << wl[i]->lit() << " ";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
it = m_vwatch.begin(), end = m_vwatch.end();
|
||||
for (; it != end; ++it) {
|
||||
out << "watch (v): " << literal(it->m_key) << " |-> ";
|
||||
watch_list const& wl = *it->m_value;
|
||||
for (unsigned i = 0; i < wl.size(); ++i) {
|
||||
out << wl[i]->lit() << " ";
|
||||
for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) {
|
||||
ineq* c = m_var_infos[vi].m_ineq;
|
||||
if (c) {
|
||||
display(out, *c, true);
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
u_map<ineq*>::iterator itc = m_ineqs.begin(), endc = m_ineqs.end();
|
||||
for (; itc != endc; ++itc) {
|
||||
ineq& c = *itc->m_value;
|
||||
display(out, c, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,10 +193,29 @@ namespace smt {
|
|||
typedef ptr_vector<ineq> watch_list;
|
||||
typedef map<arg_t, bool_var, arg_t::hash, arg_t::eq> arg_map;
|
||||
|
||||
struct var_info {
|
||||
watch_list* m_lit_watch[2];
|
||||
watch_list* m_var_watch;
|
||||
ineq* m_ineq;
|
||||
|
||||
var_info(): m_var_watch(0), m_ineq(0)
|
||||
{
|
||||
m_lit_watch[0] = 0;
|
||||
m_lit_watch[1] = 0;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
dealloc(m_lit_watch[0]);
|
||||
dealloc(m_lit_watch[1]);
|
||||
dealloc(m_var_watch);
|
||||
dealloc(m_ineq);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
theory_pb_params m_params;
|
||||
u_map<watch_list*> m_lwatch; // per literal.
|
||||
u_map<watch_list*> m_vwatch; // per variable.
|
||||
u_map<ineq*> m_ineqs; // per inequality.
|
||||
|
||||
svector<var_info> m_var_infos;
|
||||
arg_map m_ineq_rep; // Simplex: representative inequality
|
||||
u_map<row_info> m_ineq_row_info; // Simplex: row information per variable
|
||||
uint_set m_vars; // Simplex: 0-1 variables.
|
||||
|
@ -221,6 +240,7 @@ namespace smt {
|
|||
literal compile_arg(expr* arg);
|
||||
void add_watch(ineq& c, unsigned index);
|
||||
void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index);
|
||||
void init_watch(bool_var v);
|
||||
void init_watch_literal(ineq& c);
|
||||
void init_watch_var(ineq& c);
|
||||
void clear_watch(ineq& c);
|
||||
|
@ -242,6 +262,7 @@ namespace smt {
|
|||
std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const;
|
||||
std::ostream& display(std::ostream& out, arg_t const& c, bool values = false) const;
|
||||
virtual void display(std::ostream& out) const;
|
||||
void display_watch(std::ostream& out, bool_var v, bool sign) const;
|
||||
void display_resolved_lemma(std::ostream& out) const;
|
||||
|
||||
void add_clause(ineq& c, literal_vector const& lits);
|
||||
|
@ -316,6 +337,7 @@ namespace smt {
|
|||
virtual void collect_statistics(::statistics & st) const;
|
||||
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
|
||||
virtual void init_model(model_generator & m);
|
||||
virtual bool include_func_interp(func_decl* f) { return false; }
|
||||
|
||||
static literal assert_ge(context& ctx, unsigned k, unsigned n, literal const* xs);
|
||||
};
|
||||
|
|
|
@ -196,6 +196,7 @@ theory_seq::theory_seq(ast_manager& m):
|
|||
theory(m.mk_family_id("seq")),
|
||||
m(m),
|
||||
m_rep(m, m_dm),
|
||||
m_reset_cache(false),
|
||||
m_eq_id(0),
|
||||
m_find(*this),
|
||||
m_factory(0),
|
||||
|
@ -242,8 +243,13 @@ void theory_seq::init(context* ctx) {
|
|||
}
|
||||
|
||||
final_check_status theory_seq::final_check_eh() {
|
||||
if (m_reset_cache) {
|
||||
m_rep.reset_cache();
|
||||
m_reset_cache = false;
|
||||
}
|
||||
m_new_propagation = false;
|
||||
TRACE("seq", display(tout << "level: " << get_context().get_scope_level() << "\n"););
|
||||
TRACE("seq_verbose", get_context().display(tout););
|
||||
if (simplify_and_solve_eqs()) {
|
||||
++m_stats.m_solve_eqs;
|
||||
TRACE("seq", tout << ">>solve_eqs\n";);
|
||||
|
@ -1004,6 +1010,17 @@ bool theory_seq::is_nth(expr* e) const {
|
|||
return is_skolem(m_nth, e);
|
||||
}
|
||||
|
||||
bool theory_seq::is_nth(expr* e, expr*& e1, expr*& e2) const {
|
||||
if (is_nth(e)) {
|
||||
e1 = to_app(e)->get_arg(0);
|
||||
e2 = to_app(e)->get_arg(1);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool theory_seq::is_tail(expr* e, expr*& s, unsigned& idx) const {
|
||||
rational r;
|
||||
return
|
||||
|
@ -1033,6 +1050,10 @@ expr_ref theory_seq::mk_nth(expr* s, expr* idx) {
|
|||
return mk_skolem(m_nth, s, idx, 0, char_sort);
|
||||
}
|
||||
|
||||
expr_ref theory_seq::mk_sk_ite(expr* c, expr* t, expr* e) {
|
||||
return mk_skolem(symbol("seq.if"), c, t, e, m.get_sort(t));
|
||||
}
|
||||
|
||||
expr_ref theory_seq::mk_last(expr* s) {
|
||||
zstring str;
|
||||
if (m_util.str.is_string(s, str) && str.length() > 0) {
|
||||
|
@ -1128,7 +1149,7 @@ bool theory_seq::check_extensionality() {
|
|||
continue;
|
||||
}
|
||||
TRACE("seq", tout << m_lhs << " = " << m_rhs << "\n";);
|
||||
ctx.assume_eq(n1, n2);
|
||||
ctx.assume_eq(n1, n2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1366,7 +1387,7 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) {
|
|||
|
||||
bool theory_seq::occurs(expr* a, expr_ref_vector const& b) {
|
||||
for (unsigned i = 0; i < b.size(); ++i) {
|
||||
if (a == b[i]) return true;
|
||||
if (a == b[i] || m.is_ite(b[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1379,7 +1400,7 @@ bool theory_seq::occurs(expr* a, expr* b) {
|
|||
m_todo.push_back(b);
|
||||
while (!m_todo.empty()) {
|
||||
b = m_todo.back();
|
||||
if (a == b) {
|
||||
if (a == b || m.is_ite(b)) {
|
||||
m_todo.reset();
|
||||
return true;
|
||||
}
|
||||
|
@ -1794,7 +1815,10 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
for (unsigned i = 0; i < n.lits().size(); ++i) {
|
||||
switch (ctx.get_assignment(n.lits(i))) {
|
||||
case l_false:
|
||||
TRACE("seq", display_disequation(tout << "has false literal\n", n););
|
||||
TRACE("seq", display_disequation(tout << "has false literal\n", n);
|
||||
ctx.display_literal_verbose(tout, n.lits(i));
|
||||
tout << "\n" << n.lits(i) << " " << ctx.is_relevant(n.lits(i)) << "\n";
|
||||
);
|
||||
return true;
|
||||
case l_true:
|
||||
break;
|
||||
|
@ -1820,7 +1844,10 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
change = canonize(n.rs(i), rs, deps) || change;
|
||||
|
||||
if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs, change)) {
|
||||
TRACE("seq", display_disequation(tout << "reduces to false: ", n););
|
||||
TRACE("seq", display_disequation(tout << "reduces to false: ", n);
|
||||
tout << n.ls(i) << " -> " << ls << "\n";
|
||||
tout << n.rs(i) << " -> " << rs << "\n";);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (!change) {
|
||||
|
@ -2197,42 +2224,130 @@ bool theory_seq::check_int_string() {
|
|||
if (m_util.str.is_itos(e) && add_itos_axiom(e)) {
|
||||
change = true;
|
||||
}
|
||||
else if (m_util.str.is_stoi(e, n)) {
|
||||
// not (yet) handled.
|
||||
// we would check that in the current proto-model
|
||||
// the string at 'n', when denoting integer would map to the
|
||||
// proper integer.
|
||||
else if (m_util.str.is_stoi(e, n) && add_stoi_axiom(e)) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
bool theory_seq::add_stoi_axiom(expr* e) {
|
||||
context& ctx = get_context();
|
||||
expr* n;
|
||||
rational val;
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
VERIFY(m_util.str.is_stoi(e, n));
|
||||
if (get_num_value(e, val) && !m_stoi_axioms.contains(val)) {
|
||||
m_stoi_axioms.insert(val);
|
||||
if (!val.is_minus_one()) {
|
||||
app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m);
|
||||
expr_ref n1(arith_util(m).mk_numeral(val, true), m);
|
||||
literal eq1 = mk_eq(e, n1, false);
|
||||
literal eq2 = mk_eq(n, e1, false);
|
||||
add_axiom(~eq1, eq2);
|
||||
add_axiom(~eq2, eq1);
|
||||
ctx.force_phase(eq1);
|
||||
ctx.force_phase(eq2);
|
||||
m_trail_stack.push(insert_map<theory_seq, rational_set, rational>(m_stoi_axioms, val));
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (upper_bound(n, val) && get_length(n, val) && val.is_pos() && !m_stoi_axioms.contains(val)) {
|
||||
zstring s;
|
||||
SASSERT(val.is_unsigned());
|
||||
unsigned sz = val.get_unsigned();
|
||||
expr_ref len1(m), len2(m), ith_char(m), num(m), coeff(m);
|
||||
expr_ref_vector nums(m);
|
||||
len1 = m_util.str.mk_length(n);
|
||||
len2 = m_autil.mk_int(sz);
|
||||
literal lit = mk_eq(len1, len2, false);
|
||||
literal_vector lits;
|
||||
lits.push_back(~lit);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
ith_char = mk_nth(n, m_autil.mk_int(i));
|
||||
lits.push_back(~is_digit(ith_char));
|
||||
nums.push_back(digit2int(ith_char));
|
||||
}
|
||||
for (unsigned i = sz-1, c = 1; i > 0; c *= 10) {
|
||||
--i;
|
||||
coeff = m_autil.mk_int(c);
|
||||
nums[i] = m_autil.mk_mul(coeff, nums[i].get());
|
||||
}
|
||||
num = m_autil.mk_add(nums.size(), nums.c_ptr());
|
||||
lits.push_back(mk_eq(e, num, false));
|
||||
++m_stats.m_add_axiom;
|
||||
m_new_propagation = true;
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
ctx.mark_as_relevant(lits[i]);
|
||||
}
|
||||
ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
|
||||
m_stoi_axioms.insert(val);
|
||||
m_trail_stack.push(insert_map<theory_seq, rational_set, rational>(m_stoi_axioms, val));
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
literal theory_seq::is_digit(expr* ch) {
|
||||
bv_util bv(m);
|
||||
literal isd = mk_literal(mk_skolem(symbol("seq.is_digit"), ch, 0, 0, m.mk_bool_sort()));
|
||||
expr_ref d2i = digit2int(ch);
|
||||
expr_ref _lo(bv.mk_ule(bv.mk_numeral(rational('0'), bv.mk_sort(8)), ch), m);
|
||||
expr_ref _hi(bv.mk_ule(ch, bv.mk_numeral(rational('9'), bv.mk_sort(8))), m);
|
||||
literal lo = mk_literal(_lo);
|
||||
literal hi = mk_literal(_hi);
|
||||
add_axiom(~lo, ~hi, isd);
|
||||
add_axiom(~isd, lo);
|
||||
add_axiom(~isd, hi);
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
add_axiom(~mk_eq(ch, bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), false), mk_eq(d2i, m_autil.mk_int(i), false));
|
||||
}
|
||||
return isd;
|
||||
}
|
||||
|
||||
expr_ref theory_seq::digit2int(expr* ch) {
|
||||
return expr_ref(mk_skolem(symbol("seq.digit2int"), ch, 0, 0, m_autil.mk_int()), m);
|
||||
}
|
||||
|
||||
bool theory_seq::add_itos_axiom(expr* e) {
|
||||
context& ctx = get_context();
|
||||
rational val;
|
||||
expr* n;
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
VERIFY(m_util.str.is_itos(e, n));
|
||||
if (get_value(n, val)) {
|
||||
if (get_num_value(n, val)) {
|
||||
if (!m_itos_axioms.contains(val)) {
|
||||
m_itos_axioms.insert(val);
|
||||
app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m);
|
||||
expr_ref n1(arith_util(m).mk_numeral(val, true), m);
|
||||
|
||||
#if 1
|
||||
// itos(n) = "25" <=> n = 25
|
||||
add_axiom(~mk_eq(n1, n , false), mk_eq(e, e1, false));
|
||||
add_axiom(mk_eq(n1, n, false), ~mk_eq(e, e1, false));
|
||||
#else
|
||||
// "25" = itos(25)
|
||||
// stoi(itos(n)) = n
|
||||
app_ref e2(m_util.str.mk_stoi(e), m);
|
||||
add_axiom(mk_eq(e2, n, false));
|
||||
add_axiom(mk_eq(m_util.str.mk_itos(n1), e1, false));
|
||||
#endif
|
||||
literal eq1 = mk_eq(n1, n , false);
|
||||
literal eq2 = mk_eq(e, e1, false);
|
||||
add_axiom(~eq1, eq2);
|
||||
add_axiom(~eq2, eq1);
|
||||
ctx.force_phase(eq1);
|
||||
ctx.force_phase(eq2);
|
||||
|
||||
m_trail_stack.push(insert_map<theory_seq, rational_set, rational>(m_itos_axioms, val));
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// stoi(itos(n)) = n
|
||||
app_ref e2(m_util.str.mk_stoi(e), m);
|
||||
if (ctx.e_internalized(e2) && ctx.get_enode(e2)->get_root() == ctx.get_enode(n)->get_root()) {
|
||||
return false;
|
||||
}
|
||||
add_axiom(mk_eq(e2, n, false));
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2394,6 +2509,11 @@ void theory_seq::init_model(expr_ref_vector const& es) {
|
|||
void theory_seq::init_model(model_generator & mg) {
|
||||
m_factory = alloc(seq_factory, get_manager(), get_family_id(), mg.get_model());
|
||||
mg.register_factory(m_factory);
|
||||
for (unsigned j = 0; j < m_nqs.size(); ++j) {
|
||||
ne const& n = m_nqs[j];
|
||||
m_factory->register_value(n.l());
|
||||
m_factory->register_value(n.r());
|
||||
}
|
||||
for (unsigned j = 0; j < m_nqs.size(); ++j) {
|
||||
ne const& n = m_nqs[j];
|
||||
for (unsigned i = 0; i < n.ls().size(); ++i) {
|
||||
|
@ -2405,26 +2525,38 @@ void theory_seq::init_model(model_generator & mg) {
|
|||
|
||||
|
||||
class theory_seq::seq_value_proc : public model_value_proc {
|
||||
enum source_t { unit_source, int_source, string_source };
|
||||
theory_seq& th;
|
||||
sort* m_sort;
|
||||
svector<model_value_dependency> m_dependencies;
|
||||
ptr_vector<expr> m_strings;
|
||||
svector<bool> m_source;
|
||||
svector<source_t> m_source;
|
||||
public:
|
||||
seq_value_proc(theory_seq& th, sort* s): th(th), m_sort(s) {
|
||||
}
|
||||
virtual ~seq_value_proc() {}
|
||||
void add_dependency(enode* n) {
|
||||
void add_unit(enode* n) {
|
||||
m_dependencies.push_back(model_value_dependency(n));
|
||||
m_source.push_back(true);
|
||||
m_source.push_back(unit_source);
|
||||
}
|
||||
void add_int(enode* n) {
|
||||
m_dependencies.push_back(model_value_dependency(n));
|
||||
m_source.push_back(int_source);
|
||||
}
|
||||
void add_string(expr* n) {
|
||||
m_strings.push_back(n);
|
||||
m_source.push_back(false);
|
||||
m_source.push_back(string_source);
|
||||
}
|
||||
virtual void get_dependencies(buffer<model_value_dependency> & result) {
|
||||
result.append(m_dependencies.size(), m_dependencies.c_ptr());
|
||||
}
|
||||
|
||||
void add_buffer(svector<unsigned>& sbuffer, zstring const& zs) {
|
||||
for (unsigned l = 0; l < zs.length(); ++l) {
|
||||
sbuffer.push_back(zs[l]);
|
||||
}
|
||||
}
|
||||
|
||||
virtual app * mk_value(model_generator & mg, ptr_vector<expr> & values) {
|
||||
SASSERT(values.size() == m_dependencies.size());
|
||||
expr_ref_vector args(th.m);
|
||||
|
@ -2438,28 +2570,51 @@ public:
|
|||
unsigned sz;
|
||||
|
||||
for (unsigned i = 0; i < m_source.size(); ++i) {
|
||||
if (m_source[i]) {
|
||||
switch (m_source[i]) {
|
||||
case unit_source: {
|
||||
VERIFY(bv.is_numeral(values[j++], val, sz));
|
||||
sbuffer.push_back(val.get_unsigned());
|
||||
break;
|
||||
}
|
||||
else {
|
||||
case string_source: {
|
||||
dependency* deps = 0;
|
||||
expr_ref tmp = th.canonize(m_strings[k], deps);
|
||||
zstring zs;
|
||||
if (th.m_util.str.is_string(m_strings[k++], zs)) {
|
||||
for (unsigned l = 0; l < zs.length(); ++l) {
|
||||
sbuffer.push_back(zs[l]);
|
||||
}
|
||||
if (th.m_util.str.is_string(tmp, zs)) {
|
||||
add_buffer(sbuffer, zs);
|
||||
}
|
||||
else {
|
||||
TRACE("seq", tout << "Not a string: " << tmp << "\n";);
|
||||
}
|
||||
++k;
|
||||
break;
|
||||
}
|
||||
case int_source: {
|
||||
std::ostringstream strm;
|
||||
arith_util arith(th.m);
|
||||
VERIFY(arith.is_numeral(values[j++], val));
|
||||
if (val.is_neg()) strm << "-";
|
||||
strm << abs(val);
|
||||
zstring zs(strm.str().c_str());
|
||||
add_buffer(sbuffer, zs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = th.m_util.str.mk_string(zstring(sbuffer.size(), sbuffer.c_ptr()));
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < m_source.size(); ++i) {
|
||||
if (m_source[i]) {
|
||||
switch (m_source[i]) {
|
||||
case unit_source:
|
||||
args.push_back(th.m_util.str.mk_unit(values[j++]));
|
||||
}
|
||||
else {
|
||||
break;
|
||||
case string_source:
|
||||
args.push_back(m_strings[k++]);
|
||||
break;
|
||||
case int_source:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = th.mk_concat(args, m_sort);
|
||||
|
@ -2472,18 +2627,37 @@ public:
|
|||
|
||||
|
||||
model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
|
||||
if (m_util.is_seq(n->get_owner())) {
|
||||
app* e = n->get_owner();
|
||||
context& ctx = get_context();
|
||||
expr* e1, *e2, *e3;
|
||||
if (m.is_ite(e, e1, e2, e3) && ctx.e_internalized(e2) && ctx.e_internalized(e3) &&
|
||||
(ctx.get_enode(e2)->get_root() == n->get_root() ||
|
||||
ctx.get_enode(e3)->get_root() == n->get_root())) {
|
||||
if (ctx.get_enode(e2)->get_root() == n->get_root()) {
|
||||
return mk_value(ctx.get_enode(e2), mg);
|
||||
}
|
||||
else {
|
||||
return mk_value(ctx.get_enode(e3), mg);
|
||||
}
|
||||
}
|
||||
else if (m_util.is_seq(e)) {
|
||||
ptr_vector<expr> concats;
|
||||
get_concat(n->get_owner(), concats);
|
||||
context& ctx = get_context();
|
||||
sort* srt = m.get_sort(n->get_owner());
|
||||
get_concat(e, concats);
|
||||
sort* srt = m.get_sort(e);
|
||||
seq_value_proc* sv = alloc(seq_value_proc, *this, srt);
|
||||
|
||||
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
for (unsigned i = 0; i < concats.size(); ++i) {
|
||||
expr* c = concats[i], *c1;
|
||||
TRACE("seq", tout << mk_pp(c, m) << "\n";);
|
||||
if (m_util.str.is_unit(c, c1)) {
|
||||
if (ctx.e_internalized(c1)) {
|
||||
sv->add_dependency(ctx.get_enode(c1));
|
||||
sv->add_unit(ctx.get_enode(c1));
|
||||
}
|
||||
}
|
||||
else if (m_util.str.is_itos(c, c1)) {
|
||||
if (ctx.e_internalized(c1)) {
|
||||
sv->add_int(ctx.get_enode(c1));
|
||||
}
|
||||
}
|
||||
else if (m_util.str.is_string(c)) {
|
||||
|
@ -2496,7 +2670,7 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
|
|||
return sv;
|
||||
}
|
||||
else {
|
||||
return alloc(expr_wrapper_proc, mk_value(n->get_owner()));
|
||||
return alloc(expr_wrapper_proc, mk_value(e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2619,7 +2793,23 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) {
|
|||
result = m_util.str.mk_index(expand(e1, deps), expand(e2, deps), e3);
|
||||
}
|
||||
else if (m.is_ite(e, e1, e2, e3)) {
|
||||
if (ctx.e_internalized(e) && ctx.e_internalized(e2) && ctx.get_enode(e)->get_root() == ctx.get_enode(e2)->get_root()) {
|
||||
result = expand(e2, deps);
|
||||
add_dependency(deps, ctx.get_enode(e), ctx.get_enode(e2));
|
||||
}
|
||||
else if (ctx.e_internalized(e) && ctx.e_internalized(e2) && ctx.get_enode(e)->get_root() == ctx.get_enode(e3)->get_root()) {
|
||||
result = expand(e3, deps);
|
||||
add_dependency(deps, ctx.get_enode(e), ctx.get_enode(e3));
|
||||
}
|
||||
else {
|
||||
literal lit(mk_literal(e1));
|
||||
#if 0
|
||||
expr_ref sk_ite = mk_sk_ite(e1, e2, e3);
|
||||
add_axiom(~lit, mk_eq(e2, sk_ite, false));
|
||||
add_axiom( lit, mk_eq(e3, sk_ite, false));
|
||||
result = sk_ite;
|
||||
|
||||
#else
|
||||
switch (ctx.get_assignment(lit)) {
|
||||
case l_true:
|
||||
deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(lit)));
|
||||
|
@ -2630,13 +2820,19 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) {
|
|||
result = expand(e3, deps);
|
||||
break;
|
||||
case l_undef:
|
||||
result = e;
|
||||
result = e;
|
||||
m_reset_cache = true;
|
||||
TRACE("seq", tout << "undef: " << result << "\n";
|
||||
tout << lit << "@ level: " << ctx.get_scope_level() << "\n";);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (m_util.str.is_itos(e, e1)) {
|
||||
rational val;
|
||||
if (get_value(e1, val)) {
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
if (get_num_value(e1, val)) {
|
||||
TRACE("seq", tout << mk_pp(e, m) << " -> " << val << "\n";);
|
||||
expr_ref num(m), res(m);
|
||||
num = m_autil.mk_numeral(val, true);
|
||||
|
@ -2744,8 +2940,8 @@ void theory_seq::deque_axiom(expr* n) {
|
|||
encode that s is not contained in of xs1
|
||||
where s1 is all of s, except the last element.
|
||||
|
||||
lit or s = "" or s = s1*(unit c)
|
||||
lit or s = "" or !contains(x*s1, s)
|
||||
s = "" or s = s1*(unit c)
|
||||
s = "" or !contains(x*s1, s)
|
||||
*/
|
||||
void theory_seq::tightest_prefix(expr* s, expr* x) {
|
||||
expr_ref s1 = mk_first(s);
|
||||
|
@ -2762,46 +2958,45 @@ void theory_seq::tightest_prefix(expr* s, expr* x) {
|
|||
let i = Index(t, s, offset):
|
||||
|
||||
offset >= len(t) => i = -1
|
||||
|
||||
offset fixed to 0:
|
||||
|
||||
len(t) != 0 & !contains(t, s) => i = -1
|
||||
len(t) != 0 & contains(t, s) => t = xsy & i = len(x)
|
||||
|
||||
|
||||
offset = 0 & len(t) != 0 & contains(t, s) => t = xsy & i = len(x)
|
||||
tightest_prefix(x, s)
|
||||
|
||||
offset not fixed:
|
||||
|
||||
0 <= offset < len(t) => xy = t &
|
||||
len(x) = offset &
|
||||
(-1 = indexof(y, s, 0) => -1 = i) &
|
||||
(indexof(y, s, 0) >= 0 => indexof(t, s, 0) + offset = i)
|
||||
|
||||
if offset < 0
|
||||
under specified
|
||||
offset < 0 => i = -1
|
||||
|
||||
optional lemmas:
|
||||
(len(s) > len(t) -> i = -1)
|
||||
(len(s) <= len(t) -> i <= len(t)-len(s))
|
||||
*/
|
||||
void theory_seq::add_indexof_axiom(expr* i) {
|
||||
expr* s, *t, *offset = 0;
|
||||
expr* s = 0, *t = 0, *offset = 0;
|
||||
rational r;
|
||||
VERIFY(m_util.str.is_index(i, t, s) ||
|
||||
m_util.str.is_index(i, t, s, offset));
|
||||
expr_ref minus_one(m_autil.mk_int(-1), m);
|
||||
expr_ref zero(m_autil.mk_int(0), m);
|
||||
expr_ref xsy(m);
|
||||
|
||||
literal cnt = mk_literal(m_util.str.mk_contains(t, s));
|
||||
literal i_eq_m1 = mk_eq(i, minus_one, false);
|
||||
add_axiom(cnt, i_eq_m1);
|
||||
literal s_eq_empty = mk_eq_empty(s);
|
||||
add_axiom(~s_eq_empty, mk_eq(i, zero, false));
|
||||
add_axiom(s_eq_empty, ~mk_eq_empty(t), i_eq_m1);
|
||||
|
||||
if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) {
|
||||
expr_ref x = mk_skolem(m_indexof_left, t, s);
|
||||
expr_ref y = mk_skolem(m_indexof_right, t, s);
|
||||
xsy = mk_concat(x, s, y);
|
||||
expr_ref lenx(m_util.str.mk_length(x), m);
|
||||
literal cnt = mk_literal(m_util.str.mk_contains(t, s));
|
||||
literal s_eq_empty = mk_eq_empty(s);
|
||||
add_axiom(cnt, mk_eq(i, minus_one, false));
|
||||
add_axiom(~s_eq_empty, mk_eq(i, zero, false));
|
||||
add_axiom(s_eq_empty, ~mk_eq_empty(t), mk_eq(i, minus_one, false));
|
||||
add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy));
|
||||
add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx, false));
|
||||
tightest_prefix(s, x);
|
||||
|
@ -2811,7 +3006,7 @@ void theory_seq::add_indexof_axiom(expr* i) {
|
|||
|
||||
expr_ref len_t(m_util.str.mk_length(t), m);
|
||||
literal offset_ge_len = mk_literal(m_autil.mk_ge(mk_sub(offset, len_t), zero));
|
||||
add_axiom(offset_ge_len, mk_eq(i, minus_one, false));
|
||||
add_axiom(~offset_ge_len, mk_eq(i, minus_one, false));
|
||||
|
||||
expr_ref x = mk_skolem(m_indexof_left, t, s, offset);
|
||||
expr_ref y = mk_skolem(m_indexof_right, t, s, offset);
|
||||
|
@ -2828,10 +3023,13 @@ void theory_seq::add_indexof_axiom(expr* i) {
|
|||
add_axiom(~offset_ge_0, offset_ge_len, mk_seq_eq(t, mk_concat(x, y)));
|
||||
add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false));
|
||||
add_axiom(~offset_ge_0, offset_ge_len,
|
||||
~mk_eq(indexof0, minus_one, false), mk_eq(i, minus_one, false));
|
||||
~mk_eq(indexof0, minus_one, false), i_eq_m1);
|
||||
add_axiom(~offset_ge_0, offset_ge_len,
|
||||
~mk_literal(m_autil.mk_ge(indexof0, zero)),
|
||||
mk_eq(offset_p_indexof0, i, false));
|
||||
|
||||
// offset < 0 => -1 = i
|
||||
add_axiom(offset_ge_0, i_eq_m1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2850,10 +3048,14 @@ void theory_seq::add_replace_axiom(expr* r) {
|
|||
expr_ref y = mk_skolem(m_indexof_right, a, s);
|
||||
expr_ref xty = mk_concat(x, t, y);
|
||||
expr_ref xsy = mk_concat(x, s, y);
|
||||
literal cnt = mk_literal(m_util.str.mk_contains(a ,s));
|
||||
literal cnt = mk_literal(m_util.str.mk_contains(a, s));
|
||||
literal a_emp = mk_eq_empty(a);
|
||||
literal s_emp = mk_eq_empty(s);
|
||||
add_axiom(~a_emp, s_emp, mk_seq_eq(r, a));
|
||||
add_axiom(cnt, mk_seq_eq(r, a));
|
||||
add_axiom(~cnt, mk_seq_eq(a, xsy));
|
||||
add_axiom(~cnt, mk_seq_eq(r, xty));
|
||||
add_axiom(~s_emp, mk_seq_eq(r, mk_concat(t, a)));
|
||||
add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(a, xsy));
|
||||
add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(r, xty));
|
||||
tightest_prefix(s, x);
|
||||
}
|
||||
|
||||
|
@ -2885,7 +3087,7 @@ void theory_seq::add_elim_string_axiom(expr* n) {
|
|||
*/
|
||||
void theory_seq::add_length_axiom(expr* n) {
|
||||
context& ctx = get_context();
|
||||
expr* x;
|
||||
expr* x = 0;
|
||||
VERIFY(m_util.str.is_length(n, x));
|
||||
if (m_util.str.is_concat(x) ||
|
||||
m_util.str.is_unit(x) ||
|
||||
|
@ -2908,58 +3110,65 @@ void theory_seq::add_length_axiom(expr* n) {
|
|||
}
|
||||
|
||||
void theory_seq::add_itos_length_axiom(expr* len) {
|
||||
expr* x, *n;
|
||||
expr* x = 0, *n = 0;
|
||||
VERIFY(m_util.str.is_length(len, x));
|
||||
VERIFY(m_util.str.is_itos(x, n));
|
||||
|
||||
add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1))));
|
||||
rational val;
|
||||
if (get_value(n, val)) {
|
||||
bool neg = val.is_neg();
|
||||
rational ten(10);
|
||||
if (neg) val.neg();
|
||||
unsigned num_char = neg?2:1;
|
||||
// 0 < x < 10
|
||||
// 10 < x < 100
|
||||
// 100 < x < 1000
|
||||
rational hi(10);
|
||||
while (val > hi) {
|
||||
++num_char;
|
||||
hi *= ten;
|
||||
unsigned num_char1 = 1, num_char2 = 1;
|
||||
rational len1, len2;
|
||||
rational ten(10);
|
||||
if (get_num_value(n, len1)) {
|
||||
bool neg = len1.is_neg();
|
||||
if (neg) len1.neg();
|
||||
num_char1 = neg?2:1;
|
||||
// 0 <= x < 10
|
||||
// 10 <= x < 100
|
||||
// 100 <= x < 1000
|
||||
rational upper(10);
|
||||
while (len1 > upper) {
|
||||
++num_char1;
|
||||
upper *= ten;
|
||||
}
|
||||
rational lo(div(hi - rational(1), ten));
|
||||
|
||||
literal len_le(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(num_char))));
|
||||
literal len_ge(mk_literal(m_autil.mk_le(len, m_autil.mk_int(num_char))));
|
||||
literal n_le_mlo(mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-lo, true))));
|
||||
literal n_ge_lo(mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(lo, true))));
|
||||
|
||||
// len >= num_char => n <= -lo or n >= lo
|
||||
// len <= num_char => -hi < n < hi
|
||||
|
||||
add_axiom(~len_ge, n_le_mlo, n_ge_lo);
|
||||
if (neg) {
|
||||
// n <= -lo => len >= num_char
|
||||
// -hi < n <= 0 => len <= num_char
|
||||
// n <= -hi or ~(n <= 0) or len <= num_char
|
||||
|
||||
add_axiom(~n_le_mlo, len_ge);
|
||||
literal n_le_mhi(mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-hi, true))));
|
||||
literal n_le_0(mk_literal(m_autil.mk_le(n, m_autil.mk_int(0))));
|
||||
add_axiom(n_le_mhi, ~n_le_0, len_le);
|
||||
add_axiom(~len_le, ~n_le_mhi);
|
||||
}
|
||||
else {
|
||||
// n >= lo => len >= num_char
|
||||
// 0 <= n < hi => len <= num_char
|
||||
add_axiom(~n_ge_lo, len_ge);
|
||||
literal n_ge_hi(mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(hi, true))));
|
||||
literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
|
||||
add_axiom(n_ge_hi, ~n_ge_0, len_le);
|
||||
add_axiom(~len_le, ~n_ge_hi);
|
||||
}
|
||||
SASSERT(len1 <= upper);
|
||||
}
|
||||
if (get_num_value(len, len2) && len2.is_unsigned()) {
|
||||
num_char2 = len2.get_unsigned();
|
||||
}
|
||||
unsigned num_char = std::max(num_char1, num_char2);
|
||||
|
||||
|
||||
literal len_le(mk_literal(m_autil.mk_le(len, m_autil.mk_int(num_char))));
|
||||
literal len_ge(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(num_char))));
|
||||
|
||||
if (num_char == 1) {
|
||||
add_axiom(len_ge);
|
||||
literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
|
||||
literal n_ge_10(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(10))));
|
||||
add_axiom(~n_ge_0, n_ge_10, len_le);
|
||||
add_axiom(~len_le, n_ge_0);
|
||||
add_axiom(~len_le, ~n_ge_10);
|
||||
return;
|
||||
}
|
||||
rational hi(1);
|
||||
for (unsigned i = 2; i < num_char; ++i) {
|
||||
hi *= ten;
|
||||
}
|
||||
// n <= -hi or n >= hi*10 <=> len >= num_chars
|
||||
// -10*hi < n < 100*hi <=> len <= num_chars
|
||||
literal n_le_hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-hi, true)));
|
||||
literal n_ge_10hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*hi, true)));
|
||||
literal n_le_m10hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-ten*hi, true)));
|
||||
literal n_ge_100hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*ten*hi, true)));
|
||||
|
||||
add_axiom(~n_le_hi, len_ge);
|
||||
add_axiom(~n_ge_10hi, len_ge);
|
||||
add_axiom(n_le_hi, n_ge_10hi, ~len_ge);
|
||||
|
||||
add_axiom(n_le_m10hi, n_ge_100hi, len_le);
|
||||
add_axiom(~n_le_m10hi, ~len_le);
|
||||
add_axiom(~n_ge_100hi, ~len_le);
|
||||
|
||||
add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1))));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3056,12 +3265,20 @@ static theory_mi_arith* get_th_arith(context& ctx, theory_id afid, expr* e) {
|
|||
}
|
||||
}
|
||||
|
||||
bool theory_seq::get_value(expr* e, rational& val) const {
|
||||
bool theory_seq::get_num_value(expr* e, rational& val) const {
|
||||
context& ctx = get_context();
|
||||
theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e);
|
||||
expr_ref _val(m);
|
||||
if (!tha || !tha->get_value(ctx.get_enode(e), _val)) return false;
|
||||
return m_autil.is_numeral(_val, val) && val.is_int();
|
||||
if (!tha) return false;
|
||||
enode* next = ctx.get_enode(e), *n = next;
|
||||
do {
|
||||
if (tha->get_value(next, _val) && m_autil.is_numeral(_val, val) && val.is_int()) {
|
||||
return true;
|
||||
}
|
||||
next = next->get_next();
|
||||
}
|
||||
while (next != n);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool theory_seq::lower_bound(expr* _e, rational& lo) const {
|
||||
|
@ -3134,15 +3351,18 @@ bool theory_seq::get_length(expr* e, rational& val) const {
|
|||
|
||||
let e = extract(s, i, l)
|
||||
|
||||
0 <= i <= len(s) -> prefix(xe,s)
|
||||
0 <= i <= len(s) -> len(x) = i
|
||||
0 <= i <= len(s) & 0 <= l <= len(s) - i -> len(e) = l
|
||||
0 <= i <= len(s) & len(s) < l + i -> len(e) = len(s) - i
|
||||
0 <= i <= len(s) & l < 0 -> len(e) = 0
|
||||
* i < 0 -> e = empty
|
||||
* i > len(s) -> e = empty
|
||||
0 <= i <= |s| -> prefix(xe,s)
|
||||
0 <= i <= |s| -> len(x) = i
|
||||
0 <= i <= |s| & 0 <= l <= |s| - i -> |e| = l
|
||||
0 <= i <= |s| & |s| < l + i -> |e| = |s| - i
|
||||
0 <= i <= |s| & l < 0 -> |e| = 0
|
||||
i >= |s| => |e| = 0
|
||||
i < 0 => |e| = 0
|
||||
l <= 0 => |e| = 0
|
||||
|
||||
It follows that:
|
||||
|e| = min(l, |s| - i) for 0 <= i < |s| and 0 < |l|
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
@ -3176,16 +3396,20 @@ void theory_seq::add_extract_axiom(expr* e) {
|
|||
expr_ref zero(m_autil.mk_int(0), m);
|
||||
|
||||
literal i_ge_0 = mk_literal(m_autil.mk_ge(i, zero));
|
||||
literal i_le_ls = mk_literal(m_autil.mk_le(mk_sub(i, ls), zero));
|
||||
literal ls_le_i = mk_literal(m_autil.mk_le(mk_sub(i, ls), zero));
|
||||
literal li_ge_ls = mk_literal(m_autil.mk_ge(ls_minus_i_l, zero));
|
||||
literal l_ge_zero = mk_literal(m_autil.mk_ge(l, zero));
|
||||
literal ls_le_0 = mk_literal(m_autil.mk_le(ls, zero));
|
||||
|
||||
// add_axiom(~i_ge_0, ~i_le_ls, mk_literal(m_util.str.mk_prefix(xe, s)));
|
||||
add_axiom(~i_ge_0, ~i_le_ls, mk_seq_eq(xey, s));
|
||||
add_axiom(~i_ge_0, ~i_le_ls, mk_eq(lx, i, false));
|
||||
add_axiom(~i_ge_0, ~i_le_ls, ~l_ge_zero, ~li_ge_ls, mk_eq(le, l, false));
|
||||
add_axiom(~i_ge_0, ~i_le_ls, li_ge_ls, mk_eq(le, mk_sub(ls, i), false));
|
||||
add_axiom(~i_ge_0, ~i_le_ls, l_ge_zero, mk_eq(le, zero, false));
|
||||
// add_axiom(~i_ge_0, ~ls_le_i, mk_literal(m_util.str.mk_prefix(xe, s)));
|
||||
add_axiom(~i_ge_0, ~ls_le_i, mk_seq_eq(xey, s));
|
||||
add_axiom(~i_ge_0, ~ls_le_i, mk_eq(lx, i, false));
|
||||
add_axiom(~i_ge_0, ~ls_le_i, ~l_ge_zero, ~li_ge_ls, mk_eq(le, l, false));
|
||||
add_axiom(~i_ge_0, ~ls_le_i, li_ge_ls, mk_eq(le, mk_sub(ls, i), false));
|
||||
add_axiom(~i_ge_0, ~ls_le_i, l_ge_zero, mk_eq(le, zero, false));
|
||||
add_axiom(i_ge_0, mk_eq(le, zero, false));
|
||||
add_axiom(ls_le_i, mk_eq(le, zero, false));
|
||||
add_axiom(~ls_le_0, mk_eq(le, zero, false));
|
||||
}
|
||||
|
||||
void theory_seq::add_tail_axiom(expr* e, expr* s) {
|
||||
|
@ -3273,7 +3497,7 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) {
|
|||
|
||||
*/
|
||||
void theory_seq::add_at_axiom(expr* e) {
|
||||
expr* s, *i;
|
||||
expr* s = 0, *i = 0;
|
||||
VERIFY(m_util.str.is_at(e, s, i));
|
||||
expr_ref len_e(m_util.str.mk_length(e), m);
|
||||
expr_ref len_s(m_util.str.mk_length(s), m);
|
||||
|
@ -3560,7 +3784,10 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
|
|||
else if (is_skolem(symbol("seq.split"), e)) {
|
||||
// propagate equalities
|
||||
}
|
||||
else if (is_skolem(symbol("seq.is_digit"), e)) {
|
||||
}
|
||||
else {
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
@ -3592,6 +3819,15 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
|
|||
solve_eqs(m_eqs.size()-1);
|
||||
enforce_length_coherence(n1, n2);
|
||||
}
|
||||
else if (n1 != n2 && m_util.is_re(n1->get_owner())) {
|
||||
warning_msg("equality between regular expressions is not yet supported");
|
||||
eautomaton* a1 = get_automaton(n1->get_owner());
|
||||
eautomaton* a2 = get_automaton(n2->get_owner());
|
||||
// eautomaton* b1 = mk_difference(*a1, *a2);
|
||||
// eautomaton* b2 = mk_difference(*a2, *a1);
|
||||
// eautomaton* c = mk_union(*b1, *b2);
|
||||
// then some emptiness check.
|
||||
}
|
||||
}
|
||||
|
||||
void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {
|
||||
|
@ -3601,16 +3837,17 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {
|
|||
expr_ref e2(n2->get_owner(), m);
|
||||
m_exclude.update(e1, e2);
|
||||
expr_ref eq(m.mk_eq(e1, e2), m);
|
||||
TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";);
|
||||
m_rewrite(eq);
|
||||
if (!m.is_false(eq)) {
|
||||
TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";);
|
||||
|
||||
literal lit = mk_eq(e1, e2, false);
|
||||
|
||||
// propagate x != "" into x = (++ (unit (nth x 0) (tail x 0)))
|
||||
|
||||
if (m_util.str.is_empty(e2)) {
|
||||
std::swap(e1, e2);
|
||||
}
|
||||
|
||||
if (false && m_util.str.is_empty(e1)) {
|
||||
expr_ref head(m), tail(m), conc(m);
|
||||
mk_decompose(e2, head, tail);
|
||||
|
@ -3618,13 +3855,13 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {
|
|||
propagate_eq(~lit, e2, conc, true);
|
||||
}
|
||||
#if 0
|
||||
|
||||
// (e1 = "" & e2 = xdz) or (e2 = "" & e1 = xcy) or (e1 = xcy & e2 = xdz & c != d) or (e1 = x & e2 = xdz) or (e2 = x & e1 = xcy)
|
||||
// e1 = "" or e1 = xcy or e1 = x
|
||||
// e2 = "" or e2 = xdz or e2 = x
|
||||
// e1 = xcy or e2 = xdz
|
||||
// c != d
|
||||
|
||||
literal lit = mk_seq_eq(e1, e2);
|
||||
sort* char_sort = 0;
|
||||
expr_ref emp(m);
|
||||
VERIFY(m_util.is_seq(m.get_sort(e1), char_sort));
|
||||
|
@ -4068,7 +4305,7 @@ void theory_seq::propagate_not_prefix2(expr* e) {
|
|||
|
||||
void theory_seq::propagate_not_suffix(expr* e) {
|
||||
context& ctx = get_context();
|
||||
expr* e1, *e2;
|
||||
expr* e1 = 0, *e2 = 0;
|
||||
VERIFY(m_util.str.is_suffix(e, e1, e2));
|
||||
literal lit = ctx.get_literal(e);
|
||||
SASSERT(ctx.get_assignment(lit) == l_false);
|
||||
|
@ -4097,7 +4334,7 @@ void theory_seq::propagate_not_suffix(expr* e) {
|
|||
*/
|
||||
bool theory_seq::add_prefix2prefix(expr* e, bool& change) {
|
||||
context& ctx = get_context();
|
||||
expr* e1, *e2;
|
||||
expr* e1 = 0, *e2 = 0;
|
||||
VERIFY(m_util.str.is_prefix(e, e1, e2));
|
||||
SASSERT(ctx.get_assignment(e) == l_false);
|
||||
if (canonizes(false, e)) {
|
||||
|
@ -4169,7 +4406,7 @@ bool theory_seq::add_prefix2prefix(expr* e, bool& change) {
|
|||
*/
|
||||
bool theory_seq::add_suffix2suffix(expr* e, bool& change) {
|
||||
context& ctx = get_context();
|
||||
expr* e1, *e2;
|
||||
expr* e1 = 0, *e2 = 0;
|
||||
VERIFY(m_util.str.is_suffix(e, e1, e2));
|
||||
SASSERT(ctx.get_assignment(e) == l_false);
|
||||
if (canonizes(false, e)) {
|
||||
|
@ -4254,7 +4491,7 @@ bool theory_seq::canonizes(bool sign, expr* e) {
|
|||
|
||||
bool theory_seq::add_contains2contains(expr* e, bool& change) {
|
||||
context& ctx = get_context();
|
||||
expr* e1, *e2;
|
||||
expr* e1 = 0, *e2 = 0;
|
||||
VERIFY(m_util.str.is_contains(e, e1, e2));
|
||||
SASSERT(ctx.get_assignment(e) == l_false);
|
||||
if (canonizes(false, e)) {
|
||||
|
@ -4324,7 +4561,7 @@ bool theory_seq::propagate_automata() {
|
|||
}
|
||||
|
||||
void theory_seq::get_concat(expr* e, ptr_vector<expr>& concats) {
|
||||
expr* e1, *e2;
|
||||
expr* e1 = 0, *e2 = 0;
|
||||
while (true) {
|
||||
e = m_rep.find(e);
|
||||
if (m_util.str.is_concat(e, e1, e2)) {
|
||||
|
|
|
@ -294,6 +294,7 @@ namespace smt {
|
|||
ast_manager& m;
|
||||
dependency_manager m_dm;
|
||||
solution_map m_rep; // unification representative.
|
||||
bool m_reset_cache; // invalidate cache.
|
||||
scoped_vector<eq> m_eqs; // set of current equations.
|
||||
scoped_vector<ne> m_nqs; // set of current disequalities.
|
||||
scoped_vector<nc> m_ncs; // set of non-contains constraints.
|
||||
|
@ -308,6 +309,7 @@ namespace smt {
|
|||
bool m_incomplete; // is the solver (clearly) incomplete for the fragment.
|
||||
expr_ref_vector m_int_string;
|
||||
rational_set m_itos_axioms;
|
||||
rational_set m_stoi_axioms;
|
||||
obj_hashtable<expr> m_length; // is length applied
|
||||
scoped_ptr_vector<apply> m_replay; // set of actions to replay
|
||||
model_generator* m_mg;
|
||||
|
@ -447,10 +449,12 @@ namespace smt {
|
|||
bool is_var(expr* b);
|
||||
bool add_solution(expr* l, expr* r, dependency* dep);
|
||||
bool is_nth(expr* a) const;
|
||||
bool is_nth(expr* a, expr*& e1, expr*& e2) const;
|
||||
bool is_tail(expr* a, expr*& s, unsigned& idx) const;
|
||||
bool is_eq(expr* e, expr*& a, expr*& b) const;
|
||||
bool is_pre(expr* e, expr*& s, expr*& i);
|
||||
bool is_post(expr* e, expr*& s, expr*& i);
|
||||
expr_ref mk_sk_ite(expr* c, expr* t, expr* f);
|
||||
expr_ref mk_nth(expr* s, expr* idx);
|
||||
expr_ref mk_last(expr* e);
|
||||
expr_ref mk_first(expr* e);
|
||||
|
@ -493,7 +497,10 @@ namespace smt {
|
|||
void add_elim_string_axiom(expr* n);
|
||||
void add_at_axiom(expr* n);
|
||||
void add_in_re_axiom(expr* n);
|
||||
bool add_stoi_axiom(expr* n);
|
||||
bool add_itos_axiom(expr* n);
|
||||
literal is_digit(expr* ch);
|
||||
expr_ref digit2int(expr* ch);
|
||||
void add_itos_length_axiom(expr* n);
|
||||
literal mk_literal(expr* n);
|
||||
literal mk_eq_empty(expr* n, bool phase = true);
|
||||
|
@ -507,7 +514,7 @@ namespace smt {
|
|||
|
||||
|
||||
// arithmetic integration
|
||||
bool get_value(expr* s, rational& val) const;
|
||||
bool get_num_value(expr* s, rational& val) const;
|
||||
bool lower_bound(expr* s, rational& lo) const;
|
||||
bool upper_bound(expr* s, rational& hi) const;
|
||||
bool get_length(expr* s, rational& val) const;
|
||||
|
|
|
@ -126,6 +126,22 @@ namespace smt {
|
|||
symbol sym;
|
||||
if (u.str.is_string(n, sym)) {
|
||||
m_strings.insert(sym);
|
||||
if (sym.str().find(m_unique_delim) != std::string::npos) {
|
||||
add_new_delim();
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
void add_new_delim() {
|
||||
bool found = true;
|
||||
while (found) {
|
||||
found = false;
|
||||
m_unique_delim += "!";
|
||||
symbol_set::iterator it = m_strings.begin(), end = m_strings.end();
|
||||
for (; it != end && !found; ++it) {
|
||||
found = it->str().find(m_unique_delim) != std::string::npos;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -250,7 +250,7 @@ namespace smt {
|
|||
std::stringstream msg;
|
||||
msg << "found non utvpi logic expression:\n" << mk_pp(n, get_manager()) << "\n";
|
||||
TRACE("utvpi", tout << msg.str(););
|
||||
warning_msg(msg.str().c_str());
|
||||
warning_msg("%s", msg.str().c_str());
|
||||
get_context().push_trail(value_trail<context, bool>(m_non_utvpi_exprs));
|
||||
m_non_utvpi_exprs = true;
|
||||
}
|
||||
|
@ -901,7 +901,7 @@ namespace smt {
|
|||
bool is_int = a.is_int(n->get_owner());
|
||||
rational num = mk_value(v, is_int);
|
||||
TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";);
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int));
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, is_int));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,291 +21,352 @@ Notes:
|
|||
#include "smt_context.h"
|
||||
#include "ast_pp.h"
|
||||
#include "theory_wmaxsat.h"
|
||||
#include "smt_justification.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
theory_wmaxsat::theory_wmaxsat(ast_manager& m, filter_model_converter& mc):
|
||||
theory(m.mk_family_id("weighted_maxsat")),
|
||||
m_mc(mc),
|
||||
m_vars(m),
|
||||
m_fmls(m),
|
||||
m_zweights(m_mpz),
|
||||
m_old_values(m_mpz),
|
||||
m_zcost(m_mpz),
|
||||
m_zmin_cost(m_mpz),
|
||||
m_found_optimal(false),
|
||||
m_propagate(false),
|
||||
m_normalize(false)
|
||||
{}
|
||||
|
||||
theory_wmaxsat::~theory_wmaxsat() {
|
||||
m_old_values.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief return the complement of variables that are currently assigned.
|
||||
*/
|
||||
void theory_wmaxsat::get_assignment(svector<bool>& result) {
|
||||
result.reset();
|
||||
theory_wmaxsat::theory_wmaxsat(ast_manager& m, filter_model_converter& mc):
|
||||
theory(m.mk_family_id("weighted_maxsat")),
|
||||
m_mc(mc),
|
||||
m_vars(m),
|
||||
m_fmls(m),
|
||||
m_zweights(m_mpz),
|
||||
m_old_values(m_mpz),
|
||||
m_zcost(m_mpz),
|
||||
m_zmin_cost(m_mpz),
|
||||
m_found_optimal(false),
|
||||
m_propagate(false),
|
||||
m_normalize(false),
|
||||
m_den(1)
|
||||
{}
|
||||
|
||||
if (!m_found_optimal) {
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
result.push_back(false);
|
||||
}
|
||||
theory_wmaxsat::~theory_wmaxsat() {
|
||||
m_old_values.reset();
|
||||
}
|
||||
else {
|
||||
std::sort(m_cost_save.begin(), m_cost_save.end());
|
||||
for (unsigned i = 0,j = 0; i < m_vars.size(); ++i) {
|
||||
if (j < m_cost_save.size() && m_cost_save[j] == static_cast<theory_var>(i)) {
|
||||
|
||||
/**
|
||||
\brief return the complement of variables that are currently assigned.
|
||||
*/
|
||||
void theory_wmaxsat::get_assignment(svector<bool>& result) {
|
||||
result.reset();
|
||||
|
||||
if (!m_found_optimal) {
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
result.push_back(false);
|
||||
++j;
|
||||
}
|
||||
else {
|
||||
result.push_back(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::sort(m_cost_save.begin(), m_cost_save.end());
|
||||
for (unsigned i = 0,j = 0; i < m_vars.size(); ++i) {
|
||||
if (j < m_cost_save.size() && m_cost_save[j] == static_cast<theory_var>(i)) {
|
||||
result.push_back(false);
|
||||
++j;
|
||||
}
|
||||
else {
|
||||
result.push_back(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("opt",
|
||||
tout << "cost save: ";
|
||||
for (unsigned i = 0; i < m_cost_save.size(); ++i) {
|
||||
tout << m_cost_save[i] << " ";
|
||||
}
|
||||
tout << "\nvars: ";
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
tout << mk_pp(m_vars[i].get(), get_manager()) << " ";
|
||||
}
|
||||
tout << "\nassignment: ";
|
||||
for (unsigned i = 0; i < result.size(); ++i) {
|
||||
tout << result[i] << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
}
|
||||
TRACE("opt",
|
||||
tout << "cost save: ";
|
||||
for (unsigned i = 0; i < m_cost_save.size(); ++i) {
|
||||
tout << m_cost_save[i] << " ";
|
||||
}
|
||||
tout << "\nvars: ";
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
tout << mk_pp(m_vars[i].get(), get_manager()) << " ";
|
||||
}
|
||||
tout << "\nassignment: ";
|
||||
for (unsigned i = 0; i < result.size(); ++i) {
|
||||
tout << result[i] << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
|
||||
}
|
||||
|
||||
void theory_wmaxsat::init_search_eh() {
|
||||
m_propagate = true;
|
||||
}
|
||||
|
||||
bool_var theory_wmaxsat::assert_weighted(expr* fml, rational const& w) {
|
||||
context & ctx = get_context();
|
||||
ast_manager& m = get_manager();
|
||||
app_ref var(m), wfml(m);
|
||||
var = m.mk_fresh_const("w", m.mk_bool_sort());
|
||||
m_mc.insert(var->get_decl());
|
||||
wfml = m.mk_or(var, fml);
|
||||
ctx.assert_expr(wfml);
|
||||
m_rweights.push_back(w);
|
||||
m_vars.push_back(var);
|
||||
m_fmls.push_back(fml);
|
||||
m_assigned.push_back(false);
|
||||
m_rmin_cost += w;
|
||||
m_normalize = true;
|
||||
return register_var(var, true);
|
||||
}
|
||||
|
||||
bool_var theory_wmaxsat::register_var(app* var, bool attach) {
|
||||
context & ctx = get_context();
|
||||
bool_var bv;
|
||||
SASSERT(!ctx.e_internalized(var));
|
||||
enode* x = ctx.mk_enode(var, false, true, true);
|
||||
if (ctx.b_internalized(var)) {
|
||||
bv = ctx.get_bool_var(var);
|
||||
void theory_wmaxsat::init_search_eh() {
|
||||
m_propagate = true;
|
||||
}
|
||||
else {
|
||||
bv = ctx.mk_bool_var(var);
|
||||
|
||||
expr* theory_wmaxsat::assert_weighted(expr* fml, rational const& w) {
|
||||
context & ctx = get_context();
|
||||
ast_manager& m = get_manager();
|
||||
app_ref var(m), wfml(m);
|
||||
var = m.mk_fresh_const("w", m.mk_bool_sort());
|
||||
m_mc.insert(var->get_decl());
|
||||
wfml = m.mk_or(var, fml);
|
||||
ctx.assert_expr(wfml);
|
||||
m_rweights.push_back(w);
|
||||
m_vars.push_back(var);
|
||||
m_fmls.push_back(fml);
|
||||
m_assigned.push_back(false);
|
||||
m_enabled.push_back(true);
|
||||
m_normalize = true;
|
||||
bool_var bv = register_var(var, true);
|
||||
(void)bv;
|
||||
TRACE("opt", tout << "enable: v" << m_bool2var[bv] << " b" << bv << " " << mk_pp(var, get_manager()) << "\n";
|
||||
tout << wfml << "\n";);
|
||||
return var;
|
||||
}
|
||||
ctx.set_enode_flag(bv, true);
|
||||
if (attach) {
|
||||
ctx.set_var_theory(bv, get_id());
|
||||
theory_var v = mk_var(x);
|
||||
ctx.attach_th_var(x, this, v);
|
||||
m_bool2var.insert(bv, v);
|
||||
SASSERT(v == static_cast<theory_var>(m_var2bool.size()));
|
||||
m_var2bool.push_back(bv);
|
||||
SASSERT(ctx.bool_var2enode(bv));
|
||||
}
|
||||
return bv;
|
||||
}
|
||||
|
||||
rational const& theory_wmaxsat::get_min_cost() {
|
||||
unsynch_mpq_manager mgr;
|
||||
scoped_mpq q(mgr);
|
||||
mgr.set(q, m_zmin_cost, m_den.to_mpq().numerator());
|
||||
m_rmin_cost = rational(q);
|
||||
return m_rmin_cost;
|
||||
}
|
||||
|
||||
void theory_wmaxsat::assign_eh(bool_var v, bool is_true) {
|
||||
TRACE("opt", tout << "Assign " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << " " << is_true << "\n";);
|
||||
if (is_true) {
|
||||
if (m_normalize) normalize();
|
||||
void theory_wmaxsat::disable_var(expr* var) {
|
||||
context& ctx = get_context();
|
||||
theory_var tv = m_bool2var[v];
|
||||
if (m_assigned[tv]) return;
|
||||
scoped_mpz w(m_mpz);
|
||||
w = m_zweights[tv];
|
||||
ctx.push_trail(numeral_trail(m_zcost, m_old_values));
|
||||
ctx.push_trail(push_back_vector<context, svector<theory_var> >(m_costs));
|
||||
ctx.push_trail(value_trail<context, bool>(m_assigned[tv]));
|
||||
m_zcost += w;
|
||||
m_costs.push_back(tv);
|
||||
m_assigned[tv] = true;
|
||||
if (m_zcost > m_zmin_cost) {
|
||||
block();
|
||||
SASSERT(ctx.b_internalized(var));
|
||||
bool_var bv = ctx.get_bool_var(var);
|
||||
theory_var tv = m_bool2var[bv];
|
||||
m_enabled[tv] = false;
|
||||
TRACE("opt", tout << "disable: v" << tv << " b" << bv << " " << mk_pp(var, get_manager()) << "\n";);
|
||||
}
|
||||
|
||||
bool_var theory_wmaxsat::register_var(app* var, bool attach) {
|
||||
context & ctx = get_context();
|
||||
bool_var bv;
|
||||
SASSERT(!ctx.e_internalized(var));
|
||||
enode* x = ctx.mk_enode(var, false, true, true);
|
||||
if (ctx.b_internalized(var)) {
|
||||
bv = ctx.get_bool_var(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final_check_status theory_wmaxsat::final_check_eh() {
|
||||
if (m_normalize) normalize();
|
||||
return FC_DONE;
|
||||
}
|
||||
|
||||
|
||||
void theory_wmaxsat::reset_eh() {
|
||||
theory::reset_eh();
|
||||
reset_local();
|
||||
}
|
||||
|
||||
void theory_wmaxsat::reset_local() {
|
||||
m_vars.reset();
|
||||
m_fmls.reset();
|
||||
m_rweights.reset();
|
||||
m_rmin_cost.reset();
|
||||
m_rcost.reset();
|
||||
m_zweights.reset();
|
||||
m_zcost.reset();
|
||||
m_zmin_cost.reset();
|
||||
m_cost_save.reset();
|
||||
m_bool2var.reset();
|
||||
m_var2bool.reset();
|
||||
m_propagate = false;
|
||||
m_found_optimal = false;
|
||||
m_assigned.reset();
|
||||
}
|
||||
|
||||
|
||||
void theory_wmaxsat::propagate() {
|
||||
context& ctx = get_context();
|
||||
for (unsigned i = 0; m_propagate && i < m_vars.size(); ++i) {
|
||||
bool_var bv = m_var2bool[i];
|
||||
lbool asgn = ctx.get_assignment(bv);
|
||||
if (asgn == l_true) {
|
||||
assign_eh(bv, true);
|
||||
else {
|
||||
bv = ctx.mk_bool_var(var);
|
||||
}
|
||||
ctx.set_enode_flag(bv, true);
|
||||
if (attach) {
|
||||
ctx.set_var_theory(bv, get_id());
|
||||
theory_var v = mk_var(x);
|
||||
ctx.attach_th_var(x, this, v);
|
||||
m_bool2var.insert(bv, v);
|
||||
SASSERT(v == static_cast<theory_var>(m_var2bool.size()));
|
||||
m_var2bool.push_back(bv);
|
||||
SASSERT(ctx.bool_var2enode(bv));
|
||||
}
|
||||
return bv;
|
||||
}
|
||||
m_propagate = false;
|
||||
}
|
||||
|
||||
bool theory_wmaxsat::is_optimal() const {
|
||||
return !m_found_optimal || m_zcost < m_zmin_cost;
|
||||
}
|
||||
|
||||
expr_ref theory_wmaxsat::mk_block() {
|
||||
++m_stats.m_num_blocks;
|
||||
ast_manager& m = get_manager();
|
||||
expr_ref_vector disj(m);
|
||||
compare_cost compare_cost(*this);
|
||||
svector<theory_var> costs(m_costs);
|
||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||
scoped_mpz weight(m_mpz);
|
||||
m_mpz.reset(weight);
|
||||
for (unsigned i = 0; i < costs.size() && m_mpz.lt(weight, m_zmin_cost); ++i) {
|
||||
weight += m_zweights[costs[i]];
|
||||
disj.push_back(m.mk_not(m_vars[costs[i]].get()));
|
||||
}
|
||||
if (is_optimal()) {
|
||||
|
||||
rational theory_wmaxsat::get_cost() {
|
||||
unsynch_mpq_manager mgr;
|
||||
scoped_mpq q(mgr);
|
||||
mgr.set(q, m_zmin_cost, m_den.to_mpq().numerator());
|
||||
rational rw = rational(q);
|
||||
m_zmin_cost = weight;
|
||||
m_found_optimal = true;
|
||||
mgr.set(q, m_zcost, m_den.to_mpq().numerator());
|
||||
return rational(q);
|
||||
}
|
||||
|
||||
void theory_wmaxsat::init_min_cost(rational const& r) {
|
||||
m_rmin_cost = r;
|
||||
m_zmin_cost = (m_rmin_cost * m_den).to_mpq().numerator();
|
||||
}
|
||||
|
||||
|
||||
void theory_wmaxsat::assign_eh(bool_var v, bool is_true) {
|
||||
if (is_true) {
|
||||
if (m_normalize) normalize();
|
||||
context& ctx = get_context();
|
||||
theory_var tv = m_bool2var[v];
|
||||
if (m_assigned[tv] || !m_enabled[tv]) return;
|
||||
scoped_mpz w(m_mpz);
|
||||
w = m_zweights[tv];
|
||||
ctx.push_trail(numeral_trail(m_zcost, m_old_values));
|
||||
ctx.push_trail(push_back_vector<context, svector<theory_var> >(m_costs));
|
||||
ctx.push_trail(value_trail<context, bool>(m_assigned[tv]));
|
||||
m_zcost += w;
|
||||
TRACE("opt", tout << "Assign v" << tv << " weight: " << w << " cost: " << m_zcost << " " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << "\n";);
|
||||
m_costs.push_back(tv);
|
||||
m_assigned[tv] = true;
|
||||
if (m_zcost >= m_zmin_cost) {
|
||||
block();
|
||||
}
|
||||
else {
|
||||
m_can_propagate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final_check_status theory_wmaxsat::final_check_eh() {
|
||||
if (m_normalize) normalize();
|
||||
TRACE("opt", tout << "cost: " << m_zcost << " min cost: " << m_zmin_cost << "\n";);
|
||||
return FC_DONE;
|
||||
}
|
||||
|
||||
|
||||
void theory_wmaxsat::reset_eh() {
|
||||
theory::reset_eh();
|
||||
reset_local();
|
||||
}
|
||||
|
||||
void theory_wmaxsat::reset_local() {
|
||||
m_vars.reset();
|
||||
m_fmls.reset();
|
||||
m_rweights.reset();
|
||||
m_rmin_cost.reset();
|
||||
m_zweights.reset();
|
||||
m_zcost.reset();
|
||||
m_zmin_cost.reset();
|
||||
m_cost_save.reset();
|
||||
m_cost_save.append(m_costs);
|
||||
m_bool2var.reset();
|
||||
m_var2bool.reset();
|
||||
m_propagate = false;
|
||||
m_can_propagate = false;
|
||||
m_found_optimal = false;
|
||||
m_assigned.reset();
|
||||
m_enabled.reset();
|
||||
}
|
||||
|
||||
|
||||
void theory_wmaxsat::propagate() {
|
||||
context& ctx = get_context();
|
||||
for (unsigned i = 0; m_propagate && i < m_vars.size(); ++i) {
|
||||
bool_var bv = m_var2bool[i];
|
||||
lbool asgn = ctx.get_assignment(bv);
|
||||
if (asgn == l_true) {
|
||||
assign_eh(bv, true);
|
||||
}
|
||||
}
|
||||
m_propagate = false;
|
||||
//while (m_found_optimal && max_unassigned_is_blocked() && !ctx.inconsistent()) { }
|
||||
|
||||
m_can_propagate = false;
|
||||
}
|
||||
|
||||
bool theory_wmaxsat::is_optimal() const {
|
||||
return !m_found_optimal || m_zcost < m_zmin_cost;
|
||||
}
|
||||
|
||||
expr_ref theory_wmaxsat::mk_block() {
|
||||
++m_stats.m_num_blocks;
|
||||
ast_manager& m = get_manager();
|
||||
expr_ref_vector disj(m);
|
||||
compare_cost compare_cost(*this);
|
||||
svector<theory_var> costs(m_costs);
|
||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||
scoped_mpz weight(m_mpz);
|
||||
m_mpz.reset(weight);
|
||||
for (unsigned i = 0; i < costs.size() && m_mpz.lt(weight, m_zmin_cost); ++i) {
|
||||
theory_var tv = costs[i];
|
||||
if (m_enabled[tv]) {
|
||||
weight += m_zweights[tv];
|
||||
disj.push_back(m.mk_not(m_vars[tv].get()));
|
||||
}
|
||||
}
|
||||
if (is_optimal()) {
|
||||
m_found_optimal = true;
|
||||
m_cost_save.reset();
|
||||
m_cost_save.append(m_costs);
|
||||
TRACE("opt",
|
||||
tout << "costs: ";
|
||||
for (unsigned i = 0; i < m_costs.size(); ++i) {
|
||||
tout << mk_pp(get_enode(m_costs[i])->get_owner(), get_manager()) << " ";
|
||||
}
|
||||
tout << "\n";
|
||||
//get_context().display(tout);
|
||||
);
|
||||
}
|
||||
expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m);
|
||||
TRACE("opt",
|
||||
tout << "costs: ";
|
||||
for (unsigned i = 0; i < m_costs.size(); ++i) {
|
||||
tout << mk_pp(get_enode(m_costs[i])->get_owner(), get_manager()) << " ";
|
||||
}
|
||||
tout << "\n";
|
||||
get_context().display(tout);
|
||||
);
|
||||
tout << result << " weight: " << weight << "\n";
|
||||
tout << "cost: " << m_zcost << " min-cost: " << m_zmin_cost << "\n";);
|
||||
return result;
|
||||
}
|
||||
expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m);
|
||||
TRACE("opt",
|
||||
tout << result << " weight: " << weight << "\n";
|
||||
tout << "cost: " << m_zcost << " min-cost: " << m_zmin_cost << "\n";);
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref theory_wmaxsat::mk_optimal_block(svector<bool_var> const& ws, rational const& weight) {
|
||||
ast_manager& m = get_manager();
|
||||
expr_ref_vector disj(m);
|
||||
rational new_w = weight*m_den;
|
||||
m_zmin_cost = new_w.to_mpq().numerator();
|
||||
m_cost_save.reset();
|
||||
for (unsigned i = 0; i < ws.size(); ++i) {
|
||||
bool_var bv = ws[i];
|
||||
theory_var v = m_bool2var[bv];
|
||||
m_cost_save.push_back(v);
|
||||
disj.push_back(m.mk_not(m_vars[v].get()));
|
||||
}
|
||||
expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m);
|
||||
return result;
|
||||
}
|
||||
void theory_wmaxsat::restart_eh() {}
|
||||
|
||||
void theory_wmaxsat::block() {
|
||||
if (m_vars.empty()) {
|
||||
return;
|
||||
void theory_wmaxsat::block() {
|
||||
if (m_vars.empty()) {
|
||||
return;
|
||||
}
|
||||
++m_stats.m_num_blocks;
|
||||
context& ctx = get_context();
|
||||
literal_vector lits;
|
||||
compare_cost compare_cost(*this);
|
||||
svector<theory_var> costs(m_costs);
|
||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||
|
||||
scoped_mpz weight(m_mpz);
|
||||
m_mpz.reset(weight);
|
||||
for (unsigned i = 0; i < costs.size() && weight < m_zmin_cost; ++i) {
|
||||
weight += m_zweights[costs[i]];
|
||||
lits.push_back(literal(m_var2bool[costs[i]]));
|
||||
}
|
||||
TRACE("opt", ctx.display_literals_verbose(tout, lits); tout << "\n";);
|
||||
|
||||
ctx.set_conflict(
|
||||
ctx.mk_justification(
|
||||
ext_theory_conflict_justification(get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), 0, 0, 0, 0)));
|
||||
}
|
||||
|
||||
bool theory_wmaxsat::max_unassigned_is_blocked() {
|
||||
context& ctx = get_context();
|
||||
unsigned max_unassigned = m_max_unassigned_index;
|
||||
if (max_unassigned < m_sorted_vars.size() &&
|
||||
m_zcost + m_zweights[m_sorted_vars[max_unassigned]] < m_zmin_cost) {
|
||||
return false;
|
||||
}
|
||||
// update value of max-unassigned
|
||||
while (max_unassigned < m_sorted_vars.size() &&
|
||||
ctx.get_assignment(m_var2bool[m_sorted_vars[max_unassigned]]) != l_undef) {
|
||||
++max_unassigned;
|
||||
}
|
||||
//
|
||||
if (max_unassigned > m_max_unassigned_index) {
|
||||
ctx.push_trail(value_trail<context, unsigned>(m_max_unassigned_index));
|
||||
m_max_unassigned_index = max_unassigned;
|
||||
}
|
||||
if (max_unassigned < m_sorted_vars.size() &&
|
||||
m_zcost + m_zweights[m_sorted_vars[max_unassigned]] >= m_zmin_cost) {
|
||||
theory_var tv = m_sorted_vars[max_unassigned];
|
||||
propagate(m_var2bool[tv]);
|
||||
m_max_unassigned_index++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
++m_stats.m_num_blocks;
|
||||
context& ctx = get_context();
|
||||
literal_vector lits;
|
||||
compare_cost compare_cost(*this);
|
||||
svector<theory_var> costs(m_costs);
|
||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||
|
||||
scoped_mpz weight(m_mpz);
|
||||
m_mpz.reset(weight);
|
||||
for (unsigned i = 0; i < costs.size() && weight < m_zmin_cost; ++i) {
|
||||
weight += m_zweights[costs[i]];
|
||||
lits.push_back(~literal(m_var2bool[costs[i]]));
|
||||
}
|
||||
TRACE("opt",
|
||||
ast_manager& m = get_manager();
|
||||
tout << "block: ";
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
expr_ref tmp(m);
|
||||
ctx.literal2expr(lits[i], tmp);
|
||||
tout << tmp << " ";
|
||||
}
|
||||
tout << "\n";
|
||||
);
|
||||
|
||||
ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
|
||||
}
|
||||
void theory_wmaxsat::propagate(bool_var v) {
|
||||
++m_stats.m_num_propagations;
|
||||
context& ctx = get_context();
|
||||
literal_vector lits;
|
||||
literal lit(v, true);
|
||||
|
||||
SASSERT(ctx.get_assignment(lit) == l_undef);
|
||||
|
||||
for (unsigned i = 0; i < m_costs.size(); ++i) {
|
||||
bool_var w = m_var2bool[m_costs[i]];
|
||||
lits.push_back(literal(w));
|
||||
}
|
||||
TRACE("opt",
|
||||
ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr());
|
||||
ctx.display_literal_verbose(tout << " --> ", lit););
|
||||
|
||||
region& r = ctx.get_region();
|
||||
ctx.assign(lit, ctx.mk_justification(
|
||||
ext_theory_propagation_justification(
|
||||
get_id(), r, lits.size(), lits.c_ptr(), 0, 0, lit, 0, 0)));
|
||||
}
|
||||
|
||||
|
||||
void theory_wmaxsat::normalize() {
|
||||
m_den = rational::one();
|
||||
for (unsigned i = 0; i < m_rweights.size(); ++i) {
|
||||
m_den = lcm(m_den, denominator(m_rweights[i]));
|
||||
void theory_wmaxsat::normalize() {
|
||||
m_den = rational::one();
|
||||
for (unsigned i = 0; i < m_rweights.size(); ++i) {
|
||||
if (m_enabled[i]) {
|
||||
m_den = lcm(m_den, denominator(m_rweights[i]));
|
||||
}
|
||||
}
|
||||
m_den = lcm(m_den, denominator(m_rmin_cost));
|
||||
SASSERT(!m_den.is_zero());
|
||||
m_zweights.reset();
|
||||
m_sorted_vars.reset();
|
||||
for (unsigned i = 0; i < m_rweights.size(); ++i) {
|
||||
rational r = m_rweights[i]*m_den;
|
||||
SASSERT(r.is_int());
|
||||
mpq const& q = r.to_mpq();
|
||||
m_zweights.push_back(q.numerator());
|
||||
m_sorted_vars.push_back(i);
|
||||
}
|
||||
compare_cost compare_cost(*this);
|
||||
std::sort(m_sorted_vars.begin(), m_sorted_vars.end(), compare_cost);
|
||||
m_max_unassigned_index = 0;
|
||||
|
||||
m_zcost.reset();
|
||||
rational r = m_rmin_cost * m_den;
|
||||
m_zmin_cost = r.to_mpq().numerator();
|
||||
m_normalize = false;
|
||||
}
|
||||
m_den = lcm(m_den, denominator(m_rmin_cost));
|
||||
SASSERT(!m_den.is_zero());
|
||||
m_zweights.reset();
|
||||
for (unsigned i = 0; i < m_rweights.size(); ++i) {
|
||||
rational r = m_rweights[i]*m_den;
|
||||
SASSERT(r.is_int());
|
||||
mpq const& q = r.to_mpq();
|
||||
m_zweights.push_back(q.numerator());
|
||||
}
|
||||
rational r = m_rcost* m_den;
|
||||
m_zcost = r.to_mpq().numerator();
|
||||
r = m_rmin_cost * m_den;
|
||||
m_zmin_cost = r.to_mpq().numerator();
|
||||
m_normalize = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace smt {
|
|||
class theory_wmaxsat : public theory {
|
||||
struct stats {
|
||||
unsigned m_num_blocks;
|
||||
unsigned m_num_propagations;
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
stats() { reset(); }
|
||||
};
|
||||
|
@ -39,27 +40,31 @@ namespace smt {
|
|||
scoped_mpz_vector m_zweights;
|
||||
scoped_mpz_vector m_old_values;
|
||||
svector<theory_var> m_costs; // set of asserted theory variables
|
||||
unsigned m_max_unassigned_index; // index of literal that is not yet assigned and has maximal weight.
|
||||
svector<theory_var> m_sorted_vars; // set of all theory variables, sorted by cost
|
||||
svector<theory_var> m_cost_save; // set of asserted theory variables
|
||||
rational m_rcost; // current sum of asserted costs
|
||||
rational m_rmin_cost; // current maximal cost assignment.
|
||||
scoped_mpz m_zcost; // current sum of asserted costs
|
||||
scoped_mpz m_zmin_cost; // current maximal cost assignment.
|
||||
bool m_found_optimal;
|
||||
u_map<theory_var> m_bool2var; // bool_var -> theory_var
|
||||
svector<bool_var> m_var2bool; // theory_var -> bool_var
|
||||
bool m_propagate;
|
||||
bool m_propagate;
|
||||
bool m_can_propagate;
|
||||
bool m_normalize;
|
||||
rational m_den; // lcm of denominators for rational weights.
|
||||
svector<bool> m_assigned;
|
||||
svector<bool> m_assigned, m_enabled;
|
||||
stats m_stats;
|
||||
public:
|
||||
theory_wmaxsat(ast_manager& m, filter_model_converter& mc);
|
||||
virtual ~theory_wmaxsat();
|
||||
void get_assignment(svector<bool>& result);
|
||||
virtual void init_search_eh();
|
||||
bool_var assert_weighted(expr* fml, rational const& w);
|
||||
expr* assert_weighted(expr* fml, rational const& w);
|
||||
void disable_var(expr* var);
|
||||
bool_var register_var(app* var, bool attach);
|
||||
rational const& get_min_cost();
|
||||
rational get_cost();
|
||||
void init_min_cost(rational const& r);
|
||||
|
||||
class numeral_trail : public trail<context> {
|
||||
typedef scoped_mpz T;
|
||||
T & m_value;
|
||||
|
@ -79,6 +84,8 @@ namespace smt {
|
|||
m_old_values.shrink(m_old_values.size() - 1);
|
||||
}
|
||||
};
|
||||
|
||||
virtual void init_search_eh();
|
||||
virtual void assign_eh(bool_var v, bool is_true);
|
||||
virtual final_check_status final_check_eh();
|
||||
virtual bool use_diseqs() const {
|
||||
|
@ -95,23 +102,30 @@ namespace smt {
|
|||
virtual void new_eq_eh(theory_var v1, theory_var v2) { }
|
||||
virtual void new_diseq_eh(theory_var v1, theory_var v2) { }
|
||||
virtual void display(std::ostream& out) const {}
|
||||
virtual void restart_eh();
|
||||
|
||||
virtual void collect_statistics(::statistics & st) const {
|
||||
st.update("wmaxsat num blocks", m_stats.m_num_blocks);
|
||||
st.update("wmaxsat num props", m_stats.m_num_propagations);
|
||||
}
|
||||
virtual bool can_propagate() {
|
||||
return m_propagate;
|
||||
return m_propagate || m_can_propagate;
|
||||
}
|
||||
|
||||
virtual void propagate();
|
||||
|
||||
bool is_optimal() const;
|
||||
expr_ref mk_block();
|
||||
|
||||
expr_ref mk_optimal_block(svector<bool_var> const& ws, rational const& weight);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void block();
|
||||
void propagate(bool_var v);
|
||||
void normalize();
|
||||
|
||||
bool max_unassigned_is_blocked();
|
||||
|
||||
class compare_cost {
|
||||
theory_wmaxsat& m_th;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue