module HITs where

------------------------------------------------------------------------------
-- We'll be using the Cubical Agda standard Library:

open import Cubical.Foundations.Prelude
  renaming ( congS to ap
           ; cong to apd
           ; congP to apP
           ; subst to tpt
           )
open import Cubical.Foundations.Transport
  renaming ( substComposite to tptComp )
open import Cubical.Foundations.GroupoidLaws
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Function
open import Cubical.Foundations.Univalence
open import Cubical.Data.Sigma
open import Cubical.Data.Nat hiding (_^_)

variable
   ℓ' ℓ'' : Level
  A B C : Type 



------------------------------------------------------------------------------
-- HITs
------------------------------------------------------------------------------

module Int where

  data  : Type where
    pos : (n : )  
    neg : (n : )  
    zero : pos 0  neg 0






  succ :   
  succ (pos n) = pos (suc n)
  succ (neg 0) = pos 1
  succ (neg (suc n)) = neg n
  succ (zero i) = pos 1

  pred :   
  pred (pos 0) = neg 1
  pred (pos (suc n)) = pos n
  pred (neg n) = neg (suc n)
  pred (zero i) = neg 1





  predSucc : (n : )  pred (succ n)  n
  predSucc (pos n) = refl
  predSucc (neg 0) = zero
  predSucc (neg (suc x)) = refl
  predSucc (zero i) j = zero (i  j)

  succPred : (n : )  succ (pred n)  n
  succPred (pos 0) = sym zero
  succPred (pos (suc n)) = refl
  succPred (neg n) = refl
  succPred (zero i) j = zero (i  ~ j)





  succEquiv :   
  succEquiv = isoToEquiv (iso succ pred succPred predSucc)








------------------------------------------------------------------------------
-- Some shapes
------------------------------------------------------------------------------

module Circle where
  open Int

  data  : Type where
    base : 
    loop : base  base


  {- Universal property of S¹ -}

  module S¹Elim where

    module _ (P :   Type ℓ')
      (base* : P base)
      (loop* : PathP  i  P (loop i)) base* base*) where

      ind : (x : )  P x
      ind base = base*
      ind (loop i) = loop* i

    module _ (P : Type ℓ')
      (base* : P)
      (loop* : base*  base*) where

      rec : (x : )  P
      rec = ind  _  P) base* loop*


  Ω : Σ (Type )  X  X)  Type 
  Ω (X , x) = x  x

  S¹Univ : (X : Type )  (  X)  Σ X  x  Ω (X , x))
  S¹Univ X = isoToEquiv (iso f2l l2f f2l2f l2f2l)
    where
      f2l : (  X)  Σ X  x  Ω (X , x))
      f2l f = (f base) , ap f loop
      l2f : Σ X  x  Ω (X , x))    X
      l2f (x , p) base = x
      l2f (x , p) (loop i) = p i
      f2l2f :  x  f2l (l2f x)  x
      f2l2f (x , p) = refl
      l2f2l :  f  l2f (f2l f)  f
      l2f2l f i base = f base
      l2f2l f i (loop j) = f (loop j)



  {- involution on S¹ -}

  twist :   
  twist base = base
  twist (loop i) = loop (~ i)

  twist² : (x : )  twist (twist x)  x
  twist² base = refl
  twist² (loop i) = refl




  {- universal cover of S¹ -}

  cover :   (base  base)
  cover (pos zero) = refl
  cover (pos (suc x)) = loop  cover (pos x)
  cover (neg zero) = refl
  cover (neg (suc x)) = loop ⁻¹  cover (neg x)
  cover (zero i) = refl

  code :   Type
  code base = 
  code (loop i) = ua succEquiv i

  encode : (x : )  (base  x)  code x
  encode x p = tpt code p (pos 0)

  {- winding numbers -}

  winding : (base  base)  
  winding = encode base

  _^_ :  {a : A}  (p : a  a)    a  a
  p ^ (pos 0) = refl
  p ^ (pos (suc x)) = (p ^ (pos x))  p
  p ^ (neg 0) = refl
  p ^ (neg (suc x)) = (p ^ (neg x))  sym p
  p ^ (zero i) = refl



  _ : winding (loop ^ (pos 4))  pos 4
  _ = refl







  windingCount : (n : )  encode base (loop ^ n)  n
  windingCount (pos 0) = refl
  windingCount (pos (suc x)) = tptComp code (loop ^ (pos x)) loop (pos 0)  ap succ (windingCount (pos x))
  windingCount (neg 0) = zero
  windingCount (neg (suc x)) = tptComp code (loop ^ (neg x)) (sym loop) (pos 0)  ap pred (windingCount (neg x))
  windingCount (zero i) j = zero (i  j)








------------------------------------------------------------------------------
--- Shapes
------------------------------------------------------------------------------

module CW where

  open Circle

  data  : Type where
    base : 
    loop1 : base  base
    loop2 : base  base
    surf : Square loop1 loop1 loop2 loop2
        -- loop1 ∙ loop2 ≡ loop2 ∙ loop1

  data  : Type where
    base : 
    loop1 : base  base
    loop2 : base  base
    surf : Square loop1 loop2 (sym loop1) loop2
        -- loop1 ∙ loop2 ∙ loop1 ≡ loop2

  data RP² : Type where
    base : RP²
    loop : base  base
    loop² : Square loop refl refl loop
        -- loop ∙ loop = refl




------------------------------------------------------------------------------
-- S¹ × S¹ ≃ T²
------------------------------------------------------------------------------

  c2t : ( × )  
  c2t (base , base) = base
  c2t (loop i , base) = loop1 i
  c2t (base , loop j) = loop2 j
  c2t (loop i , loop j) = surf j i

  t2c :   ( × )
  t2c base = (base , base)
  t2c (loop1 i) = (loop i , base)
  t2c (loop2 i) = (base , loop i)
  t2c (surf i j) = (loop j) , (loop i)

  c2t2c : (x :  × )  t2c (c2t x)  x
  c2t2c (base , base) = refl
  c2t2c (base , loop j) = refl
  c2t2c (loop i , base) = refl
  c2t2c (loop i , loop j) = refl

  t2c2t : (x : )  c2t (t2c x)  x
  t2c2t base = refl
  t2c2t (loop1 i) = refl
  t2c2t (loop2 i) = refl
  t2c2t (surf i j) = refl

  t=c :  ×   
  t=c = isoToEquiv (iso c2t t2c t2c2t c2t2c)