{-# OPTIONS --lossy-unification #-}

-- This file contains definition of CW complexes and skeleta.

module Cubical.CW.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Function
open import Cubical.Foundations.Pointed

open import Cubical.Data.Nat renaming (_+_ to _+ℕ_)
open import Cubical.Data.Nat.Order
open import Cubical.Data.Fin.Inductive.Base
open import Cubical.Data.Sigma
open import Cubical.Data.Sequence
open import Cubical.Data.FinSequence

open import Cubical.HITs.Sn
open import Cubical.HITs.Pushout
open import Cubical.HITs.Susp
open import Cubical.HITs.SequentialColimit
open import Cubical.HITs.SphereBouquet
open import Cubical.HITs.PropositionalTruncation as PT

open import Cubical.Algebra.AbGroup
open import Cubical.Algebra.AbGroup.Instances.FreeAbGroup

open import Cubical.Relation.Nullary

open Sequence



private
  variable
     ℓ' : Level

--- CW complexes ---
-- Definition of (the skeleton) of an arbitrary CW complex
-- New def: X 0 is empty and C (suc n) is pushout
yieldsCWskel : (  Type )  Type 
yieldsCWskel X =
  Σ[ f  (  ) ]
    Σ[ α  ((n : )  (Fin (f n) × (S⁻ n))  X n) ]
      ((¬ X zero) ×
      ((n : )  X (suc n)  Pushout (α n) fst))

CWskel : ( : Level)  Type (ℓ-suc )
CWskel  = Σ[ X  (  Type ) ] (yieldsCWskel X)

module CWskel-fields (C : CWskel ) where
  card = C .snd .fst
  A = Fin  card
  α = C .snd .snd .fst
  e = C .snd .snd .snd .snd

  ℤ[A_] : (n : )  AbGroup ℓ-zero
  ℤ[A n ] = ℤ[Fin (snd C .fst n) ]

-- Technically, a CW complex should be the sequential colimit over the following maps
CW↪ : (T : CWskel )  (n : )  fst T n  fst T (suc n)
CW↪ (X , f , α , e₀ , e₊) n x = invEq (e₊ n) (inl x)

-- But if it stabilises, no need for colimits.
yieldsFinCWskel : (n : ) (X :   Type )  Type 
yieldsFinCWskel n X =
  Σ[ CWskel  yieldsCWskel X ] ((k : )  isEquiv (CW↪ (X , CWskel) (k +ℕ n)))

-- ... which should give us finite CW complexes.
finCWskel : ( : Level)  (n : )  Type (ℓ-suc )
finCWskel  n = Σ[ C  (  Type ) ] (yieldsFinCWskel n C)

isFinCWskel :  {} (C : CWskel )  Type 
isFinCWskel C = Σ[ m   ] ((k : )  isEquiv (CW↪ C (k +ℕ m)))

finCWskel→CWskel : (n : )  finCWskel  n  CWskel 
finCWskel→CWskel n C = fst C , fst (snd C)

realiseSeq : CWskel   Sequence 
Sequence.obj (realiseSeq (C , p)) = C
Sequence.map (realiseSeq C) = CW↪ C _

realiseFinSeq : (m : )  CWskel   FinSequence m 
realiseFinSeq m C = Sequence→FinSequence m (realiseSeq C)

-- realisation of CW complex from skeleton
realise : CWskel   Type 
realise C = SeqColim (realiseSeq C)

-- Finally: definition of CW complexes
hasCWskel : (X : Type )  Type (ℓ-suc )
hasCWskel { = } X = Σ[ X'  CWskel  ] X  realise X'

isCW : (X : Type )  Type (ℓ-suc )
isCW X =  hasCWskel X ∥₁

CW : ( : Level)  Type (ℓ-suc )
CW  = Σ[ A  Type  ] (isCW A)

CWexplicit : ( : Level)  Type (ℓ-suc )
CWexplicit  = Σ[ A  Type  ] (hasCWskel A)

CWexplicit→CWskel :  {}  CWexplicit   CWskel 
CWexplicit→CWskel C = fst (snd C)

CWexplicit→CW :  {}  CWexplicit   CW 
CWexplicit→CW C = fst C ,  snd C ∣₁

-- Finite CW complexes
isFinIsCW : {X : Type }  hasCWskel X  Type 
isFinIsCW X = Σ[ n   ] (((k : )  isEquiv (CW↪ (X .fst) (k +ℕ n))))

hasFinCWskel : (X : Type )  Type (ℓ-suc )
hasFinCWskel { = } X =
  Σ[ m   ] (Σ[ X'  finCWskel  m ] X  realise (finCWskel→CWskel m X'))

isFinCW : (X : Type )  Type (ℓ-suc )
isFinCW { = } X =  hasFinCWskel X ∥₁

finCW : ( : Level)  Type (ℓ-suc )
finCW  = Σ[ A  Type  ] (isFinCW A)

finCW∙ : ( : Level)  Type (ℓ-suc )
finCW∙  = Σ[ A  Pointed  ] (isFinCW (fst A))

finCWexplicit : ( : Level)  Type (ℓ-suc )
finCWexplicit  = Σ[ A  Type  ] (hasFinCWskel A)

hasFinCWskel→hasCWskel : (X : Type )  hasFinCWskel X  hasCWskel X
hasFinCWskel→hasCWskel X (n , X' , str) = (finCWskel→CWskel n X') , str

finCW→CW : finCW   CW 
finCW→CW (X , p) = X , PT.map (hasFinCWskel→hasCWskel X) p

-- Pointed complexes (with basepoint in X₀)
CWskel∙ :  {} (X : CWskel )  fst X 1  (n : )  fst X (suc n)
CWskel∙ X x zero = x
CWskel∙ X x (suc n) = CW↪ X (suc n) (CWskel∙ X x n)

CWskel∞∙ :  {} (X : CWskel )  fst X 1  (n : )  realise X
CWskel∞∙ X x₀ n = incl (CWskel∙ X x₀ n)

CWskel∞∙Id :  {} (X : CWskel ) (x₀ : fst X 1) (n : )  CWskel∞∙ X x₀ n  incl x₀
CWskel∞∙Id X x₀ zero = refl
CWskel∞∙Id X x₀ (suc n) = sym (push (CWskel∙ X x₀ n))  CWskel∞∙Id X x₀ n

incl∙ :  {} (X : CWskel ) (x₀ : fst X 1) {n : }
   (fst X (suc n) , CWskel∙ X x₀ n) →∙ (realise X , incl x₀)
fst (incl∙ X x₀ {n = n}) = incl
snd (incl∙ X x₀ {n = n}) = CWskel∞∙Id X x₀ n

-- morphisms
_→ᶜʷ_ : CW   CW ℓ'  Type (ℓ-max  ℓ')
C →ᶜʷ D = fst C  fst D

--the cofibre of the inclusion of X n into X (suc n)
cofibCW :  {} (n : ) (C : CWskel )  Type 
cofibCW n C = cofib (CW↪ C n)

--...is basically a sphere bouquet
cofibCW≃bouquet :  {} (n : ) (C : CWskel )
   cofibCW n C  SphereBouquet n (Fin (snd C .fst n))
cofibCW≃bouquet n C = Bouquet≃-gen n (snd C .fst n) (α n) e
  where
  s = Bouquet≃-gen
  α = C .snd .snd .fst
  e = C .snd .snd .snd .snd n

--sending X (suc n) into the cofibCW
to_cofibCW : (n : ) (C : CWskel )  fst C (suc n)  cofibCW n C
to_cofibCW n C x = inr x

--the connecting map of the long exact sequence
δ-pre :  {A : Type } {B : Type ℓ'} (conn : A  B)
   cofib conn  Susp A
δ-pre conn (inl x) = north
δ-pre conn (inr x) = south
δ-pre conn (push a i) = merid a i

δ : (n : ) (C : CWskel )  cofibCW n C  Susp (fst C n)
δ n C = δ-pre (CW↪ C n)

-- send the stage n to the realization (the same as incl, but with explicit args and type)
CW↪∞ : (C : CWskel )  (n : )  fst C n  realise C
CW↪∞ C n x = incl x

CW↪Iterate :  {} (T : CWskel ) (n m : )  fst T n  fst T (m +ℕ n)
CW↪Iterate T n zero = idfun _
CW↪Iterate T n (suc m) x = CW↪ T (m +ℕ n) (CW↪Iterate T n m x)

finCW↑ : (n m : )  (m  n)  finCWskel  n  finCWskel  m
fst (finCW↑ m n p C) = fst C
fst (snd (finCW↑ m n p C)) = snd C .fst
snd (snd (finCW↑ m n p C)) k =
  subst  r  isEquiv (CW↪ (fst C , snd C .fst) r))
        (sym (+-assoc k (fst p) m)  cong (k +ℕ_) (snd p))
        (snd C .snd (k +ℕ fst p))