Library Veq

Require Import Vbase.


Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Open Scope bool_scope.

Notation "x : T" := (x : T)
  (at level 100, right associativity,
   format "'[hv' x '/ ' : T ']'") : core_scope.

Notation "T : 'Type'" := (T%type : Type)
  (at level 100, only parsing) : core_scope.
Notation "P : 'Prop'" := (P%type : Prop)
  (at level 100, only parsing) : core_scope.

Delimit Scope eq_scope with EQ.
Open Scope eq_scope.


Section Contrapositives.

Variables (T : eqType) (b : bool) (x y : T).

Lemma contraTeq : (x != y -> negb b) -> b -> x = y.
Proof. by case b; case eqP; ins; exploit H. Qed.

Lemma contraNeq : (x != y -> b) -> negb b -> x = y.
Proof. by case b; case eqP; ins; exploit H. Qed.

Lemma contraTneq : (x = y -> negb b) -> b -> x != y.
Proof. by case b; case eqP; ins; exploit H. Qed.

Lemma contraNneq : (x = y -> b) -> negb b -> x != y.
Proof. by case b; case eqP; ins; exploit H. Qed.

End Contrapositives.

Theorem eq_irrelevance : forall (T : eqType) (x y : T) (e1 e2 : x = y), e1 = e2.
Proof.
intros; revert e2; subst y.
apply Eqdep_dec.K_dec; try done.
clear; intros; case (@eqP T x y); vauto.
Qed.

Corollary eq_axiomK : forall (T : eqType) (x : T), all_equal_to (Logic.eq_refl x).
Proof. by red; intros; apply @eq_irrelevance. Qed.

Module Type EqTypePredSig.
Parameter sort : eqType -> predArgType.
End EqTypePredSig.
Module MakeEqTypePred (eqmod : EqTypePredSig).
Coercion eqmod.sort : eqType >-> predArgType.
End MakeEqTypePred.
Module EqTypePred := MakeEqTypePred Equality.

Comparison for unit

Lemma unit_eqP : Equality.axiom (fun _ _ : unit => true).
Proof. intros [] []; vauto. Qed.

Definition unit_eqMixin := EqMixin unit_eqP.
Canonical Structure unit_eqType := Eval hnf in EqType unit unit_eqMixin.

Comparison for booleans

Definition eqb (x y : bool) : bool :=
  match x, y with true, true => true | false, false => true | _, _ => false end.

Lemma eqbP : Equality.axiom eqb.
Proof. by intros [] []; constructor. Qed.

Canonical Structure bool_eqMixin := EqMixin eqbP.
Canonical Structure bool_eqType := Eval hnf in EqType bool bool_eqMixin.

Lemma eqbE : eqb = (@eq_op _).
Proof. done. Qed.

Lemma bool_irrelevance : forall (x y : bool) (E E' : x = y), E = E'.
Proof. apply eq_irrelevance. Qed.

Lemma negb_add : forall b1 b2, negb (xorb b1 b2) = (b1 == b2).
Proof. by intros [] []. Qed.

Lemma negb_eqb : forall b1 b2, (b1 != b2) = xorb b1 b2.
Proof. by intros [] []. Qed.

Lemma eqb_id : forall b, (b == true) = b.
Proof. by intros []. Qed.

Comparison for nat

Fixpoint eqn_rec (x y: nat) {struct x} :=
   match x, y with
     | O, O => true
     | S x, S y => eqn_rec x y
     | _, _ => false
   end.

Definition eqn := match tt with tt => eqn_rec end.

Lemma eqnP: forall x y, reflect (x = y) (eqn x y).
Proof.
  induction[] x [y]; vauto.
  change (eqn (S x) (S y)) with (eqn x y).
  case IHx; constructor; congruence.
Qed.

Canonical Structure nat_eqMixin := EqMixin eqnP.
Canonical Structure nat_eqType := Eval hnf in EqType nat nat_eqMixin.

Lemma eqnE : eqn = (@eq_op _).
Proof. done. Qed.

Lemma nat_irrelevance : forall (x y : nat) (E E' : x = y), E = E'.
Proof. apply eq_irrelevance. Qed.

Equality-based predicates

Notation xpred1 := (fun a1 x => x == a1).
Notation xpred2 := (fun a1 a2 x => (x == a1) || (x == a2)).
Notation xpred3 := (fun a1 a2 a3 x => (x == a1) || (x == a2) || (x == a3)).
Notation xpred4 :=
   (fun a1 a2 a3 a4 x => (x == a1) || (x == a2) || (x == a3) || (x == a4)).
Notation xpredU1 := (fun a1 (p : pred _) x => (x == a1) || p x).
Notation xpredC1 := (fun a1 x => x != a1).
Notation xpredD1 := (fun (p : pred _) a1 x => (x != a1) && p x).

Section EqPred.

Variable T : eqType.

Definition pred1 (a1 : T) := SimplPred (xpred1 a1).
Definition pred2 (a1 a2 : T) := SimplPred (xpred2 a1 a2).
Definition pred3 (a1 a2 a3 : T) := SimplPred (xpred3 a1 a2 a3).
Definition pred4 (a1 a2 a3 a4 : T) := SimplPred (xpred4 a1 a2 a3 a4).
Definition predU1 (a1 : T) p := SimplPred (xpredU1 a1 p).
Definition predC1 (a1 : T) := SimplPred (xpredC1 a1).
Definition predD1 p (a1 : T) := SimplPred (xpredD1 p a1).

Lemma pred1E : pred1 =2 eq_op.
Proof. intros x y; simpl; apply beq_sym. Qed.

Variables (T2 : eqType) (x y : T) (z u : T2) (b : bool).

Lemma predU1P : reflect (x = y \/ b) ((x == y) || b).
Proof. eapply iffP; auto with vlib_refl; ins; desf; clarsimp; vauto. Qed.

Lemma pred2P : reflect (x = y \/ z = u) ((x == y) || (z == u)).
Proof. eapply iffP; auto with vlib_refl; ins; desf; clarsimp; vauto. Qed.

Lemma predD1P : reflect (x <> y /\ b) ((x != y) && b).
Proof. apply (iffP (andP _ _)); case eqP; ins; desf. Qed.

Lemma predU1l : x = y -> (x == y) || b.
Proof. by case eqP. Qed.

Lemma predU1r : b -> (x == y) || b.
Proof. by rewrite orbC; case b. Qed.

Lemma eqVneq : {x = y} + {x != y}.
Proof. by case eqP; [left | right]. Qed.

End EqPred.

Implicit Arguments predU1P [T x y b].
Implicit Arguments pred2P [T T2 x y z u].
Implicit Arguments predD1P [T x y b].

Notation "[ 'predU1' x & A ]" := (predU1 x [mem A])
  (at level 0, format "[ 'predU1' x & A ]") : fun_scope.
Notation "[ 'predD1' A & x ]" := (predD1 [mem A] x)
  (at level 0, format "[ 'predD1' A & x ]") : fun_scope.

Lemmas for reflected equality and functions

Section EqFun.

Section Exo.

Variables (aT rT : eqType) (D : pred aT) (f : aT -> rT) (g : rT -> aT).

Lemma inj_eq : injective f -> forall x y, (f x == f y) = (x == y).
Proof.
intros inj_f x y; specialize (inj_f x y).
case eqP; case eqP; intuition congruence.
Qed.

Lemma can_eq : cancel f g -> forall x y, (f x == f y) = (x == y).
Proof. eby intros; eapply inj_eq, can_inj. Qed.

Lemma bij_eq : bijective f -> forall x y, (f x == f y) = (x == y).
Proof. by intros; apply inj_eq, bij_inj. Qed.

Lemma can2_eq : cancel f g -> cancel g f -> forall x y, (f x == y) = (x == g y).
Proof. by intros; rewrite <- (H0 y) at 1; apply can_eq. Qed.

Lemma inj_in_eq :
  {in D &, injective f} -> {in D &, forall x y, (f x == f y) = (x == y)}.
Proof. by intros inj_f x y Dx Dy; do 2 case eqP; clarsimp; apply inj_f in e. Qed.

Lemma can_in_eq :
  {in D, cancel f g} -> {in D &, forall x y, (f x == f y) = (x == y)}.
Proof. eauto using inj_in_eq, can_in_inj. Qed.

End Exo.

Section Endo.

Variables (T : eqType) (f : T -> T).

Definition frel := [rel x y : T | f x == y].

Lemma inv_eq : involutive f -> forall x y, (f x == y) = (x == f y).
Proof. by intros; apply can2_eq. Qed.

End Endo.

Variable aT : Type.


Definition invariant (rT : eqType) f (k : aT -> rT) :=
  [pred x | k (f x) == k x].

Variables (rT1 rT2 : eqType) (f : aT -> aT) (h : rT1 -> rT2) (k : aT -> rT1).

Lemma invariant_comp : subpred (invariant f k) (invariant f (h \o k)).
Proof. by red; ins; rewrite (eqP _ _ H). Qed.

Lemma invariant_inj : injective h -> invariant f (h \o k) =1 invariant f k.
Proof. by red; ins; apply inj_eq. Qed.

End EqFun.


Section FunWith.

Variables (aT : eqType) (rT : Type).

Inductive fun_delta : Type := FunDelta (_ : aT) (_ : rT).

Definition fwith x y (f : aT -> rT) := [fun z => if z == x then y else f z].

Definition app_fdelta df f z :=
  match df with FunDelta x y => if z == x then y else f z end.

End FunWith.


Notation "x |-> y" := (FunDelta x y)
  (at level 190, no associativity,
   format "'[hv' x '/ ' |-> y ']'") : fun_delta_scope.

Delimit Scope fun_delta_scope with FUN_DELTA.
Arguments Scope app_fdelta [_ type_scope fun_delta_scope _ _].

Definition SimplFunDelta aT rT (f : aT -> aT -> rT) := [fun z => f z z].

Notation "[ 'fun' z : T => F 'with' d1 , .. , dn ]" :=
  (SimplFunDelta (fun z : T =>
     app_fdelta d1%FUN_DELTA .. (app_fdelta dn%FUN_DELTA (fun _ => F)) ..))
  (at level 0, z ident, only parsing) : fun_scope.

Notation "[ 'fun' z => F 'with' d1 , .. , dn ]" :=
  (SimplFunDelta (fun z =>
     app_fdelta d1%FUN_DELTA .. (app_fdelta dn%FUN_DELTA (fun _ => F)) ..))
  (at level 0, z ident, format
   "'[hv' [ '[' 'fun' z => '/ ' F ']' '/' 'with' '[' d1 , '/' .. , '/' dn ']' ] ']'"
   ) : fun_scope.

Notation "[ 'eta' f 'with' d1 , .. , dn ]" :=
  (SimplFunDelta (fun _ =>
     app_fdelta d1%FUN_DELTA .. (app_fdelta dn%FUN_DELTA f) ..))
  (at level 0, z ident, format
  "'[hv' [ '[' 'eta' '/ ' f ']' '/' 'with' '[' d1 , '/' .. , '/' dn ']' ] ']'"
  ) : fun_scope.

Various EqType constructions

Section ComparableType.

Variable T : Type.

Definition comparable := forall x y : T, {x = y} + {x <> y}.

Hypothesis Hcompare : forall x y : T, {x = y} + {x <> y}.

Definition compareb x y :=
  match Hcompare x y with
    | left _ => true
    | right _ => false
  end.

Lemma compareP : Equality.axiom compareb.
Proof. by intros x y; unfold compareb; case (Hcompare x y); constructor. Qed.

Definition comparableClass := EqMixin compareP.

End ComparableType.

Definition eq_comparable (T : eqType) : comparable T :=
  fun x y => decP (eqP x y).

Section SubType.

Variables (T : Type) (P : pred T).

Structure subType : Type := SubType {
  sub_sort :> Type;
  val : sub_sort -> T;
  Sub : forall x, P x -> sub_sort;
  _ : forall K (_ : forall x Px, K (@Sub x Px)) u, K u;
  _ : forall x Px, val (@Sub x Px) = x
}.

Implicit Arguments Sub [s].
Lemma vrefl : forall x, P x -> x = x.
Proof. done. Qed.

Definition clone_subType U v :=
  fun sT (_ : sub_sort sT -> U) =>
  fun c Urec cK (sT' := @SubType U v c Urec cK) (_ : phant_id sT' sT) => sT'.

Variable sT : subType.

Inductive Sub_spec : sT -> Type := SubSpec x Px : Sub_spec (Sub x Px).

Lemma SubP : forall u, Sub_spec u.
Proof. by generalize Sub_spec SubSpec; case sT. Qed.

Lemma SubK : forall x Px, @val sT (Sub x Px) = x.
Proof. by case sT. Qed.

Definition insub x :=
  match @idP (P x) with
    | ReflectT Px => @Some sT (Sub x Px)
    | ReflectF _ => None
  end.

Definition insubd u0 x := odflt u0 (insub x).

Inductive insub_spec x : option sT -> Type :=
  | InsubSome: forall u (_: P x) (_ : val u = x), insub_spec x (Some u)
  | InsubNone: forall (_: negb (P x)), insub_spec x None.

Lemma insubP : forall x, insub_spec x (insub x).
Proof.
unfold insub; intros; generalize (@idP (P x)); generalize (P x) at 2.
by destruct r as [X|X]; [left; rewrite ?SubK | right; apply/negP].
Qed.

Lemma insubT : forall x Px, insub x = Some (Sub x Px).
Proof.
intros x; case insubP; [|by case negP].
intro u; destruct (SubP u); intros.
by rewrite SubK in *; clarify; rewrite (bool_irrelevance Px Px0).
Qed.

Lemma insubF : forall x, P x = false -> insub x = None.
Proof. intros; case insubP; clarsimp. Qed.

Lemma insubN : forall x, negb (P x) -> insub x = None.
Proof. by intros; apply insubF; destruct (P x). Qed.
Lemma insubK : ocancel insub (@val _).
Proof. by intro; case insubP. Qed.

Lemma valP : forall u : sT, P (val u).
Proof. by intros; destruct (SubP u); rewrite SubK. Qed.

Lemma valK : pcancel (@val _) insub.
Proof. intro u; case (SubP u); intros x Px; rewrite SubK; apply insubT. Qed.

Lemma val_inj : injective (@val sT).
Proof. apply (pcan_inj valK). Qed.

Lemma valKd : forall u0, cancel (@val _) (insubd u0).
Proof. by intros u0 u; unfold insubd; rewrite valK. Qed.

Lemma val_insubd : forall u0 x, val (insubd u0 x) = if P x then x else val u0.
Proof.
by unfold insubd; intros u0 x; case insubP; clarsimp; rewrite (negPf i).
Qed.

Lemma insubdK : forall u0, {in P, cancel (insubd u0) (@val _)}.
Proof. by intros u0 x Px; rewrite val_insubd, Px. Qed.

Definition insub_eq x :=
  let Some_sub Px := Some (Sub x Px : sT) in
  let None_sub _ := None in
  (if P x as Px return P x = Px -> _ then Some_sub else None_sub) Logic.eq_refl.

Lemma insub_eqE : insub_eq =1 insub.
Proof.
unfold insub_eq, insub; intros x.
generalize (Logic.eq_refl (P x)), (@idP (P x)); generalize (P x) at 2 4 5.
by destruct r; clarify; repeat f_equal; apply eq_irrelevance.
Qed.

End SubType.

Implicit Arguments SubType [T P].
Implicit Arguments Sub [T P s].
Implicit Arguments vrefl [T P].
Implicit Arguments clone_subType [T P sT c Urec cK].
Implicit Arguments insub [T P sT].
Implicit Arguments insubT [T sT x].
Implicit Arguments val_inj [T P sT].
Implicit Arguments val [[T] [P] [s]].

Notation "[ 'subType' 'for' v 'by' rec ]" := (SubType _ v _ rec vrefl)
 (at level 0, format "[ 'subType' 'for' v 'by' rec ]") : form_scope.

Notation "[ 'subType' 'for' v , U ]" := (clone_subType U v id [eta idfun])
 (at level 0, format "[ 'subType' 'for' v , U ]") : form_scope.

Notation "[ 'subType' 'for' v ]" := (clone_subType _ v id idfun)
 (at level 0, format "[ 'subType' 'for' v ]") : form_scope.

Notation "[ 'subType' 'of' U ]" := (clone_subType U _ id id)
 (at level 0, format "[ 'subType' 'of' U ]") : form_scope.

Definition NewType T U v c Urec :=
  let Urec' P IH := Urec P (fun x : T => IH x (eq_refl true) : P _) in
  SubType U v (fun x _ => c x) Urec'.
Implicit Arguments NewType [T U].

Notation "[ 'newType' 'for' v 'by' rec ]" := (NewType v _ rec vrefl)
 (at level 0, format "[ 'newType' 'for' v 'by' rec ]") : form_scope.

Definition innew T nT x := @Sub T predT nT x (eq_refl true).
Implicit Arguments innew [[T] [nT]].

Lemma innew_val : forall T nT, cancel val (@innew T nT).
Proof. by intros T nT u; apply val_inj, SubK. Qed.

Notation sval := (@proj1_sig _ _).
Notation "@ 'sval'" := (@proj1_sig) (at level 10, format "@ 'sval'").

Section SigProj.

Variables (T : Type) (P Q : T -> Prop).

Lemma svalP : forall u : sig P, P (sval u).
Proof. by intros []. Qed.

Definition s2val (u : sig2 P Q) := match u with exist2 x _ _ => x end.

Lemma s2valP : forall u, P (s2val u).
Proof. by intros []. Qed.

Lemma s2valP' : forall u, Q (s2val u).
Proof. by intros []. Qed.

End SigProj.


Section TransferEqType.

Variables (T : Type) (eT : eqType) (f : T -> eT).

Lemma inj_eqAxiom : injective f -> Equality.axiom (fun x y => f x == f y).
Proof. intros f_inj x y. apply (iffP (eqP _ _)); autos. Qed.

Definition InjEqMixin f_inj := EqMixin (inj_eqAxiom f_inj).

Definition PcanEqMixin g (fK : pcancel f g) := InjEqMixin (pcan_inj fK).

Definition CanEqMixin g (fK : cancel f g) := InjEqMixin (can_inj fK).

End TransferEqType.

Section SubEqType.

Variables (T : eqType) (P : pred T) (sT : subType P).

Notation Local ev_ax := (fun T v => @Equality.axiom T (fun x y => v x == v y)).

Lemma val_eqP : ev_ax sT val.
Proof. by simpl; apply inj_eqAxiom, val_inj. Qed.

Definition sub_eqMixin := EqMixin val_eqP.
Canonical Structure sub_eqType := Eval hnf in EqType sT sub_eqMixin.

Definition SubEqMixin :=
  (match sT as sT' return ev_ax sT' val -> Equality.class_of sT' with
     | SubType _ v _ _ _ =>
   fun vP : ev_ax _ v => EqMixin vP
   end) val_eqP.

Lemma val_eqE : forall u v : sT, (val u == val v) = (u == v).
Proof. done. Qed.

End SubEqType.

Implicit Arguments val_eqP [[T] [P] [sT] x y].

Notation "[ 'eqMixin' 'of' T 'by' <: ]" := (SubEqMixin _ : Equality.class_of T)
  (at level 0, format "[ 'eqMixin' 'of' T 'by' <: ]") : form_scope.

Section SigEqType.

Variables (T : eqType) (P : pred T).

End SigEqType.

Section ProdEqType.

Variable T1 T2 : eqType.

Definition pair_eq := [rel u v : T1 * T2 | (fst u == fst v) && (snd u == snd v)].

Lemma pair_eqP : Equality.axiom pair_eq.
Proof.
intros [x1 x2] [y1 y2]; simpl; apply (iffP (andP _ _)); clarsimp; desf; clarify.
Qed.

Definition prod_eqMixin := EqMixin pair_eqP.
Canonical Structure prod_eqType := Eval hnf in EqType (T1 * T2) prod_eqMixin.

Lemma pair_eqE : pair_eq = eq_op :> rel _.
Proof. done. Qed.

Lemma xpair_eqE : forall (x1 y1 : T1) (x2 y2 : T2),
  ((x1, x2) == (y1, y2)) = ((x1 == y1) && (x2 == y2)).
Proof. done. Qed.

Tactic Notation "move" "/" reference(X) hyp_list(Y) :=
  revert Y; let top := fresh in intro top;
  first [ generalize (X top); clear top
        | generalize (X _ top); clear top
        | generalize (X _ _ top); clear top
        | generalize (X _ _ _ top); clear top
        | generalize (X _ _ _ _ top); clear top
        | apply X in top; revert top
        | apply -> X in top; revert top
        | apply <- X in top; revert top].

Variables u v : T1 * T2.

Lemma pair_eq1 : u == v -> fst u == fst v.
Proof. case u, v; move/andP; tauto. Qed.

Lemma pair_eq2 : u == v -> snd u == snd v.
Proof. case u, v; move/andP; tauto. Qed.

End ProdEqType.

Definition predX T1 T2 (p1 : pred T1) (p2 : pred T2) :=
  [pred z | p1 (fst z) && p2 (snd z)].

Notation "[ 'predX' A1 & A2 ]" := (predX [mem A1] [mem A2])
  (at level 0, format "[ 'predX' A1 & A2 ]") : fun_scope.

Section OptionEqType.

Variable T : eqType.

Definition opt_eq (u v : option T) : bool :=
  oapp (fun x => oapp (eq_op x) false v) (match v with Some _ => false | None => true end) u.

Lemma opt_eqP : Equality.axiom opt_eq.
Proof.
red; intros [x|] [y|]; simpls; vauto.
apply (iffP (@eqP _ _ _)); clarsimp.
Qed.

Canonical Structure option_eqMixin := EqMixin opt_eqP.
Canonical Structure option_eqType :=
  Eval hnf in EqType (option T) option_eqMixin.

End OptionEqType.

Definition tag := projS1.
Definition tagged I T_ : forall u, T_(tag u) := @projS2 I [eta T_].
Definition Tagged I i T_ x := @existS I [eta T_] i x.
Implicit Arguments Tagged [I i].

Section TaggedAs.

Variables (I : eqType) (T_ : I -> Type).
Implicit Types u v : {i : I & T_ i}.

Definition tagged_as u v :=
  match eqP (tag u) (tag v) with
    | ReflectT eq_uv => eq_rect_r T_ (tagged v) eq_uv
    | _ => tagged u
  end.

Lemma tagged_asE : forall u x, tagged_as u (Tagged T_ x) = x.
Proof.
  ins; unfold tagged_as; case eqP; simpls.
  by intros; rewrite eq_axiomK.
Qed.

End TaggedAs.

Section TagEqType.

Variables (I : eqType) (T_ : I -> eqType).
Implicit Types u v : {i : I & T_ i}.

Definition tag_eq u v := (tag u == tag v) && (tagged u == tagged_as u v).

Lemma tag_eqP : Equality.axiom tag_eq.
Proof.
  red; destruct x, y; unfold tag_eq; ins.
  case eqP; simpls; [|constructor]; intro; clarify.
  assert (M:= tagged_asE); unfold Tagged in M.
  by apply (iffP (eqP _ _)); [intros ->|intros <-]; rewrite M.
Qed.

Canonical Structure tag_eqMixin := EqMixin tag_eqP.
Canonical Structure tag_eqType := Eval hnf in EqType {i : I & T_ i} tag_eqMixin.

Lemma tag_eqE : tag_eq = eq_op.
Proof. done. Qed.

Lemma eq_tag u v : u == v -> tag u = tag v.
Proof. by move/eqP; intro; clarify. Qed.

Lemma eq_Tagged u x : (u == Tagged _ x) = (tagged u == x).
Proof. by rewrite <-tag_eqE; unfold tag_eq; rewrite eqxx, tagged_asE. Qed.

End TagEqType.

Implicit Arguments tag_eqP [I T_ x y].

Section SumEqType.

Variables T1 T2 : eqType.
Implicit Types u v : T1 + T2.

Definition sum_eq u v :=
  match u, v with
  | inl x, inl y | inr x, inr y => x == y
  | _, _ => false
  end.

Lemma sum_eqP : Equality.axiom sum_eq.
Proof. case x, y; simpl; vauto; case eqP; constructor; congruence. Qed.

Canonical Structure sum_eqMixin := EqMixin sum_eqP.
Canonical Structure sum_eqType := Eval hnf in EqType (T1 + T2) sum_eqMixin.

Lemma sum_eqE : sum_eq = eq_op.
Proof. done. Qed.

End SumEqType.

Implicit Arguments sum_eqP [T1 T2 x y].