{-

This file contains:

- Properties of cardinality
- Preordering of cardinalities

-}
{-# OPTIONS --safe #-}
module Cubical.Data.Cardinal.Properties where

open import Cubical.HITs.SetTruncation as ∥₂
open import Cubical.Data.Cardinal.Base

open import Cubical.Algebra.CommSemiring

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure
open import Cubical.Functions.Embedding
open import Cubical.Data.Empty as 
open import Cubical.Data.Sigma
open import Cubical.Data.Sum as 
open import Cubical.Data.Unit
open import Cubical.HITs.PropositionalTruncation as ∥₁
open import Cubical.Relation.Binary.Base
open import Cubical.Relation.Binary.Order.Preorder.Base
open import Cubical.Relation.Binary.Order.Properties

private
  variable
     ℓ' ℓ'' ℓa ℓb ℓc ℓd : Level

-- Cardinality is a commutative semiring
module _ where
  private
    +Assoc : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc})
            A + (B + C)  (A + B) + C
    +Assoc = ∥₂.elim3  _ _ _  isProp→isSet (isSetCard _ _))
                      λ _ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                                  (sym (isoToPath ⊎-assoc-Iso)))

    ·Assoc : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc})
            A · (B · C)  (A · B) · C
    ·Assoc = ∥₂.elim3  _ _ _  isProp→isSet (isSetCard _ _))
                      λ _ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                                  (sym (isoToPath Σ-assoc-Iso)))

    +IdR𝟘 : (A : Card {})  A + 𝟘 {}  A
    +IdR𝟘 = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
                    λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                            (isoToPath ⊎-IdR-⊥*-Iso))

    +IdL𝟘 : (A : Card {})  𝟘 {} + A  A
    +IdL𝟘 = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
                    λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                            (isoToPath ⊎-IdL-⊥*-Iso))

    ·IdR𝟙 : (A : Card {})  A · 𝟙 {}  A
    ·IdR𝟙 = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
                    λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                            (isoToPath rUnit*×Iso))

    ·IdL𝟙 : (A : Card {})  𝟙 {} · A  A
    ·IdL𝟙 = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
                    λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                            (isoToPath lUnit*×Iso))

    +Comm : (A : Card {ℓa}) (B : Card {ℓb})
           (A + B)  (B + A)
    +Comm = ∥₂.elim2  _ _  isProp→isSet (isSetCard _ _))
                     λ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                               (isoToPath ⊎-swap-Iso))

    ·Comm : (A : Card {ℓa}) (B : Card {ℓb})
           (A · B)  (B · A)
    ·Comm = ∥₂.elim2  _ _  isProp→isSet (isSetCard _ _))
                     λ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                               (isoToPath Σ-swap-Iso))

    ·LDist+ : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc})
             A · (B + C)  (A · B) + (A · C)
    ·LDist+ = ∥₂.elim3  _ _ _  isProp→isSet (isSetCard _ _))
                       λ _ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                                   (isoToPath ×DistR⊎Iso))

    AnnihilL : (A : Card {})  𝟘 · A  𝟘
    AnnihilL = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
                       λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                               (isoToPath (ΣEmpty*Iso λ _  _)))

  isCardCommSemiring : IsCommSemiring {ℓ-suc } 𝟘 𝟙 _+_ _·_
  isCardCommSemiring = makeIsCommSemiring isSetCard +Assoc +IdR𝟘 +Comm ·Assoc ·IdR𝟙 ·LDist+ AnnihilL ·Comm

-- Exponentiation is also well-behaved

^AnnihilR𝟘 : (A : Card {})  A ^ 𝟘 {}  𝟙 {}
^AnnihilR𝟘 = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
             λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                            (isoToPath (iso⊥ _)))
           where iso⊥ :  A  Iso (⊥*  A) Unit*
                 Iso.fun (iso⊥ A) _        = tt*
                 Iso.inv (iso⊥ A) _        ()
                 Iso.rightInv (iso⊥ A) _   = refl
                 Iso.leftInv  (iso⊥ A) _ i ()

^IdR𝟙 : (A : Card {})  A ^ 𝟙 {}  A
^IdR𝟙 = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
                λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                               (isoToPath (iso⊤ _)))
        where iso⊤ :  A  Iso (Unit*  A) A
              Iso.fun (iso⊤ _) f      = f tt*
              Iso.inv (iso⊤ _) a _    = a
              Iso.rightInv (iso⊤ _) _ = refl
              Iso.leftInv  (iso⊤ _) _ = refl

^AnnihilL𝟙 : (A : Card {})  𝟙 {} ^ A  𝟙 {}
^AnnihilL𝟙 = ∥₂.elim  _  isProp→isSet (isSetCard _ _))
                     λ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                             (isoToPath (iso⊤ _)))
             where iso⊤ :  A  Iso (A  Unit*) Unit*
                   Iso.fun (iso⊤ _) _      = tt*
                   Iso.inv (iso⊤ _) _ _    = tt*
                   Iso.rightInv (iso⊤ _) _ = refl
                   Iso.leftInv  (iso⊤ _) _ = refl

^LDist+ : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc})
         A ^ (B + C)  (A ^ B) · (A ^ C)
^LDist+ = ∥₂.elim3  _ _ _  isProp→isSet (isSetCard _ _))
                   λ _ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                               (isoToPath Π⊎Iso))

^Assoc· : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc})
         A ^ (B · C)  (A ^ B) ^ C
^Assoc· = ∥₂.elim3  _ _ _  isProp→isSet (isSetCard _ _))
                   λ _ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                               (isoToPath (is _ _ _)))
          where is :  A B C  Iso (B × C  A) (C  B  A)
                is A B C = (B × C  A) Iso⟨ domIso Σ-swap-Iso 
                           (C × B  A) Iso⟨ curryIso 
                           (C  B  A) ∎Iso

^RDist· : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc})
         (A · B) ^ C  (A ^ C) · (B ^ C)
^RDist· = ∥₂.elim3  _ _ _  isProp→isSet (isSetCard _ _))
                   λ _ _ _  cong ∣_∣₂ (Σ≡Prop  _  isPropIsSet)
                                               (isoToPath Σ-Π-Iso))


-- With basic arithmetic done, we can now define an ordering over cardinals
module _ where
  private
    _≲'_ : Card {}  Card {ℓ'}  hProp (ℓ-max  ℓ')
    _≲'_ = ∥₂.rec2 isSetHProp λ (A , _) (B , _)   A  B ∥₁ , isPropPropTrunc

  _≲_ : Rel (Card {}) (Card {ℓ'}) (ℓ-max  ℓ')
  A  B =  A ≲' B 

  isPropValued≲ : (A : Card {}) (B : Card {ℓ'})  isProp (A  B)
  isPropValued≲ a b = str (a ≲' b)

  isRefl≲ : BinaryRelation.isRefl {A = Card {}} _≲_
  isRefl≲ = ∥₂.elim  A  isProp→isSet (isPropValued≲ A A))
                     λ (A , _)   id↪ A ∣₁

  isTrans≲ : (A : Card {}) (B : Card {ℓ'}) (C : Card {ℓ''})
            A  B  B  C  A  C
  isTrans≲ = ∥₂.elim3
              x _ z  isSetΠ2 λ _ _  isProp→isSet (isPropValued≲ x z))
             λ (A , _) (B , _) (C , _)
                ∥₁.map2 λ A↪B B↪C  compEmbedding B↪C A↪B

  isPreorder≲ : IsPreorder {ℓ-suc } _≲_
  isPreorder≲
    = ispreorder isSetCard isPropValued≲ isRefl≲ isTrans≲

isLeast𝟘 : ∀{}  isLeast isPreorder≲ (Card {} , id↪ (Card {})) (𝟘 {})
isLeast𝟘 = ∥₂.elim  x  isProp→isSet (isPropValued≲ 𝟘 x))
                    _   ⊥.rec* ,  ()) ∣₁)

-- Our arithmetic behaves as expected over our preordering
+Monotone≲ : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc}) (D : Card {ℓd})
            A  C  B  D  (A + B)  (C + D)
+Monotone≲
  = ∥₂.elim4  w x y z  isSetΠ2 λ _ _  isProp→isSet (isPropValued≲
                                                       (w + x)
                                                       (y + z)))
              λ (A , _) (B , _) (C , _) (D , _)
               ∥₁.map2 λ A↪C B↪D  ⊎Monotone↪ A↪C B↪D

·Monotone≲ : (A : Card {ℓa}) (B : Card {ℓb}) (C : Card {ℓc}) (D : Card {ℓd})
            A  C  B  D  (A · B)  (C · D)
·Monotone≲
  = ∥₂.elim4  w x y z  isSetΠ2 λ _ _  isProp→isSet (isPropValued≲
                                                       (w · x)
                                                       (y · z)))
              λ (A , _) (B , _) (C , _) (D , _)
               ∥₁.map2 λ A↪C B↪D  ×Monotone↪ A↪C B↪D