Lvc.Constr.CSetTac

Require Export Setoid Coq.Classes.Morphisms.
Require Import EqDec CSetNotation Util.
Require Export Sets SetInterface SetConstructs SetProperties Get.

Lemma In_add_empty {X} `{OrderedType X} x y
  : In x (add y empty) x === y.
Proof.
  rewrite add_iff. split; firstorder.
  exfalso. eapply empty_iff; eauto.
Qed.

Lemma In_single {X} `{OrderedType X} x y
  : In x (singleton y) y === x.
Proof.
  split.
  - eapply singleton_1.
  - eapply singleton_2.
Qed.

Lemma not_In_add_empty {X} `{OrderedType X} x y
  : ¬In x (add y empty) x =/= y.
Proof.
  rewrite add_iff. split; firstorder.
  intro; firstorder. eapply empty_iff; eauto.
Qed.

Lemma not_In_single {X} `{OrderedType X} x y
  : ¬In x (singleton y) y =/= x.
Proof.
  split; intros B; intro A; eapply B; clear B; eapply In_single; eauto.
Qed.

Lemma not_in_empty {X} `{OrderedType X} (x:X)
: x .
Proof.
  hnf; intros. eapply empty_iff in H0; eauto.
Qed.

Lemma de_morgan_dec {A} `{Computable A} {B} `{Computable B}
: not (A B) (not A not B).
Proof.
  decide A; decide B; intuition.
Qed.

Lemma dneg_dec {A} `{Computable A}
: not (not A) A.
Proof.
  decide A; intuition.
Qed.

Lemma P_or_False P
: (P False) P.
Proof.
  intuition.
Qed.

Lemma not_or_dist A B
: not (A B) not A not B.
Proof.
  intuition.
Qed.

Lemma not_False_is_True
: not False True.
Proof.
  intuition.
Qed.

Lemma and_True_away_right A
: A True A.
Proof.
  intuition.
Qed.

Lemma and_True_away_left A
: True A A.
Proof.
  intuition.
Qed.

Lemma of_list_app X `{OrderedType X} (A B: list X)
  : of_list (A ++ B) [=] of_list A of_list B.
Proof.
  split; intros H0.
  - rewrite of_list_1 in H0. eapply InA_app in H0.
    eapply union_iff. repeat rewrite of_list_1. intuition.
  - rewrite of_list_1. eapply InA_app_iff.
    eapply union_iff in H0.
    repeat rewrite of_list_1 in H0. intuition.
Qed.

  Ltac cset_assumption :=
    match goal with
      | [ H : context [ In _ (union ?s ?t) ] |- _ ] ⇒
        setoid_rewrite (union_iff s t _) in H
      | [ H : context [ In _ (diff ?s ?t) ] |- _ ] ⇒
        setoid_rewrite (diff_iff s t) in H
      | [ |- context [ In _ (diff ?s ?t) ] ] ⇒
        setoid_rewrite (diff_iff s t)
      | [ H : context [ In _ (add ?s ?t) ] |- _ ] ⇒
        setoid_rewrite (add_iff t s) in H
      | [ H : context [ In _ (inter ?s ?t) ] |- _ ] ⇒
        setoid_rewrite (inter_iff s t _) in H
      | [ H : context [ (?P False) ] |- _ ] ⇒
        setoid_rewrite (P_or_False P) in H
      | [ |- context [ (?P False) ] ] ⇒
        setoid_rewrite (P_or_False P)
      | [ H : context [ not (_ _) ] |- _ ] ⇒
        setoid_rewrite not_or_dist in H
      | [ |- context [ not (_ _) ] ] ⇒
        setoid_rewrite not_or_dist
      | [ |- context [ In _ (add ?s ?t) ] ] ⇒
        setoid_rewrite (add_iff t s)


      | [ H : In ?x ?s, H' : ¬In ?x ?s |- _ ] ⇒ exfalso; eapply H'; eapply H
      | [ H : In ?x ?s, H' : ¬In ?y ?s |- _ ] ⇒
        match goal with
          | [ H'' : x =/= y |- _ ] ⇒ fail 1
          | [ H'' : x === y |- _ ] ⇒ fail 1
          | [ H'' : ¬x === y |- _ ] ⇒ fail 1
          | [ H'' : ¬y === x |- _ ] ⇒ fail 1
          | [ H'' : y =/= x |- _ ] ⇒ fail 1
          | [ H'' : y === x |- _ ] ⇒ fail 1
          | [ |- _ ] ⇒ decide(x === y)
        end
      | [ H : context [ not False ] |- _ ] ⇒
        setoid_rewrite not_False_is_True in H
      | [ |- context [ not False ] ] ⇒
        setoid_rewrite not_False_is_True

      | [ H : context [ In _ empty ] |- _ ] ⇒
        setoid_rewrite empty_iff in H
      | [ |- context [ In _ empty ] ] ⇒
        setoid_rewrite empty_iff

      | [ H : context [ _ True ] |- _ ] ⇒
        setoid_rewrite and_True_away_right in H
      | [ |- context [ _ True ] ] ⇒
        setoid_rewrite and_True_away_right
      | [ H : context [ True _ ] |- _ ] ⇒
        setoid_rewrite and_True_away_left in H
      | [ |- context [ True _ ] ] ⇒
        setoid_rewrite and_True_away_left

      | [ H : context [ In _ (add _ empty) ] |- _ ] ⇒
        setoid_rewrite In_add_empty in H
      | [ |- context [ In _ (add _ empty) ] ] ⇒
        setoid_rewrite In_add_empty
      | [ H : context [ In _ (singleton _) ] |- _ ] ⇒
        setoid_rewrite In_single in H
      | [ |- context [ In _ (singleton _) ] ] ⇒
        setoid_rewrite In_single


    
      | [ |- context [ In _ (union ?s ?t) ]] ⇒
        setoid_rewrite (union_iff s t _)

      | [ H : ?x === ?y, H' : In ?x ?s, H'' : ¬In ?y ?s |- _ ] ⇒
        now (exfalso; rewrite H in H'; eauto)
      | [ H : ?x === ?y, H' : In ?y ?s, H'' : ¬In ?x ?s |- _ ] ⇒
        now (exfalso; rewrite <- H in H'; eauto)
      | [ H : ?x === ?y, H' : In ?y ?s |- In ?x ?s ] ⇒
        now (rewrite H; eauto)
      | [ H : ?y === ?x, H' : In ?y ?s |- In ?x ?s ] ⇒
        now (rewrite <- H; eauto)
      | [ H : ?x === ?y, H' : In ?y ?s |- (In ?x ?s) _ ] ⇒
        now (left; rewrite H; eauto)
      | [ H : ?y === ?x, H' : In ?y ?s |- (In ?x ?s) _ ] ⇒
        now (left; rewrite <- H; eauto)
      | [ H : ?x === ?y, H' : In ?y ?s |- _ (In ?x ?s) ] ⇒
        now (right; rewrite H; eauto)
      | [ H : ?y === ?x, H' : In ?y ?s |- _ (In ?x ?s) ] ⇒
        now (right; rewrite <- H; eauto)
      | [ H : ?s === ?s', H' : In ?x ?s' |- (In ?x ?s) _ ] ⇒
        now (left; rewrite H; eauto)
      | [ H : ?s === ?s', H' : In ?x ?s |- (In ?x ?s') _ ] ⇒
        now (left; rewrite <- H; eauto)
      | [ H : ?s === ?s', H' : In ?y ?s' |- _ (In ?x ?s) ] ⇒
        now (right; rewrite H; eauto)
      | [ H : ?s === ?s', H' : In ?y ?s |- _ (In ?x ?s') ] ⇒
        now (right; rewrite <- H; eauto)
      | [ H : ?s === ?s', H' : In ?y ?s' |- In ?x ?s ] ⇒
        now (rewrite H; eauto)
      | [ H : ?s === ?s', H' : In ?y ?s |- In ?x ?s' ] ⇒
        now (rewrite <- H; eauto)
      | [ H : ?x === ?y, H' : ¬In ?y ?s |- ¬In ?x ?s ] ⇒
        now (rewrite H; eauto)
      | [ H : ?y === ?x, H' : ¬In ?y ?s |- ¬In ?x ?s ] ⇒
        now (rewrite <- H; eauto)
      | [ |- context [ In _ (diff ?s ?t) ] ] ⇒
        setoid_rewrite (diff_iff s t)
      | [ |- context [ In _ (inter ?s ?t) ] ] ⇒
        setoid_rewrite (inter_iff s t)
      | [ |- ?s [=] ?t] ⇒ intro
      | [ |- complement _ _ _ ] ⇒ intro
      | [ H : ?x =/= ?y |- ¬In ?x (add ?y empty) ] ⇒
        now (rewrite not_In_add_empty; eauto)
      | [ |- context [¬In ?x (add ?y empty)] ] ⇒
        setoid_rewrite (not_In_add_empty x y)
      | [ |- context [¬In _ (singleton _)] ] ⇒
        setoid_rewrite (not_In_single)
      | [ H : context [¬In _ (singleton _)] |- _ ] ⇒
        setoid_rewrite not_In_single in H
      | [ |- context [In ?x (add ?y empty)] ] ⇒
        setoid_rewrite (In_add_empty x y)
      | [ |- context [In ?x empty] ] ⇒
        setoid_rewrite (empty_iff x)
      | [ |- context [ ¬In ?x empty ] ] ⇒
        setoid_rewrite (empty_iff x)
      | [ |- _ _ ] ⇒ hnf; intros
      | [ |- context [ In ?x (diff ?s ?t) ]] ⇒
        intros
      | [ |- context [ In ?x (singleton ?y) ]] ⇒
        setoid_rewrite (singleton_iff y x)
      | [ H : context [ In ?x (singleton ?y) ] |- _ ] ⇒
        setoid_rewrite (singleton_iff y x) in H
      | [ |- context [ In ?y (add ?x ?s) ]] ⇒
        setoid_rewrite (add_iff s x y )
      | [ H : context [ In ?y (add ?x ?s) ] |- _ ] ⇒
        setoid_rewrite (add_iff s x y ) in H
      | [ H : ?A [=] |- _ ] ⇒
        assert (A );
          [ let H := fresh "H" in
            edestruct (double_inclusion A ) as [[H ?] ?]; eauto| clear H]
      | [ H : ?A |- _ ] ⇒
        assert ( a, a A False);[
            let a := fresh "a" in let C := fresh "H" in
                                  intros a C;
                                    eapply (@not_in_empty _ _ a (H _ C))| clear H]
      | [ |- ?a ?s ( _ ?a ?s) ] ⇒
        lazymatch goal with
          | [ H : a s |- _ ] ⇒ fail
          | [ H : a s |- _ ] ⇒ fail
          | [ H : a s False |- _ ] ⇒ fail
          | _decide (a s)
        end
      | [ |- ?a ?s ( _ (?a ?s False) ) ] ⇒
        lazymatch goal with
        | [ H : a s |- _ ] ⇒ fail
        | [ H : a s |- _ ] ⇒ fail
        | [ H : a s False |- _ ] ⇒ fail
        | _decide (a s)
        end
      | [ |- ( _ (?a ?s False) ?a ?s) ] ⇒
        lazymatch goal with
        | [ H : a s |- _ ] ⇒ fail
        | [ H : a s |- _ ] ⇒ fail
        | [ H : a s False |- _ ] ⇒ fail
        | _decide (a s)
        end
      | [ H: (not ?A) False |- ?A ] ⇒ try now (eapply dneg_dec; intuition)
      | [ H : context [ InA _ ?x ?l ] |- _ ] ⇒ setoid_rewrite <- of_list_1 in H
      | [ |- context [ InA _ ?x ?l ] ] ⇒ setoid_rewrite <- of_list_1
      | [ H : (?x ?s False) False |- _ ] ⇒
        lazymatch goal with
        | [ H : x s |- _ ] ⇒ fail
        | [ H : x s |- _ ] ⇒ fail
        | [ H : x s False |- _ ] ⇒ fail
        | _decide (x s)
        end
      | [ INCL: ?s1 ?s2, NINCL : ¬ ?t1 ?t2 |- _ ] ⇒
        match s1 with
        | t1
          match s2 with
          | t2exfalso; eapply NINCL, INCL
          | _match goal with
                | [ H : s2 [=] t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H; eapply INCL
                | [ H : t2 [=] s2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite H; eapply INCL
                | [ H : s2 t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H; eapply INCL
                end
          end
        | _match goal with
              | [ H1 : s1 [=] t1 |- _ ] ⇒
                match s2 with
                | t2exfalso; eapply NINCL; rewrite <- H1; eapply INCL
                | _match goal with
                      | [ H : s2 [=] t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H1, <- H; eapply INCL
                      | [ H : t2 [=] s2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H1, H; eapply INCL
                      | [ H : s2 t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H1, <- H; eapply INCL
                      end
                end
              | [ H1 : t1 [=] s1 |- _ ] ⇒
                match s2 with
                | t2exfalso; eapply NINCL; rewrite H1; INCL
                | _match goal with
                      | [ H : s2 [=] t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite H1, <- H; eapply INCL
                      | [ H : t2 [=] s2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite H1, H; eapply INCL
                      | [ H : s2 t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite H1, <- H; eapply INCL
                      end
                end
              | [ H1 : s1 t1 |- _ ] ⇒
                match s2 with
                | t2exfalso; eapply NINCL; rewrite <- H1; eapply INCL
                | _match goal with
                      | [ H : s2 [=] t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H1, <- H; eapply INCL
                      | [ H : t2 [=] s2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H1, H; eapply INCL
                      | [ H : s2 t2 |- _ ] ⇒ exfalso; eapply NINCL; rewrite <- H1, <- H; eapply INCL
                      end
                end
              end
        end
      | [ H : ?s [=] ?t |- _ ] ⇒ unfold Equal in H
    end.

  Ltac mycleartrivial :=
    try (progress (clear_trivial_eqs;
              match goal with
                | [ H : @Equivalence.equiv _
                                           (@_eq _ (@SOT_as_OT _ (@eq _) nat_OrderedType))
                                           (@OT_Equivalence _ (@SOT_as_OT _ (@eq _) nat_OrderedType))
                                           ?a ?b |- _ ] ⇒
                  is_var a; is_var b; invc H; clear_trivial_eqs
              end)).

  Ltac cset_tac_step f :=
    intros; (try subst); dcr; destr; mycleartrivial; (try cset_assumption);
    (try (f tt)); (try bool_to_prop); (try (bool_to_prop in *)); mycleartrivial.

  Ltac set_tac f :=
    repeat ((repeat (eauto using get; cset_tac_step f))
            || intuition (eauto using get; cset_tac_step f)).

  Ltac cset_tac := set_tac idtac.

Hint Extern 9 ⇒
     match goal with
       | [ H : ?x === ?y, H' : In ?x ?s, H'' : ¬In ?y ?s |- _ ] ⇒
        now (exfalso; rewrite H in H'; eauto)
       | [ H : ?x === ?y, H' : In ?y ?s, H'' : ¬In ?x ?s |- _ ] ⇒
         now (exfalso; rewrite <- H in H'; eauto)
     end.

Hint Extern 10 ⇒ match goal with
                   | [ H : ?x ?s, H' : ?y ?s False, H'' : ?y === ?x |- _ ] ⇒ exfalso; eapply H'; rewrite H''; eapply H
                   | [ H : ?x ?s, H' : ?y ?s False, H'' : ?x === ?y |- _ ] ⇒ exfalso; eapply H'; rewrite <- H''; eapply H
                 end.

Hint Extern 20 (Subset ?a ?a') ⇒ progress (first [ has_evar a | has_evar a' | reflexivity ]).
Hint Extern 20 (Equal ?a ?a') ⇒ progress (first [ has_evar a | has_evar a' | reflexivity ]).

Ltac srewrite s :=
  match goal with
  | [ H : s [=] _ |- _ ] ⇒ rewrite H
  | [ H : _ [=] s |- _ ] ⇒ rewrite <- H
  end.