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

module Cardinality.Finite.Cardinal where

open import Prelude
open import Cardinality.Finite.ManifestBishop
open import Cardinality.Finite.ManifestBishop.Inductive
open import Cardinality.Finite.ManifestBishop.Isomorphism
open import Cardinality.Finite.SplitEnumerable hiding (_|×|_)
open import Cardinality.Finite.SplitEnumerable.Isomorphism

open import HITs.PropositionalTruncation
open import HITs.PropositionalTruncation.Sugar

open import Relation.Nullary.Discrete.Properties


open import Relation.Nullary.Decidable.Logic
open import Data.Fin

𝒞 : Type a  Type a
\end{code}
%<*cardinal-def>
\begin{code}
𝒞 A =   A 
\end{code}
%</cardinal-def>
%<*no-gap-card-bishop>
\begin{code}
¬⟨𝒞⋂ℬᶜ⟩ : ¬ Σ[ A  Type a ] 𝒞 A × ¬  A
¬⟨𝒞⋂ℬᶜ⟩ (_ , c , ¬b) = rec isProp⊥ ¬b c
\end{code}
%</no-gap-card-bishop>
%<*refute-trunc-pair>
\begin{code}
¬⟨∥A∥׬A⟩ : ¬  A  × ¬ A
¬⟨∥A∥׬A⟩ (∣A∣ , ¬A) = rec isProp⊥ ¬A ∣A∣
\end{code}
%</refute-trunc-pair>
\begin{code}

𝒞≃Fin≃ : 𝒞 A   Σ[ n   ] (Fin n  A) 
𝒞≃Fin≃ = iso (ℬ⇔Fin≃ .fun  𝕃⇔ℒ⟨ℬ⟩ .fun ∥$∥_) (𝕃⇔ℒ⟨ℬ⟩ .inv  ℬ⇔Fin≃ .inv ∥$∥_)  _  squash _ _) λ _  squash _ _

ℬ⇒𝒞 :  A  𝒞 A
ℬ⇒𝒞 = ∣_∣

private
  variable
    u : Level
    U : A  Type u

𝒞⇒Choice : 𝒞 A  Π[ x  A ]  U x    Π[ x  A ] U x 
𝒞⇒Choice ca p = ca >>= flip ℬ⇒Choice p

𝒞⟨⊥⟩ : 𝒞 
𝒞⟨⊥⟩ =  ℰ!⇒ℬ ℰ!⟨⊥⟩ 

𝒞⟨⊤⟩ : 𝒞 
𝒞⟨⊤⟩ =  ℰ!⇒ℬ ℰ!⟨⊤⟩ 

𝒞⟨Bool⟩ : 𝒞 Bool
𝒞⟨Bool⟩ =  ℰ!⇒ℬ ℰ!⟨2⟩ 


infixr 3 _∥Σ∥_
_∥Σ∥_ : 𝒞 A  (∀ x  𝒞 (U x))  𝒞 (Σ A U)
xs ∥Σ∥ ys = do
  x  xs
  y  ℬ⇒Choice x ys
   ℰ!⇒ℬ (ℬ⇒ℰ! x |Σ| (ℬ⇒ℰ!  y)) 

_∥⊎∥_ : 𝒞 A  𝒞 B  𝒞 (A  B)
xs ∥⊎∥ ys = do
  x  xs
  y  ys
   ℰ!⇒ℬ (ℬ⇒ℰ! x |⊎| ℬ⇒ℰ! y) 

_∥Π∥_ : 𝒞 A  (∀ x  𝒞 (U x))  𝒞 (Π A U)
xs ∥Π∥ ys = do
  x  xs
  y  ℬ⇒Choice x ys
   ℰ!⇒ℬ (ℬ⇒ℰ! x |Π| (ℬ⇒ℰ!  y)) 

_∥→∥_ : 𝒞 A  𝒞 B  𝒞 (A  B)
xs ∥→∥ ys = xs ∥Π∥ const ys

open BishopClosures
\end{code}
%<*times-clos-impl>
\begin{code}
_∥×∥_ :  𝒞 A 
         𝒞 B 
         𝒞 (A × B)
xs ∥×∥ ys = do
  x  xs
  y  ys
   x |×| y 
\end{code}
%</times-clos-impl>
\begin{code}
𝒞⇒Discrete :
\end{code}
%<*card-discrete>
\begin{code}
 𝒞 A  Discrete A
\end{code}
%</card-discrete>
\begin{code}
𝒞⇒Discrete = rec isPropDiscrete (ℰ!⇒Discrete  𝕃⇔ℒ⟨ℰ!⟩ .fun  ℬ⇒ℰ!)

open import Data.Sigma.Properties
open import Data.Fin.Properties using (Fin-inj)
open import Data.Nat.Properties using (isSetℕ)
open import Cubical.Foundations.HLevels


cardinality :  ∃[ n ] (Fin n  A)   ∃[ n ]  Fin n  A 
cardinality {A = A} = rec→set card-isSet alg const-alg
  where
  card-isSet : isSet (∃[ n ]  Fin n  A )
  card-isSet = isOfHLevelΣ 2 isSetℕ λ _  isProp→isSet squash

  alg : Σ[ n   ] (Fin n  A)  Σ[ n   ]  Fin n  A 
  alg (n , f≃A) = n ,  f≃A 

  const-alg : (x y : ∃[ n ] (Fin n  A))  alg x  alg y
  const-alg (n , x) (m , y) =
    ΣProp≡
       _  squash)
      {n ,  x } {m ,  y }
      (Fin-inj n m (ua (x  trans-≃  (sym-≃ y))))

# : 𝒞 A  
# = fst  cardinality  _∥$∥_ (ℬ⇔Fin≃ .fun  𝕃⇔ℒ⟨ℬ⟩ .fun)

∥map∥ : (A  B)   A    B 
∥map∥ f = rec squash (∣_∣  f)

module _ {a} {A : Type a} where
\end{code}
%<*cardinality-is-unique>
\begin{code}
  cardinality-is-unique : 𝒞 A  ∃[ n ]  Fin n  A 
\end{code}
%</cardinality-is-unique>
%<*cardinality-is-unique-impl>
\begin{code}
  cardinality-is-unique = rec→set card-isSet alg const-alg  ∥map∥ ℬ⇒Fin≃
\end{code}
%</cardinality-is-unique-impl>
\begin{code}
    where
\end{code}
%<*card-isSet>
\begin{code}
    card-isSet : isSet (∃[ n ]  Fin n  A )
\end{code}
%</card-isSet>
\begin{code}
    card-isSet = isOfHLevelΣ 2 isSetℕ λ _  isProp→isSet squash

\end{code}
%<*alg>
\begin{code}
    alg : Σ[ n   ] (Fin n  A)  Σ[ n   ]  Fin n  A 
    alg (n , f≃A) = n ,  f≃A 
\end{code}
%</alg>
%<*const-alg>
\begin{code}
    const-alg : (x y : ∃[ n ] (Fin n  A))  alg x  alg y
\end{code}
%</const-alg>
\begin{code}

    const-alg (n , x) (m , y) =
      ΣProp≡
         _  squash)
        {n ,  x } {m ,  y }
        (Fin-inj n m (ua (x  trans-≃  (sym-≃ y))))


module _ {a b} {A : Type a} {B : Type b} where
 _∥⇔∥_ : 𝒞 A  𝒞 B  𝒞 (A  B)
 xs ∥⇔∥ ys = subst 𝒞 (isoToPath form) p
   where
   𝒞⟨f⟩ : 𝒞 (A  B)
   𝒞⟨f⟩ = xs ∥→∥ ys

   𝒞⟨g⟩ : 𝒞 (B  A)
   𝒞⟨g⟩ = ys ∥→∥ xs

   p : 𝒞 (Σ[ fg  ((A  B) × (B  A)) ] (((fg .fst  fg .snd)  id) × ((fg .snd  fg .fst)  id)))
   p = ℰ!⇒ℬ  filter-subobject
      fg  isOfHLevelΣ 1 (Discrete→isSet (𝒞⇒Discrete (ys ∥→∥ ys)) _ _) λ _  (Discrete→isSet (𝒞⇒Discrete (xs ∥→∥ xs)) _ _))
      { (f , g)  𝒞⇒Discrete (ys ∥→∥ ys) (f  g) id && 𝒞⇒Discrete (xs ∥→∥ xs) (g  f) id})  ℬ⇒ℰ!
     ∥$∥ (𝒞⟨f⟩ ∥×∥ 𝒞⟨g⟩)

   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

open import Relation.Binary
open import Data.List.Relation.Binary.Permutation
perm-ℬ :
\end{code}
%<*perm-bish>
\begin{code}
 (xs ys :  A)  xs .fst  ys .fst
\end{code}
%</perm-bish>
\begin{code}
perm-ℬ xs ys  x .fun  _    = ys  .snd x .fst
perm-ℬ xs ys  x .inv  _    = xs  .snd x .fst
perm-ℬ xs ys  x .rightInv  = ys  .snd x .snd
perm-ℬ xs ys  x .leftInv   = xs  .snd x .snd

module _ {e r} {E : Type e} (totalOrder : TotalOrder E r) where
  open import Data.List.Sort totalOrder
  open import HITs.PropositionalTruncation using (rec→set)
  open import Data.Sigma.Properties
  open import Cardinality.Finite.ManifestBishop using (ℰ!⇒ℬ)
  open import Cardinality.Finite.ManifestEnumerable.Inductive
  open import Cardinality.Finite.ManifestEnumerable

  𝒞⇒ℬ : 𝒞 E   E
  𝒞⇒ℬ xs = (ℰ!⇒ℬ  ℰ⇒ℰ! discreteE  rec→set (isSet⟨ℰ⟩ (Discrete→isSet discreteE)) alg const-alg) xs
    where
    discreteE = 𝒞⇒Discrete xs

    alg :  E   E
    alg xs .fst = sort (xs .fst)
    alg xs .snd x =  sort-perm (xs .fst) x .inv (xs .snd x .fst) 

    const-alg : (xs ys :  E)  alg xs  alg ys
    const-alg xs ys =
      ΣProp≡
         _  hLevelPi 1  _  squash))
        (perm-invar (xs .fst) (ys .fst) (perm-ℬ xs ys))

open import Cardinality.Finite.SplitEnumerable using (ℰ!⟨≡⟩)

𝒞⟨≡⟩ : (x y : A)  𝒞 A  𝒞 (x  y)
𝒞⟨≡⟩ x y ca = ℰ!⇒ℬ  ℰ!⟨≡⟩ x y  ℬ⇒ℰ! ∥$∥ ca
\end{code}