mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	Merge branch 'master' into polysat
This commit is contained in:
		
						commit
						f54f33551e
					
				
					 308 changed files with 6606 additions and 18485 deletions
				
			
		|  | @ -3958,7 +3958,7 @@ namespace { | |||
|         void relevant_eh(enode * n, bool lazy) override { | ||||
|             TRACE("trigger_bug", tout << "relevant_eh:\n" << mk_ismt2_pp(n->get_expr(), m) << "\n"; | ||||
|                   tout << "mam: " << this << "\n";); | ||||
|             TRACE("mam", tout << "relevant_eh: #" << n->get_owner_id() << "\n";); | ||||
|             TRACE("mam", tout << "relevant_eh: #" << enode_pp(n, m_context) << "\n";); | ||||
|             if (n->has_lbl_hash()) | ||||
|                 update_lbls(n, n->get_lbl_hash()); | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ void preprocessor_params::updt_local_params(params_ref const & _p) { | |||
|     m_elim_unconstrained      = p.elim_unconstrained(); | ||||
|     m_solve_eqs               = p.solve_eqs(); | ||||
|     m_ng_lift_ite             = static_cast<lift_ite_kind>(p.q_lift_ite()); | ||||
|     m_bound_simplifier        = p.bound_simplifier(); | ||||
| } | ||||
| 
 | ||||
| void preprocessor_params::updt_params(params_ref const & p) { | ||||
|  | @ -63,4 +64,5 @@ void preprocessor_params::display(std::ostream & out) const { | |||
|     DISPLAY_PARAM(m_max_bv_sharing); | ||||
|     DISPLAY_PARAM(m_pre_simplifier); | ||||
|     DISPLAY_PARAM(m_nlquant_elim); | ||||
|     DISPLAY_PARAM(m_bound_simplifier); | ||||
| } | ||||
|  |  | |||
|  | @ -49,6 +49,7 @@ struct preprocessor_params : public pattern_inference_params, | |||
|     bool            m_max_bv_sharing = true; | ||||
|     bool            m_pre_simplifier = true; | ||||
|     bool            m_nlquant_elim = false; | ||||
|     bool            m_bound_simplifier = true; | ||||
| 
 | ||||
| public: | ||||
|     preprocessor_params(params_ref const & p = params_ref()): | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ def_module_params(module_name='smt', | |||
|                           ('elim_unconstrained', BOOL, True, 'pre-processing: eliminate unconstrained subterms'), | ||||
|                           ('solve_eqs', BOOL, True, 'pre-processing: solve equalities'), | ||||
|                           ('propagate_values', BOOL, True, 'pre-processing: propagate values'), | ||||
|                           ('bound_simplifier', BOOL, True, 'apply bounds simplification during pre-processing'), | ||||
|                           ('pull_nested_quantifiers', BOOL, False, 'pre-processing: pull nested quantifiers'), | ||||
|                           ('refine_inj_axioms', BOOL, True, 'pre-processing: refine injectivity axioms'), | ||||
| 	                  ('candidate_models', BOOL, False, 'create candidate models even when quantifier or theory reasoning is incomplete'), | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ proto_model::proto_model(ast_manager & m, params_ref const & p): | |||
|     model_core(m), | ||||
|     m_eval(*this), | ||||
|     m_rewrite(m) { | ||||
|     register_factory(alloc(basic_factory, m)); | ||||
|     register_factory(alloc(basic_factory, m, m.get_num_asts())); | ||||
|     m_user_sort_factory = alloc(user_sort_factory, m); | ||||
|     register_factory(m_user_sort_factory); | ||||
|     m_model_partial = model_params(p).partial(); | ||||
|  | @ -288,42 +288,33 @@ bool proto_model::is_finite(sort * s) const { | |||
| } | ||||
| 
 | ||||
| expr * proto_model::get_some_value(sort * s) { | ||||
|     if (m.is_uninterp(s)) { | ||||
|         return m_user_sort_factory->get_some_value(s); | ||||
|     } | ||||
|     else if (value_factory * f = get_factory(s->get_family_id())) { | ||||
|         return f->get_some_value(s); | ||||
|     } | ||||
|     else { | ||||
|     if (m.is_uninterp(s))  | ||||
|         return m_user_sort_factory->get_some_value(s);     | ||||
|     else if (value_factory * f = get_factory(s->get_family_id()))  | ||||
|         return f->get_some_value(s);     | ||||
|     else  | ||||
|         // there is no factory for the family id, then assume s is uninterpreted.
 | ||||
|         return m_user_sort_factory->get_some_value(s); | ||||
|     } | ||||
|         return m_user_sort_factory->get_some_value(s);     | ||||
| } | ||||
| 
 | ||||
| bool proto_model::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { | ||||
|     if (m.is_uninterp(s)) { | ||||
|         return m_user_sort_factory->get_some_values(s, v1, v2); | ||||
|     } | ||||
|     else if (value_factory * f = get_factory(s->get_family_id())) { | ||||
|         return f->get_some_values(s, v1, v2); | ||||
|     } | ||||
|     else { | ||||
|         return false; | ||||
|     } | ||||
|     if (m.is_uninterp(s))  | ||||
|         return m_user_sort_factory->get_some_values(s, v1, v2);     | ||||
|     else if (value_factory * f = get_factory(s->get_family_id()))  | ||||
|         return f->get_some_values(s, v1, v2);     | ||||
|     else  | ||||
|         return false;     | ||||
| } | ||||
| 
 | ||||
| expr * proto_model::get_fresh_value(sort * s) { | ||||
|     if (m.is_uninterp(s)) { | ||||
|         return m_user_sort_factory->get_fresh_value(s); | ||||
|     } | ||||
|     else if (value_factory * f = get_factory(s->get_family_id())) { | ||||
|         return f->get_fresh_value(s); | ||||
|     } | ||||
|     else { | ||||
|     if (m.is_uninterp(s))  | ||||
|         return m_user_sort_factory->get_fresh_value(s);     | ||||
|     else if (value_factory * f = get_factory(s->get_family_id()))  | ||||
|         return f->get_fresh_value(s);     | ||||
|     else  | ||||
|         // Use user_sort_factory if the theory has no support for model construnction.
 | ||||
|         // This is needed when dummy theories are used for arithmetic or arrays.
 | ||||
|         return m_user_sort_factory->get_fresh_value(s); | ||||
|     } | ||||
|         return m_user_sort_factory->get_fresh_value(s);     | ||||
| } | ||||
| 
 | ||||
| void proto_model::register_value(expr * n) { | ||||
|  |  | |||
|  | @ -964,7 +964,7 @@ namespace { | |||
|         } | ||||
| 
 | ||||
|         void display(std::ostream & out) override { | ||||
|             if (m_queue.empty() && m_queue2.empty()) | ||||
|             if (m_queue.empty()) | ||||
|                 return; | ||||
|             out << "case-splits:\n"; | ||||
|             display_core(out, m_queue, m_head, 1); | ||||
|  |  | |||
|  | @ -233,7 +233,7 @@ namespace smt { | |||
|         TRACE("context", tout << "get-proof " << ctx.get_fparams().m_clause_proof << "\n";); | ||||
|         if (!ctx.get_fparams().m_clause_proof)  | ||||
|             return proof_ref(m); | ||||
|         proof_ref_vector ps(m); | ||||
|         expr_ref_vector ps(m); | ||||
|         for (auto& info : m_trail) { | ||||
|             expr_ref fact = mk_or(info.m_clause); | ||||
|             proof* pr = info.m_proof; | ||||
|  |  | |||
|  | @ -3024,7 +3024,8 @@ namespace smt { | |||
|         SASSERT(is_well_sorted(m, e)); | ||||
|         TRACE("begin_assert_expr", tout << mk_pp(e, m) << " " << mk_pp(pr, m) << "\n";); | ||||
|         TRACE("begin_assert_expr_ll", tout << mk_ll_pp(e, m) << "\n";); | ||||
|         pop_to_base_lvl(); | ||||
|         if (!m_searching) | ||||
|             pop_to_base_lvl(); | ||||
|         if (pr == nullptr) | ||||
|             m_asserted_formulas.assert_expr(e); | ||||
|         else | ||||
|  |  | |||
|  | @ -704,14 +704,20 @@ namespace smt { | |||
|         for (clause* cp : m_lemmas) | ||||
|             if (cp->get_num_literals() == 2) | ||||
|                 ++bin_lemmas; | ||||
|         auto num_units = [&]() { | ||||
|             if (m_scopes.empty()) | ||||
|                 return m_assigned_literals.size(); | ||||
|             else | ||||
|                 return m_scopes[0].m_assigned_literals_lim; | ||||
|         }; | ||||
|         std::stringstream strm; | ||||
|         strm << "(smt.stats "  | ||||
|              << std::setw(4) << m_stats.m_num_restarts << " " | ||||
|              << std::setw(6) << m_stats.m_num_conflicts << " " | ||||
|              << std::setw(6) << m_stats.m_num_decisions << " "  | ||||
|              << std::setw(6) << m_stats.m_num_propagations << " " | ||||
|              << std::setw(5) << (m_aux_clauses.size() + bin_clauses) << "/" << bin_clauses << " " | ||||
|              << std::setw(5) << m_lemmas.size(); if (bin_lemmas > 0) strm << "/" << bin_lemmas << " "; | ||||
|              << std::setw(5) << (m_aux_clauses.size() + bin_clauses) << "/" << bin_clauses << "/" << num_units() | ||||
|              << std::setw(7) << m_lemmas.size(); if (bin_lemmas > 0) strm << "/" << bin_lemmas << " "; | ||||
|         strm << std::setw(5) << m_stats.m_num_simplifications << " " | ||||
|              << std::setw(4) << m_stats.m_num_del_clauses << " " | ||||
|              << std::setw(7) << mem_stat() << ")\n"; | ||||
|  | @ -739,8 +745,8 @@ namespace smt { | |||
|             m_last_position_log = m_stats.m_num_restarts; | ||||
|             // restarts       decisions      clauses    simplifications  memory
 | ||||
|             //      conflicts       propagations    lemmas       deletions
 | ||||
|             int adjust[9] = { -3, -3, -3, -3, -3, -3, -4, -4, -1 }; | ||||
|             char const* tag[9] = { ":restarts ", ":conflicts ", ":decisions ", ":propagations ", ":clauses/bin ", ":lemmas ", ":simplify ", ":deletions", ":memory" }; | ||||
|             int adjust[9] = { -3, -3, -3, -3, -3, -4, -4, -4, -1 }; | ||||
|             char const* tag[9] = { ":restarts ", ":conflicts ", ":decisions ", ":propagations ", ":clauses/bin/units ", ":lemmas ", ":simplify ", ":deletions", ":memory" }; | ||||
| 
 | ||||
|             std::stringstream l1, l2; | ||||
|             l1 << "(smt.stats "; | ||||
|  |  | |||
|  | @ -1536,7 +1536,7 @@ namespace smt { | |||
|             fml = mk_or(fmls); | ||||
|             m_lemma_visitor.collect(fml); | ||||
|             m_lemma_visitor.display_skolem_decls(std::cout); | ||||
|             m_lemma_visitor.display_assert(std::cout, fml.get(), true); | ||||
|             m_lemma_visitor.display_assert(std::cout, fml.get(), false); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ Revision History: | |||
| #include "ast/rewriter/rewriter_def.h" | ||||
| #include "ast/ast_pp.h" | ||||
| #include "ast/array_decl_plugin.h" | ||||
| #include "ast/special_relations_decl_plugin.h" | ||||
| #include "ast/ast_smt2_pp.h" | ||||
| #include "smt/smt_model_checker.h" | ||||
| #include "smt/smt_context.h" | ||||
|  | @ -358,7 +359,7 @@ namespace smt { | |||
|          | ||||
|         TRACE("model_checker", tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";); | ||||
|         if (r != l_true) { | ||||
|             return r == l_false; // quantifier is satisfied by m_curr_model
 | ||||
|             return is_safe_for_mbqi(q) && r == l_false; // quantifier is satisfied by m_curr_model
 | ||||
|         } | ||||
| 
 | ||||
|         model_ref complete_cex; | ||||
|  | @ -398,6 +399,26 @@ namespace smt { | |||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool model_checker::is_safe_for_mbqi(quantifier * q) const { | ||||
|         special_relations_util sp(m); | ||||
|         if (!sp.has_special_relation()) | ||||
|             return true; | ||||
|         ast_fast_mark1 visited; | ||||
|         struct proc { | ||||
|             special_relations_util& sp; | ||||
|             bool found = false; | ||||
|             proc(special_relations_util& sp):sp(sp) {} | ||||
|             void operator()(app* f) { | ||||
|                 found |= sp.is_special_relation(f); | ||||
|             } | ||||
|             void operator()(expr* e) {} | ||||
|         }; | ||||
|         proc p(sp); | ||||
|         quick_for_each_expr(p, visited, q); | ||||
|         return !p.found; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void model_checker::init_aux_context() { | ||||
|         if (!m_fparams) { | ||||
|             m_fparams = alloc(smt_params, m_context->get_fparams()); | ||||
|  |  | |||
|  | @ -87,6 +87,7 @@ namespace smt { | |||
|         expr_mark m_visited; | ||||
|         bool contains_model_value(expr * e); | ||||
|         void add_instance(quantifier * q, expr_ref_vector const & bindings, unsigned max_generation, expr * def); | ||||
|         bool is_safe_for_mbqi(quantifier * q) const; | ||||
| 
 | ||||
|     public: | ||||
|         model_checker(ast_manager & m, qi_params const & p, model_finder & mf); | ||||
|  |  | |||
|  | @ -802,7 +802,7 @@ namespace smt { | |||
|         setup_dl(); | ||||
|         setup_seq_str(st); | ||||
|         setup_fpa(); | ||||
|         if (st.m_has_sr) setup_special_relations(); | ||||
|         setup_special_relations(); | ||||
|     } | ||||
| 
 | ||||
|     void setup::setup_unknown(static_features & st) { | ||||
|  | @ -818,7 +818,7 @@ namespace smt { | |||
|             setup_seq_str(st); | ||||
|             setup_fpa(); | ||||
|             setup_recfuns(); | ||||
|             if (st.m_has_sr) setup_special_relations(); | ||||
|             setup_special_relations(); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ Revision History: | |||
| namespace smt { | ||||
|      | ||||
|     struct theory_arith_stats { | ||||
|         unsigned m_conflicts, m_add_rows, m_pivots, m_diseq_cs, m_gomory_cuts, m_branches, m_gcd_tests, m_patches, m_patches_succ; | ||||
|         unsigned m_conflicts, m_add_rows, m_pivots, m_diseq_cs, m_gomory_cuts, m_branches, m_gcd_tests, m_gcd_conflicts, m_patches, m_patches_succ; | ||||
|         unsigned m_assert_lower, m_assert_upper, m_assert_diseq, m_core2th_eqs, m_core2th_diseqs; | ||||
|         unsigned m_th2core_eqs, m_th2core_diseqs, m_bound_props, m_offset_eqs, m_fixed_eqs, m_offline_eqs; | ||||
|         unsigned m_max_min;  | ||||
|  | @ -452,18 +452,18 @@ namespace smt { | |||
|         svector<int>            m_var_pos;          // temporary array used in add_rows
 | ||||
|         atoms                   m_atoms;            // set of theory atoms
 | ||||
|         ptr_vector<bound>       m_asserted_bounds;  // set of asserted bounds
 | ||||
|         unsigned                m_asserted_qhead;    | ||||
|         unsigned                m_asserted_qhead = 0;    | ||||
|         ptr_vector<atom>        m_new_atoms;        // new bound atoms that have yet to be internalized.
 | ||||
|         svector<theory_var>     m_nl_monomials;     // non linear monomials
 | ||||
|         svector<theory_var>     m_nl_propagated;    // non linear monomials that became linear
 | ||||
|         v_dependency_manager    m_dep_manager;      // for tracking bounds during non-linear reasoning
 | ||||
| 
 | ||||
|         vector<uint_set>        m_row_vars;         // variables in a given row. Used during internalization to detect repeated variables.
 | ||||
|         unsigned                m_row_vars_top; | ||||
|         unsigned                m_row_vars_top = 0; | ||||
| 
 | ||||
|         var_heap                m_to_patch;         // heap containing all variables v s.t. m_value[v] does not satisfy bounds of v.
 | ||||
|         nat_set                 m_left_basis;       // temporary: set of variables that already left the basis in make_feasible
 | ||||
|         bool                    m_blands_rule; | ||||
|         bool                    m_blands_rule = false; | ||||
| 
 | ||||
|         svector<unsigned>       m_update_trail_stack;    // temporary trail stack used to restore the last feasible assignment.
 | ||||
|         nat_set                 m_in_update_trail_stack; // set of variables in m_update_trail_stack
 | ||||
|  | @ -473,11 +473,11 @@ namespace smt { | |||
|          | ||||
|         inf_numeral             m_tmp; | ||||
|         random_gen              m_random; | ||||
|         unsigned                m_num_conflicts; | ||||
|         unsigned                m_num_conflicts = 0; | ||||
| 
 | ||||
|         unsigned                m_branch_cut_counter; | ||||
|         unsigned                m_branch_cut_counter = 0; | ||||
|         bool                    m_eager_gcd; // true if gcd should be applied at every add_row
 | ||||
|         unsigned                m_final_check_idx; | ||||
|         unsigned                m_final_check_idx = 0; | ||||
| 
 | ||||
| 
 | ||||
|         // backtracking
 | ||||
|  | @ -676,7 +676,7 @@ namespace smt { | |||
| 
 | ||||
|            See also m_changed_assignment flag. | ||||
|         */ | ||||
|         bool    m_liberal_final_check;  | ||||
|         bool    m_liberal_final_check = true;  | ||||
|         final_check_status final_check_core(); | ||||
|         final_check_status final_check_eh() override; | ||||
|          | ||||
|  | @ -734,7 +734,7 @@ namespace smt { | |||
|         // Assignment management
 | ||||
|         //
 | ||||
|         // -----------------------------------
 | ||||
|         bool m_changed_assignment; //!< auxiliary variable set to true when the assignment is changed.
 | ||||
|         bool m_changed_assignment = false; //!< auxiliary variable set to true when the assignment is changed.
 | ||||
|         void save_value(theory_var v); | ||||
|         void discard_update_trail(); | ||||
|         void restore_assignment(); | ||||
|  | @ -790,11 +790,11 @@ namespace smt { | |||
|         void mark_row_for_bound_prop(unsigned r1); | ||||
|         void mark_rows_for_bound_prop(theory_var v); | ||||
|         void is_row_useful_for_bound_prop(row const & r, int & lower_idx, int & upper_idx) const; | ||||
|         void imply_bound_for_monomial(row const & r, int idx, bool lower); | ||||
|         void imply_bound_for_all_monomials(row const & r, bool lower); | ||||
|         unsigned imply_bound_for_monomial(row const & r, int idx, bool lower); | ||||
|         unsigned imply_bound_for_all_monomials(row const & r, bool lower); | ||||
|         void explain_bound(row const & r, int idx, bool lower, inf_numeral & delta,  | ||||
|                            antecedents & antecedents); | ||||
|         void mk_implied_bound(row const & r, unsigned idx, bool lower, theory_var v, bound_kind kind, inf_numeral const & k); | ||||
|         unsigned mk_implied_bound(row const & r, unsigned idx, bool lower, theory_var v, bound_kind kind, inf_numeral const & k); | ||||
|         void assign_bound_literal(literal l, row const & r, unsigned idx, bool lower, inf_numeral & delta); | ||||
|         void propagate_bounds(); | ||||
| 
 | ||||
|  | @ -821,7 +821,7 @@ namespace smt { | |||
|         var_set         m_tmp_var_set; | ||||
|         var_set         m_tmp_var_set2; | ||||
|         svector<std::pair<theory_var, theory_var> >       m_assume_eq_candidates; | ||||
|         unsigned                                          m_assume_eq_head; | ||||
|         unsigned                                          m_assume_eq_head = 0; | ||||
|         bool random_update(theory_var v); | ||||
|         void mutate_assignment(); | ||||
|         bool assume_eqs_core(); | ||||
|  | @ -953,10 +953,10 @@ namespace smt { | |||
|         //
 | ||||
|         // -----------------------------------
 | ||||
|         typedef int_hashtable<int_hash, default_eq<int> > row_set; | ||||
|         bool            m_model_depends_on_computed_epsilon; | ||||
|         unsigned        m_nl_rounds; | ||||
|         bool            m_nl_gb_exhausted; | ||||
|         unsigned        m_nl_strategy_idx; // for fairness
 | ||||
|         bool            m_model_depends_on_computed_epsilon = false; | ||||
|         unsigned        m_nl_rounds = 0; | ||||
|         bool            m_nl_gb_exhausted = false; | ||||
|         unsigned        m_nl_strategy_idx = 0; // for fairness
 | ||||
|         expr_ref_vector m_nl_new_exprs; | ||||
|         typedef obj_map<expr, unsigned> var2num_occs; | ||||
|         var2num_occs m_var2num_occs; | ||||
|  |  | |||
|  | @ -47,11 +47,15 @@ namespace smt { | |||
|         else if (m_util.is_idiv(n)) {                 | ||||
|             e = m_util.mk_idiv0(n->get_arg(0), n->get_arg(1)); | ||||
|         } | ||||
|         else if (m_util.is_rem(n)) {                 | ||||
|             e = m_util.mk_rem0(n->get_arg(0), n->get_arg(1)); | ||||
|         else if (m_util.is_rem(n)) { | ||||
|             expr* z = m_util.mk_int(0); | ||||
|             e = m_util.mk_rem0(n->get_arg(0), z); | ||||
|             n = m_util.mk_rem(n->get_arg(0), z); | ||||
|         } | ||||
|         else if (m_util.is_mod(n)) {                 | ||||
|             e = m_util.mk_mod0(n->get_arg(0), n->get_arg(1)); | ||||
|         else if (m_util.is_mod(n)) { | ||||
|             expr* z = m_util.mk_int(0); | ||||
|             e = m_util.mk_mod0(n->get_arg(0), z); | ||||
|             n = m_util.mk_mod(n->get_arg(0), z); | ||||
|         } | ||||
|         else if (m_util.is_power(n)) {                 | ||||
|             e = m_util.mk_power0(n->get_arg(0), n->get_arg(1)); | ||||
|  | @ -154,7 +158,6 @@ namespace smt { | |||
|             case OP_MOD: | ||||
|             case OP_DIV0: | ||||
|             case OP_IDIV0: | ||||
|             case OP_REM0: | ||||
|             case OP_MOD0: | ||||
|                 return true; | ||||
|             default: | ||||
|  | @ -1732,23 +1735,11 @@ namespace smt { | |||
|         m_util(m), | ||||
|         m_arith_eq_solver(m), | ||||
|         m_arith_eq_adapter(*this, m_util), | ||||
|         m_asserted_qhead(0), | ||||
|         m_row_vars_top(0), | ||||
|         m_to_patch(1024), | ||||
|         m_blands_rule(false), | ||||
|         m_random(ctx.get_fparams().m_arith_random_seed), | ||||
|         m_num_conflicts(0), | ||||
|         m_branch_cut_counter(0), | ||||
|         m_eager_gcd(m_params.m_arith_eager_gcd), | ||||
|         m_final_check_idx(0), | ||||
|         m_antecedents_index(0), | ||||
|         m_var_value_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), | ||||
|         m_liberal_final_check(true), | ||||
|         m_changed_assignment(false), | ||||
|         m_assume_eq_head(0), | ||||
|         m_model_depends_on_computed_epsilon(false), | ||||
|         m_nl_rounds(0), | ||||
|         m_nl_gb_exhausted(false), | ||||
|         m_nl_new_exprs(m), | ||||
|         m_bound_watch(null_bool_var) { | ||||
|     } | ||||
|  | @ -2700,8 +2691,9 @@ namespace smt { | |||
|        Then this bound is used to produce a bound for the monomial variable. | ||||
|     */ | ||||
|     template<typename Ext> | ||||
|     void theory_arith<Ext>::imply_bound_for_monomial(row const & r, int idx, bool is_lower) { | ||||
|     unsigned theory_arith<Ext>::imply_bound_for_monomial(row const & r, int idx, bool is_lower) { | ||||
|         row_entry const & entry = r[idx]; | ||||
|         unsigned count = 0; | ||||
|         if (m_unassigned_atoms[entry.m_var] > 0) { | ||||
|             inf_numeral implied_k; | ||||
|             typename vector<row_entry>::const_iterator it  = r.begin_entries(); | ||||
|  | @ -2723,7 +2715,7 @@ namespace smt { | |||
|                           tout << "implying lower bound for v" << entry.m_var << " " << implied_k << " using row:\n"; | ||||
|                           display_row_info(tout, r); | ||||
|                           display_var(tout, entry.m_var);); | ||||
|                     mk_implied_bound(r, idx, is_lower, entry.m_var, B_LOWER, implied_k); | ||||
|                     count += mk_implied_bound(r, idx, is_lower, entry.m_var, B_LOWER, implied_k); | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|  | @ -2734,10 +2726,11 @@ namespace smt { | |||
|                           tout << "implying upper bound for v" << entry.m_var << " " << implied_k << " using row:\n"; | ||||
|                           display_row_info(tout, r); | ||||
|                           display_var(tout, entry.m_var);); | ||||
|                     mk_implied_bound(r, idx, is_lower, entry.m_var, B_UPPER, implied_k); | ||||
|                     count += mk_implied_bound(r, idx, is_lower, entry.m_var, B_UPPER, implied_k); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -2748,7 +2741,7 @@ namespace smt { | |||
|        for the monomial variables. | ||||
|     */ | ||||
|     template<typename Ext> | ||||
|     void theory_arith<Ext>::imply_bound_for_all_monomials(row const & r, bool is_lower) { | ||||
|     unsigned theory_arith<Ext>::imply_bound_for_all_monomials(row const & r, bool is_lower) { | ||||
|         // Traverse the row once and compute
 | ||||
|         // bb = (Sum_{a_i < 0} -a_i*lower(x_i)) + (Sum_{a_j > 0} -a_j * upper(x_j))  If is_lower = true
 | ||||
|         // bb = (Sum_{a_i > 0} -a_i*lower(x_i)) + (Sum_{a_j < 0} -a_j * upper(x_j))  If is_lower = false
 | ||||
|  | @ -2761,6 +2754,7 @@ namespace smt { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         unsigned count = 0; | ||||
|         inf_numeral implied_k; | ||||
|         typename vector<row_entry>::const_iterator it  = r.begin(); | ||||
|         typename vector<row_entry>::const_iterator end = r.end(); | ||||
|  | @ -2784,7 +2778,7 @@ namespace smt { | |||
|                               tout << "implying lower bound for v" << it->m_var << " " << implied_k << " using row:\n"; | ||||
|                               display_row_info(tout, r); | ||||
|                               display_var(tout, it->m_var);); | ||||
|                         mk_implied_bound(r, idx, is_lower, it->m_var, B_LOWER, implied_k); | ||||
|                         count += mk_implied_bound(r, idx, is_lower, it->m_var, B_LOWER, implied_k); | ||||
|                     } | ||||
|                 } | ||||
|                 else { | ||||
|  | @ -2796,11 +2790,12 @@ namespace smt { | |||
|                               tout << "implying upper bound for v" << it->m_var << " " << implied_k << " using row:\n"; | ||||
|                               display_row_info(tout, r); | ||||
|                               display_var(tout, it->m_var);); | ||||
|                         mk_implied_bound(r, idx, is_lower, it->m_var, B_UPPER, implied_k); | ||||
|                         count += mk_implied_bound(r, idx, is_lower, it->m_var, B_UPPER, implied_k); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -2922,10 +2917,11 @@ namespace smt { | |||
|     } | ||||
| 
 | ||||
|     template<typename Ext> | ||||
|     void theory_arith<Ext>::mk_implied_bound(row const & r, unsigned idx, bool is_lower, theory_var v, bound_kind kind, inf_numeral const & k) { | ||||
|     unsigned theory_arith<Ext>::mk_implied_bound(row const & r, unsigned idx, bool is_lower, theory_var v, bound_kind kind, inf_numeral const & k) { | ||||
|         atoms const & as                 = m_var_occs[v]; | ||||
|         inf_numeral const & epsilon      = get_epsilon(v); | ||||
|         inf_numeral delta; | ||||
|         unsigned count = 0; | ||||
|         for (atom* a : as) { | ||||
|             bool_var bv = a->get_bool_var(); | ||||
|             literal  l(bv); | ||||
|  | @ -2942,6 +2938,7 @@ namespace smt { | |||
|                         TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", v" << v << " >= " << k2 << ", delta: " << delta << "\n"; | ||||
|                               display_row(tout, r);); | ||||
|                         assign_bound_literal(l, r, idx, is_lower, delta); | ||||
|                         ++count; | ||||
|                     } | ||||
|                     // v <= k  k <  k2  |-  v < k2  |- not v >= k2
 | ||||
|                     if (kind == B_UPPER && k <  k2) { | ||||
|  | @ -2958,6 +2955,7 @@ namespace smt { | |||
|                             TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", not v" << v << " >= " << k2 << ", delta: " << delta << "\n"; | ||||
|                                   display_row(tout, r);); | ||||
|                             assign_bound_literal(~l, r, idx, is_lower, delta); | ||||
|                             ++count; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | @ -2973,6 +2971,7 @@ namespace smt { | |||
|                             TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", not v" << v << " <= " << k2 << ", delta: " << delta << "\n"; | ||||
|                                   display_row(tout, r);); | ||||
|                             assign_bound_literal(~l, r, idx, is_lower, delta); | ||||
|                             ++count; | ||||
|                         } | ||||
|                     } | ||||
|                     // v <= k  k <= k2 |-  v <= k2
 | ||||
|  | @ -2984,10 +2983,12 @@ namespace smt { | |||
|                         TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", v" << v << " <= " << k2 << ", delta: " << delta << "\n"; | ||||
|                               display_row(tout, r);); | ||||
|                         assign_bound_literal(l, r, idx, is_lower, delta); | ||||
|                         ++count; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -2998,11 +2999,17 @@ namespace smt { | |||
|         antecedents ante(*this); | ||||
|         explain_bound(r, idx, is_lower, delta, ante); | ||||
| 
 | ||||
| 
 | ||||
|         TRACE("propagate_bounds", | ||||
|               ante.display(tout) << " --> "; | ||||
|               ctx.display_detailed_literal(tout, l); | ||||
|               tout << "\n";); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         TRACE("arith", tout << ctx.get_scope_level() << "\n"; | ||||
|               ctx.display_detailed_literal(tout, l) << "\n"); | ||||
| 
 | ||||
|         if (ante.lits().size() < small_lemma_size() && ante.eqs().empty()) { | ||||
|             literal_vector & lits = m_tmp_literal_vector2; | ||||
|             lits.reset(); | ||||
|  | @ -3031,6 +3038,7 @@ namespace smt { | |||
|     template<typename Ext> | ||||
|     void theory_arith<Ext>::propagate_bounds() { | ||||
|         TRACE("propagate_bounds_detail", display(tout);); | ||||
|         unsigned num_prop = 0, count = 0; | ||||
|         for (unsigned r_idx : m_to_check) { | ||||
|             row & r = m_rows[r_idx]; | ||||
|             if (r.get_base_var() != null_theory_var) { | ||||
|  | @ -3039,15 +3047,21 @@ namespace smt { | |||
|                     int upper_idx; | ||||
|                     is_row_useful_for_bound_prop(r, lower_idx, upper_idx); | ||||
| 
 | ||||
|                     ++num_prop; | ||||
|                     if (lower_idx >= 0)  | ||||
|                         imply_bound_for_monomial(r, lower_idx, true); | ||||
|                         count += imply_bound_for_monomial(r, lower_idx, true); | ||||
|                     else if (lower_idx == -1)  | ||||
|                         imply_bound_for_all_monomials(r, true); | ||||
| 
 | ||||
|                         count += imply_bound_for_all_monomials(r, true); | ||||
|                     else | ||||
|                         --num_prop; | ||||
|                      | ||||
|                     ++num_prop; | ||||
|                     if (upper_idx >= 0)  | ||||
|                         imply_bound_for_monomial(r, upper_idx, false); | ||||
|                         count += imply_bound_for_monomial(r, upper_idx, false); | ||||
|                     else if (upper_idx == -1)  | ||||
|                         imply_bound_for_all_monomials(r, false); | ||||
|                         count += imply_bound_for_all_monomials(r, false); | ||||
|                     else | ||||
|                         --num_prop; | ||||
| 
 | ||||
|                     // sneaking cheap eq detection in this loop
 | ||||
|                     propagate_cheap_eq(r_idx); | ||||
|  | @ -3063,6 +3077,7 @@ namespace smt { | |||
| #endif | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         TRACE("arith_eq", tout << "done\n";); | ||||
|         m_to_check.reset(); | ||||
|         m_in_to_check.reset(); | ||||
|  | @ -3377,7 +3392,7 @@ namespace smt { | |||
|     } | ||||
| 
 | ||||
|     template<typename Ext> | ||||
|     void theory_arith<Ext>::pop_scope_eh(unsigned num_scopes) { | ||||
|     void theory_arith<Ext>::pop_scope_eh(unsigned num_scopes) {         | ||||
|         CASSERT("arith", wf_rows()); | ||||
|         CASSERT("arith", wf_columns()); | ||||
|         CASSERT("arith", valid_row_assignment()); | ||||
|  | @ -3397,7 +3412,6 @@ namespace smt { | |||
|         restore_unassigned_atoms(s.m_unassigned_atoms_trail_lim); | ||||
|         m_asserted_bounds.shrink(s.m_asserted_bounds_lim); | ||||
|         m_asserted_qhead = s.m_asserted_qhead_old; | ||||
|         TRACE("arith_pop_scope_bug", tout << "num_vars: " << get_num_vars() << ", num_old_vars: " << get_old_num_vars(num_scopes) << "\n";); | ||||
|         restore_nl_propagated_flag(s.m_nl_propagated_lim); | ||||
|         m_nl_monomials.shrink(s.m_nl_monomials_lim); | ||||
|         del_atoms(s.m_atoms_lim); | ||||
|  |  | |||
|  | @ -514,9 +514,11 @@ namespace smt { | |||
|         // SASSERT(m_value[x_i].is_rational()); // infinitesimals are not used for integer variables
 | ||||
|         SASSERT(!m_value[x_i].is_int());     // the base variable is not assigned to an integer value.
 | ||||
| 
 | ||||
|         if (constrain_free_vars(r) || !is_gomory_cut_target(r)) { | ||||
|         bool cfv = constrain_free_vars(r); | ||||
| 
 | ||||
|         if (cfv || !is_gomory_cut_target(r)) { | ||||
|             TRACE("gomory_cut", tout << "failed to apply gomory cut:\n"; | ||||
|                   tout << "constrain_free_vars(r):  " << constrain_free_vars(r) << "\n";); | ||||
|                   tout << "constrain_free_vars(r):  " << cfv << "\n";); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|  | @ -752,6 +754,7 @@ namespace smt { | |||
|         if (!(consts / gcds).is_int()) { | ||||
|             TRACE("gcd_test", tout << "row failed the GCD test:\n"; display_row_info(tout, r);); | ||||
|             antecedents ante(*this); | ||||
|             m_stats.m_gcd_conflicts++; | ||||
|             collect_fixed_var_justifications(r, ante); | ||||
|             context & ctx         = get_context(); | ||||
|             ctx.set_conflict( | ||||
|  | @ -831,6 +834,7 @@ namespace smt { | |||
|         numeral u1 = floor(u/gcds); | ||||
|          | ||||
|         if (u1 < l1) { | ||||
|             m_stats.m_gcd_conflicts++; | ||||
|             TRACE("gcd_test", tout << "row failed the extended GCD test:\n"; display_row_info(tout, r);); | ||||
|             collect_fixed_var_justifications(r, ante); | ||||
|             context & ctx         = get_context(); | ||||
|  |  | |||
|  | @ -892,6 +892,7 @@ bool theory_arith<Ext>::propagate_linear_monomial(theory_var v) { | |||
|           } | ||||
|           tout << "\n";); | ||||
| 
 | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -2264,8 +2265,10 @@ typename theory_arith<Ext>::gb_result theory_arith<Ext>::compute_grobner(svector | |||
|             return GB_FAIL; | ||||
|         if (get_gb_eqs_and_look_for_conflict(eqs, gb)) | ||||
|             return GB_PROGRESS; | ||||
|         if (scan_for_linear(eqs, gb)) | ||||
|             return GB_NEW_EQ; | ||||
|     } | ||||
|     while(scan_for_linear(eqs, gb) && m_params.m_nl_arith_gb_perturbate &&  | ||||
|     while(m_params.m_nl_arith_gb_perturbate &&  | ||||
|           (!m_nl_gb_exhausted) && try_to_modify_eqs(eqs, gb, next_weight)); | ||||
|     return GB_FAIL; | ||||
| } | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ namespace smt { | |||
|         st.update("arith assume eqs", m_stats.m_assume_eqs); | ||||
|         st.update("arith offset eqs", m_stats.m_offset_eqs); | ||||
|         st.update("arith gcd tests", m_stats.m_gcd_tests); | ||||
|         st.update("arith gcd conflicts", m_stats.m_gcd_conflicts); | ||||
|         st.update("arith ineq splits", m_stats.m_branches); | ||||
|         st.update("arith gomory cuts", m_stats.m_gomory_cuts); | ||||
|         st.update("arith branch int", m_stats.m_branch_infeasible_int); | ||||
|  | @ -82,8 +83,9 @@ namespace smt { | |||
| 
 | ||||
|     template<typename Ext> | ||||
|     void theory_arith<Ext>::display_row(std::ostream & out, row const & r, bool compact) const { | ||||
|          | ||||
|         out << "(v" << r.get_base_var() << ") : "; | ||||
| 
 | ||||
|         column const & c   = m_columns[r.get_base_var()]; | ||||
|         out << "(v" << r.get_base_var() << " r" << c[0].m_row_id << ") : "; | ||||
|         bool first = true; | ||||
|         for (auto const& e : r) { | ||||
|             if (!e.is_dead()) { | ||||
|  |  | |||
|  | @ -252,6 +252,8 @@ namespace smt { | |||
|         else if (m.is_lambda_def(n->get_decl())) { | ||||
|             instantiate_default_lambda_def_axiom(n); | ||||
|             d->m_lambdas.push_back(n); | ||||
|             m_lambdas.push_back(n); | ||||
|             ctx.push_trail(push_back_vector(m_lambdas)); | ||||
|         } | ||||
|         return r; | ||||
|     } | ||||
|  | @ -830,6 +832,12 @@ namespace smt { | |||
|                     return true; | ||||
|                 } | ||||
|         } | ||||
|         for (enode* n : m_lambdas)  | ||||
|             for (enode* p : n->get_parents()) | ||||
|                 if (!is_default(p) && !ctx.is_beta_redex(p, n)) { | ||||
|                     TRACE("array", tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n"); | ||||
|                     return true; | ||||
|                 } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -86,6 +86,7 @@ namespace smt { | |||
|         bool has_unitary_domain(app* array_term); | ||||
|         std::pair<app*,func_decl*> mk_epsilon(sort* s); | ||||
|         enode_vector m_as_array; | ||||
|         enode_vector m_lambdas; | ||||
|         bool has_non_beta_as_array(); | ||||
| 
 | ||||
|         bool instantiate_select_const_axiom(enode* select, enode* cnst); | ||||
|  |  | |||
|  | @ -811,6 +811,7 @@ namespace smt { | |||
|         init_bits(e, bits);                                                                 | ||||
|     } | ||||
| 
 | ||||
|     MK_UNARY(internalize_neg,       mk_neg); | ||||
|     MK_UNARY(internalize_not,       mk_not); | ||||
|     MK_UNARY(internalize_redand,    mk_redand); | ||||
|     MK_UNARY(internalize_redor,     mk_redor); | ||||
|  | @ -895,6 +896,7 @@ namespace smt { | |||
|         } | ||||
|         switch (term->get_decl_kind()) { | ||||
|         case OP_BV_NUM:         internalize_num(term); return true; | ||||
|         case OP_BNEG:           internalize_neg(term); return true; | ||||
|         case OP_BADD:           internalize_add(term); return true; | ||||
|         case OP_BSUB:           internalize_sub(term); return true; | ||||
|         case OP_BMUL:           internalize_mul(term); return true; | ||||
|  | @ -944,6 +946,9 @@ namespace smt { | |||
|                 internalize_bv2int(term);  | ||||
|             } | ||||
|             return params().m_bv_enable_int2bv2int; | ||||
|         case OP_BSREM:        return false; | ||||
|         case OP_BUREM:        return false; | ||||
|         case OP_BSMOD:        return false; | ||||
|         default: | ||||
|             TRACE("bv_op", tout << "unsupported operator: " << mk_ll_pp(term, m) << "\n";); | ||||
|             UNREACHABLE(); | ||||
|  |  | |||
|  | @ -196,6 +196,7 @@ namespace smt { | |||
|         void internalize_ext_rotate_right(app * n); | ||||
|         void internalize_and(app * n); | ||||
|         void internalize_or(app * n); | ||||
|         void internalize_neg(app * n); | ||||
|         void internalize_not(app * n); | ||||
|         void internalize_nand(app * n); | ||||
|         void internalize_nor(app * n); | ||||
|  |  | |||
|  | @ -19,9 +19,6 @@ | |||
| 
 | ||||
|   --*/ | ||||
| #include "util/stopwatch.h" | ||||
| #include "math/lp/lp_solver.h" | ||||
| #include "math/lp/lp_primal_simplex.h" | ||||
| #include "math/lp/lp_dual_simplex.h" | ||||
| #include "math/lp/indexed_value.h" | ||||
| #include "math/lp/lar_solver.h" | ||||
| #include "math/lp/nla_solver.h" | ||||
|  | @ -48,6 +45,7 @@ | |||
| #include "ast/ast_ll_pp.h" | ||||
| #include "util/cancel_eh.h" | ||||
| #include "util/scoped_timer.h" | ||||
| #include "util/distribution.h" | ||||
| 
 | ||||
| typedef lp::var_index lpvar; | ||||
| 
 | ||||
|  | @ -318,11 +316,13 @@ class theory_lra::imp { | |||
|         else if (a.is_idiv(n, x, y)) {                 | ||||
|             e = a.mk_idiv0(x, y); | ||||
|         } | ||||
|         else if (a.is_rem(n, x, y)) {                 | ||||
|             e = a.mk_rem0(x, y); | ||||
|         else if (a.is_rem(n, x, y)) { | ||||
|             n = a.mk_rem(x, a.mk_int(0)); | ||||
|             e = a.mk_rem0(x, a.mk_int(0)); | ||||
|         } | ||||
|         else if (a.is_mod(n, x, y)) {                 | ||||
|             e = a.mk_mod0(x, y); | ||||
|             n = a.mk_mod(x, a.mk_int(0)); | ||||
|             e = a.mk_mod0(x, a.mk_int(0)); | ||||
|         } | ||||
|         else if (a.is_power(n, x, y)) {                 | ||||
|             e = a.mk_power0(x, y); | ||||
|  | @ -439,6 +439,9 @@ class theory_lra::imp { | |||
|                     if (ctx().relevancy()) ctx().add_relevancy_dependency(n, mod); | ||||
|                     if (m_nla && !a.is_numeral(n2)) { | ||||
|                         // shortcut to create non-linear division axioms.
 | ||||
|                         internalize_term(to_app(n)); | ||||
|                         internalize_term(to_app(n1)); | ||||
|                         internalize_term(to_app(n2)); | ||||
|                         theory_var q = mk_var(n); | ||||
|                         theory_var x = mk_var(n1); | ||||
|                         theory_var y = mk_var(n2); | ||||
|  | @ -446,6 +449,9 @@ class theory_lra::imp { | |||
|                     } | ||||
|                     if (a.is_numeral(n2) && a.is_bounded(n1)) { | ||||
|                         ensure_nla(); | ||||
|                         internalize_term(to_app(n)); | ||||
|                         internalize_term(to_app(n1)); | ||||
|                         internalize_term(to_app(n2)); | ||||
|                         theory_var q = mk_var(n); | ||||
|                         theory_var x = mk_var(n1); | ||||
|                         theory_var y = mk_var(n2); | ||||
|  | @ -466,7 +472,7 @@ class theory_lra::imp { | |||
|                     st.to_ensure_var().push_back(n1); | ||||
|                     st.to_ensure_var().push_back(n2); | ||||
|                 } | ||||
|                 else if (a.is_idiv0(n, n1, n2) || a.is_mod0(n, n1, n2) || a.is_rem0(n, n1, n2)) { | ||||
|                 else if (a.is_idiv0(n, n1, n2) || a.is_mod0(n, n1, n2)) { | ||||
|                     st.to_ensure_var().push_back(n1); | ||||
|                     st.to_ensure_var().push_back(n2);        | ||||
|                 } | ||||
|  | @ -814,12 +820,13 @@ class theory_lra::imp { | |||
|     } | ||||
| 
 | ||||
|     lpvar get_lpvar(expr* e) { | ||||
|         return get_lpvar(get_enode(e)); | ||||
|         theory_var v = mk_var(e); | ||||
|         m_solver->register_existing_terms(); | ||||
|         return register_theory_var_in_lar_solver(v); | ||||
|     } | ||||
| 
 | ||||
|     lpvar get_lpvar(enode* n)  { | ||||
|         ensure_column(n); | ||||
|         return n ? get_lpvar(n->get_th_var(get_id())) : lp::null_lpvar; | ||||
|         return get_lpvar(n->get_expr()); | ||||
|     } | ||||
| 
 | ||||
|     lpvar get_lpvar(theory_var v) const { | ||||
|  | @ -1134,6 +1141,17 @@ public: | |||
|             expr_ref zero(a.mk_real(0), m); | ||||
|             mk_axiom(~mk_literal(a.mk_le(p, zero))); | ||||
|         } | ||||
|         bool can_be_underspecified = false; | ||||
|         if (a.is_numeral(x, r) && r == 0 && (!a.is_numeral(y, r) || r == 0)) | ||||
|             can_be_underspecified = true; | ||||
|         if (!a.is_extended_numeral(x, r) &&  | ||||
|             !a.is_extended_numeral(y, r))  | ||||
|             can_be_underspecified = true; | ||||
|         if (can_be_underspecified) { | ||||
|             literal lit = th.mk_eq(p, a.mk_power0(x, y), false); | ||||
|             ctx().mark_as_relevant(lit); | ||||
|             ctx().assign(lit, nullptr); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //  n < 0 || rem(a, n) =  mod(a, n)
 | ||||
|  | @ -1299,7 +1317,6 @@ public: | |||
|             expr_ref abs_q(m.mk_ite(a.mk_ge(q, zero), q, a.mk_uminus(q)), m); | ||||
|             expr_ref mone(a.mk_int(-1), m); | ||||
|             expr_ref modmq(a.mk_sub(mod, abs_q), m); | ||||
|             ctx().get_rewriter()(modmq); | ||||
|             literal eqz = mk_literal(m.mk_eq(q, zero)); | ||||
|             literal mod_ge_0 = mk_literal(a.mk_ge(mod, zero)); | ||||
|             literal mod_lt_q = mk_literal(a.mk_le(modmq, mone)); | ||||
|  | @ -1514,21 +1531,23 @@ public: | |||
|             }  | ||||
|         } | ||||
|         TRACE("arith",  | ||||
|               for (theory_var v = 0; v < sz; ++v) { | ||||
|                   if (th.is_relevant_and_shared(get_enode(v))) {  | ||||
|               for (theory_var v = 0; v < sz; ++v)  | ||||
|                   if (th.is_relevant_and_shared(get_enode(v)))   | ||||
|                       tout << "v" << v << " "; | ||||
|                   } | ||||
|               } | ||||
|               tout << "\n"; ); | ||||
|         if (!vars.empty()) { | ||||
|             lp().random_update(vars.size(), vars.data()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool assume_eqs() {         | ||||
|     bool assume_eqs() { | ||||
|         if (delayed_assume_eqs()) | ||||
|             return true; | ||||
| 
 | ||||
|         TRACE("arith", display(tout);); | ||||
|         random_update(); | ||||
|         m_model_eqs.reset(); | ||||
|                          | ||||
|         theory_var sz = static_cast<theory_var>(th.get_num_vars());             | ||||
|         unsigned old_sz = m_assume_eq_candidates.size(); | ||||
|         unsigned num_candidates = 0; | ||||
|  | @ -1577,8 +1596,10 @@ public: | |||
|             CTRACE("arith",  | ||||
|                    is_eq(v1, v2) && n1->get_root() != n2->get_root(), | ||||
|                    tout << "assuming eq: v" << v1 << " = v" << v2 << "\n";); | ||||
|             if (is_eq(v1, v2) &&  n1->get_root() != n2->get_root() && th.assume_eq(n1, n2))  | ||||
|             if (is_eq(v1, v2) &&  n1->get_root() != n2->get_root() && th.assume_eq(n1, n2)) { | ||||
|                 ++m_stats.m_assume_eqs; | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | @ -1596,8 +1617,12 @@ public: | |||
| 
 | ||||
|     final_check_status eval_power(expr* e) { | ||||
|         expr* x, * y; | ||||
|         rational r; | ||||
|         VERIFY(a.is_power(e, x, y)); | ||||
| 
 | ||||
|         if (a.is_numeral(x, r) && r == 0 && a.is_numeral(y, r) && r == 0) | ||||
|             return FC_DONE; | ||||
|         if (!m_nla) | ||||
|             return FC_GIVEUP; | ||||
|         switch (m_nla->check_power(get_lpvar(e), get_lpvar(x), get_lpvar(y), m_nla_lemma_vector)) { | ||||
|         case l_true: | ||||
|             return FC_DONE; | ||||
|  | @ -1616,9 +1641,14 @@ public: | |||
|     final_check_status eval_unsupported(expr* e) { | ||||
|         if (a.is_power(e))  | ||||
|             return eval_power(e);         | ||||
|         if (a.is_power0(e))  | ||||
|             return FC_DONE; | ||||
|         return FC_GIVEUP; | ||||
|     } | ||||
| 
 | ||||
|     unsigned m_final_check_idx = 0; | ||||
|     distribution m_dist { 0 }; | ||||
|      | ||||
|     final_check_status final_check_eh() { | ||||
|         if (propagate_core()) | ||||
|             return FC_CONTINUE; | ||||
|  | @ -1629,53 +1659,95 @@ public: | |||
|         if (!lp().is_feasible() || lp().has_changed_columns()) { | ||||
|             is_sat = make_feasible(); | ||||
|         } | ||||
|         bool giveup = false; | ||||
|         final_check_status st = FC_DONE; | ||||
| 
 | ||||
|         m_final_check_idx = 0; // remove to experiment.
 | ||||
|         unsigned old_idx = m_final_check_idx; | ||||
|         switch (is_sat) { | ||||
|         case l_true: | ||||
|             TRACE("arith", display(tout)); | ||||
| 
 | ||||
|             switch (check_lia()) { | ||||
|             case l_true: | ||||
|                 break; | ||||
|             case l_false: | ||||
|                 return FC_CONTINUE; | ||||
|             case l_undef: | ||||
|                 TRACE("arith", tout << "check-lia giveup\n";); | ||||
|                 if (ctx().get_fparams().m_arith_ignore_int) | ||||
|             // if (lp().has_fixed_at_bound()) // explain and propagate.
 | ||||
| 
 | ||||
| #if 0 | ||||
|             m_dist.reset(); | ||||
|             m_dist.push(0, 1); | ||||
|             m_dist.push(1, 1); | ||||
|             m_dist.push(2, 1); | ||||
| 
 | ||||
|             for (auto idx : m_dist) { | ||||
|                 if (!m.inc()) | ||||
|                     return FC_GIVEUP; | ||||
|                 st = FC_CONTINUE; | ||||
|                 break; | ||||
| 
 | ||||
|                 switch (idx) { | ||||
|                 case 0: | ||||
|                     if (assume_eqs())  | ||||
|                         st = FC_CONTINUE;                     | ||||
|                     break; | ||||
|                 case 1: | ||||
|                     st = check_nla(); | ||||
|                     break; | ||||
|                 case 2: | ||||
|                     st = check_lia(); | ||||
|                     break; | ||||
|                 default: | ||||
|                     UNREACHABLE(); | ||||
|                     break;                     | ||||
|                 } | ||||
|                 switch (st) { | ||||
|                 case FC_DONE: | ||||
|                     break; | ||||
|                 case FC_CONTINUE: | ||||
|                     return st; | ||||
|                 case FC_GIVEUP: | ||||
|                     giveup = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             switch (check_nla()) { | ||||
|             case l_true: | ||||
|                 break; | ||||
|             case l_false: | ||||
|                 return FC_CONTINUE; | ||||
|             case l_undef: | ||||
|                 TRACE("arith", tout << "check-nra giveup\n";); | ||||
|                 st = FC_GIVEUP; | ||||
|                 break; | ||||
|             } | ||||
| #else | ||||
|              | ||||
|             if (delayed_assume_eqs()) { | ||||
|                 ++m_stats.m_assume_eqs; | ||||
|                 return FC_CONTINUE; | ||||
|             } | ||||
|             if (assume_eqs()) { | ||||
|                 ++m_stats.m_assume_eqs; | ||||
|                 return FC_CONTINUE; | ||||
|             do { | ||||
|                 if (!m.inc()) | ||||
|                     return FC_GIVEUP; | ||||
|                  | ||||
|                 switch (m_final_check_idx) { | ||||
|                 case 0: | ||||
|                     if (assume_eqs())  | ||||
|                         st = FC_CONTINUE;                     | ||||
|                     break; | ||||
|                 case 1: | ||||
|                     st = check_lia(); | ||||
|                     break; | ||||
|                 case 2: | ||||
|                     st = check_nla(); | ||||
|                     break; | ||||
|                 } | ||||
|                 m_final_check_idx = (m_final_check_idx + 1) % 3; | ||||
|                 switch (st) { | ||||
|                 case FC_DONE: | ||||
|                     break; | ||||
|                 case FC_CONTINUE: | ||||
|                     return st; | ||||
|                 case FC_GIVEUP: | ||||
|                     giveup = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             while (old_idx != m_final_check_idx); | ||||
| #endif | ||||
| 
 | ||||
|             if (giveup) | ||||
|                 return FC_GIVEUP; | ||||
|             for (expr* e : m_not_handled) { | ||||
|                 if (!ctx().is_relevant(e)) | ||||
|                     continue; | ||||
|                 st = FC_DONE; | ||||
|                 switch (eval_unsupported(e)) { | ||||
|                 case FC_CONTINUE: | ||||
|                     st = FC_CONTINUE; | ||||
|                     break; | ||||
|                 case FC_GIVEUP: | ||||
|                     TRACE("arith", tout << "give up " << mk_pp(e, m) << "\n"); | ||||
|                     if (st != FC_CONTINUE)  | ||||
|                         st = FC_GIVEUP; | ||||
|                     break; | ||||
|  | @ -1894,21 +1966,19 @@ public: | |||
|         visitor.display_asserts(out, fmls, true); | ||||
|         out << "(check-sat)\n";             | ||||
|     } | ||||
| 
 | ||||
|     lbool check_lia() { | ||||
|      | ||||
|     final_check_status check_lia() { | ||||
|         TRACE("arith",); | ||||
|         if (!m.inc()) { | ||||
|             TRACE("arith", tout << "canceled\n";); | ||||
|             return l_undef; | ||||
|             return FC_CONTINUE; | ||||
|         } | ||||
|         lbool lia_check = l_undef; | ||||
|         auto cr = m_lia->check(&m_explanation); | ||||
|         if (cr != lp::lia_move::sat && ctx().get_fparams().m_arith_ignore_int)  | ||||
|             return l_undef; | ||||
|             return FC_GIVEUP; | ||||
| 
 | ||||
|         switch (cr) { | ||||
|         case lp::lia_move::sat: | ||||
|             lia_check = l_true; | ||||
|             break; | ||||
| 
 | ||||
|         case lp::lia_move::branch: { | ||||
|  | @ -1931,13 +2001,12 @@ public: | |||
|             // TBD: ctx().force_phase(ctx().get_literal(b));
 | ||||
|             // at this point we have a new unassigned atom that the 
 | ||||
|             // SAT core assigns a value to
 | ||||
|             lia_check = l_false; | ||||
|             ++m_stats.m_branch; | ||||
|             break; | ||||
|             return FC_CONTINUE; | ||||
|         } | ||||
|         case lp::lia_move::cut: { | ||||
|             if (ctx().get_fparams().m_arith_ignore_int)  | ||||
|                 return l_undef; | ||||
|                 return FC_GIVEUP; | ||||
|             TRACE("arith", tout << "cut\n";); | ||||
|             ++m_stats.m_gomory_cuts; | ||||
|             // m_explanation implies term <= k
 | ||||
|  | @ -1959,28 +2028,28 @@ public: | |||
|                   ctx().display_lemma_as_smt_problem(tout << "new cut:\n", m_core.size(), m_core.data(), m_eqs.size(), m_eqs.data(), lit); | ||||
|                   display(tout);); | ||||
|             assign(lit, m_core, m_eqs, m_params); | ||||
|             lia_check = l_false; | ||||
|             break; | ||||
|             return FC_CONTINUE; | ||||
|         } | ||||
|         case lp::lia_move::conflict: | ||||
|             TRACE("arith", tout << "conflict\n";); | ||||
|             // ex contains unsat core
 | ||||
|             set_conflict(); | ||||
|             return l_false; | ||||
|             return FC_CONTINUE; | ||||
|         case lp::lia_move::undef: | ||||
|             TRACE("arith", tout << "lia undef\n";); | ||||
|             lia_check = l_undef; | ||||
|             break; | ||||
|             return FC_CONTINUE; | ||||
|         case lp::lia_move::continue_with_check: | ||||
|             lia_check = l_undef; | ||||
|             break; | ||||
|             return FC_CONTINUE; | ||||
|         default: | ||||
|             UNREACHABLE(); | ||||
|         } | ||||
|         if (lia_check != l_false && !check_idiv_bounds())  | ||||
|             return l_false; | ||||
|         if (!check_idiv_bounds()) | ||||
|             return FC_CONTINUE; | ||||
| 
 | ||||
|         return lia_check; | ||||
|         if (assume_eqs()) | ||||
|             return FC_CONTINUE; | ||||
|          | ||||
|         return FC_DONE; | ||||
|     } | ||||
| 
 | ||||
|     nla::lemma m_lemma; | ||||
|  | @ -2017,36 +2086,31 @@ public: | |||
|         set_conflict_or_lemma(core, false); | ||||
|     } | ||||
|      | ||||
|     lbool check_nla_continue() { | ||||
|     final_check_status check_nla_continue() { | ||||
|         m_a1 = nullptr; m_a2 = nullptr; | ||||
|         lbool r = m_nla->check(m_nla_lemma_vector); | ||||
|         switch (r) { | ||||
|         case l_false: { | ||||
|         case l_false:  | ||||
|             for (const nla::lemma & l : m_nla_lemma_vector)  | ||||
|                 false_case_of_check_nla(l);             | ||||
|             break; | ||||
|         } | ||||
|                 false_case_of_check_nla(l); | ||||
|             return FC_CONTINUE; | ||||
|         case l_true: | ||||
|             if (assume_eqs()) { | ||||
|                 return l_false; | ||||
|             } | ||||
|             break; | ||||
|         case l_undef: | ||||
|             break; | ||||
|             return assume_eqs()? FC_CONTINUE: FC_DONE; | ||||
|         default: | ||||
|             return FC_GIVEUP; | ||||
|         } | ||||
|         return r; | ||||
|     } | ||||
| 
 | ||||
|     lbool check_nla() { | ||||
|     final_check_status check_nla() { | ||||
|         if (!m.inc()) { | ||||
|             TRACE("arith", tout << "canceled\n";); | ||||
|             return l_undef; | ||||
|             return FC_GIVEUP;             | ||||
|         } | ||||
|         CTRACE("arith",!m_nla, tout << "no nla\n";); | ||||
|         if (!m_nla)             | ||||
|             return l_true;         | ||||
|             return FC_DONE;         | ||||
|         if (!m_nla->need_check())  | ||||
|             return l_true; | ||||
|             return FC_DONE; | ||||
|         return check_nla_continue(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -2168,7 +2232,6 @@ public: | |||
|         set_evidence(j, m_core, m_eqs); | ||||
|         m_explanation.add_pair(j, v); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     void propagate_bounds_with_lp_solver() { | ||||
|         if (!should_propagate())  | ||||
|  | @ -2182,13 +2245,16 @@ public: | |||
| 
 | ||||
|         if (is_infeasible()) { | ||||
|             get_infeasibility_explanation_and_set_conflict(); | ||||
|             // verbose_stream() << "unsat\n";
 | ||||
|         } | ||||
|         else { | ||||
|             unsigned count = 0, prop = 0; | ||||
|             for (auto& ib : m_bp.ibounds()) { | ||||
|                 m.inc(); | ||||
|                 if (ctx().inconsistent()) | ||||
|                     break; | ||||
|                 propagate_lp_solver_bound(ib); | ||||
|                 ++prop; | ||||
|                 count += propagate_lp_solver_bound(ib); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -2209,12 +2275,14 @@ public: | |||
| 
 | ||||
|         return false; | ||||
|     } | ||||
|     void propagate_lp_solver_bound(const lp::implied_bound& be) { | ||||
| 
 | ||||
| #if 0 | ||||
|     unsigned propagate_lp_solver_bound_dry_run(const lp::implied_bound& be) { | ||||
|         lpvar vi = be.m_j; | ||||
|         theory_var v = lp().local_to_external(vi); | ||||
| 
 | ||||
|         if (v == null_theory_var)  | ||||
|             return; | ||||
|             return 0; | ||||
| 
 | ||||
|         TRACE("arith", tout << "v" << v << " " << be.kind() << " " << be.m_bound << "\n";); | ||||
| 
 | ||||
|  | @ -2222,20 +2290,58 @@ public: | |||
|              | ||||
|         if (m_unassigned_bounds[v] == 0 && !should_refine_bounds()) { | ||||
|             TRACE("arith", tout << "return\n";); | ||||
|             return; | ||||
|             return 0; | ||||
|         } | ||||
|         lp_bounds const& bounds = m_bounds[v]; | ||||
|         bool first = true; | ||||
|         unsigned count = 0; | ||||
|         for (unsigned i = 0; i < bounds.size(); ++i) { | ||||
|             api_bound* b = bounds[i]; | ||||
|             if (ctx().get_assignment(b->get_lit()) != l_undef) { | ||||
|             if (ctx().get_assignment(b->get_lit()) != l_undef)  | ||||
|                 continue; | ||||
|             } | ||||
|             literal lit = is_bound_implied(be.kind(), be.m_bound, *b); | ||||
|             if (lit == null_literal) { | ||||
|             if (lit == null_literal)  | ||||
|                 continue; | ||||
|             } | ||||
|             TRACE("arith", tout << lit << " bound: " << *b << " first: " << first << "\n";); | ||||
|             ctx().display_literal_verbose(verbose_stream() << "miss ", lit) << "\n"; | ||||
|             display(verbose_stream()); | ||||
|             TRACE("arith", ctx().display_literal_verbose(tout << "miss ", lit) << "\n"); | ||||
|             exit(0); | ||||
|              | ||||
|             ++count; | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
| #endif | ||||
|      | ||||
|     unsigned propagate_lp_solver_bound(const lp::implied_bound& be) { | ||||
|         lpvar vi = be.m_j; | ||||
|         theory_var v = lp().local_to_external(vi); | ||||
| 
 | ||||
|         if (v == null_theory_var)  | ||||
|             return 0; | ||||
| 
 | ||||
|         TRACE("arith", tout << "v" << v << " " << be.kind() << " " << be.m_bound << "\n";); | ||||
| 
 | ||||
|         reserve_bounds(v); | ||||
|              | ||||
|         if (m_unassigned_bounds[v] == 0 && !should_refine_bounds()) { | ||||
|             TRACE("arith", tout << "return\n";); | ||||
|             return 0; | ||||
|         } | ||||
|         lp_bounds const& bounds = m_bounds[v]; | ||||
|         bool first = true; | ||||
|         unsigned count = 0; | ||||
|         for (unsigned i = 0; i < bounds.size(); ++i) { | ||||
|             api_bound* b = bounds[i]; | ||||
|             if (ctx().get_assignment(b->get_lit()) != l_undef)  | ||||
|                 continue; | ||||
|             literal lit = is_bound_implied(be.kind(), be.m_bound, *b); | ||||
|             if (lit == null_literal)  | ||||
|                 continue; | ||||
|             TRACE("arith", tout << lit << " bound: " << *b << " first: " << first << "\n";); | ||||
| 
 | ||||
|             ++count; | ||||
| 
 | ||||
|             lp().settings().stats().m_num_of_implied_bounds ++; | ||||
|             if (first) { | ||||
|  | @ -2254,6 +2360,8 @@ public: | |||
|                   display_evidence(tout, m_explanation); | ||||
|                   lp().print_implied_bound(be, tout); | ||||
|                   ); | ||||
| 
 | ||||
| 
 | ||||
|             DEBUG_CODE( | ||||
|                 for (auto& lit : m_core) { | ||||
|                     VERIFY(ctx().get_assignment(lit) == l_true); | ||||
|  | @ -2263,7 +2371,9 @@ public: | |||
|         } | ||||
|          | ||||
|         if (should_refine_bounds() && first)  | ||||
|             refine_bound(v, be);         | ||||
|             refine_bound(v, be); | ||||
| 
 | ||||
|         return count; | ||||
|     } | ||||
| 
 | ||||
|     void refine_bound(theory_var v, const lp::implied_bound& be) { | ||||
|  | @ -2887,7 +2997,7 @@ public: | |||
|             propagate_eqs(b.tv(), ci, k, b, value.get_rational()); | ||||
|         } | ||||
| #if 0 | ||||
|         if (propagation_mode() != BP_NONE) | ||||
|         if (should_propagate()) | ||||
|             lp().mark_rows_for_bound_prop(b.tv().id()); | ||||
| #endif | ||||
|     } | ||||
|  | @ -3125,7 +3235,7 @@ public: | |||
|             return l_false; | ||||
|         TRACE("arith", tout << "status treated as inconclusive: " << status << "\n";); | ||||
|             // TENTATIVE_UNBOUNDED, UNBOUNDED, TENTATIVE_DUAL_UNBOUNDED, DUAL_UNBOUNDED, 
 | ||||
|             // FLOATING_POINT_ERROR, TIME_EXAUSTED, EMPTY, UNSTABLE
 | ||||
|             // TIME_EXAUSTED, EMPTY, UNSTABLE
 | ||||
|         return l_undef; | ||||
|     } | ||||
|   | ||||
|  | @ -3908,5 +4018,6 @@ void theory_lra::setup() { | |||
| } | ||||
| template  class lp::lp_bound_propagator<smt::theory_lra::imp>; | ||||
| template void lp::lar_solver::propagate_bounds_for_touched_rows<smt::theory_lra::imp>(lp::lp_bound_propagator<smt::theory_lra::imp>&); | ||||
| template void lp::lar_solver::check_missed_propagations<smt::theory_lra::imp>(lp::lp_bound_propagator<smt::theory_lra::imp>&); | ||||
| template void lp::lar_solver::explain_implied_bound<smt::theory_lra::imp>(const lp::implied_bound&, lp::lp_bound_propagator<smt::theory_lra::imp>&); | ||||
| template void lp::lar_solver::calculate_implied_bounds_for_row<smt::theory_lra::imp>(unsigned int, lp::lp_bound_propagator<smt::theory_lra::imp>&); | ||||
| template unsigned lp::lar_solver::calculate_implied_bounds_for_row<smt::theory_lra::imp>(unsigned int, lp::lp_bound_propagator<smt::theory_lra::imp>&); | ||||
|  |  | |||
|  | @ -1604,7 +1604,7 @@ namespace smt { | |||
|             std::cout << B << "\n"; | ||||
|         } | ||||
| #endif | ||||
|         SASSERT(is_sat != l_true); | ||||
|         VERIFY(is_sat != l_true); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -71,7 +71,7 @@ namespace smt { | |||
|         ensure_var(v1); | ||||
|         ensure_var(v2); | ||||
|         literal_vector ls; | ||||
|         ls.push_back(l); | ||||
|         ls.push_back(l);         | ||||
|         return m_graph.add_non_strict_edge(v1, v2, ls) && m_graph.add_non_strict_edge(v2, v1, ls); | ||||
|     } | ||||
| 
 | ||||
|  | @ -130,6 +130,7 @@ namespace smt { | |||
|     } | ||||
| 
 | ||||
|     bool theory_special_relations::internalize_term(app * term) { | ||||
|         verbose_stream() << mk_pp(term, m) << "\n"; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|  | @ -156,9 +157,8 @@ namespace smt { | |||
|     } | ||||
| 
 | ||||
|     theory_var theory_special_relations::mk_var(expr* e) { | ||||
|         if (!ctx.e_internalized(e)) { | ||||
|         if (!ctx.e_internalized(e))  | ||||
|             ctx.internalize(e, false); | ||||
|         } | ||||
|         enode * n = ctx.get_enode(e); | ||||
|         theory_var v = n->get_th_var(get_id()); | ||||
|         if (null_theory_var == v) { | ||||
|  | @ -405,6 +405,12 @@ namespace smt { | |||
|                 TRACE("special_relations", tout << "already: " << a.v2() << " <= " << a.v1() << "\n";); | ||||
|                 continue; | ||||
|             } | ||||
|             if (a.v1() == a.v2()) { | ||||
|                 r.m_explanation.reset(); | ||||
|                 r.m_explanation.push_back(a.explanation()); | ||||
|                 set_conflict(r);                 | ||||
|                 return l_false; | ||||
|             } | ||||
|             // the nodes visited from v1 become target for v2
 | ||||
|             if (r.m_graph.reachable(a.v2(), visited, target, w)) { | ||||
|                 //
 | ||||
|  | @ -582,18 +588,18 @@ namespace smt { | |||
|     lbool theory_special_relations::final_check_po(relation& r) { | ||||
|         for (atom* ap : r.m_asserted_atoms) { | ||||
|             atom& a = *ap; | ||||
|             if (!a.phase() && r.m_uf.find(a.v1()) == r.m_uf.find(a.v2())) { | ||||
|                 // v1 !-> v2
 | ||||
|                 // find v1 -> v3 -> v4 -> v2 path
 | ||||
|                 r.m_explanation.reset(); | ||||
|                 unsigned timestamp = r.m_graph.get_timestamp(); | ||||
|                 bool found_path = r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); | ||||
|                 if (found_path) { | ||||
|                     TRACE("special_relations", tout << "check po conflict\n";); | ||||
|                     r.m_explanation.push_back(a.explanation()); | ||||
|                     set_conflict(r); | ||||
|                     return l_false; | ||||
|                 } | ||||
|             if (a.phase()) | ||||
|                 continue; | ||||
|             // v1 !-> v2
 | ||||
|             // find v1 -> v3 -> v4 -> v2 path
 | ||||
|             r.m_explanation.reset(); | ||||
|             unsigned timestamp = r.m_graph.get_timestamp(); | ||||
|             bool found_path = a.v1() == a.v2() || r.m_graph.find_shortest_reachable_path(a.v1(), a.v2(), timestamp, r); | ||||
|             if (found_path) { | ||||
|                 TRACE("special_relations", tout << "check po conflict\n";); | ||||
|                 r.m_explanation.push_back(a.explanation()); | ||||
|                 set_conflict(r); | ||||
|                 return l_false; | ||||
|             } | ||||
|         } | ||||
|         return l_true; | ||||
|  | @ -601,9 +607,8 @@ namespace smt { | |||
| 
 | ||||
|     void theory_special_relations::propagate() { | ||||
|         if (m_can_propagate) { | ||||
|             for (auto const& kv : m_relations) { | ||||
|             for (auto const& kv : m_relations)  | ||||
|                 propagate(*kv.m_value); | ||||
|             } | ||||
|             m_can_propagate = false; | ||||
|         } | ||||
|     } | ||||
|  | @ -1124,12 +1129,12 @@ namespace smt { | |||
|     } | ||||
| 
 | ||||
|     void theory_special_relations::display(std::ostream & out) const { | ||||
|         if (m_relations.empty()) return; | ||||
|         if (m_relations.empty()) | ||||
|             return; | ||||
|         out << "Theory Special Relations\n"; | ||||
|         display_var2enode(out); | ||||
|         for (auto const& kv : m_relations) { | ||||
|         for (auto const& kv : m_relations)  | ||||
|             kv.m_value->display(*this, out); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void theory_special_relations::collect_asserted_po_atoms(vector<std::pair<bool_var, bool>>& atoms) const { | ||||
|  |  | |||
|  | @ -92,6 +92,9 @@ void theory_user_propagator::propagate_cb( | |||
| 
 | ||||
|     expr_ref _conseq(conseq, m); | ||||
|     ctx.get_rewriter()(conseq, _conseq); | ||||
|     if (!ctx.get_manager().is_true(_conseq) && !ctx.get_manager().is_false(_conseq)) | ||||
|         ctx.mark_as_relevant((expr*)_conseq); | ||||
| 
 | ||||
|     if (ctx.lit_internalized(_conseq) && ctx.get_assignment(ctx.get_literal(_conseq)) == l_true)  | ||||
|         return; | ||||
|     m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, _conseq));     | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue