{-# OPTIONS --cubical --safe #-}

module Basis where

import Cubical.Core.Everything                as CE
import Cubical.Data.Sigma                     as 
import Cubical.Data.Sum                       as DS
import Cubical.Foundations.Prelude            as FP
import Cubical.Foundations.Equiv              as FE
import Cubical.Functions.Logic                as FL
import Cubical.Foundations.Structure          as FS
import Cubical.Foundations.HLevels            as FH
import Cubical.Foundations.Isomorphism        as FI
import Cubical.Foundations.Equiv.HalfAdjoint  as HAE
import Cubical.Functions.FunExtEquiv          as FEE
import Cubical.Foundations.Function           as FF

open import Cubical.Foundations.Univalence public using (ua)

open CE  public using     (_≡_; Type; Σ; Σ-syntax; _,_; _≃_; equivFun; isEquiv; Level;
                           ℓ-max; ℓ-zero; ℓ-suc)
open   public using     (Σ≡Prop; ΣPathTransport→PathΣ; PathΣ→ΣPathTransport; _×_; _,_)
                renaming  (fst to π₀; snd to π₁)
open DS  public using     (inl; inr; _⊎_)
open FP  public using     (funExt; funExt⁻; subst; isContr; isProp; isPropIsProp; isSet;
                           isProp→isSet; cong; refl; sym; _≡⟨_⟩_; _∎; transport;
                           transportRefl; J; JRefl)
open FE  public using     (idEquiv; invEquiv; secEq; retEq; fiber; equivToIso;
                           isPropIsEquiv)
open FL  public using     ( _⇔_ ; _⇒_ ; ⇔toPath ; _⊓_ ; ∃[∶]-syntax; ∀[∶]-syntax; ∀[]-syntax; ¬_)
                renaming  (isProp⟨⟩ to isProp[])
open FS  public using     () renaming (⟨_⟩ to [_])
open FH public using      (hProp; isSetHProp; isPropIsSet; isPropΣ; isOfHLevel;
                           isOfHLevelΠ; isOfHLevelΣ; isOfHLevelSuc; isSetΣ;
                           isSetΠ; isSetΠ2; isPropΠ; isPropΠ2; isPropΠ3)
open FI  public using     (isoToPath; isoToEquiv; iso; section; retract; Iso)
open FF  public using     (_∘_) renaming (idfun to id)
open FEE public using     (funExtEquiv; funExt₂; funExt₂Equiv; funExt₂Path)
open HAE public using     (isHAEquiv; equiv→HAEquiv)

open import Cubical.Data.Nat  using (; _+_) renaming (suc to sucℕ; zero to zeroℕ)
open import Cubical.Data.Nat.Properties using (injSuc; snotz; +-comm)
open import Cubical.Data.Nat.Order
open import Cubical.Data.Empty using (rec; )
open import Cubical.Data.List using (List; length; _∷_; [])
open import Cubical.Data.Fin  using (Fin)
open import Cubical.Relation.Nullary.DecidableEq using (Discrete→isSet)
open import Cubical.Relation.Nullary using (Discrete; yes; no; Dec)
variable
   ℓ′ ℓ₀ ℓ₁ ℓ₂ ℓ₃ ℓ₀′ ℓ₁′ ℓ₂′ ℓ₀′′ ℓ₁′′ ℓ₂′′ : Level

variable
  A    : Type ℓ₀
  B    : A  Type ℓ₀
  A₀   : Type ℓ₁

_↔_ : (A : Type ) (B : Type ℓ′)  Type _
A  B = (A  B) × (B  A)

↔-to : {A : Type } {B : Type ℓ′}  A  B  A  B
↔-to (to , _) = to

↔-from : {A : Type } {B : Type ℓ′}  A  B  B  A
↔-from (_ , from) = from

Levels

Escardó-style level notation.

infixr 5 _∨_

Universe : Type₀
Universe = Level

variable
  𝒰 𝒱 𝒲 𝓤 𝓥 𝓦 𝓤′ 𝓥′ 𝓦′ : Universe

_∨_ : Level  Level  Level
ℓ₀  ℓ₁ = ℓ-max ℓ₀ ℓ₁

infix 6 _⁺

_⁺ : Level  Level
  = ℓ-suc 

infix 6 

 : ( : Level)  Type ( )
 ̇ = Type 

𝓤₀ : Level
𝓤₀ = ℓ-zero

𝓤₁ : Level
𝓤₁ = 𝓤₀ 

The unit type

data Unit ( : Level) : Type  where
  tt : Unit 

Unit-prop : { : Level}  isProp (Unit )
Unit-prop tt tt = refl

Bottom

data 𝟘 ( : Level) : Type  where

bot : ( : Level)  hProp 
bot  = 𝟘  , λ ()

Booleans

data Bool ( : Level) : Type  where
  true  : Bool 
  false : Bool 
true≠false : _≡_ { = 𝓤} true false  
true≠false p = subst  { true  Unit 𝓤₀ ; false   }) p tt
_=b=_ : Discrete (Bool 𝓤)
true  =b= true  = yes refl
true  =b= false = no true≠false
false =b= true  = no (true≠false  sym)
false =b= false = yes refl
Bool-set : isSet (Bool 𝓤)
Bool-set = Discrete→isSet _=b=_
if_then_else_ : {A : Type ℓ₀}  Bool ℓ₁  A  A  A
if true  then x else y = x
if false then x else y = y

Propositions

is-true-prop : (P : hProp )  isProp [ P ]
is-true-prop (P , P-prop) = P-prop
∃_ : {A : Type ℓ₀}  (A  hProp ℓ₁)  Type _
∃_ {A = A} P = Σ[ x  A ] [ P x ]

Extensional equality

_~_ : (f g : (x : A)  B x)  Type _
_~_ {A = A} f g = (x : A)  f x  g x

Powerset

𝒫 : Type   Type _
𝒫 {} A = A  hProp 

_∈_ : A  𝒫 A  hProp _
x  U = U x

∈-prop : {A : Type } {x : A}  (U : 𝒫 A)  isProp [ x  U ]
∈-prop {x = x} U = is-true-prop (x  U)

𝒫-set : (A : Type )  isSet (𝒫 A)
𝒫-set A = isSetΠ λ _  isSetHProp

_^c : {A : Type }  𝒫 A  𝒫 A
U ^c = λ x  ¬ (x  U)

variable
  U V : 𝒫 A

_⊆⊆_ : {A : Type }  (A  Type ℓ₀)  (A  Type ℓ₁)  Type _
_⊆⊆_ {A = A} U V =  (x : A)  U x  V x

_⊆_ : {A : Type }  𝒫 A  𝒫 A  hProp 
_⊆_ {A = A} U V = ((λ -  [ U - ]) ⊆⊆  -  [ V - ])) , prop
  where
    prop : isProp ((x : A)  [ U x ]  [ V x ])
    prop = isPropΠ λ x  isPropΠ λ _  is-true-prop (V x)

⊆-antisym : [ U  V ]  [ V  U ]  U  V
⊆-antisym {U = U} {V} U⊆V V⊆V = funExt  x  ⇔toPath (U⊆V x) (V⊆V x))

 : 𝒫 A
  _ = bot _

entire : {A : Type }  𝒫 A
entire { = } _ = Unit  , Unit-prop

_∩_ : 𝒫 A  𝒫 A  𝒫 A
_∩_ {A = A} U V = λ x  ([ U x ] × [ V x ]) , prop x
  where
    prop : (x : A)  isProp ([ U x ] × [ V x ])
    prop x = isPropΣ (is-true-prop (x  U)) λ _  is-true-prop (V x)
U∩U^c=∅ : {A : Type }  (U : 𝒫 A)  Σ[ x  A ] [ x  (U  (U ^c)) ]  Cubical.Data.Empty.⊥
U∩U^c=∅ U (x , (x∈U , x∈U^c)) = rec (x∈U^c x∈U)

Family

Fam : (ℓ₀ : Level)  Type ℓ₁  Type _
Fam ℓ₀ A = Σ (Set ℓ₀)  I  I  A)

index : Fam ℓ₁ A  Type ℓ₁
index (I , _) = I

-- Application of a family over X to an index.
_$_ : ( : Fam ℓ₀ A)  index   A
_$_ (_ , f) = f

infixr 7 _$_

-- Membership for families.
_ε_ : A  Fam ℓ₁ A  Type _
x ε (_ , f) = fiber f x

_⊆fam_ : {A : Type }  Fam ℓ₁ A  Fam ℓ₁ A  Type (ℓ-max  ℓ₁)
_⊆fam_ {A = A} U V = (x : A)  x ε U  x ε V

-- Composition of a family with a function.
_⟨$⟩_ : {X : Type ℓ₀} {Y : Type ℓ₁}  (g : X  Y)  ( : Fam ℓ₂ X)  Fam ℓ₂ Y
g ⟨$⟩  = (index ) , g  (_$_ )

fmap : {X : Type ℓ₀} {Y : Type ℓ₁}  (g : X  Y)  ( : Fam ℓ₂ X)  Fam ℓ₂ Y
fmap = _⟨$⟩_

syntax fmap  x  e)  =  e  x ε  

compr-∶-syntax : {X : Type ℓ₀}  (I : Type ℓ₂)  (I  X)  Fam ℓ₂ X
compr-∶-syntax I f = (I , f)

syntax compr-∶-syntax I  i  e) =  e  i  I 

-- Forall quantification for families.
fam-forall : {X : Type ℓ₀} ( : Fam ℓ₂ X)  (X  hProp ℓ₁)  hProp _
fam-forall {X = X}  P = ((x : X)  x ε   [ P x ]) , prop
  where
    prop : isProp ((x : X)  x ε   [ P x ])
    prop = isPropΠ λ x  isPropΠ λ _  is-true-prop (P x)

syntax fam-forall   x  P) = ∀[ x ε  ] P

-- Familification of a given powerset.
⟪_⟫ : {A : Type ℓ₀}  (A  hProp ℓ₁)  Fam _ A
⟪_⟫ {A = A} U = (Σ[ x  A ] [ U x ]) , π₀

lookup : {A : Type ℓ₀}  (xs : List A)  Fin (length xs)  A
lookup []       (_      , zeroℕ  , p) = rec (snotz p)
lookup []       (_      , sucℕ i , p) = rec (snotz p)
lookup (x  xs) (zeroℕ  , _)          = x
lookup (x  xs) (sucℕ i , p)          = lookup xs (i , pred-≤-pred p)

famFromList : {A : Type ℓ₀}  List A  Fam _ A
famFromList xs = Fin (length xs) , lookup xs

_×f_ : {A : Type ℓ₀}  Fam ℓ₂ A  Fam ℓ₂′ A  Fam (ℓ-max ℓ₂ ℓ₂′) (A × A)
_×f_ (I , f) (J , g) = I × J ,  { (i , j)  f i , g j })

_∪f_ : {A : 𝓤 ̇}  Fam 𝓦 A  Fam 𝓦 A  Fam 𝓦 A
_∪f_ (I , f) (J , g) = I  J , λ { (inl i)  f i ; (inr j)  g j }

⁅_,_⁆ : {A : 𝓤 ̇} {𝓦 : Universe}  A  A  Fam 𝓦 A
⁅_,_⁆ {𝓦 = 𝓦} x y = Bool 𝓦 , λ b  if b then x else y

Truncation

data ∥_∥ (A : Type ) : Type  where
  ∣_∣    : A   A 
  squash : (x y :  A )  x  y

∥∥-prop : (A : Type )  isProp  A 
∥∥-prop _ = squash

∥_∥Ω : (A : 𝓤 ̇)  hProp 𝓤
 A ∥Ω =  A  , ∥∥-prop A

∥∥-rec : {X : Type } {Y : Type ℓ₀}  isProp Y  (X  Y)   X   Y
∥∥-rec Y-prop f  x                 = f x
∥∥-rec Y-prop f (squash ∣x∣₀ ∣x∣₁ i) =
  Y-prop (∥∥-rec Y-prop f ∣x∣₀) (∥∥-rec Y-prop f ∣x∣₁) i

∥∥-× : {A : Type ℓ₀} {B : Type ℓ₁}   A    B    A × B 
∥∥-× {A = A} {B} p q = ∥∥-rec (∥∥-prop (A × B)) NTS p
  where
    NTS′ : B  A   A × B 
    NTS′ y x =  x , y 

    NTS : A   A × B 
    NTS = ∥∥-rec (isPropΠ  _  ∥∥-prop (A × B))) NTS′ q