fix(library/unifier): fixes #705

This commit is contained in:
Leonardo de Moura 2015-06-26 19:10:46 -07:00
parent e3e9220ab9
commit 1886b71c17
2 changed files with 43 additions and 16 deletions

View file

@ -55,17 +55,26 @@ Author: Leonardo de Moura
#define LEAN_DEFAULT_UNIFIER_NONCHRONOLOGICAL true #define LEAN_DEFAULT_UNIFIER_NONCHRONOLOGICAL true
#endif #endif
#ifndef LEAN_DEFAULT_UNIFIER_NORMALIZER_MAX_STEPS
#define LEAN_DEFAULT_UNIFIER_NORMALIZER_MAX_STEPS 512
#endif
namespace lean { namespace lean {
static name * g_unifier_max_steps = nullptr; static name * g_unifier_max_steps = nullptr;
static name * g_unifier_computation = nullptr; static name * g_unifier_computation = nullptr;
static name * g_unifier_expensive_classes = nullptr; static name * g_unifier_expensive_classes = nullptr;
static name * g_unifier_conservative = nullptr; static name * g_unifier_conservative = nullptr;
static name * g_unifier_nonchronological = nullptr; static name * g_unifier_nonchronological = nullptr;
static name * g_unifier_normalizer_max_steps = nullptr;
unsigned get_unifier_max_steps(options const & opts) { unsigned get_unifier_max_steps(options const & opts) {
return opts.get_unsigned(*g_unifier_max_steps, LEAN_DEFAULT_UNIFIER_MAX_STEPS); return opts.get_unsigned(*g_unifier_max_steps, LEAN_DEFAULT_UNIFIER_MAX_STEPS);
} }
unsigned get_unifier_normalizer_max_steps(options const & opts) {
return opts.get_unsigned(*g_unifier_normalizer_max_steps, LEAN_DEFAULT_UNIFIER_NORMALIZER_MAX_STEPS);
}
bool get_unifier_computation(options const & opts) { bool get_unifier_computation(options const & opts) {
return opts.get_bool(*g_unifier_computation, LEAN_DEFAULT_UNIFIER_COMPUTATION); return opts.get_bool(*g_unifier_computation, LEAN_DEFAULT_UNIFIER_COMPUTATION);
} }
@ -85,6 +94,7 @@ bool get_unifier_nonchronological(options const & opts) {
unifier_config::unifier_config(bool use_exceptions, bool discard): unifier_config::unifier_config(bool use_exceptions, bool discard):
m_use_exceptions(use_exceptions), m_use_exceptions(use_exceptions),
m_max_steps(LEAN_DEFAULT_UNIFIER_MAX_STEPS), m_max_steps(LEAN_DEFAULT_UNIFIER_MAX_STEPS),
m_normalizer_max_steps(LEAN_DEFAULT_UNIFIER_NORMALIZER_MAX_STEPS),
m_computation(LEAN_DEFAULT_UNIFIER_COMPUTATION), m_computation(LEAN_DEFAULT_UNIFIER_COMPUTATION),
m_expensive_classes(LEAN_DEFAULT_UNIFIER_EXPENSIVE_CLASSES), m_expensive_classes(LEAN_DEFAULT_UNIFIER_EXPENSIVE_CLASSES),
m_discard(discard), m_discard(discard),
@ -97,6 +107,7 @@ unifier_config::unifier_config(bool use_exceptions, bool discard):
unifier_config::unifier_config(options const & o, bool use_exceptions, bool discard): unifier_config::unifier_config(options const & o, bool use_exceptions, bool discard):
m_use_exceptions(use_exceptions), m_use_exceptions(use_exceptions),
m_max_steps(get_unifier_max_steps(o)), m_max_steps(get_unifier_max_steps(o)),
m_normalizer_max_steps(get_unifier_normalizer_max_steps(o)),
m_computation(get_unifier_computation(o)), m_computation(get_unifier_computation(o)),
m_expensive_classes(get_unifier_expensive_classes(o)), m_expensive_classes(get_unifier_expensive_classes(o)),
m_discard(discard), m_discard(discard),
@ -740,6 +751,9 @@ struct unifier_fn {
} }
enum status { Solved, Failed, Continue }; enum status { Solved, Failed, Continue };
struct interrupt_normalizer {};
/** /**
\brief Process constraints of the form <tt>lhs =?= rhs</tt> where lhs is of the form <tt>?m</tt> or <tt>(?m l_1 .... l_n)</tt>, \brief Process constraints of the form <tt>lhs =?= rhs</tt> where lhs is of the form <tt>?m</tt> or <tt>(?m l_1 .... l_n)</tt>,
where all \c l_i are distinct local variables. In this case, the method returns Solved, if the method assign succeeds. where all \c l_i are distinct local variables. In this case, the method returns Solved, if the method assign succeeds.
@ -762,17 +776,26 @@ struct unifier_fn {
if (status == occurs_check_status::FailLocal || status == occurs_check_status::FailCircular) { if (status == occurs_check_status::FailLocal || status == occurs_check_status::FailCircular) {
// Try to normalize rhs // Try to normalize rhs
// Example: ?M := f (pr1 (pair 0 ?M)) // Example: ?M := f (pr1 (pair 0 ?M))
constraint_seq cs; try {
auto is_target_fn = [&](expr const & e) { unsigned counter = 0;
if (status == occurs_check_status::FailLocal && occurs(bad_local, e)) constraint_seq cs;
return true; auto is_target_fn = [&](expr const & e) {
else if (status == occurs_check_status::FailCircular && occurs(*m, e)) if ((status == occurs_check_status::FailLocal && occurs(bad_local, e)) ||
return true; (status == occurs_check_status::FailCircular && occurs(*m, e))) {
return false; counter++;
}; if (counter > m_config.m_normalizer_max_steps)
expr rhs_n = normalize(*m_tc, rhs, is_target_fn, cs); throw interrupt_normalizer();
if (rhs != rhs_n && process_constraints(cs)) return true;
return process_metavar_eq(lhs, rhs_n, j); } else {
return false;
}
};
expr rhs_n = normalize(*m_tc, rhs, is_target_fn, cs);
if (rhs != rhs_n && process_constraints(cs))
return process_metavar_eq(lhs, rhs_n, j);
} catch (interrupt_normalizer &) {
// exceeded maximum number of steps
}
} }
switch (status) { switch (status) {
case occurs_check_status::FailLocal: case occurs_check_status::FailLocal:
@ -2864,13 +2887,15 @@ void open_unifier(lua_State * L) {
} }
void initialize_unifier() { void initialize_unifier() {
g_unifier_max_steps = new name{"unifier", "max_steps"}; g_unifier_max_steps = new name{"unifier", "max_steps"};
g_unifier_computation = new name{"unifier", "computation"}; g_unifier_normalizer_max_steps = new name{"unifier", "normalizer_max_steps"};
g_unifier_expensive_classes = new name{"unifier", "expensive_classes"}; g_unifier_computation = new name{"unifier", "computation"};
g_unifier_conservative = new name{"unifier", "conservative"}; g_unifier_expensive_classes = new name{"unifier", "expensive_classes"};
g_unifier_nonchronological = new name{"unifier", "nonchronological"}; g_unifier_conservative = new name{"unifier", "conservative"};
g_unifier_nonchronological = new name{"unifier", "nonchronological"};
register_unsigned_option(*g_unifier_max_steps, LEAN_DEFAULT_UNIFIER_MAX_STEPS, "(unifier) maximum number of steps"); register_unsigned_option(*g_unifier_max_steps, LEAN_DEFAULT_UNIFIER_MAX_STEPS, "(unifier) maximum number of steps");
register_unsigned_option(*g_unifier_normalizer_max_steps, LEAN_DEFAULT_UNIFIER_NORMALIZER_MAX_STEPS, "(unifier) maximum number of steps the normalization procedure may perform when invoked by the unifier");
register_bool_option(*g_unifier_computation, LEAN_DEFAULT_UNIFIER_COMPUTATION, register_bool_option(*g_unifier_computation, LEAN_DEFAULT_UNIFIER_COMPUTATION,
"(unifier) always case-split on reduction/computational steps when solving flex-rigid and delta-delta constraints"); "(unifier) always case-split on reduction/computational steps when solving flex-rigid and delta-delta constraints");
register_bool_option(*g_unifier_expensive_classes, LEAN_DEFAULT_UNIFIER_EXPENSIVE_CLASSES, register_bool_option(*g_unifier_expensive_classes, LEAN_DEFAULT_UNIFIER_EXPENSIVE_CLASSES,
@ -2888,6 +2913,7 @@ void finalize_unifier() {
delete g_tmp_prefix; delete g_tmp_prefix;
delete g_dont_care_cnstr; delete g_dont_care_cnstr;
delete g_unifier_max_steps; delete g_unifier_max_steps;
delete g_unifier_normalizer_max_steps;
delete g_unifier_computation; delete g_unifier_computation;
delete g_unifier_expensive_classes; delete g_unifier_expensive_classes;
delete g_unifier_conservative; delete g_unifier_conservative;

View file

@ -37,6 +37,7 @@ enum class unifier_kind { Cheap, VeryConservative, Conservative, Liberal };
struct unifier_config { struct unifier_config {
bool m_use_exceptions; bool m_use_exceptions;
unsigned m_max_steps; unsigned m_max_steps;
unsigned m_normalizer_max_steps;
bool m_computation; bool m_computation;
bool m_expensive_classes; bool m_expensive_classes;
// If m_discard is true, then constraints that cannot be solved are discarded (or incomplete methods are used) // If m_discard is true, then constraints that cannot be solved are discarded (or incomplete methods are used)