3
0
Fork 0
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:
Murphy Berzish 2017-02-18 15:04:44 -05:00
commit 235ea79043
588 changed files with 21784 additions and 15202 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -47,6 +47,8 @@ public:
}
void updt_params(params_ref const & _p);
void display(std::ostream & out) const;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -71,6 +71,7 @@ struct theory_array_params : public array_simplifier_params {
}
#endif
void display(std::ostream & out) const;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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
View 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_ */

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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