\begin{code}
{-# OPTIONS --cubical --safe --postfix-projections #-}

module Cardinality.Finite.ManifestBishop where

open import Prelude hiding (_≃_; isEquiv)

import Cardinality.Finite.ManifestBishop.Inductive as 𝕃
import Cardinality.Finite.ManifestBishop.Container as 

open import Cardinality.Finite.ManifestBishop.Isomorphism

open import Data.Fin

private
  variable
    u : Level
    U : A  Type u

private
 module DisplayBishEquiv {a} {A : Type a} where
  open 
  open import Snippets.Equivalence
  open import Container
  open import Container.List
  open import Data.Sigma.Properties

  open import Relation.Binary.Equivalence.Reasoning (⇔-equiv {a}) public
  ℬ⇔Fin≃ :
\end{code}
%<*bishop-is-equiv-type>
\begin{code}
    A  ∃[ n ] (Fin n  A)
\end{code}
%</bishop-is-equiv-type>
\begin{code}
  ℬ⇔Fin≃ =
\end{code}
%<*bishop-is-equiv>
\begin{code}
     A                                                      ≋⟨⟩
    Σ[ xs  List A ] ((x : A)  x ∈! xs)                     ≋⟨⟩
    Σ[ xs  List A ] ((x : A)  isContr (x  xs))            ≋⟨⟩
    Σ[ xs  List A ] ((x : A)  isContr (fiber (snd xs) x))  ≋⟨⟩
    Σ[ xs  List A ] isEquiv (snd xs)                        ≋⟨⟩
    Σ[ xs    , Fin  A ] isEquiv (snd xs)                 ≋⟨⟩
    Σ[ xs  Σ[ n   ] (Fin n  A) ] isEquiv (snd xs)        ≋⟨ reassoc 
    Σ[ n   ] Σ[ f  (Fin n  A) ] isEquiv f                ≋⟨⟩
    ∃[ n ] (Fin n  A) 
\end{code}
%</bishop-is-equiv>
\begin{code}


open import Prelude using (_≃_; isEquiv)

module _ where
  open 
  ℬ⇔Fin≃ :  A  ∃[ n ] (Fin n  A)
  ℬ⇔Fin≃ .fun ((n , xs) , cov) .fst = n
  ℬ⇔Fin≃ .fun ((n , xs) , cov) .snd .fst = xs
  ℬ⇔Fin≃ .fun ((n , xs) , cov) .snd .snd .equiv-proof = cov
  ℬ⇔Fin≃ .inv (n , (xs , cov)) = ((n , xs) , cov .equiv-proof)
  ℬ⇔Fin≃ .rightInv (n , (xs , cov)) i .fst = n
  ℬ⇔Fin≃ .rightInv (n , (xs , cov)) i .snd .fst = xs
  ℬ⇔Fin≃ .rightInv (n , (xs , cov)) i .snd .snd .equiv-proof = cov .equiv-proof
  ℬ⇔Fin≃ .leftInv _ = refl

module _ where
  open 𝕃

  open import Cardinality.Finite.SplitEnumerable hiding (_|×|_; ℰ!⟨Tuple⟩)
  import Cardinality.Finite.SplitEnumerable as SplitEnumerable
  open import Cardinality.Finite.SplitEnumerable.Inductive
  open import Cardinality.Finite.SplitEnumerable.Isomorphism

  ℬ⇒ℰ! :  A  ℰ! A
  ℬ⇒ℰ! xs .fst = xs .fst
  ℬ⇒ℰ! xs .snd x = xs .snd x .fst

  ℬ⇒Discrete :  A  Discrete A
  ℬ⇒Discrete = ℰ!⇒Discrete  fun 𝕃⇔ℒ⟨ℰ!⟩  ℬ⇒ℰ!

  module SplitEnumToBishop where
    ℰ!⇒ℬ : ℰ! A   A
    ℰ!⇒ℬ xs = λ where
        .fst  uniques disc (xs .fst)
        .snd x  ∈⇒∈! disc x (xs .fst) (xs .snd x)
      where
      disc = ℰ!⇒Discrete (𝕃⇔ℒ⟨ℰ!⟩ .fun xs)

  ℬ⇒Fin≃ :  A  ∃[ n ] (Fin n  A)
  ℬ⇒Fin≃ = ℬ⇔Fin≃ .fun  𝕃⇔ℒ⟨ℬ⟩ .fun

  private
    module PiClosNoPoly {A : Type₀} {U : A  Type₀} where
      open import Data.Tuple.UniverseMonomorphic
      open TupleUniverseMonomorphic
      ℰ!⇒ℬ : ℰ! B  _
      ℰ!⇒ℬ = 𝕃⇔ℒ⟨ℬ⟩ .fun  SplitEnumToBishop.ℰ!⇒ℬ

      _|Π|_ : ℰ! A  ((x : A)  ℰ! (U x))  ℰ! ((x : A)  U x)
      _|Π|_ xs =
        subst
           t  {A : t  Type _}  ((x : t)  ℰ! (A x))  ℰ! ((x : t)  (A x)))
          (ua (ℬ⇔Fin≃ .fun (ℰ!⇒ℬ xs) .snd))
          (subst ℰ! (isoToPath Tuple⇔ΠFin)  ℰ!⟨Tuple⟩)

  open SplitEnumToBishop public
  isoLift : Lift b A  A
  isoLift = iso lower lift  _  refl) λ _  refl
  open import Data.Tuple

  module _ {a} {u} {A : Type a} {U : A  Type u} where
\end{code}
%<*pi-clos>
\begin{code}
    _|Π|_ : ℰ! A  ((x : A)  ℰ! (U x))  ℰ! ((x : A)  U x)
\end{code}
%</pi-clos>
\begin{code}
    _|Π|_ xs =
      subst
         t  {A : t  Type _}  ((x : t)  ℰ! (A x))  ℰ! ((x : t)  (A x)))
        (ua (isoToEquiv isoLift  trans-≃  ℬ⇔Fin≃ .fun (𝕃⇔ℒ⟨ℬ⟩ .fun (ℰ!⇒ℬ xs)) .snd))
        (subst ℰ! (isoToPath (isoLift {b = a}  trans-⇔  Tuple⇔ΠFin))  ℰ!⟨Lift⟩  SplitEnumerable.ℰ!⟨Tuple⟩)

  open import HITs.PropositionalTruncation.Sugar

  ℬ⇒Choice :  A  ((x : A)   U x )   (∀ x  U x) 
  ℬ⇒Choice ba =
    subst
       t  {U : t  Type _}  ((x : t)   U x )   ((x : t)  U x) )
      (ua (isoToEquiv isoLift  trans-≃  ℬ⇔Fin≃ .fun (𝕃⇔ℒ⟨ℬ⟩ .fun ba) .snd))
      ((ind ∥$∥_)  trav _  tab)
    where
    trav :  n {T : Lift a (Fin n)  Type b}  Tuple n (∥_∥  T)   Tuple n T 
    trav zero    xs =  _ 
    trav (suc n) (x , xs) = do
      x′  x
      xs′  trav n xs
       x′ , xs′ 

  module BishopClosures where
\end{code}
%<*times-clos-sig>
\begin{code}
    _|×|_ :   A 
              B 
              (A × B)
\end{code}
%</times-clos-sig>
\begin{code}
    xs |×| ys = ℰ!⇒ℬ (ℬ⇒ℰ! xs SplitEnumerable.|×| ℬ⇒ℰ! ys)
\end{code}
\begin{code}

    open import Cubical.Foundations.HLevels
    open import Relation.Nullary.Decidable.Logic

    _|→|_ :  A   B   (A  B)
    xs |→| ys = ℰ!⇒ℬ (ℬ⇒ℰ! xs |Π| λ _  ℬ⇒ℰ! ys)

    filter :  {p} {P : A  Type p}  (∀ x  isProp (P x))  (∀ x  Dec (P x))   A   (Σ[ x  A ] P x)
    filter isPropP P? = ℰ!⇒ℬ  filter-subobject isPropP P?  ℬ⇒ℰ!

    module _ {a} {b} {A : Type a} {B : Type b} where
\end{code}
%<*iso-finite>
\begin{code}
      iso-finite :   A 
                     B 
                     (Σ[ f,g  (A  B) × (B  A) ]
                        (  (f,g .fst  f,g .snd  id) ×
                           (f,g .snd  f,g .fst  id)))
      iso-finite ℬ⟨A⟩ ℬ⟨B⟩ =
        filter
           _  isPropEqs)
           { (f , g)  (f  g) ≟ᴮ id && (g  f) ≟ᴬ id})
          ((ℬ⟨A⟩ |→| ℬ⟨B⟩) |×| (ℬ⟨B⟩ |→| ℬ⟨A⟩))
\end{code}
%</iso-finite>
\begin{code}
        where
        ℬ⟨f⟩ :  (A  B)
        ℬ⟨f⟩ = (ℬ⟨A⟩ |→| ℬ⟨B⟩)

        ℬ⟨g⟩ :  (B  A)
        ℬ⟨g⟩ = (ℬ⟨B⟩ |→| ℬ⟨A⟩)

        _≟ᴮ_ = ℬ⇒Discrete (ℬ⟨B⟩ |→| ℬ⟨B⟩)
        _≟ᴬ_ = ℬ⇒Discrete (ℬ⟨A⟩ |→| ℬ⟨A⟩)

        isPropEqs : {g : A  A} {f : B  B}  isProp ((f  id) × (g  id))
        isPropEqs = isOfHLevelΣ 1 (Discrete→isSet _≟ᴮ_ _ _) λ _  (Discrete→isSet _≟ᴬ_ _ _)

      _|⇔|_ :  A   B   (A  B)
      xs |⇔| ys = subst  (isoToPath form) (iso-finite xs ys)
        where
        form : (Σ[ fg  ((A  B) × (B  A)) ] (((fg .fst  fg .snd)  id) × ((fg .snd  fg .fst)  id)))  (A  B)
        form .fun ((f , g) , (leftInv , rightInv)) = iso f g  x i  leftInv i x)  x i  rightInv i x)
        form .inv (iso f g leftInv rightInv) = ((f , g) , ((λ i x  leftInv x i) ,  i x  rightInv x i)))
        form .rightInv _ = refl
        form .leftInv  _ = refl

    private
      module DecTerm (f : A  B) (g : B  A) where
        decTerm : Type _
        decTerm =
\end{code}
%<*dec-type>
\begin{code}
          Dec (f  g  id)
\end{code}
%</dec-type>