feat(library/tactic): add rotate_left/rotate_right tactics, closes #278

This commit is contained in:
Leonardo de Moura 2014-10-29 19:13:55 -07:00
parent 8e9f97e95e
commit 9547e2d077
7 changed files with 74 additions and 1 deletions

View file

@ -38,6 +38,9 @@ opaque definition id : tactic := builtin
opaque definition beta : tactic := builtin
opaque definition info : tactic := builtin
opaque definition whnf : tactic := builtin
opaque definition rotate_left (k : num) := builtin
opaque definition rotate_right (k : num) := builtin
definition rotate (k : num) := rotate_left k
-- This is just a trick to embed expressions into tactics.
-- The nested expressions are "raw". They tactic should

View file

@ -119,7 +119,7 @@
;; tactics
(,(rx (not (any "\.")) word-start
(or "\\b.*_tac" "Cond" "or_else" "then" "try" "when" "assumption" "eassumption" "rapply" "apply" "rename" "intro" "intros"
"generalize" "back" "beta" "done" "exact" "repeat" "whnf")
"generalize" "back" "beta" "done" "exact" "repeat" "whnf" "rotate" "rotate_left" "rotate_right")
word-end)
. 'font-lock-constant-face)
;; Types

View file

@ -272,6 +272,25 @@ void register_unary_num_tac(name const & n, std::function<tactic(tactic const &,
});
}
void register_num_tac(name const & n, std::function<tactic(unsigned k)> f) {
register_tac(n, [=](type_checker & tc, elaborate_fn const &, expr const & e, pos_info_provider const * p) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 1)
throw expr_to_tactic_exception(e, "invalid tactic, it must have one argument");
optional<mpz> k = to_num(args[0]);
if (!k)
k = to_num(tc.whnf(args[0]).first);
if (!k)
throw expr_to_tactic_exception(e, "invalid tactic, argument must be a numeral");
if (!k->is_unsigned_int())
throw expr_to_tactic_exception(e,
"invalid tactic, argument does not fit in "
"a machine unsigned integer");
return f(k->get_unsigned_int());
});
}
static name * g_by_name = nullptr;
expr mk_by(expr const & e) { return mk_annotation(*g_by_name, e); }
@ -351,6 +370,9 @@ void initialize_expr_to_tactic() {
[](tactic const & t, unsigned k) { return focus(t, k); });
register_unary_num_tac(name(*g_tactic_name, "try_for"),
[](tactic const & t, unsigned k) { return try_for(t, k); });
register_num_tac(name(*g_tactic_name, "rotate_left"), [](unsigned k) { return rotate_left(k); });
register_num_tac(name(*g_tactic_name, "rotate_right"), [](unsigned k) { return rotate_right(k); });
register_tac(fixpoint_name,
[](type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
if (!is_constant(app_fn(e)))

View file

@ -79,6 +79,7 @@ void register_simple_tac(name const & n, std::function<tactic()> f);
void register_bin_tac(name const & n, std::function<tactic(tactic const &, tactic const &)> f);
void register_unary_tac(name const & n, std::function<tactic(tactic const &)> f);
void register_unary_num_tac(name const & n, std::function<tactic(tactic const &, unsigned)> f);
void register_num_tac(name const & n, std::function<tactic(unsigned k)> f);
void initialize_expr_to_tactic();
void finalize_expr_to_tactic();

View file

@ -110,6 +110,32 @@ tactic using_params(tactic const & t, options const & opts) {
});
}
proof_state rotate_left(proof_state const & s, unsigned n) {
buffer<goal> gs;
to_buffer(s.get_goals(), gs);
unsigned sz = gs.size();
if (sz == 0)
return s;
n = n%sz;
std::rotate(gs.begin(), gs.begin() + n, gs.end());
return proof_state(s, to_list(gs.begin(), gs.end()));
}
tactic rotate_left(unsigned n) {
return tactic1([=](environment const &, io_state const &, proof_state const & s) -> proof_state {
return rotate_left(s, n);
});
}
tactic rotate_right(unsigned n) {
return tactic1([=](environment const &, io_state const &, proof_state const & s) -> proof_state {
unsigned ngoals = length(s.get_goals());
if (ngoals == 0)
return s;
return rotate_left(s, ngoals - n%ngoals);
});
}
tactic try_for(tactic const & t, unsigned ms, unsigned check_ms) {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
return timeout(t(env, ios, s), ms, check_ms);

View file

@ -71,6 +71,12 @@ tactic try_for(tactic const & t, unsigned ms, unsigned check_ms = 1);
from tactic \c t2.
*/
tactic append(tactic const & t1, tactic const & t2);
/** \brief Return a tactic that rotate goals to the left n steps */
tactic rotate_left(unsigned n);
/** \brief Return a tactic that rotate goals to the right n steps */
tactic rotate_right(unsigned n);
inline tactic operator+(tactic const & t1, tactic const & t2) { return append(t1, t2); }
/**
\brief Execute both tactics and and combines their results.

View file

@ -0,0 +1,15 @@
import tools.tactic
open tactic
theorem foo (A : Type) (a b c : A) : a = b → b = c → a = c ∧ c = a :=
begin
intros (Hab, Hbc),
apply and.intro,
apply eq.trans,
rotate 2,
apply eq.trans,
apply (eq.symm Hbc),
apply (eq.symm Hab),
apply Hab,
apply Hbc,
end