{-# OPTIONS --without-K #-}
module Function.Inverse.NP where

open import Function.Inverse public
import Function as F
open import Function.Equality using (_⟨$⟩_)
open import Relation.Binary
open import Data.Product
open import Type hiding ()
open import Relation.Binary.PropositionalEquality using (→-to-⟶)
import Function.Equality as FE
open import Function.LeftInverse using (_LeftInverseOf_; _RightInverseOf_)

isEquivalence :  {f₁ f₂}  IsEquivalence (Inverse {f₁} {f₂})
isEquivalence = record
   { refl  = id
   ; sym   = sym
   ; trans = F.flip _∘_ }

setoid :  {c }  Setoid _ _
setoid {c} {} = record
  { Carrier       = Setoid c 
  ; _≈_           = Inverse
  ; isEquivalence = isEquivalence }

inverses :  {f t}
             {From :  f} {To :  t}
             (to   : From  To) 
             (from : To  From) 
             (→-to-⟶ from) LeftInverseOf (→-to-⟶ to) 
             (→-to-⟶ from) RightInverseOf (→-to-⟶ to) 
             From  To
inverses to from left right =
  record { inverse-of = inv }
  where inv : →-to-⟶ from InverseOf →-to-⟶ to
        inv = record { left-inverse-of = left ; right-inverse-of = right }

_$₁_ :  {f₁ f₂ t₁ t₂}
         {From : Setoid f₁ f₂} {To : Setoid t₁ t₂}
        Inverse From To  Setoid.Carrier From  Setoid.Carrier To
iso $₁ x = Inverse.to iso ⟨$⟩ x

_$₂_ :  {f₁ f₂ t₁ t₂}
         {From : Setoid f₁ f₂} {To : Setoid t₁ t₂}
        Inverse From To  Setoid.Carrier To  Setoid.Carrier From
iso $₂ x = Inverse.from iso ⟨$⟩ x

module _ {a b ra rb}
         {A  : Setoid a ra}
         {B  : Setoid b rb}
  where
  module  = Setoid A
  module  = Setoid B
  open  renaming (_≈_ to _≈ᴬ_)
  open  renaming (_≈_ to _≈ᴮ_)

  module _ (xᵢ : Setoid.Carrier A × Setoid.Carrier B)
           (f  : Inverse A B)
           where
    x₁ = proj₁ xᵢ
    x₂ = proj₂ xᵢ

    _∈_  :  rb
    _∈_  = f $₁ x₁ ≈ᴮ x₂

    _∈′_ :  ra
    _∈′_ = x₁ ≈ᴬ f $₂ x₂

  ∈→∈′ :  f xᵢ  xᵢ  f  xᵢ ∈′ f
  ∈→∈′ f (x₁ , x₂) p = Aˢ.trans (Aˢ.sym (Inverse.left-inverse-of f x₁)) (FE.cong (Inverse.from f) p)

  ∈′→∈ :  f xᵢ  xᵢ ∈′ f  xᵢ  f
  ∈′→∈ f (x₁ , x₂) p = Bˢ.trans (FE.cong (Inverse.to f) p) (Inverse.right-inverse-of f x₂)