mirror of
https://github.com/Z3Prover/z3
synced 2026-08-09 23:42:21 +00:00
Fix linprobe perf regression and refactor the probe into a reusable combinator
Perf: remove combined_solver::try_linprobe
It ran the *non-incremental* solver1 only when m_inc_mode or assumptions were
present, i.e. exactly the modes where combined_solver mandates solver2, so
solver1 re-preprocessed the whole assertion stack on every check-sat. Its
wall-clock scoped_timer did not bound that work (linprobe_timeout=1 was slower
than 100), it consumed the caller's rlimit and so changed verdicts, and it made
rlimit-based runs non-deterministic: the same binary on
queries-FStar.UInt128.smt2 returned different unsat counts depending on whether
stdout was redirected or piped.
On the F* ulib queries this is a 3.99x aggregate speedup (224.35s -> 56.29s over
10 files; UInt128 80.2s -> 20.7s, BV 19.9s -> 1.7s) with verdicts identical to
master. The feature itself is unaffected: it lives in the smt tactic, which is
what arith.nl.linprobe documents, and solver1 reaches it via mk_smt_tactic.
Params: declare arith.nl.linprobe_mode and arith.nl.linprobe_timeout
arith.nl.linprobe_mode was read by raw string lookup in four places but never
declared, so it was invisible to -pm and rejected by set-option. The 100ms
timeout was hard-coded twice, in two different libraries.
Refactor
- Move the generic part of linprobe_tactic to tactical.{h,cpp} beside or_else as
or_else_no_user_propagate(); the class was an or_else reimplementation whose
only new behaviour was bypassing t1 once user propagators are registered.
smt_tactic.cpp shrinks from 231 to 100 lines.
- unary_tactical: forward the ten missing user_propagate_* methods so wrappers
such as using_params do not drop propagator support.
- nla_core: drop the cached m_linprobe flag and use params().arith_nl_linprobe_mode()
through a new core::linprobe_mode(), matching how every other nla parameter is read.
- theory_lra: replace a per-final-check string parameter lookup with
m_nla->linprobe_mode().
- mk_smt_tactic_using: restore mk_smt_tactic_core_using as the fallback so
parallel.enable keeps selecting mk_parallel_smt_tactic.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
98bb6245ca
commit
36738a0394
10 changed files with 180 additions and 203 deletions
|
|
@ -22,7 +22,6 @@ namespace nla {
|
|||
if (add_lemma())
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool monomial_bounds::is_too_big(mpq const &q) const {
|
||||
|
|
@ -1131,3 +1130,4 @@ namespace nla {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit & lim) :
|
|||
lra(s),
|
||||
m_reslim(lim),
|
||||
m_params(p),
|
||||
m_linprobe(p.get_bool("arith.nl.linprobe_mode", false)),
|
||||
m_tangents(this),
|
||||
m_basics(this),
|
||||
m_order(this),
|
||||
|
|
@ -55,7 +54,8 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit & lim) :
|
|||
}
|
||||
|
||||
void core::updt_params(params_ref const& p) {
|
||||
m_linprobe = p.get_bool("arith.nl.linprobe_mode", false);
|
||||
// m_params is a view on the params_ref owned by the caller, so nla parameters
|
||||
// (including arith.nl.linprobe_mode) are always read back through params().
|
||||
m_grobner.updt_params(p);
|
||||
}
|
||||
|
||||
|
|
@ -1547,7 +1547,7 @@ bool core::propagate() {
|
|||
propagated = true;
|
||||
if (m_monomial_bounds.tighten_lp_bounds())
|
||||
propagated = true;
|
||||
if (m_linprobe) {
|
||||
if (linprobe_mode()) {
|
||||
if (m_monomial_bounds.propagate_linear_bounds())
|
||||
propagated = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ class core {
|
|||
lp::lar_solver& lra;
|
||||
reslimit& m_reslim;
|
||||
smt_params_helper m_params;
|
||||
bool m_linprobe;
|
||||
std::function<bool(lpvar)> m_relevant;
|
||||
vector<lemma> m_lemmas;
|
||||
vector<ineq> m_literals;
|
||||
|
|
@ -187,6 +186,9 @@ public:
|
|||
|
||||
smt_params_helper const & params() const { return m_params; }
|
||||
|
||||
// true when nla is restricted to the monomial linearization used by the linprobe pass
|
||||
bool linprobe_mode() const { return params().arith_nl_linprobe_mode(); }
|
||||
|
||||
// returns true if the combination of the Horner's schema and Grobner Basis should be called
|
||||
bool need_run_horner() const {
|
||||
return params().arith_nl_horner() && lp_settings().stats().m_nla_calls % params().arith_nl_horner_frequency() == 0;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ namespace nla {
|
|||
vector<lp::fixed_equality> const& fixed_equalities() const;
|
||||
vector<lp::equality> const& equalities() const;
|
||||
bool should_check_feasible() const { return m_core->should_check_feasible(); }
|
||||
bool linprobe_mode() const { return m_core->linprobe_mode(); }
|
||||
|
||||
const vector<nla::lemma>& lemmas() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ def_module_params(module_name='smt',
|
|||
('arith.nl.reduce_pseudo_linear', BOOL, True, 'create incremental linearization axioms for pseudo-linear monomials'),
|
||||
('arith.nl.delay', UINT, 10, 'number of calls to final check before invoking bounded nlsat check'),
|
||||
('arith.nl.linprobe', BOOL, True, 'run a short monomial linearization probe before the SMT tactic'),
|
||||
('arith.nl.linprobe_mode', BOOL, False, 'restrict nonlinear propagation to the monomial linearization used by the linprobe pass'),
|
||||
('arith.nl.linprobe_timeout', UINT, 100, 'timeout in milliseconds given to the monomial linearization probe'),
|
||||
('arith.nl.propagate_linear_monomials', BOOL, True, 'propagate linear monomials'),
|
||||
('arith.nl.optimize_bounds', BOOL, True, 'enable bounds optimization'),
|
||||
('arith.nl.propagate_fixed_rows', BOOL, False, 'scan LP rows for fixed variables'),
|
||||
|
|
|
|||
|
|
@ -1750,7 +1750,7 @@ public:
|
|||
is_sat = make_feasible();
|
||||
if (ctx().inconsistent())
|
||||
return FC_CONTINUE;
|
||||
if (nla_progress && is_sat == l_true && ctx().get_params().get_bool("arith.nl.linprobe_mode", false))
|
||||
if (nla_progress && is_sat == l_true && m_nla && m_nla->linprobe_mode())
|
||||
return FC_CONTINUE;
|
||||
final_check_status st = FC_DONE;
|
||||
bool int_undef = false;
|
||||
|
|
|
|||
|
|
@ -21,14 +21,11 @@ Notes:
|
|||
#include "util/scoped_timer.h"
|
||||
#include "util/common_msgs.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "params/smt_params_helper.hpp"
|
||||
#include "solver/solver.h"
|
||||
#include "solver/combined_solver_params.hpp"
|
||||
#include <atomic>
|
||||
#define PS_VB_LVL 15
|
||||
|
||||
static constexpr unsigned linprobe_timeout_ms = 100;
|
||||
|
||||
/**
|
||||
\brief Implementation of the solver API that combines two given solvers.
|
||||
|
||||
|
|
@ -59,7 +56,6 @@ private:
|
|||
bool m_inc_mode;
|
||||
bool m_check_sat_executed;
|
||||
bool m_use_solver1_results;
|
||||
bool m_has_callbacks;
|
||||
ref<solver> m_solver1;
|
||||
ref<solver> m_solver2;
|
||||
// We delay sending assertions to solver 2
|
||||
|
|
@ -118,28 +114,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
lbool try_linprobe(unsigned num_assumptions, expr* const* assumptions) {
|
||||
if (m_has_callbacks || !smt_params_helper(get_params()).arith_nl_linprobe())
|
||||
return l_undef;
|
||||
|
||||
IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using linprobe\")\n";);
|
||||
m_use_solver1_results = true;
|
||||
aux_timeout_eh eh(m_solver1.get());
|
||||
lbool r = l_undef;
|
||||
try {
|
||||
scoped_timer timer(linprobe_timeout_ms, &eh);
|
||||
r = m_solver1->check_sat_core(num_assumptions, assumptions);
|
||||
}
|
||||
catch (z3_exception&) {
|
||||
if (!eh.m_canceled)
|
||||
throw;
|
||||
}
|
||||
if (r != l_undef && !eh.m_canceled)
|
||||
return r;
|
||||
m_use_solver1_results = false;
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
public:
|
||||
combined_solver(solver * s1, solver * s2, params_ref const & p):
|
||||
solver(s1->get_manager()) {
|
||||
|
|
@ -149,7 +123,6 @@ public:
|
|||
m_inc_mode = false;
|
||||
m_check_sat_executed = false;
|
||||
m_use_solver1_results = true;
|
||||
m_has_callbacks = false;
|
||||
}
|
||||
|
||||
solver* translate(ast_manager& m, params_ref const& p) override {
|
||||
|
|
@ -160,7 +133,6 @@ public:
|
|||
r->m_inc_mode = m_inc_mode;
|
||||
r->m_check_sat_executed = m_check_sat_executed;
|
||||
r->m_use_solver1_results = m_use_solver1_results;
|
||||
r->m_has_callbacks = m_has_callbacks;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -240,12 +212,6 @@ public:
|
|||
m_check_sat_executed = true;
|
||||
m_use_solver1_results = false;
|
||||
|
||||
if (m_inc_mode || get_num_assumptions() != 0 || num_assumptions > 0 || m_ignore_solver1) {
|
||||
lbool const r = try_linprobe(num_assumptions, assumptions);
|
||||
if (r != l_undef)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (get_num_assumptions() != 0 ||
|
||||
num_assumptions > 0 || // assumptions were provided
|
||||
m_ignore_solver1) {
|
||||
|
|
@ -386,7 +352,6 @@ public:
|
|||
|
||||
void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override {
|
||||
switch_inc_mode();
|
||||
m_has_callbacks = true;
|
||||
m_solver2->register_on_clause(ctx, on_clause);
|
||||
}
|
||||
|
||||
|
|
@ -396,57 +361,46 @@ public:
|
|||
user_propagator::pop_eh_t& pop_eh,
|
||||
user_propagator::fresh_eh_t& fresh_eh) override {
|
||||
switch_inc_mode();
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_init(ctx, push_eh, pop_eh, fresh_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_fixed(user_propagator::fixed_eh_t& fixed_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_fixed(fixed_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_final(user_propagator::final_eh_t& final_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_final(final_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_eq(user_propagator::eq_eh_t& eq_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_eq(eq_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_on_binding(user_propagator::binding_eh_t& binding_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_on_binding(binding_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_expr(expr* e) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_expr(e);
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& r) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_created(r);
|
||||
}
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& r) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver2->user_propagate_register_decide(r);
|
||||
}
|
||||
|
||||
void user_propagate_clear() override {
|
||||
m_has_callbacks = false;
|
||||
m_solver2->user_propagate_clear();
|
||||
}
|
||||
|
||||
void user_propagate_initialize_value(expr* var, expr* value) override {
|
||||
m_has_callbacks = true;
|
||||
m_solver1->user_propagate_initialize_value(var, value);
|
||||
m_solver2->user_propagate_initialize_value(var, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,14 +25,18 @@ Author:
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr unsigned linprobe_timeout_ms = 100;
|
||||
/**
|
||||
\brief Parameters for the monomial linearization probe.
|
||||
|
||||
Only cheap, deterministic nonlinear propagation is enabled, and the probe is
|
||||
asked to fail (rather than report unknown) so that the full solver is used as
|
||||
a fallback.
|
||||
*/
|
||||
params_ref probe_params(params_ref const& p) {
|
||||
params_ref r = p;
|
||||
r.set_bool("auto_config", false);
|
||||
r.set_bool("parallel.enable", false);
|
||||
r.set_uint("arith.solver", 6);
|
||||
r.set_bool("arith.nl.linprobe", true);
|
||||
r.set_bool("arith.nl.linprobe_mode", true);
|
||||
r.set_bool("arith.nl.propagate_fixed_rows", true);
|
||||
r.set_bool("arith.nl.propagate_linear_monomials", true);
|
||||
|
|
@ -59,150 +63,6 @@ params_ref fallback_params(params_ref const& p) {
|
|||
return r;
|
||||
}
|
||||
|
||||
class linprobe_tactic : public tactic {
|
||||
tactic_ref m_probe;
|
||||
tactic_ref m_fallback;
|
||||
params_ref m_params;
|
||||
bool m_has_callbacks = false;
|
||||
|
||||
public:
|
||||
linprobe_tactic(tactic* probe, tactic* fallback, params_ref const& p):
|
||||
m_probe(probe),
|
||||
m_fallback(fallback),
|
||||
m_params(p) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
char const* name() const override { return "linprobe"; }
|
||||
|
||||
void operator()(goal_ref const& in, goal_ref_buffer& result) override {
|
||||
if (!smt_params_helper(m_params).arith_nl_linprobe() || m_has_callbacks) {
|
||||
(*m_fallback)(in, result);
|
||||
return;
|
||||
}
|
||||
|
||||
goal orig(*in);
|
||||
try {
|
||||
(*m_probe)(in, result);
|
||||
return;
|
||||
}
|
||||
catch (tactic_exception&) {
|
||||
result.reset();
|
||||
in->reset_all();
|
||||
in->copy_from(orig);
|
||||
}
|
||||
(*m_fallback)(in, result);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const& p) override {
|
||||
m_params.copy(p);
|
||||
m_probe->updt_params(probe_params(p));
|
||||
m_fallback->updt_params(fallback_params(p));
|
||||
}
|
||||
|
||||
void collect_param_descrs(param_descrs& r) override {
|
||||
m_fallback->collect_param_descrs(r);
|
||||
}
|
||||
|
||||
void collect_statistics(statistics& st) const override {
|
||||
m_probe->collect_statistics(st);
|
||||
m_fallback->collect_statistics(st);
|
||||
}
|
||||
|
||||
void reset_statistics() override {
|
||||
m_probe->reset_statistics();
|
||||
m_fallback->reset_statistics();
|
||||
}
|
||||
|
||||
void cleanup() override {
|
||||
m_probe->cleanup();
|
||||
m_fallback->cleanup();
|
||||
}
|
||||
|
||||
void reset() override {
|
||||
m_probe->reset();
|
||||
m_fallback->reset();
|
||||
}
|
||||
|
||||
void set_logic(symbol const& l) override {
|
||||
m_probe->set_logic(l);
|
||||
m_fallback->set_logic(l);
|
||||
}
|
||||
|
||||
void set_progress_callback(progress_callback* callback) override {
|
||||
m_probe->set_progress_callback(callback);
|
||||
m_fallback->set_progress_callback(callback);
|
||||
}
|
||||
|
||||
tactic* translate(ast_manager& m) override {
|
||||
return alloc(linprobe_tactic, m_probe->translate(m), m_fallback->translate(m), m_params);
|
||||
}
|
||||
|
||||
void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->register_on_clause(ctx, on_clause);
|
||||
}
|
||||
|
||||
void user_propagate_init(
|
||||
void* ctx,
|
||||
user_propagator::push_eh_t& push_eh,
|
||||
user_propagator::pop_eh_t& pop_eh,
|
||||
user_propagator::fresh_eh_t& fresh_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_init(ctx, push_eh, pop_eh, fresh_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_fixed(user_propagator::fixed_eh_t& fixed_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_fixed(fixed_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_final(user_propagator::final_eh_t& final_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_final(final_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_eq(user_propagator::eq_eh_t& eq_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_eq(eq_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_on_binding(user_propagator::binding_eh_t& binding_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_on_binding(binding_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_expr(expr* e) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_expr(e);
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& created_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_created(created_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& decide_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_register_decide(decide_eh);
|
||||
}
|
||||
|
||||
void user_propagate_clear() override {
|
||||
m_has_callbacks = false;
|
||||
m_fallback->user_propagate_clear();
|
||||
}
|
||||
|
||||
void user_propagate_initialize_value(expr* var, expr* value) override {
|
||||
m_has_callbacks = true;
|
||||
m_fallback->user_propagate_initialize_value(var, value);
|
||||
}
|
||||
};
|
||||
|
||||
tactic* mk_raw_smt_tactic(ast_manager& m, params_ref const& p) {
|
||||
sat_params sp(p);
|
||||
if (sp.smt())
|
||||
|
|
@ -212,20 +72,33 @@ tactic* mk_raw_smt_tactic(ast_manager& m, params_ref const& p) {
|
|||
return mk_smt_tactic_core(m, p);
|
||||
}
|
||||
|
||||
tactic* mk_linprobe_tactic(ast_manager& m, params_ref const& p) {
|
||||
/**
|
||||
\brief Run a short monomial linearization probe before \c fallback.
|
||||
|
||||
\c fallback is only reached when the probe fails to close the goal, and it is
|
||||
the only branch that supports user propagation.
|
||||
*/
|
||||
tactic* mk_linprobe_tactic(ast_manager& m, params_ref const& p, tactic* fallback) {
|
||||
params_ref pp = probe_params(p);
|
||||
tactic* probe = try_for(mk_smt_tactic_core(m, pp), linprobe_timeout_ms);
|
||||
return alloc(linprobe_tactic, probe, mk_raw_smt_tactic(m, p), p);
|
||||
unsigned timeout = smt_params_helper(pp).arith_nl_linprobe_timeout();
|
||||
tactic* probe = using_params(try_for(mk_smt_tactic_core(m, pp), timeout), pp);
|
||||
return or_else_no_user_propagate(probe, fallback, p, [](params_ref const& q) {
|
||||
return smt_params_helper(q).arith_nl_linprobe();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tactic * mk_smt_tactic(ast_manager & m, params_ref const & p) {
|
||||
return mk_linprobe_tactic(m, p);
|
||||
params_ref fp = fallback_params(p);
|
||||
return mk_linprobe_tactic(m, p, using_params(mk_raw_smt_tactic(m, fp), fp));
|
||||
}
|
||||
|
||||
tactic * mk_smt_tactic_using(ast_manager& m, bool auto_config, params_ref const& p) {
|
||||
params_ref q = p;
|
||||
q.set_bool("auto_config", auto_config);
|
||||
return using_params(mk_linprobe_tactic(m, q), q);
|
||||
params_ref fp = fallback_params(q);
|
||||
sat_params sp(fp);
|
||||
tactic* fallback = sp.euf() ? mk_sat_tactic(m, fp) : mk_smt_tactic_core_using(m, auto_config, fp);
|
||||
return mk_linprobe_tactic(m, q, using_params(fallback, fp));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -448,6 +448,126 @@ tactic * or_else(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5
|
|||
return or_else(10, ts);
|
||||
}
|
||||
|
||||
class or_else_no_user_propagate_tactical : public binary_tactical {
|
||||
params_ref m_params;
|
||||
std::function<bool(params_ref const&)> m_use_t1;
|
||||
bool m_has_callbacks = false;
|
||||
|
||||
bool use_t1() const {
|
||||
return !m_has_callbacks && (!m_use_t1 || m_use_t1(m_params));
|
||||
}
|
||||
|
||||
public:
|
||||
or_else_no_user_propagate_tactical(tactic * t1, tactic * t2, params_ref const & p,
|
||||
std::function<bool(params_ref const&)> const & use_t1):
|
||||
binary_tactical(t1, t2),
|
||||
m_params(p),
|
||||
m_use_t1(use_t1) {
|
||||
}
|
||||
|
||||
char const* name() const override { return "or_else_no_user_propagate"; }
|
||||
|
||||
void operator()(goal_ref const & in, goal_ref_buffer & result) override {
|
||||
m_clean = false;
|
||||
if (!use_t1()) {
|
||||
m_t2->operator()(in, result);
|
||||
return;
|
||||
}
|
||||
goal orig(*(in.get()));
|
||||
try {
|
||||
m_t1->operator()(in, result);
|
||||
return;
|
||||
}
|
||||
catch (tactic_exception &) {
|
||||
result.reset();
|
||||
}
|
||||
catch (rewriter_exception &) {
|
||||
result.reset();
|
||||
}
|
||||
in->reset_all();
|
||||
in->copy_from(orig);
|
||||
m_t2->operator()(in, result);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) override {
|
||||
m_params.copy(p);
|
||||
binary_tactical::updt_params(p);
|
||||
}
|
||||
|
||||
tactic * translate(ast_manager & m) override {
|
||||
return alloc(or_else_no_user_propagate_tactical, m_t1->translate(m), m_t2->translate(m), m_params, m_use_t1);
|
||||
}
|
||||
|
||||
void register_on_clause(void * ctx, user_propagator::on_clause_eh_t & on_clause) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->register_on_clause(ctx, on_clause);
|
||||
}
|
||||
|
||||
void user_propagate_init(
|
||||
void * ctx,
|
||||
user_propagator::push_eh_t & push_eh,
|
||||
user_propagator::pop_eh_t & pop_eh,
|
||||
user_propagator::fresh_eh_t & fresh_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_init(ctx, push_eh, pop_eh, fresh_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_fixed(user_propagator::fixed_eh_t & fixed_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_fixed(fixed_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_final(user_propagator::final_eh_t & final_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_final(final_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_eq(user_propagator::eq_eh_t & eq_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_eq(eq_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t & diseq_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_on_binding(user_propagator::binding_eh_t & binding_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_on_binding(binding_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_expr(expr * e) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_expr(e);
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t & created_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_created(created_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t & decide_eh) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_register_decide(decide_eh);
|
||||
}
|
||||
|
||||
void user_propagate_clear() override {
|
||||
m_has_callbacks = false;
|
||||
m_t2->user_propagate_clear();
|
||||
}
|
||||
|
||||
void user_propagate_initialize_value(expr * var, expr * value) override {
|
||||
m_has_callbacks = true;
|
||||
m_t2->user_propagate_initialize_value(var, value);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * or_else_no_user_propagate(tactic * t1, tactic * t2, params_ref const & p,
|
||||
std::function<bool(params_ref const&)> use_t1) {
|
||||
return alloc(or_else_no_user_propagate_tactical, t1, t2, p, use_t1);
|
||||
}
|
||||
|
||||
#ifdef SINGLE_THREAD
|
||||
|
||||
tactic* par(unsigned num, tactic* const* ts) {
|
||||
|
|
@ -883,6 +1003,19 @@ public:
|
|||
void reset() override { m_t->reset(); }
|
||||
void set_logic(symbol const& l) override { m_t->set_logic(l); }
|
||||
void set_progress_callback(progress_callback * callback) override { m_t->set_progress_callback(callback); }
|
||||
void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { m_t->register_on_clause(ctx, on_clause); }
|
||||
void user_propagate_init(
|
||||
void* ctx,
|
||||
user_propagator::push_eh_t& push_eh,
|
||||
user_propagator::pop_eh_t& pop_eh,
|
||||
user_propagator::fresh_eh_t& fresh_eh) override { m_t->user_propagate_init(ctx, push_eh, pop_eh, fresh_eh); }
|
||||
void user_propagate_register_fixed(user_propagator::fixed_eh_t& fixed_eh) override { m_t->user_propagate_register_fixed(fixed_eh); }
|
||||
void user_propagate_register_final(user_propagator::final_eh_t& final_eh) override { m_t->user_propagate_register_final(final_eh); }
|
||||
void user_propagate_register_eq(user_propagator::eq_eh_t& eq_eh) override { m_t->user_propagate_register_eq(eq_eh); }
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh) override { m_t->user_propagate_register_diseq(diseq_eh); }
|
||||
void user_propagate_register_on_binding(user_propagator::binding_eh_t& binding_eh) override { m_t->user_propagate_register_on_binding(binding_eh); }
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& created_eh) override { m_t->user_propagate_register_created(created_eh); }
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& decide_eh) override { m_t->user_propagate_register_decide(decide_eh); }
|
||||
void user_propagate_register_expr(expr* e) override { m_t->user_propagate_register_expr(e); }
|
||||
void user_propagate_clear() override { m_t->user_propagate_clear(); }
|
||||
void user_propagate_initialize_value(expr* var, expr* value) override { m_t->user_propagate_initialize_value(var, value); }
|
||||
|
|
|
|||
|
|
@ -44,6 +44,18 @@ tactic * or_else(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5
|
|||
tactic * or_else(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5, tactic * t6, tactic * t7, tactic * t8, tactic * t9);
|
||||
tactic * or_else(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5, tactic * t6, tactic * t7, tactic * t8, tactic * t9, tactic * t10);
|
||||
|
||||
/**
|
||||
\brief Variant of or_else(t1, t2) for the case where only \c t2 supports user
|
||||
propagation. All user propagator and on-clause registrations are forwarded to
|
||||
\c t2 only, and once any of them is registered \c t1 is bypassed entirely.
|
||||
|
||||
The optional \c use_t1 predicate is evaluated on the current parameters before
|
||||
every invocation and can additionally disable \c t1. \c p seeds those
|
||||
parameters, so the predicate is meaningful even when updt_params is never called.
|
||||
*/
|
||||
tactic * or_else_no_user_propagate(tactic * t1, tactic * t2, params_ref const & p,
|
||||
std::function<bool(params_ref const &)> use_t1 = nullptr);
|
||||
|
||||
tactic * repeat(tactic * t, unsigned max = UINT_MAX);
|
||||
/**
|
||||
\brief Fails if \c t produces more than \c threshold subgoals.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue