Ltac despec := 
  match goal with
    | [H : comp_spec _ _ _  |- _] => destruct H
  end.

(* Specifications: *)
Theorem comp_spec_consequence : forall (A B : Set){eqda1 eqda2 : EqDec A}{eqdb1 eqdb2 : EqDec B}(p1 p2 : A -> B -> Prop) c1 c2, (@comp_spec _ _ eqda1 eqdb1 p1 c1 c2) -> (forall a b, p1 a b -> p2 a b) -> (@comp_spec _ _ eqda2 eqdb2 p2 c1 c2).
Theorem comp_spec_symm : forall (A B : Set){eqda : EqDec A}{eqdb : EqDec B}(p : A -> B -> Prop) c1 c2, comp_spec p c1 c2 -> comp_spec (fun b a => p a b) c2 c1.
Theorem le_impl_comp_spec : forall (A B : Set){eqda : EqDec A}{eqdb : EqDec B}(c1 : Comp A)(c2 : Comp B), well_formed_comp c1 -> well_formed_comp c2 -> forall x y, evalDist c1 x <= evalDist c2 y -> comp_spec (fun a b => a = x -> b = y) c1 c2.
Theorem comp_spec_impl_le : forall (A B : Set){eqda : EqDec A}{eqdb : EqDec B}(c1 : Comp A)(c2 : Comp B), forall x y, comp_spec (fun a b => a = x -> b = y) c1 c2 -> evalDist c1 x <= evalDist c2 y.
Theorem comp_spec_eq_symm: forall (A : Set){eqda : EqDec A}(c1 c2 : Comp A), comp_spec eq c1 c2 -> comp_spec eq c2 c1.
Theorem comp_spec_ret : forall (A B : Set){eqda1 : EqDec A}{eqdb1 : EqDec B}(eqda2 : eq_dec A)(eqdb2 : eq_dec B)(P : A -> B -> Prop) a b, P a b -> @comp_spec _ _ eqda1 eqdb1 P (Ret eqda2 a) (Ret eqdb2 b).
Theorem comp_spec_eq_refl : forall (A : Set){eqd : EqDec A}(c : Comp A), comp_spec eq c c.
Theorem comp_spec_eq_trans_l : forall (A B : Set){eqd : EqDec A}{eqd : EqDec B}(c1 c2 : Comp A)(c3 : Comp B) P, comp_spec eq c1 c2 -> comp_spec P c2 c3 -> comp_spec P c1 c3.
Theorem comp_spec_eq_trans : forall (A : Set){eqd : EqDec A}(c1 c2 c3 : Comp A), comp_spec eq c1 c2 -> comp_spec eq c2 c3 -> comp_spec eq c1 c3.
Theorem comp_spec_eq_trans_r : forall (A B : Set){eqd : EqDec A}{eqd : EqDec B}(c1 : Comp A)(c2 c3 : Comp B) P, comp_spec P c1 c2 -> comp_spec eq c2 c3 -> comp_spec P c1 c3.
Theorem comp_spec_seq_eq : forall (A B C : Set){eqda : EqDec A}{eqdb : EqDec B}{eqdc : EqDec C}(c1 c2 : Comp A)(f1 : A -> Comp B)(f2 : A -> Comp C) P (b : B) (c : C), comp_spec eq c1 c2 -> (forall a, comp_spec P (f1 a) (f2 a)) -> comp_spec P (Bind c1 f1) (Bind c2 f2).
Theorem comp_spec_iso : forall (A B : Set){eqda : EqDec A}{eqdb : EqDec B}(c1 : Comp A)(c2 : Comp B)(f : A -> B)(f_inv : B -> A), (forall x : B, In x (getSupport c2) -> f (f_inv x) = x) -> (forall x : A, In x (getSupport c1) -> f_inv (f x) = x) -> (forall x : B, In x (getSupport c2) -> In (f_inv x) (getSupport c1)) -> (forall x : A, In x (getSupport c1) -> comp_spec (fun a b => a = (f x) <-> b = x) c2 c1) -> comp_spec (fun a b => f a = b) c1 c2.
Theorem comp_spec_irr_r : forall (A B C : Set){eqda : EqDec A}{eqdb : EqDec B}{eqdc : EqDec C}(c1 : Comp A)(c2 : Comp B)(f2 : B -> Comp C) P, well_formed_comp c2 -> (forall b, In b (getSupport c2) -> comp_spec P c1 (f2 b)) -> comp_spec P c1 (Bind c2 f2).
Theorem comp_spec_irr_l : forall (A B C : Set){eqda : EqDec A}{eqdb : EqDec B}{eqdc : EqDec C}(c1 : Comp A)(c2 : Comp B)(f1 : A -> Comp C) P, well_formed_comp c1 -> (forall a, In a (getSupport c1) -> comp_spec P (f1 a) c2) -> comp_spec P (Bind c1 f1) c2.
Theorem oc_comp_spec_eq : forall (A B C : Set)(c : OracleComp A B C), forall (*(eqda : EqDec A)*) (eqdb : EqDec B) (eqdc : EqDec C)(S1 S2 : Set)(o1 : S1 -> A -> Comp (B * S1))(o2 : S2 -> A -> Comp (B * S2)) eqds1 eqds2 s1 s2 (P : S1 -> S2 -> Prop), P s1 s2 -> (forall a x1 x2, P x1 x2 -> comp_spec (fun y1 y2 => fst y1 = fst y2 /\ P (snd y1) (snd y2)) (o1 x1 a) (o2 x2 a)) -> comp_spec (fun a b => fst a = fst b /\ P (snd a) (snd b)) (c _ eqds1 o1 s1) (c _ eqds2 o2 s2).
Theorem oc_comp_wf_inv : forall (A B C : Set) (c : OracleComp A B C), well_formed_oc c -> forall (S : Set) (P : S -> Prop)(eqds : EqDec S) (o : S -> A -> Comp (B * S)) (s : S), (forall (a : S) (b : A), P a -> well_formed_comp (o a b)) -> (forall a b s s', P s -> In (b, s') (getSupport (o s a)) -> P s') -> P s -> well_formed_comp (c S eqds o s).
Theorem oc_comp_spec_eq_until_bad : forall (A B C : Set)(c : OracleComp A B C), well_formed_oc c -> forall (eqdb : EqDec B) (eqdc : EqDec C)(S1 S2 : Set)(o1 : S1 -> A -> Comp (B * S1))(o2 : S2 -> A -> Comp (B * S2)) eqds1 eqds2 (bad1 : S1 -> bool)(bad2 : S2 -> bool)(inv : S1 -> S2 -> Prop), (forall a b, bad1 a = true -> well_formed_comp (o1 a b)) -> (forall a b, bad2 a = true -> well_formed_comp (o2 a b)) -> (forall x1 x2 a, inv x1 x2 -> bad1 x1 = bad2 x2 -> comp_spec (fun y1 y2 => (bad1 (snd y1) = bad2 (snd y2)) /\ (bad1 (snd y1) = false -> (inv (snd y1) (snd y2) /\ fst y1 = fst y2))) (o1 x1 a) (o2 x2 a)) -> (forall a b c d, bad1 c = true -> In (a, b) (getSupport (o1 c d)) -> bad1 b = true) -> (forall a b c d, bad2 c = true -> In (a, b) (getSupport (o2 c d)) -> bad2 b = true) -> ((forall s1 s2, inv s1 s2 -> bad1 s1 = bad2 s2 -> comp_spec (fun y1 y2 => (bad1 (snd y1) = bad2 (snd y2)) /\ (bad1 (snd y1) = false -> inv (snd y1) (snd y2) /\ (fst y1 = fst y2))) (c _ eqds1 o1 s1) (c _ eqds2 o2 s2))).