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
#endif
#ifndef LEAN_DEFAULT_UNIFIER_NORMALIZER_MAX_STEPS
#define LEAN_DEFAULT_UNIFIER_NORMALIZER_MAX_STEPS 512
#endif
namespace lean {
static name * g_unifier_max_steps = nullptr;
static name * g_unifier_computation = nullptr;
static name * g_unifier_expensive_classes = nullptr;
static name * g_unifier_conservative = nullptr;
static name * g_unifier_nonchronological = nullptr;
static name * g_unifier_normalizer_max_steps = nullptr;
unsigned get_unifier_max_steps(options const & opts) {
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) {
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):
m_use_exceptions(use_exceptions),
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_expensive_classes(LEAN_DEFAULT_UNIFIER_EXPENSIVE_CLASSES),
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):
m_use_exceptions(use_exceptions),
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_expensive_classes(get_unifier_expensive_classes(o)),
m_discard(discard),
@ -740,6 +751,9 @@ struct unifier_fn {
}
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>,
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) {
// Try to normalize rhs
// Example: ?M := f (pr1 (pair 0 ?M))
try {
unsigned counter = 0;
constraint_seq cs;
auto is_target_fn = [&](expr const & e) {
if (status == occurs_check_status::FailLocal && occurs(bad_local, e))
return true;
else if (status == occurs_check_status::FailCircular && occurs(*m, e))
if ((status == occurs_check_status::FailLocal && occurs(bad_local, e)) ||
(status == occurs_check_status::FailCircular && occurs(*m, e))) {
counter++;
if (counter > m_config.m_normalizer_max_steps)
throw interrupt_normalizer();
return true;
} 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) {
case occurs_check_status::FailLocal:
@ -2865,12 +2888,14 @@ void open_unifier(lua_State * L) {
void initialize_unifier() {
g_unifier_max_steps = new name{"unifier", "max_steps"};
g_unifier_normalizer_max_steps = new name{"unifier", "normalizer_max_steps"};
g_unifier_computation = new name{"unifier", "computation"};
g_unifier_expensive_classes = new name{"unifier", "expensive_classes"};
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_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,
"(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,
@ -2888,6 +2913,7 @@ void finalize_unifier() {
delete g_tmp_prefix;
delete g_dont_care_cnstr;
delete g_unifier_max_steps;
delete g_unifier_normalizer_max_steps;
delete g_unifier_computation;
delete g_unifier_expensive_classes;
delete g_unifier_conservative;

View file

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