Local Open Scope morphism_scope.
(** The basic Definition of an isomorphism in a category. An isomorphism is a pair of arrows f : a -> b and g : b -> a such that g ∘ f = id a and f ∘ g = id b. *)
Record Isomorphism {C : Category} (a b : C) : Type :=
{
iso_morphism : a –≻ b;
inverse_morphism : b –≻ a;
left_inverse : (inverse_morphism ∘ iso_morphism)%morphism = id;
right_inverse : (iso_morphism ∘ inverse_morphism)%morphism = id
}.
Bind Scope morphism_scope with Isomorphism.
Bind Scope isomorphism_scope with Isomorphism.
Hint Resolve left_inverse.
Hint Resolve right_inverse.
Coercion iso_morphism : Isomorphism >-> Hom.
Arguments iso_morphism {_ _ _} _.
Arguments inverse_morphism {_ _ _} _.
Arguments left_inverse {_ _ _} _.
Arguments right_inverse {_ _ _} _.
Notation "f '⁻¹'" := (inverse_morphism f) : morphism_scope.
Notation "a ≃ b" := (Isomorphism a b) : isomorphism_scope.
Notation "a ≃≃ b ::> C" := (@Isomorphism C a b) : isomorphism_scope.
Local Open Scope isomorphism_scope.
(* basic tactics for isomorphisms *)
Ltac simpl_isos_in_goal :=
repeat(
match goal with
| [|- context[(iso_morphism ?A ∘ inverse_morphism ?A)%morphism]] =>
rewrite (right_inverse A); simpl_ids
| [|- context[(inverse_morphism ?A ∘ iso_morphism ?A)%morphism] ] =>
rewrite (left_inverse A); simpl_ids
(* disabled due to problems with reveal_comp complexity *)
(*        | [|- context[iso_morphism ?A] ] => reveal_comp (inverse_morphism A) (iso_morphism A) + reveal_comp (iso_morphism A) (inverse_morphism A) *)
end
)
.
Ltac simpl_isos_in_I I :=
repeat(
match type of I with
| context[(iso_morphism ?A ∘ inverse_morphism ?A)%morphism] =>
rewrite (right_inverse A) in I; simpl_ids in I
| context[(inverse_morphism ?A ∘ iso_morphism ?A)%morphism] =>
rewrite (left_inverse A) in I; simpl_ids in I
(* disabled due to problems with reveal_comp complexity *)
(*        | context[inverse_morphism ?A] => reveal_comp (inverse_morphism A) (iso_morphism A) in I + reveal_comp (iso_morphism A) (inverse_morphism A) in I *)
end
)
.
Tactic Notation "simpl_isos" := simpl_isos_in_goal.
Tactic Notation "simpl_isos" "in" hyp(I) := simpl_isos_in_I I.
Hint Extern 3 => progress simpl_isos.
Hint Extern 3 => progress (dohyps (fun H => simpl_isos in H)).

(* Specifications: *)
(** simplifies equality of iso-morphisms. This theorem uses proof irrelevance to assume any two proofs for left and right inverse properties are equal. In other words, two isomorphisms are equal if their underlying morphisms are. *)
Theorem Isomorphism_eq_simplify {C : Category} {a b : C} (I I' : a ≃ b) :
(iso_morphism I = iso_morphism I') →
(inverse_morphism I = inverse_morphism I') → I = I'.