Section FuncEq.
Variables (A1 A2 A3 A4 A5 A6 A7 B : Type).
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
End FuncEq.
Ltac fequal_post :=
try solve [ reflexivity ].
(** [fequal_support_for_exist], implemented in [LibEqual], is meant to simplify goals of the form [exist _ _ = exist _ _ ] and [existT _ _ = existT _ _], by exploiting proof irrelevance. *)
Ltac fequal_support_for_exist tt :=
fail.
(** For a n-ary tuple, [fequal], unlike [f_equal] enforces a recursive call on the (n-1)-ary tuple associated with the right component. *)
Ltac fequal_base :=
match goal with
| |- (_,_,_) = (_,_,_) =>  apply args_eq_2; [ fequal_base | ]
| |- _ => first
[ fequal_support_for_exist tt
| apply args_eq_1
| apply args_eq_2
| apply args_eq_3
| apply args_eq_4
| apply args_eq_5
| apply args_eq_6
| apply args_eq_7
| f_equal (* fallback to Coq [f_equal] *) ]
end.
Tactic Notation "fequal" :=
fequal_base; fequal_post.
(** [fequals] is the same as [fequal] except that it tries and solve all trivial subgoals, using [reflexivity] and [congruence] (as well as the proof-irrelevance principle). [fequals] applies to goals of the form [f x1 .. xN = f y1 .. yN] and produces some subgoals of the form [xi = yi]). *)
Ltac fequals_post :=
try solve [ reflexivity | congruence | apply proof_irrelevance ].
Tactic Notation "fequals" :=
fequal; fequals_post.
(** [fequals_rec] calls [fequals] recursively. It is equivalent to [repeat (progress fequals)]. *)
Tactic Notation "fequals_rec" :=
repeat (progress fequals).
(* ################################################################# *)
(** * Inversion *)
(* ================================================================= *)
(** ** Basic Inversion *)
(** [invert keep H] is same to [inversion H] except that it puts all the facts obtained in the goal. The keyword [keep] means that the hypothesis [H] should not be removed. *)
Tactic Notation "invert" "keep" hyp(H) :=
pose ltac_mark; inversion H; gen_until_mark.
(** [invert keep H as X1 .. XN] is the same as [inversion H as ...] except that only hypotheses which are not variable need to be named explicitely, in a similar fashion as [introv] is used to name only hypotheses. *)
Tactic Notation "invert" "keep" hyp(H) "as" simple_intropattern(I1) :=
invert keep H; introv I1.
Tactic Notation "invert" "keep" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) :=
invert keep H; introv I1 I2.
Tactic Notation "invert" "keep" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) :=
invert keep H; introv I1 I2 I3.
(** [invert H] is same to [inversion H] except that it puts all the facts obtained in the goal and clears hypothesis [H]. In other words, it is equivalent to [invert keep H; clear H]. *)
Tactic Notation "invert" hyp(H) :=
invert keep H; clear H.
(** [invert H as X1 .. XN] is the same as [invert keep H as X1 .. XN] but it also clears hypothesis [H]. *)
Tactic Notation "invert_tactic" hyp(H) tactic(tac) :=
let H' := fresh "TEMP" in rename H into H'; tac H'; clear H'.
Tactic Notation "invert" hyp(H) "as" simple_intropattern(I1) :=
invert_tactic H (fun H => invert keep H as I1).
Tactic Notation "invert" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) :=
invert_tactic H (fun H => invert keep H as I1 I2).
Tactic Notation "invert" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) :=
invert_tactic H (fun H => invert keep H as I1 I2 I3).
(* ================================================================= *)
(** ** Inversion with Substitution *)
(** Our inversion tactics is able to get rid of dependent equalities generated by [inversion], using proof irrelevance. *)
(* --we do not import Eqdep because it imports nasty hints automatically From TLC Require Import Eqdep. *)
(* Proof using. apply Eqdep.EqdepTheory.inj_pair2. Qed. *)
Ltac inverts_tactic H i1 i2 i3 i4 i5 i6 :=
let rec go i1 i2 i3 i4 i5 i6 :=
match goal with
| |- (ltac_Mark -> _) => intros _
| |- (?x = ?y -> _) => let H := fresh "TEMP" in intro H;
first [ subst x | subst y ];
go i1 i2 i3 i4 i5 i6
| |- (existT ?P ?p ?x = existT ?P ?p ?y -> _) =>
let H := fresh "TEMP" in intro H;
generalize (@inj_pair2 _ P p x y H);
clear H; go i1 i2 i3 i4 i5 i6
| |- (?P -> ?Q) => i1; go i2 i3 i4 i5 i6 ltac:(intro)
| |- (forall _, _) => intro; go i1 i2 i3 i4 i5 i6
end in
generalize ltac_mark; invert keep H; go i1 i2 i3 i4 i5 i6;
unfold eq' in *.
(** [inverts keep H] is same to [invert keep H] except that it applies [subst] to all the equalities generated by the inversion. *)
Tactic Notation "inverts" "keep" hyp(H) :=
inverts_tactic H ltac:(intro) ltac:(intro) ltac:(intro)
ltac:(intro) ltac:(intro) ltac:(intro).
(** [inverts keep H as X1 .. XN] is the same as [invert keep H as X1 .. XN] except that it applies [subst] to all the equalities generated by the inversion *)
Tactic Notation "inverts" "keep" hyp(H) "as" simple_intropattern(I1) :=
inverts_tactic H ltac:(intros I1)
ltac:(intro) ltac:(intro) ltac:(intro) ltac:(intro) ltac:(intro).
Tactic Notation "inverts" "keep" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) :=
inverts_tactic H ltac:(intros I1) ltac:(intros I2)
ltac:(intro) ltac:(intro) ltac:(intro) ltac:(intro).
Tactic Notation "inverts" "keep" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) :=
inverts_tactic H ltac:(intros I1) ltac:(intros I2) ltac:(intros I3)
ltac:(intro) ltac:(intro) ltac:(intro).
Tactic Notation "inverts" "keep" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4) :=
inverts_tactic H ltac:(intros I1) ltac:(intros I2) ltac:(intros I3)
ltac:(intros I4) ltac:(intro) ltac:(intro).
Tactic Notation "inverts" "keep" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4)
simple_intropattern(I5) :=
inverts_tactic H ltac:(intros I1) ltac:(intros I2) ltac:(intros I3)
ltac:(intros I4) ltac:(intros I5) ltac:(intro).
Tactic Notation "inverts" "keep" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4)
simple_intropattern(I5) simple_intropattern(I6) :=
inverts_tactic H ltac:(intros I1) ltac:(intros I2) ltac:(intros I3)
ltac:(intros I4) ltac:(intros I5) ltac:(intros I6).
(** [inverts H] is same to [inverts keep H] except that it clears hypothesis [H]. *)
Tactic Notation "inverts" hyp(H) :=
inverts keep H; try clear H.
(** [inverts H as X1 .. XN] is the same as [inverts keep H as X1 .. XN] but it also clears the hypothesis [H]. *)
Tactic Notation "inverts_tactic" hyp(H) tactic(tac) :=
let H' := fresh "TEMP" in rename H into H'; tac H'; clear H'.
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1) :=
invert_tactic H (fun H => inverts keep H as I1).
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) :=
invert_tactic H (fun H => inverts keep H as I1 I2).
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) :=
invert_tactic H (fun H => inverts keep H as I1 I2 I3).
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4) :=
invert_tactic H (fun H => inverts keep H as I1 I2 I3 I4).
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4)
simple_intropattern(I5) :=
invert_tactic H (fun H => inverts keep H as I1 I2 I3 I4 I5).
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4)
simple_intropattern(I5) simple_intropattern(I6) :=
invert_tactic H (fun H => inverts keep H as I1 I2 I3 I4 I5 I6).
(** [inverts H as] performs an inversion on hypothesis [H], substitutes generated equalities, and put in the goal the other freshly-created hypotheses, for the user to name explicitly. [inverts keep H as] is the same except that it does not clear [H]. --Note: maybe reimplement [inverts] above using this one *)
Ltac inverts_as_tactic H :=
let rec go tt :=
match goal with
| |- (ltac_Mark -> _) => intros _
| |- (?x = ?y -> _) => let H := fresh "TEMP" in intro H;
first [ subst x | subst y ];
go tt
| |- (existT ?P ?p ?x = existT ?P ?p ?y -> _) =>
let H := fresh "TEMP" in intro H;
generalize (@inj_pair2 _ P p x y H);
clear H; go tt
| |- (forall _, _) =>
intro; let H := get_last_hyp tt in mark_to_generalize H; go tt
end in
pose ltac_mark; inversion H;
generalize ltac_mark; gen_until_mark;
go tt; gen_to_generalize; unfolds ltac_to_generalize;
unfold eq' in *.
Tactic Notation "inverts" "keep" hyp(H) "as" :=
inverts_as_tactic H.
Tactic Notation "inverts" hyp(H) "as" :=
inverts_as_tactic H; clear H.
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4)
simple_intropattern(I5) simple_intropattern(I6) simple_intropattern(I7) :=
inverts H as; introv I1 I2 I3 I4 I5 I6 I7.
Tactic Notation "inverts" hyp(H) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4)
simple_intropattern(I5) simple_intropattern(I6) simple_intropattern(I7)
simple_intropattern(I8) :=
inverts H as; introv I1 I2 I3 I4 I5 I6 I7 I8.
(** [lets_inverts E as I1 .. IN] is intuitively equivalent to [inverts E], with the difference that it applies to any expression and not just to the name of an hypothesis. *)
Ltac lets_inverts_base E cont :=
let H := fresh "TEMP" in lets H: E; try cont H.
Tactic Notation "lets_inverts" constr(E) :=
lets_inverts_base E ltac:(fun H => inverts H).
Tactic Notation "lets_inverts" constr(E) "as" simple_intropattern(I1) :=
lets_inverts_base E ltac:(fun H => inverts H as I1).
Tactic Notation "lets_inverts" constr(E) "as" simple_intropattern(I1)
simple_intropattern(I2) :=
lets_inverts_base E ltac:(fun H => inverts H as I1 I2).
Tactic Notation "lets_inverts" constr(E) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) :=
lets_inverts_base E ltac:(fun H => inverts H as I1 I2 I3).
Tactic Notation "lets_inverts" constr(E) "as" simple_intropattern(I1)
simple_intropattern(I2) simple_intropattern(I3) simple_intropattern(I4) :=
lets_inverts_base E ltac:(fun H => inverts H as I1 I2 I3 I4).
(* ================================================================= *)
(** ** Injection with Substitution *)
(** Underlying implementation of [injects] *)
Ltac injects_tactic H :=
let rec go _ :=
match goal with
| |- (ltac_Mark -> _) => intros _
| |- (?x = ?y -> _) => let H := fresh "TEMP" in intro H;
first [ subst x | subst y | idtac ];
go tt
end in
generalize ltac_mark; injection H; go tt.
(** [injects keep H] takes an hypothesis [H] of the form [C a1 .. aN = C b1 .. bN] and substitute all equalities [ai = bi] that have been generated. *)
Tactic Notation "injects" "keep" hyp(H) :=
injects_tactic H.
(** [injects H] is similar to [injects keep H] but clears the hypothesis [H]. *)
Tactic Notation "injects" hyp(H) :=
injects_tactic H; clear H.
(** [inject H as X1 .. XN] is the same as [injection] followed by [intros X1 .. XN] *)
Tactic Notation "inject" hyp(H) :=
injection H.
Tactic Notation "inject" hyp(H) "as" ident(X1) :=
injection H; intros X1.
Tactic Notation "inject" hyp(H) "as" ident(X1) ident(X2) :=
injection H; intros X1 X2.
Tactic Notation "inject" hyp(H) "as" ident(X1) ident(X2) ident(X3) :=
injection H; intros X1 X2 X3.
Tactic Notation "inject" hyp(H) "as" ident(X1) ident(X2) ident(X3)
ident(X4) :=
injection H; intros X1 X2 X3 X4.
Tactic Notation "inject" hyp(H) "as" ident(X1) ident(X2) ident(X3)
ident(X4) ident(X5) :=
injection H; intros X1 X2 X3 X4 X5.
(* ================================================================= *)
(** ** Inversion and Injection with Substitution --rough implementation *)
(** The tactics [inversions] and [injections] provided in this section are similar to [inverts] and [injects] except that they perform substitution on all equalities from the context and not only the ones freshly generated. The counterpart is that they have simpler implementations.  DEPRECATED: these tactics should no longer be used. *)
(** [inversions keep H] is the same as [inversions H] but it does not clear hypothesis [H]. *)
Tactic Notation "inversions" "keep" hyp(H) :=
inversion H; subst.
(** [inversions H] is a shortcut for [inversion H] followed by [subst] and [clear H]. It is a rough implementation of [inverts keep H] which behave badly when the proof context already contains equalities. It is provided in case the better implementation turns out to be too slow. *)
Tactic Notation "inversions" hyp(H) :=
inversion H; subst; try clear H.
(** [injections keep H] is the same as [injection H] followed by [intros] and [subst]. It is a rough implementation of [injects keep H] which behave badly when the proof context already contains equalities, or when the goal starts with a forall or an implication. *)
Tactic Notation "injections" "keep" hyp(H) :=
injection H; intros; subst.
(** [injections H] is the same as [injection H] followed by [clear H] and [intros] and [subst]. It is a rough implementation of [injects keep H] which behave badly when the proof context already contains equalities, or when the goal starts with a forall or an implication. *)
Tactic Notation "injections" "keep" hyp(H) :=
injection H; clear H; intros; subst.
(* ================================================================= *)
(** ** Case Analysis *)
(** [cases] is similar to [case_eq E] except that it generates the equality in the context and not in the goal, and generates the equality the other way round. The syntax [cases E as H] allows specifying the name [H] of that hypothesis. *)
Tactic Notation "cases" constr(E) "as" ident(H) :=
let X := fresh "TEMP" in
set (X := E) in *; def_to_eq_sym X H E;
destruct X.
Tactic Notation "cases" constr(E) :=
let H := fresh "Eq" in cases E as H.
(** [case_if_post H] is to be defined later as a tactic to clean up hypothesis [H] and the goal. By defaults, it looks for obvious contradictions. Currently, this tactic is extended in LibReflect to clean up boolean propositions. *)
Ltac case_if_post H :=
tryfalse.
(** [case_if] looks for a pattern of the form [if ?B then ?E1 else ?E2] in the goal, and perform a case analysis on [B] by calling [destruct B]. Subgoals containing a contradiction are discarded. [case_if] looks in the goal first, and otherwise in the first hypothesis that contains an [if] statement. [case_if in H] can be used to specify which hypothesis to consider. Syntaxes [case_if as Eq] and [case_if in H as Eq] allows to name the hypothesis coming from the case analysis. *)
Ltac case_if_on_tactic_core E Eq :=
match type of E with
| {_}+{_} => destruct E as [Eq | Eq]
| _ => let X := fresh "TEMP" in
sets_eq <- X Eq: E;
destruct X
end.
Ltac case_if_on_tactic E Eq :=
case_if_on_tactic_core E Eq; case_if_post Eq.
Tactic Notation "case_if_on" constr(E) "as" simple_intropattern(Eq) :=
case_if_on_tactic E Eq.
Tactic Notation "case_if" "as" simple_intropattern(Eq) :=
match goal with
| |- context [if ?B then _ else _] => case_if_on B as Eq
| K: context [if ?B then _ else _] |- _ => case_if_on B as Eq
end.
Tactic Notation "case_if" "in" hyp(H) "as" simple_intropattern(Eq) :=
match type of H with context [if ?B then _ else _] =>
case_if_on B as Eq end.
Tactic Notation "case_if" :=
let Eq := fresh "C" in case_if as Eq.
Tactic Notation "case_if" "in" hyp(H) :=
let Eq := fresh "C" in case_if in H as Eq.
(** [cases_if] is similar to [case_if] with two main differences: if it creates an equality of the form [x = y] and then substitutes it in the goal *)
Ltac cases_if_on_tactic_core E Eq :=
match type of E with
| {_}+{_} => destruct E as [Eq|Eq]; try subst_hyp Eq
| _ => let X := fresh "TEMP" in
sets_eq <- X Eq: E;
destruct X
end.
Ltac cases_if_on_tactic E Eq :=
cases_if_on_tactic_core E Eq; tryfalse; case_if_post Eq.
Tactic Notation "cases_if_on" constr(E) "as" simple_intropattern(Eq) :=
cases_if_on_tactic E Eq.
Tactic Notation "cases_if" "as" simple_intropattern(Eq) :=
match goal with
| |- context [if ?B then _ else _] => cases_if_on B as Eq
| K: context [if ?B then _ else _] |- _ => cases_if_on B as Eq
end.
Tactic Notation "cases_if" "in" hyp(H) "as" simple_intropattern(Eq) :=
match type of H with context [if ?B then _ else _] =>
cases_if_on B as Eq end.
Tactic Notation "cases_if" :=
let Eq := fresh "C" in cases_if as Eq.
Tactic Notation "cases_if" "in" hyp(H) :=
let Eq := fresh "C" in cases_if in H as Eq.
(** [case_ifs] is like [repeat case_if] *)
Ltac case_ifs_core :=
repeat case_if.
Tactic Notation "case_ifs" :=
case_ifs_core.
(** [destruct_if] looks for a pattern of the form [if ?B then ?E1 else ?E2] in the goal, and perform a case analysis on [B] by calling [destruct B]. It looks in the goal first, and otherwise in the first hypothesis that contains an [if] statement. *)
Ltac destruct_if_post := tryfalse.
Tactic Notation "destruct_if"
"as" simple_intropattern(Eq1) simple_intropattern(Eq2) :=
match goal with
| |- context [if ?B then _ else _] => destruct B as [Eq1|Eq2]
| K: context [if ?B then _ else _] |- _ => destruct B as [Eq1|Eq2]
end;
destruct_if_post.
Tactic Notation "destruct_if" "in" hyp(H)
"as" simple_intropattern(Eq1) simple_intropattern(Eq2) :=
match type of H with context [if ?B then _ else _] =>
destruct B as [Eq1|Eq2] end;
destruct_if_post.
Tactic Notation "destruct_if" "as" simple_intropattern(Eq) :=
destruct_if as Eq Eq.
Tactic Notation "destruct_if" "in" hyp(H) "as" simple_intropattern(Eq) :=
destruct_if in H as Eq Eq.
Tactic Notation "destruct_if" :=
let Eq := fresh "C" in destruct_if as Eq Eq.
Tactic Notation "destruct_if" "in" hyp(H) :=
let Eq := fresh "C" in destruct_if in H as Eq Eq.
(** [cases'] is provided for compatibility with [remember]. *)
(** [cases' E] is similar to [case_eq E] except that it generates the equality in the context and not in the goal. The syntax [cases' E as H] allows specifying the name [H] of that hypothesis. *)
Tactic Notation "cases'" constr(E) "as" ident(H) :=
let X := fresh "TEMP" in
set (X := E) in *; def_to_eq X H E;
destruct X.
Tactic Notation "cases'" constr(E) :=
let x := fresh "Eq" in cases' E as H.
(** [cases_if'] is similar to [cases_if] except that it generates the symmetric equality. *)
Ltac cases_if_on' E Eq :=
match type of E with
| {_}+{_} => destruct E as [Eq|Eq]; try subst_hyp Eq
| _ => let X := fresh "TEMP" in
sets_eq X Eq: E;
destruct X
end; case_if_post Eq.
Tactic Notation "cases_if'" "as" simple_intropattern(Eq) :=
match goal with
| |- context [if ?B then _ else _] => cases_if_on' B Eq
| K: context [if ?B then _ else _] |- _ => cases_if_on' B Eq
end.
Tactic Notation "cases_if'" :=
let Eq := fresh "C" in cases_if' as Eq.
(* ################################################################# *)
(** * Induction *)
(** [inductions E] is a shorthand for [dependent induction E]. [inductions E gen X1 .. XN] is a shorthand for [dependent induction E generalizing X1 .. XN]. *)
Ltac inductions_post :=
unfold eq' in *.
Tactic Notation "inductions" ident(E) :=
dependent induction E; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) :=
dependent induction E generalizing X1; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) ident(X2) :=
dependent induction E generalizing X1 X2; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) ident(X2)
ident(X3) :=
dependent induction E generalizing X1 X2 X3; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) ident(X2)
ident(X3) ident(X4) :=
dependent induction E generalizing X1 X2 X3 X4; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) ident(X2)
ident(X3) ident(X4) ident(X5) :=
dependent induction E generalizing X1 X2 X3 X4 X5; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) ident(X2)
ident(X3) ident(X4) ident(X5) ident(X6) :=
dependent induction E generalizing X1 X2 X3 X4 X5 X6; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) ident(X2)
ident(X3) ident(X4) ident(X5) ident(X6) ident(X7) :=
dependent induction E generalizing X1 X2 X3 X4 X5 X6 X7; inductions_post.
Tactic Notation "inductions" ident(E) "gen" ident(X1) ident(X2)
ident(X3) ident(X4) ident(X5) ident(X6) ident(X7) ident(X8) :=
dependent induction E generalizing X1 X2 X3 X4 X5 X6 X7 X8; inductions_post.
(** [induction_wf IH: E X] is used to apply the well-founded induction principle, for a given well-founded relation. It applies to a goal [PX] where [PX] is a proposition on [X]. First, it sets up the goal in the form [(fun a => P a) X], using [pattern X], and then it applies the well-founded induction principle instantiated on [E].  Here [E] may be either: - a proof of [wf R] for [R] of type [A->A->Prop] - a binary relation of type [A->A->Prop] - a measure of type [A -> nat] // only when LibWf is used. *)
(* DEPRECATED Tactic Notation "induction_wf" ident(IH) ":" constr(E) ident(X) := pattern X; apply (well_founded_ind E); clear X; intros X IH. *)
Ltac induction_wf_process_wf_hyp tt := (* refined in LibWf *)
idtac.
Ltac induction_wf_process_measure E := (* refined in LibWf *)
fail.
Ltac induction_wf_core_then E X cont :=
let clearX tt :=
first [ clear X | fail 3 "the variable on which the induction is done appears in the hypotheses" ] in
pattern X;
first [ eapply (@well_founded_ind _ E)
| eapply (@well_founded_ind _ (E _))
| eapply (@well_founded_ind _ (E _ _))
| eapply (@well_founded_ind _ (E _ _ _))
| induction_wf_process_measure E
| applys well_founded_ind E ];
clearX tt;
first [ induction_wf_process_wf_hyp tt
| intros X; cont tt ].
Ltac induction_wf_core IH E X :=
induction_wf_core_then E X ltac:(fun _ => intros IH).
Tactic Notation "induction_wf" ident(IH) ":" constr(E) ident(X) :=
induction_wf_core IH E X.
(** Induction on the height of a derivation: the helper tactic [induct_height] helps proving the equivalence of the auxiliary judgment that includes a counter for the maximal height (see LibTacticsDemos for an example) *)
Proof using.
intros. destruct (lt_dec n1 n2).
exists (S n2). lia.
exists (S n1). lia.
Qed.
Ltac induct_height_step x :=
match goal with
| H: exists _, _ |- _ =>
let n := fresh "n" in let y := fresh "x" in
destruct H as [n ?];
forwards (y&?&?): induct_height_max2 n x;
induct_height_step y
| _ => exists (S x); eauto
end.
Ltac induct_height := induct_height_step O.
(* ################################################################# *)
(** * Coinduction *)
(** Tactic [cofixs IH] is like [cofix IH] except that the coinduction hypothesis is tagged in the form [IH: COIND P] instead of being just [IH: P]. This helps other tactics clearing the coinduction hypothesis using [clear_coind] *)
Definition COIND (P:Prop) := P.
Tactic Notation "cofixs" ident(IH) :=
cofix IH;
match type of IH with ?P => change P with (COIND P) in IH end.
(** Tactic [clear_coind] clears all the coinduction hypotheses, assuming that they have been tagged *)
Ltac clear_coind :=
repeat match goal with H: COIND _ |- _ => clear H end.
(** Tactic [abstracts tac] is like [abstract tac] except that it clears the coinduction hypotheses so that the productivity check will be happy. For example, one can use [abstracts lia] to obtain the same behavior as [lia] but with an auxiliary lemma being generated. *)
Tactic Notation "abstracts" tactic(tac) :=
clear_coind; tac.
(* ################################################################# *)
(** * Decidable Equality *)
(** [decides_equality] is the same as [decide equality] excepts that it is able to unfold definitions at head of the current goal. *)
Ltac decides_equality_tactic :=
first [ decide equality | progress(unfolds); decides_equality_tactic ].
Tactic Notation "decides_equality" :=
decides_equality_tactic.
(* ################################################################# *)
(** * Equivalence *)
(** [iff H] can be used to prove an equivalence [P <-> Q] and name [H] the hypothesis obtained in each case. The syntaxes [iff] and [iff H1 H2] are also available to specify zero or two names. The tactic [iff <- H] swaps the two subgoals, i.e. produces (Q -> P) as first subgoal. *)
Proof using. intuition. Qed.
Tactic Notation "iff" simple_intropattern(H1) simple_intropattern(H2) :=
split; [ intros H1 | intros H2 ].
Tactic Notation "iff" simple_intropattern(H) :=
iff H H.
Tactic Notation "iff" :=
let H := fresh "H" in iff H.
Tactic Notation "iff" "<-" simple_intropattern(H1) simple_intropattern(H2) :=
apply iff_intro_swap; [ intros H1 | intros H2 ].
Tactic Notation "iff" "<-" simple_intropattern(H) :=
iff <- H H.
Tactic Notation "iff" "<-" :=
let H := fresh "H" in iff <- H.
(* ################################################################# *)
(** * N-ary Conjunctions and Disjunctions *)
(** N-ary Conjunctions Splitting in Goals *)
(** Underlying implementation of [splits]. *)
Ltac splits_tactic N :=
match N with
| O => fail
| S O => idtac
| S ?N' => split; [| splits_tactic N']
end.
Ltac unfold_goal_until_conjunction :=
match goal with
| |- _ /\ _ => idtac
| _ => progress(unfolds); unfold_goal_until_conjunction
end.
Ltac get_term_conjunction_arity T :=
match T with
| _ /\ _ /\ _ /\ _ /\ _ /\ _ /\ _ /\ _ => constr:(8)
| _ /\ _ /\ _ /\ _ /\ _ /\ _ /\ _ => constr:(7)
| _ /\ _ /\ _ /\ _ /\ _ /\ _ => constr:(6)
| _ /\ _ /\ _ /\ _ /\ _ => constr:(5)
| _ /\ _ /\ _ /\ _ => constr:(4)
| _ /\ _ /\ _ => constr:(3)
| _ /\ _ => constr:(2)
| _ -> ?T' => get_term_conjunction_arity T'
| _ => let P := get_head T in
let T' := eval unfold P in T in
match T' with
| T => fail 1
| _ => get_term_conjunction_arity T'
end
(* --todo: warning this can loop... *)
end.
Ltac get_goal_conjunction_arity :=
match goal with |- ?T => get_term_conjunction_arity T end.
(** [splits] applies to a goal of the form [(T1 /\ .. /\ TN)] and destruct it into [N] subgoals [T1] .. [TN]. If the goal is not a conjunction, then it unfolds the head definition. *)
Tactic Notation "splits" :=
unfold_goal_until_conjunction;
let N := get_goal_conjunction_arity in
splits_tactic N.
(** [splits N] is similar to [splits], except that it will unfold as many definitions as necessary to obtain an [N]-ary conjunction. *)
Tactic Notation "splits" constr(N) :=
let N := number_to_nat N in
splits_tactic N.
(** N-ary Conjunctions Deconstruction *)
(** Underlying implementation of [destructs]. *)
Ltac destructs_conjunction_tactic N T :=
match N with
| 2 => destruct T as [? ?]
| 3 => destruct T as [? [? ?]]
| 4 => destruct T as [? [? [? ?]]]
| 5 => destruct T as [? [? [? [? ?]]]]
| 6 => destruct T as [? [? [? [? [? ?]]]]]
| 7 => destruct T as [? [? [? [? [? [? ?]]]]]]
end.
(** [destructs T] allows destructing a term [T] which is a N-ary conjunction. It is equivalent to [destruct T as (H1 .. HN)], except that it does not require to manually specify N different names. *)
Tactic Notation "destructs" constr(T) :=
let TT := type of T in
let N := get_term_conjunction_arity TT in
destructs_conjunction_tactic N T.
(** [destructs N T] is equivalent to [destruct T as (H1 .. HN)], except that it does not require to manually specify N different names. Remark that it is not restricted to N-ary conjunctions. *)
Tactic Notation "destructs" constr(N) constr(T) :=
let N := number_to_nat N in
destructs_conjunction_tactic N T.
(** Proving Goals that are N-ary Disjunctions *)
(** Underlying implementation of [branch]. *)
Ltac branch_tactic K N :=
match constr:((K,N)) with
| (_,0) => fail 1
| (0,_) => fail 1
| (1,1) => idtac
| (1,_) => left
| (S ?K', S ?N') => right; branch_tactic K' N'
end.
Ltac unfold_goal_until_disjunction :=
match goal with
| |- _ \/ _ => idtac
| _ => progress(unfolds); unfold_goal_until_disjunction
end.
Ltac get_term_disjunction_arity T :=
match T with
| _ \/ _ \/ _ \/ _ \/ _ \/ _ \/ _ \/ _ => constr:(8)
| _ \/ _ \/ _ \/ _ \/ _ \/ _ \/ _ => constr:(7)
| _ \/ _ \/ _ \/ _ \/ _ \/ _ => constr:(6)
| _ \/ _ \/ _ \/ _ \/ _ => constr:(5)
| _ \/ _ \/ _ \/ _ => constr:(4)
| _ \/ _ \/ _ => constr:(3)
| _ \/ _ => constr:(2)
| _ -> ?T' => get_term_disjunction_arity T'
| _ => let P := get_head T in
let T' := eval unfold P in T in
match T' with
| T => fail 1
| _ => get_term_disjunction_arity T'
end
end.
Ltac get_goal_disjunction_arity :=
match goal with |- ?T => get_term_disjunction_arity T end.
(** [branch N] applies to a goal of the form [P1 \/ ... \/ PK \/ ... \/ PN] and leaves the goal [PK]. It only able to unfold the head definition (if there is one), but for more complex unfolding one should use the tactic [branch K of N]. *)
Tactic Notation "branch" constr(K) :=
let K := number_to_nat K in
unfold_goal_until_disjunction;
let N := get_goal_disjunction_arity in
branch_tactic K N.
(** [branch K of N] is similar to [branch K] except that the arity of the disjunction [N] is given manually, and so this version of the tactic is able to unfold definitions. In other words, applies to a goal of the form [P1 \/ ... \/ PK \/ ... \/ PN] and leaves the goal [PK]. *)
Tactic Notation "branch" constr(K) "of" constr(N) :=
let N := number_to_nat N in
let K := number_to_nat K in
branch_tactic K N.
(** N-ary Disjunction Deconstruction *)
(** Underlying implementation of [branches]. *)
Ltac destructs_disjunction_tactic N T :=
match N with
| 2 => destruct T as [? | ?]
| 3 => destruct T as [? | [? | ?]]
| 4 => destruct T as [? | [? | [? | ?]]]
| 5 => destruct T as [? | [? | [? | [? | ?]]]]
end.
(** [branches T] allows destructing a term [T] which is a N-ary disjunction. It is equivalent to [destruct T as [ H1 | .. | HN ] ], and produces [N] subgoals corresponding to the [N] possible cases. *)
Tactic Notation "branches" constr(T) :=
let TT := type of T in
let N := get_term_disjunction_arity TT in
destructs_disjunction_tactic N T.
(** [branches N T] is the same as [branches T] except that the arity is forced to [N]. This version is useful to unfold definitions on the fly. *)
Tactic Notation "branches" constr(N) constr(T) :=
let N := number_to_nat N in
destructs_disjunction_tactic N T.
(** [branches] automatically finds a hypothesis [h] that is a disjunction and destructs it. *)
Tactic Notation "branches" :=
match goal with h: _ \/ _ |- _ => branches h end.
(** N-ary Existentials *)
(** [exists T1 ... TN] is a shorthand for [exists T1; ...; exists TN]. It is intended to prove goals of the form [exist X1 .. XN, P]. If an argument provided is [__] (double underscore), then an evar is introduced. [exists T1 .. TN ___] is equivalent to [exists T1 .. TN __ __ __] with as many [__] as possible. *)
Tactic Notation "exists_original" constr(T1) :=
exists T1.
Tactic Notation "exists" constr(T1) :=
match T1 with
| ltac_wild => esplit
| ltac_wilds => repeat esplit
| _ => exists T1
end.
Tactic Notation "exists" constr(T1) constr(T2) :=
exists T1; exists T2.
Tactic Notation "exists" constr(T1) constr(T2) constr(T3) :=
exists T1; exists T2; exists T3.
Tactic Notation "exists" constr(T1) constr(T2) constr(T3) constr(T4) :=
exists T1; exists T2; exists T3; exists T4.
Tactic Notation "exists" constr(T1) constr(T2) constr(T3) constr(T4)
constr(T5) :=
exists T1; exists T2; exists T3; exists T4; exists T5.
Tactic Notation "exists" constr(T1) constr(T2) constr(T3) constr(T4)
constr(T5) constr(T6) :=
exists T1; exists T2; exists T3; exists T4; exists T5; exists T6.
(** For compatibility with Coq syntax, [exists T1, .., TN] is also provided. *)
Tactic Notation "exists" constr(T1) "," constr(T2) :=
exists T1 T2.
Tactic Notation "exists" constr(T1) "," constr(T2) "," constr(T3) :=
exists T1 T2 T3.
Tactic Notation "exists" constr(T1) "," constr(T2) "," constr(T3) "," constr(T4) :=
exists T1 T2 T3 T4.
Tactic Notation "exists" constr(T1) "," constr(T2) "," constr(T3) "," constr(T4) ","
constr(T5) :=
exists T1 T2 T3 T4 T5.
Tactic Notation "exists" constr(T1) "," constr(T2) "," constr(T3) "," constr(T4) ","
constr(T5) "," constr(T6) :=
exists T1 T2 T3 T4 T5 T6.
(** The tactic [exists], without arguments, repeats [esplit] as many times as there are visible existentials at the head of the goal. In there are zero existentials visible, the tactic [hnf] is called once. If there are still zero existentials visible, the tactic fails.  To obtain a tactic that supports arbitrary number of existentials including the possibility of having zero existentials, use [try exists]. *)
Ltac exists_noarg_positive tt :=
match goal with
| |- exists _, _ => esplit; try exists_noarg_positive tt
end.
Ltac exists_noarg tt :=
match goal with
| |- exists _, _ => exists_noarg_positive tt
| _ => hnf; exists_noarg_positive tt
end.
Tactic Notation "exists" :=
exists_noarg tt.
Definition def_with_exists (n:nat) : Prop :=
exists x, x = n.
(** The tactic [exists_nounfold] is similar to [exists], except that it does nothing if there are no existentials visible in the goal. This tactic may be useful for programming other tactics in a robust way. *)
Tactic Notation "exists_nounfold" :=
try exists_noarg_positive tt.
(** Existentials and Conjunctions in Hypotheses *)
(** [unpack] or [unpack H] destructs conjunctions and existentials in all or one hypothesis. *)
Ltac unpack_core :=
repeat match goal with
| H: _ /\ _ |- _ => destruct H
| H: exists (varname: _), _ |- _ =>
(* kludge to preserve the name of the quantified variable *)
let name := fresh varname in
destruct H as [name ?]
end.
Ltac unpack_hypothesis H :=
try match type of H with
| _ /\ _ =>
let h1 := fresh "TEMP" in
let h2 := fresh "TEMP" in
destruct H as [ h1 h2 ];
unpack_hypothesis h1;
unpack_hypothesis h2
| exists (varname: _), _ =>
(* kludge to preserve the name of the quantified variable *)
let name := fresh varname in
let body := fresh "TEMP" in
destruct H as [name body];
unpack_hypothesis body
end.
Tactic Notation "unpack" :=
unpack_core.
Tactic Notation "unpack" constr(H) :=
unpack_hypothesis H.
(* ################################################################# *)
(** * Tactics to Prove Typeclass Instances *)
(** [typeclass] is an automation tactic specialized for finding typeclass instances. *)
Tactic Notation "typeclass" :=
let go _ := eauto with typeclass_instances in
solve [ go tt | constructor; go tt ].
(** [solve_typeclass] is a simpler version of [typeclass], to use in hint tactics for resolving instances *)
Tactic Notation "solve_typeclass" :=
solve [ eauto with typeclass_instances ].
(* ################################################################# *)
(** * Tactics to Invoke Automation *)
(* ================================================================= *)
(** ** Definitions for Parsing Compatibility *)
Tactic Notation "f_equal" :=
f_equal.
Tactic Notation "constructor" :=
constructor.
Tactic Notation "simple" :=
simpl.
Tactic Notation "split" :=
split.
Tactic Notation "right" :=
right.
Tactic Notation "left" :=
left.
(* ================================================================= *)
(** ** [hint] to Add Hints Local to a Lemma *)
(** [hint E] adds [E] as an hypothesis so that automation can use it. Syntax [hint E1,..,EN] is available *)
Tactic Notation "hint" constr(E) :=
let H := fresh "Hint" in lets H: E.
Tactic Notation "hint" constr(E1) "," constr(E2) :=
hint E1; hint E2.
Tactic Notation "hint" constr(E1) "," constr(E2) "," constr(E3) :=
hint E1; hint E2; hint(E3).
Tactic Notation "hint" constr(E1) "," constr(E2) "," constr(E3) "," constr(E4) :=
hint E1; hint E2; hint(E3); hint(E4 ).
(* ================================================================= *)
(** ** [jauto], a New Automation Tactic *)
(** [jauto] is better at [intuition eauto] because it can open existentials from the context. In the same time, [jauto] can be faster than [intuition eauto] because it does not destruct disjunctions from the context. The strategy of [jauto] can be summarized as follows: - open all the existentials and conjunctions from the context - call esplit and split on the existentials and conjunctions in the goal - call eauto. *)
Tactic Notation "jauto" :=
try solve [ jauto_set; eauto ].
Tactic Notation "jauto_fast" :=
try solve [ auto | eauto | jauto ].
(** [iauto] is a shorthand for [intuition eauto] *)
Tactic Notation "iauto" := try solve [intuition eauto].
(* ================================================================= *)
(** ** Definitions of Automation Tactics *)
(** The two following tactics defined the default behaviour of "light automation" and "strong automation". These tactics may be redefined at any time using the syntax [Ltac .. ::= ..]. *)
(** [auto_tilde] is the tactic which will be called each time a symbol [~] is used after a tactic. *)
Ltac auto_tilde_default := auto.
Ltac auto_tilde := auto_tilde_default.
(** [auto_star] is the tactic which will be called each time a symbol [*] is used after a tactic. *)
Ltac auto_star_default := try solve [ auto | eauto | intuition eauto ].
(* --todo: should be jauto *)
Ltac auto_star := auto_star_default.
(** [autos~] is a notation for tactic [auto_tilde]. It may be followed by lemmas (or proofs terms) which auto will be able to use for solving the goal.  [autos] is an alias for [autos~] *)
Tactic Notation "autos" :=
auto_tilde.
Tactic Notation "autos" "~" :=
auto_tilde.
Tactic Notation "autos" "~" constr(E1) :=
lets: E1; auto_tilde.
Tactic Notation "autos" "~" constr(E1) constr(E2) :=
lets: E1; autos~ E2.
Tactic Notation "autos" "~" constr(E1) constr(E2) constr(E3) :=
lets: E1; autos~ E2 E3.
Tactic Notation "autos" "~" constr(E1) constr(E2) constr(E3) constr(E4) :=
lets: E1; autos~ E2 E3 E4.
Tactic Notation "autos" "~" constr(E1) constr(E2) constr(E3) constr(E4)
constr(E5):=
lets: E1; autos~ E2 E3 E4 E5.
(* New syntax using coma *)
Tactic Notation "autos" :=
auto_tilde.
Tactic Notation "autos" "~" :=
auto_tilde.
Tactic Notation "autos" "~" constr(E1) :=
lets: E1; auto_tilde.
Tactic Notation "autos" "~" constr(E1) "," constr(E2) :=
lets: E1; autos~ E2.
Tactic Notation "autos" "~" constr(E1) "," constr(E2) "," constr(E3) :=
lets: E1; autos~ E2 E3.
Tactic Notation "autos" "~" constr(E1) "," constr(E2) "," constr(E3) "," constr(E4) :=
lets: E1; autos~ E2 E3 E4.
Tactic Notation "autos" "~" constr(E1) "," constr(E2) "," constr(E3) "," constr(E4) ","
constr(E5):=
lets: E1; autos~ E2 E3 E4 E5.
(** [autos*] is a notation for tactic [auto_star]. It may be followed by lemmas (or proofs terms) which auto will be able to use for solving the goal. *)
Tactic Notation "autos" "*" :=
auto_star.
Tactic Notation "autos" "*" constr(E1) :=
lets: E1; auto_star.
Tactic Notation "autos" "*" constr(E1) constr(E2) :=
lets: E1; autos* E2.
Tactic Notation "autos" "*" constr(E1) constr(E2) constr(E3) :=
lets: E1; autos* E2 E3.
Tactic Notation "autos" "*" constr(E1) constr(E2) constr(E3) constr(E4) :=
lets: E1; autos* E2 E3 E4.
Tactic Notation "autos" "*" constr(E1) constr(E2) constr(E3) constr(E4)
constr(E5):=
lets: E1; autos* E2 E3 E4 E5.
(* New syntax using coma *)
Tactic Notation "autos" "*" :=
auto_star.
Tactic Notation "autos" "*" constr(E1) :=
lets: E1; auto_star.
Tactic Notation "autos" "*" constr(E1) "," constr(E2) :=
lets: E1; autos* E2.
Tactic Notation "autos" "*" constr(E1) "," constr(E2) "," constr(E3) :=
lets: E1; autos* E2 E3.
Tactic Notation "autos" "*" constr(E1) "," constr(E2) "," constr(E3) "," constr(E4) :=
lets: E1; autos* E2 E3 E4.
Tactic Notation "autos" "*" constr(E1) "," constr(E2) "," constr(E3) "," constr(E4) ","
constr(E5):=
lets: E1; autos* E2 E3 E4 E5.
(** [auto_false] is a version of [auto] able to spot some contradictions. There is an ad-hoc support for goals in [<->]: split is called first. [auto_false~] and [auto_false*] are also available. *)
Ltac auto_false_base cont :=
try solve [
intros_all; try match goal with |- _ <-> _ => split end;
solve [ cont tt | intros_all; false; cont tt ] ].
Tactic Notation "auto_false" :=
auto_false_base ltac:(fun tt => auto).
Tactic Notation "auto_false" "~" :=
auto_false_base ltac:(fun tt => auto_tilde).
Tactic Notation "auto_false" "*" :=
auto_false_base ltac:(fun tt => auto_star).
Tactic Notation "dauto" :=
dintuition eauto.
(* ================================================================= *)
(** ** Parsing for Light Automation *)
(** Any tactic followed by the symbol [~] will have [auto_tilde] called on all of its subgoals. Three exceptions: - [cuts] and [asserts] only call [auto] on their first subgoal, - [apply~] relies on [sapply] rather than [apply], - [tryfalse~] is defined as [tryfalse by auto_tilde].  Some builtin tactics are not defined using tactic notations and thus cannot be extended, e.g., [simpl] and [unfold]. For these, notation such as [simpl~] will not be available. *)
Tactic Notation "equates" "~" constr(E) :=
equates E; auto_tilde.
Tactic Notation "equates" "~" constr(n1) constr(n2) :=
equates n1 n2; auto_tilde.
Tactic Notation "equates" "~" constr(n1) constr(n2) constr(n3) :=
equates n1 n2 n3; auto_tilde.
Tactic Notation "equates" "~" constr(n1) constr(n2) constr(n3) constr(n4) :=
equates n1 n2 n3 n4; auto_tilde.
Tactic Notation "applys_eq" "~" constr(H) :=
applys_eq H; auto_tilde.
Tactic Notation "applys_eq" "~" constr(H) constr(E) :=
applys_eq H E; auto_tilde.
Tactic Notation "applys_eq" "~" constr(H) constr(n1) constr(n2) :=
applys_eq H n1 n2; auto_tilde.
Tactic Notation "applys_eq" "~" constr(H) constr(n1) constr(n2) constr(n3) :=
applys_eq H n1 n2 n3; auto_tilde.
Tactic Notation "applys_eq" "~" constr(H) constr(n1) constr(n2) constr(n3) constr(n4) :=
applys_eq H n1 n2 n3 n4; auto_tilde.
Tactic Notation "apply" "~" constr(H) :=
sapply H; auto_tilde.
Tactic Notation "destruct" "~" constr(H) :=
destruct H; auto_tilde.
Tactic Notation "destruct" "~" constr(H) "as" simple_intropattern(I) :=
destruct H as I; auto_tilde.
Tactic Notation "f_equal" "~" :=
f_equal; auto_tilde.
Tactic Notation "induction" "~" constr(H) :=
induction H; auto_tilde.
Tactic Notation "inversion" "~" constr(H) :=
inversion H; auto_tilde.
Tactic Notation "split" "~" :=
split; auto_tilde.
Tactic Notation "subst" "~" :=
subst; auto_tilde.
Tactic Notation "right" "~" :=
right; auto_tilde.
Tactic Notation "left" "~" :=
left; auto_tilde.
Tactic Notation "constructor" "~" :=
constructor; auto_tilde.
Tactic Notation "constructors" "~" :=
constructors; auto_tilde.
Tactic Notation "false" "~" :=
false; auto_tilde.
Tactic Notation "false" "~" constr(E) :=
false_then E ltac:(fun _ => auto_tilde).
Tactic Notation "false" "~" constr(E0) constr(E1) :=
false~ (>> E0 E1).
Tactic Notation "false" "~" constr(E0) constr(E1) constr(E2) :=
false~ (>> E0 E1 E2).
Tactic Notation "false" "~" constr(E0) constr(E1) constr(E2) constr(E3) :=
false~ (>> E0 E1 E2 E3).
Tactic Notation "false" "~" constr(E0) constr(E1) constr(E2) constr(E3) constr(E4) :=
false~ (>> E0 E1 E2 E3 E4).
Tactic Notation "tryfalse" "~" :=
try solve [ false~ ].
Tactic Notation "asserts" "~" simple_intropattern(H) ":" constr(E) :=
asserts H: E; [ auto_tilde | idtac ].
Tactic Notation "asserts" "~" ":" constr(E) :=
let H := fresh "H" in asserts~ H: E.
Tactic Notation "cuts" "~" simple_intropattern(H) ":" constr(E) :=
cuts H: E; [ auto_tilde | idtac ].
Tactic Notation "cuts" "~" ":" constr(E) :=
cuts: E; [ auto_tilde | idtac ].
Tactic Notation "lets" "~" simple_intropattern(I) ":" constr(E) :=
lets I: E; auto_tilde.
Tactic Notation "lets" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) :=
lets I: E0 A1; auto_tilde.
Tactic Notation "lets" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) :=
lets I: E0 A1 A2; auto_tilde.
Tactic Notation "lets" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
lets I: E0 A1 A2 A3; auto_tilde.
Tactic Notation "lets" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
lets I: E0 A1 A2 A3 A4; auto_tilde.
Tactic Notation "lets" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
lets I: E0 A1 A2 A3 A4 A5; auto_tilde.
Tactic Notation "lets" "~" ":" constr(E) :=
lets: E; auto_tilde.
Tactic Notation "lets" "~" ":" constr(E0)
constr(A1) :=
lets: E0 A1; auto_tilde.
Tactic Notation "lets" "~" ":" constr(E0)
constr(A1) constr(A2) :=
lets: E0 A1 A2; auto_tilde.
Tactic Notation "lets" "~" ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
lets: E0 A1 A2 A3; auto_tilde.
Tactic Notation "lets" "~" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
lets: E0 A1 A2 A3 A4; auto_tilde.
Tactic Notation "lets" "~" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
lets: E0 A1 A2 A3 A4 A5; auto_tilde.
Tactic Notation "forwards" "~" simple_intropattern(I) ":" constr(E) :=
forwards I: E; auto_tilde.
Tactic Notation "forwards" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) :=
forwards I: E0 A1; auto_tilde.
Tactic Notation "forwards" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) :=
forwards I: E0 A1 A2; auto_tilde.
Tactic Notation "forwards" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
forwards I: E0 A1 A2 A3; auto_tilde.
Tactic Notation "forwards" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
forwards I: E0 A1 A2 A3 A4; auto_tilde.
Tactic Notation "forwards" "~" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
forwards I: E0 A1 A2 A3 A4 A5; auto_tilde.
Tactic Notation "forwards" "~" ":" constr(E) :=
forwards: E; auto_tilde.
Tactic Notation "forwards" "~" ":" constr(E0)
constr(A1) :=
forwards: E0 A1; auto_tilde.
Tactic Notation "forwards" "~" ":" constr(E0)
constr(A1) constr(A2) :=
forwards: E0 A1 A2; auto_tilde.
Tactic Notation "forwards" "~" ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
forwards: E0 A1 A2 A3; auto_tilde.
Tactic Notation "forwards" "~" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
forwards: E0 A1 A2 A3 A4; auto_tilde.
Tactic Notation "forwards" "~" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
forwards: E0 A1 A2 A3 A4 A5; auto_tilde.
Tactic Notation "applys" "~" constr(H) :=
sapply H; auto_tilde. (*todo?*)
Tactic Notation "applys" "~" constr(E0) constr(A1) :=
applys E0 A1; auto_tilde.
Tactic Notation "applys" "~" constr(E0) constr(A1) :=
applys E0 A1; auto_tilde.
Tactic Notation "applys" "~" constr(E0) constr(A1) constr(A2) :=
applys E0 A1 A2; auto_tilde.
Tactic Notation "applys" "~" constr(E0) constr(A1) constr(A2) constr(A3) :=
applys E0 A1 A2 A3; auto_tilde.
Tactic Notation "applys" "~" constr(E0) constr(A1) constr(A2) constr(A3) constr(A4) :=
applys E0 A1 A2 A3 A4; auto_tilde.
Tactic Notation "applys" "~" constr(E0) constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
applys E0 A1 A2 A3 A4 A5; auto_tilde.
Tactic Notation "specializes" "~" hyp(H) :=
specializes H; auto_tilde.
Tactic Notation "specializes" "~" hyp(H) constr(A1) :=
specializes H A1; auto_tilde.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) :=
specializes H A1 A2; auto_tilde.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) constr(A3) :=
specializes H A1 A2 A3; auto_tilde.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) constr(A3) constr(A4) :=
specializes H A1 A2 A3 A4; auto_tilde.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
specializes H A1 A2 A3 A4 A5; auto_tilde.
Tactic Notation "fapply" "~" constr(E) :=
fapply E; auto_tilde.
Tactic Notation "sapply" "~" constr(E) :=
sapply E; auto_tilde.
Tactic Notation "logic" "~" constr(E) :=
logic_base E ltac:(fun _ => auto_tilde).
Tactic Notation "intros_all" "~" :=
intros_all; auto_tilde.
Tactic Notation "unfolds" "~" :=
unfolds; auto_tilde.
Tactic Notation "unfolds" "~" constr(F1) :=
unfolds F1; auto_tilde.
Tactic Notation "unfolds" "~" constr(F1) "," constr(F2) :=
unfolds F1, F2; auto_tilde.
Tactic Notation "unfolds" "~" constr(F1) "," constr(F2) "," constr(F3) :=
unfolds F1, F2, F3; auto_tilde.
Tactic Notation "unfolds" "~" constr(F1) "," constr(F2) "," constr(F3) ","
constr(F4) :=
unfolds F1, F2, F3, F4; auto_tilde.
Tactic Notation "simple" "~" :=
simpl; auto_tilde.
Tactic Notation "simple" "~" "in" hyp(H) :=
simpl in H; auto_tilde.
Tactic Notation "simpls" "~" :=
simpls; auto_tilde.
Tactic Notation "hnfs" "~" :=
hnfs; auto_tilde.
Tactic Notation "hnfs" "~" "in" hyp(H) :=
hnf in H; auto_tilde.
Tactic Notation "substs" "~" :=
substs; auto_tilde.
Tactic Notation "intro_hyp" "~" hyp(H) :=
subst_hyp H; auto_tilde.
Tactic Notation "intro_subst" "~" :=
intro_subst; auto_tilde.
Tactic Notation "subst_eq" "~" constr(E) :=
subst_eq E; auto_tilde.
Tactic Notation "rewrite" "~" constr(E) :=
rewrite E; auto_tilde.
Tactic Notation "rewrite" "~" "<-" constr(E) :=
rewrite <- E; auto_tilde.
Tactic Notation "rewrite" "~" constr(E) "in" hyp(H) :=
rewrite E in H; auto_tilde.
Tactic Notation "rewrite" "~" "<-" constr(E) "in" hyp(H) :=
rewrite <- E in H; auto_tilde.
Tactic Notation "rewrites" "~" constr(E) :=
rewrites E; auto_tilde.
Tactic Notation "rewrites" "~" constr(E) "in" hyp(H) :=
rewrites E in H; auto_tilde.
Tactic Notation "rewrites" "~" constr(E) "in" "*" :=
rewrites E in *; auto_tilde.
Tactic Notation "rewrites" "~" "<-" constr(E) :=
rewrites <- E; auto_tilde.
Tactic Notation "rewrites" "~" "<-" constr(E) "in" hyp(H) :=
rewrites <- E in H; auto_tilde.
Tactic Notation "rewrites" "~" "<-" constr(E) "in" "*" :=
rewrites <- E in *; auto_tilde.
Tactic Notation "rewrite_all" "~" constr(E) :=
rewrite_all E; auto_tilde.
Tactic Notation "rewrite_all" "~" "<-" constr(E) :=
rewrite_all <- E; auto_tilde.
Tactic Notation "rewrite_all" "~" constr(E) "in" ident(H) :=
rewrite_all E in H; auto_tilde.
Tactic Notation "rewrite_all" "~" "<-" constr(E) "in" ident(H) :=
rewrite_all <- E in H; auto_tilde.
Tactic Notation "rewrite_all" "~" constr(E) "in" "*" :=
rewrite_all E in *; auto_tilde.
Tactic Notation "rewrite_all" "~" "<-" constr(E) "in" "*" :=
rewrite_all <- E in *; auto_tilde.
Tactic Notation "asserts_rewrite" "~" constr(E) :=
asserts_rewrite E; auto_tilde.
Tactic Notation "asserts_rewrite" "~" "<-" constr(E) :=
asserts_rewrite <- E; auto_tilde.
Tactic Notation "asserts_rewrite" "~" constr(E) "in" hyp(H) :=
asserts_rewrite E in H; auto_tilde.
Tactic Notation "asserts_rewrite" "~" "<-" constr(E) "in" hyp(H) :=
asserts_rewrite <- E in H; auto_tilde.
Tactic Notation "asserts_rewrite" "~" constr(E) "in" "*" :=
asserts_rewrite E in *; auto_tilde.
Tactic Notation "asserts_rewrite" "~" "<-" constr(E) "in" "*" :=
asserts_rewrite <- E in *; auto_tilde.
Tactic Notation "cuts_rewrite" "~" constr(E) :=
cuts_rewrite E; auto_tilde.
Tactic Notation "cuts_rewrite" "~" "<-" constr(E) :=
cuts_rewrite <- E; auto_tilde.
Tactic Notation "cuts_rewrite" "~" constr(E) "in" hyp(H) :=
cuts_rewrite E in H; auto_tilde.
Tactic Notation "cuts_rewrite" "~" "<-" constr(E) "in" hyp(H) :=
cuts_rewrite <- E in H; auto_tilde.
Tactic Notation "erewrite" "~" constr(E) :=
erewrite E; auto_tilde.
Tactic Notation "erewrites" "~" constr(E) :=
erewrites E; auto_tilde.
Tactic Notation "fequal" "~" :=
fequal; auto_tilde.
Tactic Notation "fequals" "~" :=
fequals; auto_tilde.
Tactic Notation "pi_rewrite" "~" constr(E) :=
pi_rewrite E; auto_tilde.
Tactic Notation "pi_rewrite" "~" constr(E) "in" hyp(H) :=
pi_rewrite E in H; auto_tilde.
Tactic Notation "invert" "~" hyp(H) :=
invert H; auto_tilde.
Tactic Notation "inverts" "~" hyp(H) :=
inverts H; auto_tilde.
Tactic Notation "inverts" "~" hyp(E) "as" :=
inverts E as; auto_tilde.
Tactic Notation "injects" "~" hyp(H) :=
injects H; auto_tilde.
Tactic Notation "inversions" "~" hyp(H) :=
inversions H; auto_tilde.
Tactic Notation "cases" "~" constr(E) "as" ident(H) :=
cases E as H; auto_tilde.
Tactic Notation "cases" "~" constr(E) :=
cases E; auto_tilde.
Tactic Notation "case_if" "~" :=
case_if; auto_tilde.
Tactic Notation "case_ifs" "~" :=
case_ifs; auto_tilde.
Tactic Notation "case_if" "~" "in" hyp(H) :=
case_if in H; auto_tilde.
Tactic Notation "cases_if" "~" :=
cases_if; auto_tilde.
Tactic Notation "cases_if" "~" "in" hyp(H) :=
cases_if in H; auto_tilde.
Tactic Notation "destruct_if" "~" :=
destruct_if; auto_tilde.
Tactic Notation "destruct_if" "~" "in" hyp(H) :=
destruct_if in H; auto_tilde.
Tactic Notation "cases'" "~" constr(E) "as" ident(H) :=
cases' E as H; auto_tilde.
Tactic Notation "cases'" "~" constr(E) :=
cases' E; auto_tilde.
Tactic Notation "cases_if'" "~" "as" ident(H) :=
cases_if' as H; auto_tilde.
Tactic Notation "cases_if'" "~" :=
cases_if'; auto_tilde.
Tactic Notation "decides_equality" "~" :=
decides_equality; auto_tilde.
Tactic Notation "iff" "~" :=
iff; auto_tilde.
Tactic Notation "iff" "~" simple_intropattern(I) :=
iff I; auto_tilde.
Tactic Notation "splits" "~" :=
splits; auto_tilde.
Tactic Notation "splits" "~" constr(N) :=
splits N; auto_tilde.
Tactic Notation "destructs" "~" constr(T) :=
destructs T; auto_tilde.
Tactic Notation "destructs" "~" constr(N) constr(T) :=
destructs N T; auto_tilde.
Tactic Notation "branch" "~" constr(N) :=
branch N; auto_tilde.
Tactic Notation "branch" "~" constr(K) "of" constr(N) :=
branch K of N; auto_tilde.
Tactic Notation "branches" "~" :=
branches; auto_tilde.
Tactic Notation "branches" "~" constr(T) :=
branches T; auto_tilde.
Tactic Notation "branches" "~" constr(N) constr(T) :=
branches N T; auto_tilde.
Tactic Notation "exists" "~" :=
exists; auto_tilde.
Tactic Notation "exists" "~" constr(T1) :=
exists T1; auto_tilde.
Tactic Notation "exists" "~" constr(T1) constr(T2) :=
exists T1 T2; auto_tilde.
Tactic Notation "exists" "~" constr(T1) constr(T2) constr(T3) :=
exists T1 T2 T3; auto_tilde.
Tactic Notation "exists" "~" constr(T1) constr(T2) constr(T3) constr(T4) :=
exists T1 T2 T3 T4; auto_tilde.
Tactic Notation "exists" "~" constr(T1) constr(T2) constr(T3) constr(T4)
constr(T5) :=
exists T1 T2 T3 T4 T5; auto_tilde.
Tactic Notation "exists" "~" constr(T1) constr(T2) constr(T3) constr(T4)
constr(T5) constr(T6) :=
exists T1 T2 T3 T4 T5 T6; auto_tilde.
Tactic Notation "exists" "~" constr(T1) "," constr(T2) :=
exists T1 T2; auto_tilde.
Tactic Notation "exists" "~" constr(T1) "," constr(T2) "," constr(T3) :=
exists T1 T2 T3; auto_tilde.
Tactic Notation "exists" "~" constr(T1) "," constr(T2) "," constr(T3) ","
constr(T4) :=
exists T1 T2 T3 T4; auto_tilde.
Tactic Notation "exists" "~" constr(T1) "," constr(T2) "," constr(T3) ","
constr(T4) "," constr(T5) :=
exists T1 T2 T3 T4 T5; auto_tilde.
Tactic Notation "exists" "~" constr(T1) "," constr(T2) "," constr(T3) ","
constr(T4) "," constr(T5) "," constr(T6) :=
exists T1 T2 T3 T4 T5 T6; auto_tilde.
(* ================================================================= *)
(** ** Parsing for Strong Automation *)
(** Any tactic followed by the symbol [*] will have [auto*] called on all of its subgoals. The exceptions to these rules are the same as for light automation.  Exception: use [subs*] instead of [subst*] if you import the library [Coq.Classes.Equivalence]. *)
Tactic Notation "equates" "*" constr(E) :=
equates E; auto_star.
Tactic Notation "equates" "*" constr(n1) constr(n2) :=
equates n1 n2; auto_star.
Tactic Notation "equates" "*" constr(n1) constr(n2) constr(n3) :=
equates n1 n2 n3; auto_star.
Tactic Notation "equates" "*" constr(n1) constr(n2) constr(n3) constr(n4) :=
equates n1 n2 n3 n4; auto_star.
Tactic Notation "applys_eq" "*" constr(H) :=
applys_eq H; auto_star.
Tactic Notation "applys_eq" "*" constr(H) constr(E) :=
applys_eq H E; auto_star.
Tactic Notation "applys_eq" "*" constr(H) constr(n1) constr(n2) :=
applys_eq H n1 n2; auto_star.
Tactic Notation "applys_eq" "*" constr(H) constr(n1) constr(n2) constr(n3) :=
applys_eq H n1 n2 n3; auto_star.
Tactic Notation "applys_eq" "*" constr(H) constr(n1) constr(n2) constr(n3) constr(n4) :=
applys_eq H n1 n2 n3 n4; auto_star.
Tactic Notation "apply" "*" constr(H) :=
sapply H; auto_star.
Tactic Notation "destruct" "*" constr(H) :=
destruct H; auto_star.
Tactic Notation "destruct" "*" constr(H) "as" simple_intropattern(I) :=
destruct H as I; auto_star.
Tactic Notation "f_equal" "*" :=
f_equal; auto_star.
Tactic Notation "induction" "*" constr(H) :=
induction H; auto_star.
Tactic Notation "inversion" "*" constr(H) :=
inversion H; auto_star.
Tactic Notation "split" "*" :=
split; auto_star.
Tactic Notation "subs" "*" :=
subst; auto_star.
Tactic Notation "subst" "*" :=
subst; auto_star.
Tactic Notation "right" "*" :=
right; auto_star.
Tactic Notation "left" "*" :=
left; auto_star.
Tactic Notation "constructor" "*" :=
constructor; auto_star.
Tactic Notation "constructors" "*" :=
constructors; auto_star.
Tactic Notation "false" "*" :=
false; auto_star.
Tactic Notation "false" "*" constr(E) :=
false_then E ltac:(fun _ => auto_star).
Tactic Notation "false" "*" constr(E0) constr(E1) :=
false* (>> E0 E1).
Tactic Notation "false" "*" constr(E0) constr(E1) constr(E2) :=
false* (>> E0 E1 E2).
Tactic Notation "false" "*" constr(E0) constr(E1) constr(E2) constr(E3) :=
false* (>> E0 E1 E2 E3).
Tactic Notation "false" "*" constr(E0) constr(E1) constr(E2) constr(E3) constr(E4) :=
false* (>> E0 E1 E2 E3 E4).
Tactic Notation "tryfalse" "*" :=
try solve [ false* ].
Tactic Notation "asserts" "*" simple_intropattern(H) ":" constr(E) :=
asserts H: E; [ auto_star | idtac ].
Tactic Notation "asserts" "*" ":" constr(E) :=
let H := fresh "H" in asserts* H: E.
Tactic Notation "cuts" "*" simple_intropattern(H) ":" constr(E) :=
cuts H: E; [ auto_star | idtac ].
Tactic Notation "cuts" "*" ":" constr(E) :=
cuts: E; [ auto_star | idtac ].
Tactic Notation "lets" "*" simple_intropattern(I) ":" constr(E) :=
lets I: E; auto_star.
Tactic Notation "lets" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) :=
lets I: E0 A1; auto_star.
Tactic Notation "lets" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) :=
lets I: E0 A1 A2; auto_star.
Tactic Notation "lets" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
lets I: E0 A1 A2 A3; auto_star.
Tactic Notation "lets" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
lets I: E0 A1 A2 A3 A4; auto_star.
Tactic Notation "lets" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
lets I: E0 A1 A2 A3 A4 A5; auto_star.
Tactic Notation "lets" "*" ":" constr(E) :=
lets: E; auto_star.
Tactic Notation "lets" "*" ":" constr(E0)
constr(A1) :=
lets: E0 A1; auto_star.
Tactic Notation "lets" "*" ":" constr(E0)
constr(A1) constr(A2) :=
lets: E0 A1 A2; auto_star.
Tactic Notation "lets" "*" ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
lets: E0 A1 A2 A3; auto_star.
Tactic Notation "lets" "*" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
lets: E0 A1 A2 A3 A4; auto_star.
Tactic Notation "lets" "*" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
lets: E0 A1 A2 A3 A4 A5; auto_star.
Tactic Notation "forwards" "*" simple_intropattern(I) ":" constr(E) :=
forwards I: E; auto_star.
Tactic Notation "forwards" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) :=
forwards I: E0 A1; auto_star.
Tactic Notation "forwards" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) :=
forwards I: E0 A1 A2; auto_star.
Tactic Notation "forwards" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
forwards I: E0 A1 A2 A3; auto_star.
Tactic Notation "forwards" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
forwards I: E0 A1 A2 A3 A4; auto_star.
Tactic Notation "forwards" "*" simple_intropattern(I) ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
forwards I: E0 A1 A2 A3 A4 A5; auto_star.
Tactic Notation "forwards" "*" ":" constr(E) :=
forwards: E; auto_star.
Tactic Notation "forwards" "*" ":" constr(E0)
constr(A1) :=
forwards: E0 A1; auto_star.
Tactic Notation "forwards" "*" ":" constr(E0)
constr(A1) constr(A2) :=
forwards: E0 A1 A2; auto_star.
Tactic Notation "forwards" "*" ":" constr(E0)
constr(A1) constr(A2) constr(A3) :=
forwards: E0 A1 A2 A3; auto_star.
Tactic Notation "forwards" "*" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) :=
forwards: E0 A1 A2 A3 A4; auto_star.
Tactic Notation "forwards" "*" ":" constr(E0)
constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
forwards: E0 A1 A2 A3 A4 A5; auto_star.
Tactic Notation "applys" "*" constr(H) :=
sapply H; auto_star. (*todo?*)
Tactic Notation "applys" "*" constr(E0) constr(A1) :=
applys E0 A1; auto_star.
Tactic Notation "applys" "*" constr(E0) constr(A1) :=
applys E0 A1; auto_star.
Tactic Notation "applys" "*" constr(E0) constr(A1) constr(A2) :=
applys E0 A1 A2; auto_star.
Tactic Notation "applys" "*" constr(E0) constr(A1) constr(A2) constr(A3) :=
applys E0 A1 A2 A3; auto_star.
Tactic Notation "applys" "*" constr(E0) constr(A1) constr(A2) constr(A3) constr(A4) :=
applys E0 A1 A2 A3 A4; auto_star.
Tactic Notation "applys" "*" constr(E0) constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
applys E0 A1 A2 A3 A4 A5; auto_star.
Tactic Notation "specializes" "*" hyp(H) :=
specializes H; auto_star.
Tactic Notation "specializes" "~" hyp(H) constr(A1) :=
specializes H A1; auto_star.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) :=
specializes H A1 A2; auto_star.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) constr(A3) :=
specializes H A1 A2 A3; auto_star.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) constr(A3) constr(A4) :=
specializes H A1 A2 A3 A4; auto_star.
Tactic Notation "specializes" hyp(H) constr(A1) constr(A2) constr(A3) constr(A4) constr(A5) :=
specializes H A1 A2 A3 A4 A5; auto_star.
Tactic Notation "fapply" "*" constr(E) :=
fapply E; auto_star.
Tactic Notation "sapply" "*" constr(E) :=
sapply E; auto_star.
Tactic Notation "logic" constr(E) :=
logic_base E ltac:(fun _ => auto_star).
Tactic Notation "intros_all" "*" :=
intros_all; auto_star.
Tactic Notation "unfolds" "*" :=
unfolds; auto_star.
Tactic Notation "unfolds" "*" constr(F1) :=
unfolds F1; auto_star.
Tactic Notation "unfolds" "*" constr(F1) "," constr(F2) :=
unfolds F1, F2; auto_star.
Tactic Notation "unfolds" "*" constr(F1) "," constr(F2) "," constr(F3) :=
unfolds F1, F2, F3; auto_star.
Tactic Notation "unfolds" "*" constr(F1) "," constr(F2) "," constr(F3) ","
constr(F4) :=
unfolds F1, F2, F3, F4; auto_star.
Tactic Notation "simple" "*" :=
simpl; auto_star.
Tactic Notation "simple" "*" "in" hyp(H) :=
simpl in H; auto_star.
Tactic Notation "simpls" "*" :=
simpls; auto_star.
Tactic Notation "hnfs" "*" :=
hnfs; auto_star.
Tactic Notation "hnfs" "*" "in" hyp(H) :=
hnf in H; auto_star.
Tactic Notation "substs" "*" :=
substs; auto_star.
Tactic Notation "intro_hyp" "*" hyp(H) :=
subst_hyp H; auto_star.
Tactic Notation "intro_subst" "*" :=
intro_subst; auto_star.
Tactic Notation "subst_eq" "*" constr(E) :=
subst_eq E; auto_star.
Tactic Notation "rewrite" "*" constr(E) :=
rewrite E; auto_star.
Tactic Notation "rewrite" "*" "<-" constr(E) :=
rewrite <- E; auto_star.
Tactic Notation "rewrite" "*" constr(E) "in" hyp(H) :=
rewrite E in H; auto_star.
Tactic Notation "rewrite" "*" "<-" constr(E) "in" hyp(H) :=
rewrite <- E in H; auto_star.
Tactic Notation "rewrites" "*" constr(E) :=
rewrites E; auto_star.
Tactic Notation "rewrites" "*" constr(E) "in" hyp(H):=
rewrites E in H; auto_star.
Tactic Notation "rewrites" "*" constr(E) "in" "*":=
rewrites E in *; auto_star.
Tactic Notation "rewrites" "*" "<-" constr(E) :=
rewrites <- E; auto_star.
Tactic Notation "rewrites" "*" "<-" constr(E) "in" hyp(H):=
rewrites <- E in H; auto_star.
Tactic Notation "rewrites" "*" "<-" constr(E) "in" "*":=
rewrites <- E in *; auto_star.
Tactic Notation "rewrite_all" "*" constr(E) :=
rewrite_all E; auto_star.
Tactic Notation "rewrite_all" "*" "<-" constr(E) :=
rewrite_all <- E; auto_star.
Tactic Notation "rewrite_all" "*" constr(E) "in" ident(H) :=
rewrite_all E in H; auto_star.
Tactic Notation "rewrite_all" "*" "<-" constr(E) "in" ident(H) :=
rewrite_all <- E in H; auto_star.
Tactic Notation "rewrite_all" "*" constr(E) "in" "*" :=
rewrite_all E in *; auto_star.
Tactic Notation "rewrite_all" "*" "<-" constr(E) "in" "*" :=
rewrite_all <- E in *; auto_star.
Tactic Notation "asserts_rewrite" "*" constr(E) :=
asserts_rewrite E; auto_star.
Tactic Notation "asserts_rewrite" "*" "<-" constr(E) :=
asserts_rewrite <- E; auto_star.
Tactic Notation "asserts_rewrite" "*" constr(E) "in" hyp(H) :=
asserts_rewrite E; auto_star.
Tactic Notation "asserts_rewrite" "*" "<-" constr(E) "in" hyp(H) :=
asserts_rewrite <- E; auto_star.
Tactic Notation "asserts_rewrite" "*" constr(E) "in" "*" :=
asserts_rewrite E in *; auto_tilde.
Tactic Notation "asserts_rewrite" "*" "<-" constr(E) "in" "*" :=
asserts_rewrite <- E in *; auto_tilde.
Tactic Notation "cuts_rewrite" "*" constr(E) :=
cuts_rewrite E; auto_star.
Tactic Notation "cuts_rewrite" "*" "<-" constr(E) :=
cuts_rewrite <- E; auto_star.
Tactic Notation "cuts_rewrite" "*" constr(E) "in" hyp(H) :=
cuts_rewrite E in H; auto_star.
Tactic Notation "cuts_rewrite" "*" "<-" constr(E) "in" hyp(H) :=
cuts_rewrite <- E in H; auto_star.
Tactic Notation "erewrite" "*" constr(E) :=
erewrite E; auto_star.
Tactic Notation "erewrites" "*" constr(E) :=
erewrites E; auto_star.
Tactic Notation "fequal" "*" :=
fequal; auto_star.
Tactic Notation "fequals" "*" :=
fequals; auto_star.
Tactic Notation "pi_rewrite" "*" constr(E) :=
pi_rewrite E; auto_star.
Tactic Notation "pi_rewrite" "*" constr(E) "in" hyp(H) :=
pi_rewrite E in H; auto_star.
Tactic Notation "invert" "*" hyp(H) :=
invert H; auto_star.
Tactic Notation "inverts" "*" hyp(H) :=
inverts H; auto_star.
Tactic Notation "inverts" "*" hyp(E) "as" :=
inverts E as; auto_star.
Tactic Notation "injects" "*" hyp(H) :=
injects H; auto_star.
Tactic Notation "inversions" "*" hyp(H) :=
inversions H; auto_star.
Tactic Notation "cases" "*" constr(E) "as" ident(H) :=
cases E as H; auto_star.
Tactic Notation "cases" "*" constr(E) :=
cases E; auto_star.
Tactic Notation "case_if" "*" :=
case_if; auto_star.
Tactic Notation "case_ifs" "*" :=
case_ifs; auto_star.
Tactic Notation "case_if" "*" "in" hyp(H) :=
case_if in H; auto_star.
Tactic Notation "cases_if" "*" :=
cases_if; auto_star.
Tactic Notation "cases_if" "*" "in" hyp(H) :=
cases_if in H; auto_star.
Tactic Notation "destruct_if" "*" :=
destruct_if; auto_star.
Tactic Notation "destruct_if" "*" "in" hyp(H) :=
destruct_if in H; auto_star.
Tactic Notation "cases'" "*" constr(E) "as" ident(H) :=
cases' E as H; auto_star.
Tactic Notation "cases'" "*" constr(E) :=
cases' E; auto_star.
Tactic Notation "cases_if'" "*" "as" ident(H) :=
cases_if' as H; auto_star.
Tactic Notation "cases_if'" "*" :=
cases_if'; auto_star.
Tactic Notation "decides_equality" "*" :=
decides_equality; auto_star.
Tactic Notation "iff" "*" :=
iff; auto_star.
Tactic Notation "iff" "*" simple_intropattern(I) :=
iff I; auto_star.
Tactic Notation "splits" "*" :=
splits; auto_star.
Tactic Notation "splits" "*" constr(N) :=
splits N; auto_star.
Tactic Notation "destructs" "*" constr(T) :=
destructs T; auto_star.
Tactic Notation "destructs" "*" constr(N) constr(T) :=
destructs N T; auto_star.
Tactic Notation "branch" "*" constr(N) :=
branch N; auto_star.
Tactic Notation "branch" "*" constr(K) "of" constr(N) :=
branch K of N; auto_star.
Tactic Notation "branches" "*" constr(T) :=
branches T; auto_star.
Tactic Notation "branches" "*" constr(N) constr(T) :=
branches N T; auto_star.
Tactic Notation "exists" "*" :=
exists; auto_star.
Tactic Notation "exists" "*" constr(T1) :=
exists T1; auto_star.
Tactic Notation "exists" "*" constr(T1) constr(T2) :=
exists T1 T2; auto_star.
Tactic Notation "exists" "*" constr(T1) constr(T2) constr(T3) :=
exists T1 T2 T3; auto_star.
Tactic Notation "exists" "*" constr(T1) constr(T2) constr(T3) constr(T4) :=
exists T1 T2 T3 T4; auto_star.
Tactic Notation "exists" "*" constr(T1) constr(T2) constr(T3) constr(T4)
constr(T5) :=
exists T1 T2 T3 T4 T5; auto_star.
Tactic Notation "exists" "*" constr(T1) constr(T2) constr(T3) constr(T4)
constr(T5) constr(T6) :=
exists T1 T2 T3 T4 T5 T6; auto_star.
Tactic Notation "exists" "*" constr(T1) "," constr(T2) :=
exists T1 T2; auto_star.
Tactic Notation "exists" "*" constr(T1) "," constr(T2) "," constr(T3) :=
exists T1 T2 T3; auto_star.
Tactic Notation "exists" "*" constr(T1) "," constr(T2) "," constr(T3) ","
constr(T4) :=
exists T1 T2 T3 T4; auto_star.
Tactic Notation "exists" "*" constr(T1) "," constr(T2) "," constr(T3) ","
constr(T4) "," constr(T5) :=
exists T1 T2 T3 T4 T5; auto_star.
Tactic Notation "exists" "*" constr(T1) "," constr(T2) "," constr(T3) ","
constr(T4) "," constr(T5) ","  constr(T6) :=
exists T1 T2 T3 T4 T5 T6; auto_star.
(* ################################################################# *)
(** * Tactics to Sort Out the Proof Context *)
(* ================================================================= *)
(** ** Hiding Hypotheses *)
(* Implementation *)
Definition ltac_something (P:Type) (e:P) := e.
Notation "'Something'" :=
(@ltac_something _ _).
Proof using. auto. Qed.
Proof using. auto. Qed.
Proof using. auto. Qed.
(** [hide_def x] and [show_def x] can be used to hide/show the body of the definition [x]. *)
Tactic Notation "hide_def" hyp(x) :=
let x' := constr:(x) in
let T := eval unfold x in x' in
change T with (@ltac_something _ T) in x.
Tactic Notation "show_def" hyp(x) :=
let x' := constr:(x) in
let U := eval unfold x in x' in
match U with @ltac_something _ ?T =>
change U with T in x end.
(** [show_def] unfolds [Something] in the goal *)
Tactic Notation "show_def" :=
unfold ltac_something.
Tactic Notation "show_def" "in" hyp(H) :=
unfold ltac_something in H.
Tactic Notation "show_def" "in" "*" :=
unfold ltac_something in *.
(** [hide_defs] and [show_defs] applies to all definitions *)
Tactic Notation "hide_defs" :=
repeat match goal with H := ?T |- _ =>
match T with
| @ltac_something _ _ => fail 1
| _ => change T with (@ltac_something _ T) in H
end
end.
Tactic Notation "show_defs" :=
repeat match goal with H := (@ltac_something _ ?T) |- _ =>
change (@ltac_something _ T) with T in H end.
(** [hide_hyp H] replaces the type of [H] with the notation [Something] and [show_hyp H] reveals the type of the hypothesis. Note that the hidden type of [H] remains convertible the real type of [H]. *)
Tactic Notation "show_hyp" hyp(H) :=
apply ltac_something_show in H.
Tactic Notation "hide_hyp" hyp(H) :=
apply ltac_something_hide in H.
(** [hide_hyps] and [show_hyps] can be used to hide/show all hypotheses of type [Prop]. *)
Tactic Notation "show_hyps" :=
repeat match goal with
H: @ltac_something _ _ |- _ => show_hyp H end.
Tactic Notation "hide_hyps" :=
repeat match goal with H: ?T |- _ =>
match type of T with
| Prop =>
match T with
| @ltac_something _ _ => fail 2
| _ => hide_hyp H
end
| _ => fail 1
end
end.
(** [hide H] and [show H] automatically select between [hide_hyp] or [hide_def], and [show_hyp] or [show_def]. Similarly [hide_all] and [show_all] apply to all. *)
Tactic Notation "hide" hyp(H) :=
first [hide_def H | hide_hyp H].
Tactic Notation "show" hyp(H) :=
first [show_def H | show_hyp H].
Tactic Notation "hide_all" :=
hide_hyps; hide_defs.
Tactic Notation "show_all" :=
unfold ltac_something in *.
(** [hide_term E] can be used to hide a term from the goal. [show_term] or [show_term E] can be used to reveal it. [hide_term E in H] can be used to specify an hypothesis. *)
Tactic Notation "hide_term" constr(E) :=
change E with (@ltac_something _ E).
Tactic Notation "show_term" constr(E) :=
change (@ltac_something _ E) with E.
Tactic Notation "show_term" :=
unfold ltac_something.
Tactic Notation "hide_term" constr(E) "in" hyp(H) :=
change E with (@ltac_something _ E) in H.
Tactic Notation "show_term" constr(E) "in" hyp(H) :=
change (@ltac_something _ E) with E in H.
Tactic Notation "show_term" "in" hyp(H) :=
unfold ltac_something in H.
(** [show_unfold R] unfolds the definition of [R] and reveals the hidden definition of R. --todo:test, and implement using unfold simply *)
(* --todo: change "unfolds" *)
Tactic Notation "show_unfold" constr(R1) :=
unfold R1; show_def.
Tactic Notation "show_unfold" constr(R1) "," constr(R2) :=
unfold R1, R2; show_def.
(* ================================================================= *)
(** ** Sorting Hypotheses *)
(** [sort] sorts out hypotheses from the context by moving all the propositions (hypotheses of type Prop) to the bottom of the context. *)
Ltac sort_tactic :=
try match goal with H: ?T |- _ =>
match type of T with Prop =>
generalizes H; (try sort_tactic); intro
end end.
Tactic Notation "sort" :=
sort_tactic.
(* ================================================================= *)
(** ** Clearing Hypotheses *)
(** [clears X1 ... XN] is a variation on [clear] which clears the variables [X1]..[XN] as well as all the hypotheses which depend on them. Contrary to [clear], it never fails. *)
Tactic Notation "clears" ident(X1) :=
let rec doit _ :=
match goal with
| H:context[X1] |- _ => clear H; try (doit tt)
| _ => clear X1
end in doit tt.
Tactic Notation "clears" ident(X1) ident(X2) :=
clears X1; clears X2.
Tactic Notation "clears" ident(X1) ident(X2) ident(X3) :=
clears X1; clears X2; clears X3.
Tactic Notation "clears" ident(X1) ident(X2) ident(X3) ident(X4) :=
clears X1; clears X2; clears X3; clears X4.
Tactic Notation "clears" ident(X1) ident(X2) ident(X3) ident(X4)
ident(X5) :=
clears X1; clears X2; clears X3; clears X4; clears X5.
Tactic Notation "clears" ident(X1) ident(X2) ident(X3) ident(X4)
ident(X5) ident(X6) :=
clears X1; clears X2; clears X3; clears X4; clears X5; clears X6.
(** [clears] (without any argument) clears all the unused variables from the context. In other words, it removes any variable which is not a proposition (i.e. not of type Prop) and which does not appear in another hypothesis nor in the goal. *)
(* --todo: rename to clears_var ? *)
Ltac clears_tactic :=
match goal with H: ?T |- _ =>
match type of T with
| Prop => generalizes H; (try clears_tactic); intro
| ?TT => clear H; (try clears_tactic)
| ?TT => generalizes H; (try clears_tactic); intro
end end.
Tactic Notation "clears" :=
clears_tactic.
(** [clears_all] clears all the hypotheses from the context that can be cleared. It leaves only the hypotheses that are mentioned in the goal. *)
Ltac clears_or_generalizes_all_core :=
repeat match goal with H: _ |- _ =>
first [ clear H | generalizes H] end.
Tactic Notation "clears_all" :=
generalize ltac_mark;
clears_or_generalizes_all_core;
intro_until_mark.
(** [clears_but H1 H2 .. HN] clears all hypotheses except the one that are mentioned and those that cannot be cleared. *)
Ltac clears_but_core cont :=
generalize ltac_mark;
cont tt;
clears_or_generalizes_all_core;
intro_until_mark.
Tactic Notation "clears_but" :=
clears_but_core ltac:(fun _ => idtac).
Tactic Notation "clears_but" ident(H1) :=
clears_but_core ltac:(fun _ => gen H1).
Tactic Notation "clears_but" ident(H1) ident(H2) :=
clears_but_core ltac:(fun _ => gen H1 H2).
Tactic Notation "clears_but" ident(H1) ident(H2) ident(H3) :=
clears_but_core ltac:(fun _ => gen H1 H2 H3).
Tactic Notation "clears_but" ident(H1) ident(H2) ident(H3) ident(H4) :=
clears_but_core ltac:(fun _ => gen H1 H2 H3 H4).
Tactic Notation "clears_but" ident(H1) ident(H2) ident(H3) ident(H4) ident(H5) :=
clears_but_core ltac:(fun _ => gen H1 H2 H3 H4 H5).

Lemma demo_clears_all_and_clears_but :
forall x y:nat, y < 2 -> x = x -> x >= 2 -> x < 3 -> True.