feat(library/simplifier): filter out propositions that cannot be used as conditional equations
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
94fa987814
commit
c651d3ea2d
3 changed files with 67 additions and 9 deletions
|
@ -7,13 +7,17 @@ Author: Leonardo de Moura
|
||||||
#include "util/list_fn.h"
|
#include "util/list_fn.h"
|
||||||
#include "kernel/builtin.h"
|
#include "kernel/builtin.h"
|
||||||
#include "kernel/free_vars.h"
|
#include "kernel/free_vars.h"
|
||||||
|
#include "kernel/for_each_fn.h"
|
||||||
#include "library/expr_pair.h"
|
#include "library/expr_pair.h"
|
||||||
#include "library/ite.h"
|
#include "library/ite.h"
|
||||||
#include "library/kernel_bindings.h"
|
#include "library/kernel_bindings.h"
|
||||||
|
#include "library/eq_heq.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
static name g_Hc("Hc"); // auxiliary name for if-then-else
|
static name g_Hc("Hc"); // auxiliary name for if-then-else
|
||||||
|
|
||||||
|
bool is_ceq(ro_environment const & env, expr e);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Auxiliary functional object for creating "conditional equations"
|
\brief Auxiliary functional object for creating "conditional equations"
|
||||||
*/
|
*/
|
||||||
|
@ -96,7 +100,7 @@ public:
|
||||||
to_ceqs_fn(ro_environment const & env):m_env(env), m_idx(0) {}
|
to_ceqs_fn(ro_environment const & env):m_env(env), m_idx(0) {}
|
||||||
|
|
||||||
list<expr_pair> operator()(expr const & e, expr const & H) {
|
list<expr_pair> operator()(expr const & e, expr const & H) {
|
||||||
return apply(e, H);
|
return filter(apply(e, H), [&](expr_pair const & p) { return is_ceq(m_env, p.first); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,6 +108,39 @@ list<expr_pair> to_ceqs(ro_environment const & env, expr const & e, expr const &
|
||||||
return to_ceqs_fn(env)(e, H);
|
return to_ceqs_fn(env)(e, H);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_ceq(ro_environment const & env, expr e) {
|
||||||
|
buffer<bool> in_lhs;
|
||||||
|
context ctx;
|
||||||
|
while (is_pi(e)) {
|
||||||
|
// If a variable is a proposition, than if doesn't need to occurr in the lhs.
|
||||||
|
// So, we mark it as true.
|
||||||
|
in_lhs.push_back(env->is_proposition(abst_domain(e), ctx));
|
||||||
|
ctx = extend(ctx, abst_name(e), abst_domain(e));
|
||||||
|
e = abst_body(e);
|
||||||
|
}
|
||||||
|
if (is_eq_heq(e)) {
|
||||||
|
auto lhs_rhs = eq_heq_args(e);
|
||||||
|
// traverse lhs, and mark all variables that occur there in is_lhs.
|
||||||
|
for_each(lhs_rhs.first, [&](expr const & e, unsigned offset) {
|
||||||
|
if (is_var(e)) {
|
||||||
|
unsigned vidx = var_idx(e);
|
||||||
|
if (vidx >= offset) {
|
||||||
|
vidx -= offset;
|
||||||
|
if (vidx >= in_lhs.size()) {
|
||||||
|
// it is a free variable
|
||||||
|
} else {
|
||||||
|
in_lhs[in_lhs.size() - vidx - 1] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return std::find(in_lhs.begin(), in_lhs.end(), false) == in_lhs.end();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int to_ceqs(lua_State * L) {
|
static int to_ceqs(lua_State * L) {
|
||||||
ro_shared_environment env(L, 1);
|
ro_shared_environment env(L, 1);
|
||||||
auto r = to_ceqs(env, to_expr(L, 2), to_expr(L, 3));
|
auto r = to_ceqs(env, to_expr(L, 2), to_expr(L, 3));
|
||||||
|
@ -121,7 +158,14 @@ static int to_ceqs(lua_State * L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_ceq(lua_State * L) {
|
||||||
|
ro_shared_environment env(L, 1);
|
||||||
|
lua_pushboolean(L, is_ceq(env, to_expr(L, 2)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void open_ceq(lua_State * L) {
|
void open_ceq(lua_State * L) {
|
||||||
SET_GLOBAL_FUN(to_ceqs, "to_ceqs");
|
SET_GLOBAL_FUN(to_ceqs, "to_ceqs");
|
||||||
|
SET_GLOBAL_FUN(is_ceq, "is_ceq");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,25 @@ namespace lean {
|
||||||
[forall x : A, P] ---> forall x : A, [P]
|
[forall x : A, P] ---> forall x : A, [P]
|
||||||
|
|
||||||
P ---> P = true (if none of the rules above apply and P is not an equality)
|
P ---> P = true (if none of the rules above apply and P is not an equality)
|
||||||
|
|
||||||
|
\remark if the left-hand-side of an equation does not contain all variables, then it is
|
||||||
|
discarded. That is, all elements in the resultant list satisfy the predicate \c is_ceq.
|
||||||
*/
|
*/
|
||||||
list<expr_pair> to_ceqs(ro_environment const & env, expr const & e, expr const & H);
|
list<expr_pair> to_ceqs(ro_environment const & env, expr const & e, expr const & H);
|
||||||
|
/**
|
||||||
|
\brief Return true iff \c e is a conditional equation.
|
||||||
|
|
||||||
|
A conditional equation ceq has the form
|
||||||
|
<code>
|
||||||
|
ceq := (forall x : A, ceq)
|
||||||
|
| lhs = rhs
|
||||||
|
| lhs == rhs
|
||||||
|
</code>
|
||||||
|
|
||||||
|
Moreover, for <tt>(forall x : A, ceq)</tt>, the variable x must occur in the \c ceq left-hand-size
|
||||||
|
when \c A is not a proposition.
|
||||||
|
*/
|
||||||
|
bool is_ceq(ro_environment const & env, expr e);
|
||||||
void open_ceq(lua_State * L);
|
void open_ceq(lua_State * L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
local env = get_environment()
|
local env = get_environment()
|
||||||
|
|
||||||
function is_ceq(e)
|
|
||||||
while e:is_pi() do
|
|
||||||
_, _, e = e:fields()
|
|
||||||
end
|
|
||||||
return e:is_eq() or e:is_heq()
|
|
||||||
end
|
|
||||||
|
|
||||||
function show_ceqs(ceqs)
|
function show_ceqs(ceqs)
|
||||||
for i = 1, #ceqs do
|
for i = 1, #ceqs do
|
||||||
print(ceqs[i][1], ceqs[i][2])
|
print(ceqs[i][1], ceqs[i][2])
|
||||||
env:type_check(ceqs[i][2])
|
env:type_check(ceqs[i][2])
|
||||||
assert(is_ceq(ceqs[i][1]))
|
assert(is_ceq(env, ceqs[i][1]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -29,9 +22,13 @@ parse_lean_cmds([[
|
||||||
axiom Ax2 : forall x : Nat, x < 0 -> f (f x) = x
|
axiom Ax2 : forall x : Nat, x < 0 -> f (f x) = x
|
||||||
variable g : Nat -> Nat -> Nat
|
variable g : Nat -> Nat -> Nat
|
||||||
axiom Ax3 : forall x : Nat, not (x = 1) -> if (x < 0) then (g x x = 0) else (g x x < 0 /\ g x 0 = 1 /\ g 0 x = 2)
|
axiom Ax3 : forall x : Nat, not (x = 1) -> if (x < 0) then (g x x = 0) else (g x x < 0 /\ g x 0 = 1 /\ g 0 x = 2)
|
||||||
|
axiom Ax4 : forall x y : Nat, f x = x
|
||||||
|
axiom Ax5 : forall x y : Nat, f x = y /\ g x y = x
|
||||||
]])
|
]])
|
||||||
|
|
||||||
test_ceq("Ax1", 2)
|
test_ceq("Ax1", 2)
|
||||||
test_ceq("Ax2", 1)
|
test_ceq("Ax2", 1)
|
||||||
test_ceq("Ax3", 4)
|
test_ceq("Ax3", 4)
|
||||||
|
test_ceq("Ax4", 0)
|
||||||
|
test_ceq("Ax5", 1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue