(** ** Generic Tactics
        We begin by defining a few generic, useful tactics. *)

    (** remove logical hypothesis inter-dependencies (fix #2136). *)

    Ltac no_logical_interdep :=
      match goal with
        | H : ?P |- _ =>
          match type of P with
            | Prop =>
              match goal with H' : context [ H ] |- _ => clear dependent H' end
            | _ => fail
          end; no_logical_interdep
        | _ => idtac
      end.Ltac abstract_term t :=
      tryif (is_var t) then fail "no need to abstract a variable"
      else (let x := fresh "x" in set (x := t) in *; try clearbody x).Ltac abstract_elements :=
      repeat
        (match goal with
           | |- context [ singleton ?t ] => abstract_term t
           | _ : context [ singleton ?t ] |- _ => abstract_term t
           | |- context [ add ?t _ ] => abstract_term t
           | _ : context [ add ?t _ ] |- _ => abstract_term t
           | |- context [ remove ?t _ ] => abstract_term t
           | _ : context [ remove ?t _ ] |- _ => abstract_term t
           | |- context [ In ?t _ ] => abstract_term t
           | _ : context [ In ?t _ ] |- _ => abstract_term t
         end).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).(** ** Discarding Irrelevant Hypotheses
        We will want to clear the context of any
        non-FSet-related hypotheses in order to increase the
        speed of the tactic.  To do this, we will need to be
        able to decide which are relevant.  We do this by making
        a simple inductive definition classifying the
        propositions of interest. *)

    Inductive FSet_elt_Prop : Prop -> Prop :=
    | eq_Prop : forall (S : Type) (x y : S),
        FSet_elt_Prop (x = y)
    | eq_elt_prop : forall x y,
        FSet_elt_Prop (E.eq x y)
    | In_elt_prop : forall x s,
        FSet_elt_Prop (In x s)
    | True_elt_prop :
        FSet_elt_Prop True
    | False_elt_prop :
        FSet_elt_Prop False
    | conj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P /\ Q)
    | disj_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P \/ Q)
    | impl_elt_prop : forall P Q,
        FSet_elt_Prop P ->
        FSet_elt_Prop Q ->
        FSet_elt_Prop (P -> Q)
    | not_elt_prop : forall P,
        FSet_elt_Prop P ->
        FSet_elt_Prop (~ P).Inductive FSet_Prop : Prop -> Prop :=
    | elt_FSet_Prop : forall P,
        FSet_elt_Prop P ->
        FSet_Prop P
    | Empty_FSet_Prop : forall s,
        FSet_Prop (Empty s)
    | Subset_FSet_Prop : forall s1 s2,
        FSet_Prop (Subset s1 s2)
    | Equal_FSet_Prop : forall s1 s2,
        FSet_Prop (Equal s1 s2).Inductive FSet_Prop : Prop -> Prop :=
    | elt_FSet_Prop : forall P,
        FSet_elt_Prop P ->
        FSet_Prop P
    | Empty_FSet_Prop : forall s,
        FSet_Prop (Empty s)
    | Subset_FSet_Prop : forall s1 s2,
        FSet_Prop (Subset s1 s2)
    | Equal_FSet_Prop : forall s1 s2,
        FSet_Prop (Equal s1 s2).Inductive FSet_Prop : Prop -> Prop :=
    | elt_FSet_Prop : forall P,
        FSet_elt_Prop P ->
        FSet_Prop P
    | Empty_FSet_Prop : forall s,
        FSet_Prop (Empty s)
    | Subset_FSet_Prop : forall s1 s2,
        FSet_Prop (Subset s1 s2)
    | Equal_FSet_Prop : forall s1 s2,
        FSet_Prop (Equal s1 s2).Inductive FSet_Prop : Prop -> Prop :=
    | elt_FSet_Prop : forall P,
        FSet_elt_Prop P ->
        FSet_Prop P
    | Empty_FSet_Prop : forall s,
        FSet_Prop (Empty s)
    | Subset_FSet_Prop : forall s1 s2,
        FSet_Prop (Subset s1 s2)
    | Equal_FSet_Prop : forall s1 s2,
        FSet_Prop (Equal s1 s2).Inductive FSet_Prop : Prop -> Prop :=
    | elt_FSet_Prop : forall P,
        FSet_elt_Prop P ->
        FSet_Prop P
    | Empty_FSet_Prop : forall s,
        FSet_Prop (Empty s)
    | Subset_FSet_Prop : forall s1 s2,
        FSet_Prop (Subset s1 s2)
    | Equal_FSet_Prop : forall s1 s2,
        FSet_Prop (Equal s1 s2).Ltac discard_nonFSet :=
      repeat (
        match goal with
        | H : context [ @Logic.eq ?T ?x ?y ] |- _ =>
          tryif (change T with E.t in H) then fail
          else tryif (change T with t in H) then fail
          else clear H
        | H : ?P |- _ =>
          tryif prop (FSet_Prop P) holds by
            (auto 100 with FSet_Prop)
          then fail
          else clear H
        end).

Lemma eq_refl_iff (x : E.t) : E.eq x x <-> True.