{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Functions.Embedding where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Equiv.Properties
open import Cubical.Foundations.Equiv.HalfAdjoint
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Transport
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Path
open import Cubical.Foundations.Powerset
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Univalence using (ua; univalence)
open import Cubical.Functions.Fibration

open import Cubical.Data.Sigma
open import Cubical.Functions.Fibration
open import Cubical.Functions.FunExtEquiv
open import Cubical.Relation.Nullary using (Discrete; yes; no)
open import Cubical.Structures.Axioms

open import Cubical.Reflection.StrictEquiv

open import Cubical.Data.Nat using (ℕ; zero; suc)
open import Cubical.Data.Sigma

private
  variable
    ℓ ℓ₁ ℓ₂ : Level
    A B : Type ℓ
    f h : A → B
    w x : A
    y z : B

-- Embeddings are generalizations of injections. The usual
-- definition of injection as:
--
--    f x ≡ f y → x ≡ y
--
-- is not well-behaved with higher h-levels, while embeddings
-- are.
isEmbedding : (A → B) → Type _
isEmbedding f = ∀ w x → isEquiv {A = w ≡ x} (cong f)

isEmbeddingIsProp : isProp (isEmbedding f)
isEmbeddingIsProp {f = f} = isPropΠ2 λ _ _ → isPropIsEquiv (cong f)

-- If A and B are h-sets, then injective functions between
-- them are embeddings.
--
-- Note: It doesn't appear to be possible to omit either of
-- the `isSet` hypotheses.
injEmbedding
  : {f : A → B}
  → isSet A → isSet B
  → (∀{w x} → f w ≡ f x → w ≡ x)
  → isEmbedding f
injEmbedding {f = f} iSA iSB inj w x
  = isoToIsEquiv (iso (cong f) inj sect retr)
  where
  sect : section (cong f) inj
  sect p = iSB (f w) (f x) _ p

  retr : retract (cong f) inj
  retr p = iSA w x _ p

-- If `f` is an embedding, we'd expect the fibers of `f` to be
-- propositions, like an injective function.
hasPropFibers : (A → B) → Type _
hasPropFibers f = ∀ y → isProp (fiber f y)

-- This can be relaxed to having all prop fibers over the image, see [hasPropFibersOfImage→isEmbedding]
hasPropFibersOfImage : (A → B) → Type _
hasPropFibersOfImage f = ∀ x → isProp (fiber f (f x))

-- some notation
_↪_ : Type ℓ₁ → Type ℓ₂ → Type (ℓ-max ℓ₁ ℓ₂)
A ↪ B = Σ[ f ∈ (A → B) ] isEmbedding f

hasPropFibersIsProp : isProp (hasPropFibers f)
hasPropFibersIsProp = isPropΠ (λ _ → isPropIsProp)

private
  lemma₀ : (p : y ≡ z) → fiber f y ≡ fiber f z
  lemma₀ {f = f} p = λ i → fiber f (p i)

  lemma₁ : isEmbedding f → ∀ x → isContr (fiber f (f x))
  lemma₁ {f = f} iE x = value , path
    where
    value : fiber f (f x)
    value = (x , refl)

    path : ∀(fi : fiber f (f x)) → value ≡ fi
    path (w , p) i
      = case equiv-proof (iE w x) p of λ
      { ((q , sq) , _)
      → hfill (λ j → λ { (i = i0) → (x , refl)
                      ; (i = i1) → (w , sq j)
                      })
          (inS (q (~ i) , λ j → f (q (~ i ∨ j))))
          i1
      }

isEmbedding→hasPropFibers : isEmbedding f → hasPropFibers f
isEmbedding→hasPropFibers iE y (x , p)
  = subst (λ f → isProp f) (lemma₀ p) (isContr→isProp (lemma₁ iE x)) (x , p)

private
  fibCong→PathP
    : {f : A → B}
    → (p : f w ≡ f x)
    → (fi : fiber (cong f) p)
    → PathP (λ i → fiber f (p i)) (w , refl) (x , refl)
  fibCong→PathP p (q , r) i = q i , λ j → r j i

  PathP→fibCong
    : {f : A → B}
    → (p : f w ≡ f x)
    → (pp : PathP (λ i → fiber f (p i)) (w , refl) (x , refl))
    → fiber (cong f) p
  PathP→fibCong p pp = (λ i → fst (pp i)) , (λ j i → snd (pp i) j)

PathP≡fibCong
  : {f : A → B}
  → (p : f w ≡ f x)
  → PathP (λ i → fiber f (p i)) (w , refl) (x , refl) ≡ fiber (cong f) p
PathP≡fibCong p
  = isoToPath (iso (PathP→fibCong p) (fibCong→PathP p) (λ _ → refl) (λ _ → refl))

hasPropFibers→isEmbedding : hasPropFibers f → isEmbedding f
hasPropFibers→isEmbedding {f = f} iP w x .equiv-proof p
  = subst isContr (PathP≡fibCong p) (isProp→isContrPathP (λ i → iP (p i)) fw fx)
  where
  fw : fiber f (f w)
  fw = (w , refl)

  fx : fiber f (f x)
  fx = (x , refl)

hasPropFibersOfImage→hasPropFibers : hasPropFibersOfImage f → hasPropFibers f
hasPropFibersOfImage→hasPropFibers {f = f} fibImg y a b =
  subst (λ y → isProp (fiber f y)) (snd a) (fibImg (fst a)) a b

hasPropFibersOfImage→isEmbedding : hasPropFibersOfImage f → isEmbedding f
hasPropFibersOfImage→isEmbedding = hasPropFibers→isEmbedding ∘ hasPropFibersOfImage→hasPropFibers

isEmbedding≡hasPropFibers : isEmbedding f ≡ hasPropFibers f
isEmbedding≡hasPropFibers
  = isoToPath
      (iso isEmbedding→hasPropFibers
           hasPropFibers→isEmbedding
           (λ _ → hasPropFibersIsProp _ _)
           (λ _ → isEmbeddingIsProp _ _))

isEquiv→hasPropFibers : isEquiv f → hasPropFibers f
isEquiv→hasPropFibers e b = isContr→isProp (equiv-proof e b)

isEquiv→isEmbedding : isEquiv f → isEmbedding f
isEquiv→isEmbedding e = λ _ _ → congEquiv (_ , e) .snd

Equiv→Embedding : A ≃ B → A ↪ B
Equiv→Embedding (f , isEquivF) = (f , isEquiv→isEmbedding isEquivF)

iso→isEmbedding : ∀ {ℓ} {A B : Type ℓ}
  → (isom : Iso A B)
  -------------------------------
  → isEmbedding (Iso.fun isom)
iso→isEmbedding {A = A} {B} isom = (isEquiv→isEmbedding (equivIsEquiv (isoToEquiv isom)))

isEmbedding→Injection :
  ∀ {ℓ} {A B C : Type ℓ}
  → (a : A → B)
  → (e : isEmbedding a)
  ----------------------
  → ∀ {f g : C → A} →
  ∀ x → (a (f x) ≡ a (g x)) ≡ (f x ≡ g x)
isEmbedding→Injection a e {f = f} {g} x = sym (ua (cong a , e (f x) (g x)))

-- if `f` has a retract, then `cong f` has, as well. If `B` is a set, then `cong f`
-- further has a section, making `f` an embedding.
module _ {f : A → B} (retf : hasRetract f) where
  open Σ retf renaming (fst to g ; snd to ϕ)

  congRetract : f w ≡ f x → w ≡ x
  congRetract {w = w} {x = x} p = sym (ϕ w) ∙∙ cong g p ∙∙ ϕ x

  isRetractCongRetract : retract (cong {x = w} {y = x} f) congRetract
  isRetractCongRetract p = transport (PathP≡doubleCompPathˡ _ _ _ _) (λ i j → ϕ (p j) i)

  hasRetract→hasRetractCong : hasRetract (cong {x = w} {y = x} f)
  hasRetract→hasRetractCong = congRetract , isRetractCongRetract

  retractableIntoSet→isEmbedding : isSet B → isEmbedding f
  retractableIntoSet→isEmbedding setB w x =
    isoToIsEquiv (iso (cong f) congRetract (λ _ → setB _ _ _ _) (hasRetract→hasRetractCong .snd))

Embedding-into-Discrete→Discrete : A ↪ B → Discrete B → Discrete A
Embedding-into-Discrete→Discrete (f , isEmbeddingF) _≟_ x y with f x ≟ f y
... | yes p = yes (invIsEq (isEmbeddingF x y) p)
... | no ¬p = no (¬p ∘ cong f)

Embedding-into-isProp→isProp : A ↪ B → isProp B → isProp A
Embedding-into-isProp→isProp (f , isEmbeddingF) isProp-B x y
  = invIsEq (isEmbeddingF x y) (isProp-B (f x) (f y))

Embedding-into-isSet→isSet : A ↪ B → isSet B → isSet A
Embedding-into-isSet→isSet (f , isEmbeddingF) isSet-B x y p q =
  p ≡⟨ sym (retIsEq isEquiv-cong-f p) ⟩
  cong-f⁻¹ (cong f p) ≡⟨ cong cong-f⁻¹ cong-f-p≡cong-f-q ⟩
  cong-f⁻¹ (cong f q) ≡⟨ retIsEq isEquiv-cong-f q ⟩
  q ∎
  where
    cong-f-p≡cong-f-q = isSet-B (f x) (f y) (cong f p) (cong f q)
    isEquiv-cong-f = isEmbeddingF x y
    cong-f⁻¹ = invIsEq isEquiv-cong-f

Embedding-into-hLevel→hLevel
  : ∀ n → A ↪ B → isOfHLevel (suc n) B → isOfHLevel (suc n) A
Embedding-into-hLevel→hLevel zero = Embedding-into-isProp→isProp
Embedding-into-hLevel→hLevel (suc n) (f , isEmbeddingF) Blvl x y
  = isOfHLevelRespectEquiv (suc n) (invEquiv equiv) subLvl
  where
  equiv : (x ≡ y) ≃ (f x ≡ f y)
  equiv .fst = cong f
  equiv .snd = isEmbeddingF x y
  subLvl : isOfHLevel (suc n) (f x ≡ f y)
  subLvl = Blvl (f x) (f y)

-- We now show that the powerset is the subtype classifier
-- i.e. ℙ X ≃ Σ[A ∈ Type ℓ] (A ↪ X)
Embedding→Subset : {X : Type ℓ} → Σ[ A ∈ Type ℓ ] (A ↪ X) → ℙ X
Embedding→Subset (_ , f , isEmbeddingF) x = fiber f x , isEmbedding→hasPropFibers isEmbeddingF x

Subset→Embedding : {X : Type ℓ} → ℙ X → Σ[ A ∈ Type ℓ ] (A ↪ X)
Subset→Embedding {X = X} A = D , fst , Ψ
 where
  D = Σ[ x ∈ X ] x ∈ A

  Ψ : isEmbedding fst
  Ψ w x = isEmbeddingFstΣProp (∈-isProp A)

Subset→Embedding→Subset : {X : Type ℓ} → section (Embedding→Subset {ℓ} {X}) (Subset→Embedding {ℓ} {X})
Subset→Embedding→Subset _ = funExt λ x → Σ≡Prop (λ _ → isPropIsProp) (ua (FiberIso.fiberEquiv _ x))

Embedding→Subset→Embedding : {X : Type ℓ} → retract (Embedding→Subset {ℓ} {X}) (Subset→Embedding {ℓ} {X})
Embedding→Subset→Embedding {ℓ = ℓ} {X = X} (A , f , ψ) =
  cong (equivFun Σ-assoc-≃) (Σ≡Prop (λ _ → isEmbeddingIsProp) (secEq (fibrationEquiv X ℓ) (A , f)))

Subset≃Embedding : {X : Type ℓ} → ℙ X ≃ (Σ[ A ∈ Type ℓ ] (A ↪ X))
Subset≃Embedding = isoToEquiv (iso Subset→Embedding Embedding→Subset
                                    Embedding→Subset→Embedding Subset→Embedding→Subset)

Subset≡Embedding : {X : Type ℓ} → ℙ X ≡ (Σ[ A ∈ Type ℓ ] (A ↪ X))
Subset≡Embedding = ua Subset≃Embedding

isEmbedding-∘ : isEmbedding f → isEmbedding h → isEmbedding (f ∘ h)
isEmbedding-∘ {f = f} {h = h} Embf Embh w x
  = compEquiv (cong h , Embh w x) (cong f , Embf (h w) (h x)) .snd

isEmbedding→embedsFibersIntoSingl
  : isEmbedding f
  → ∀ z → fiber f z ↪ singl z
isEmbedding→embedsFibersIntoSingl {f = f} isE z = e , isEmbE where
  e : fiber f z → singl z
  e x = f (fst x) , sym (snd x)

  isEmbE : isEmbedding e
  isEmbE u v = goal where
    -- "adjust" ΣeqCf by trivial equivalences that hold judgementally, which should save compositions
    Dom′ : ∀ u v → Type _
    Dom′ u v = Σ[ p ∈    fst u  ≡    fst v  ] PathP (λ i → f (p i) ≡ z) (snd u) (snd v)
    Cod′ : ∀ u v → Type _
    Cod′ u v = Σ[ p ∈ f (fst u) ≡ f (fst v) ] PathP (λ i →    p i  ≡ z) (snd u) (snd v)
    ΣeqCf : Dom′ u v ≃ Cod′ u v
    ΣeqCf = Σ-cong-equiv-fst (_ , isE _ _)

    dom→ : u ≡ v → Dom′ u v
    dom→ p = cong fst p , cong snd p
    dom← : Dom′ u v → u ≡ v
    dom← p i = p .fst i , p .snd i

    cod→ : e u ≡ e v → Cod′ u v
    cod→ p = cong fst p , cong (sym ∘ snd) p
    cod← : Cod′ u v → e u ≡ e v
    cod← p i = p .fst i , sym (p .snd i)

    goal : isEquiv (cong e)
    goal .equiv-proof x .fst .fst =
      dom← (equivCtr ΣeqCf (cod→ x) .fst)
    goal .equiv-proof x .fst .snd j =
      cod← (equivCtr ΣeqCf (cod→ x) .snd j)
    goal .equiv-proof x .snd (g , p) i .fst =
      dom← (equivCtrPath ΣeqCf (cod→ x) (dom→ g , cong cod→ p) i .fst)
    goal .equiv-proof x .snd (g , p) i .snd j =
      cod← (equivCtrPath ΣeqCf (cod→ x) (dom→ g , cong cod→ p) i .snd j)

isEmbedding→hasPropFibers′ : isEmbedding f → hasPropFibers f
isEmbedding→hasPropFibers′ {f = f} iE z =
  Embedding-into-isProp→isProp (isEmbedding→embedsFibersIntoSingl iE z) isPropSingl

universeEmbedding :
  ∀ {ℓ ℓ₁ : Level}
  → (F : Type ℓ → Type ℓ₁)
  → (∀ X → F X ≃ X)
  → isEmbedding F
universeEmbedding F liftingEquiv = hasPropFibersOfImage→isEmbedding propFibersF where
  lemma : ∀ A B → (F A ≡ F B) ≃ (B ≡ A)
  lemma A B = (F A ≡ F B)  ≃⟨ univalence ⟩
              (F A ≃ F B) ≃⟨ equivComp (liftingEquiv A) (liftingEquiv B) ⟩
              (A ≃ B)     ≃⟨ invEquivEquiv ⟩
              (B ≃ A)     ≃⟨ invEquiv univalence ⟩
              (B ≡ A)      ■
  fiberSingl : ∀ X → fiber F (F X) ≃ singl X
  fiberSingl X = Σ-cong-equiv-snd (λ _ → lemma _ _)
  propFibersF : hasPropFibersOfImage F
  propFibersF X = Embedding-into-isProp→isProp (Equiv→Embedding (fiberSingl X)) isPropSingl

liftEmbedding : (ℓ ℓ₁ : Level)
              → isEmbedding (Lift {i = ℓ} {j = ℓ₁})
liftEmbedding ℓ ℓ₁ = universeEmbedding (Lift {j = ℓ₁}) (λ _ → invEquiv LiftEquiv)

module FibrationIdentityPrinciple {B : Type ℓ} {ℓ₁} where
  -- note that fibrationEquiv (for good reason) uses ℓ₁ = ℓ-max ℓ ℓ₁, so we have to work
  -- some universe magic to achieve good universe polymorphism

  -- First, prove it for the case that's dealt with in fibrationEquiv
  Fibration′ = Fibration B (ℓ-max ℓ ℓ₁)

  module Lifted (f g : Fibration′) where
    f≃g′ : Type (ℓ-max ℓ ℓ₁)
    f≃g′ = ∀ b → fiber (f .snd) b ≃ fiber (g .snd) b

    Fibration′IP : f≃g′ ≃ (f ≡ g)
    Fibration′IP =
        f≃g′
      ≃⟨ equivΠCod (λ _ → invEquiv univalence) ⟩
        (∀ b → fiber (f .snd) b ≡ fiber (g .snd) b)
      ≃⟨ funExtEquiv ⟩
        fiber (f .snd) ≡ fiber (g .snd)
      ≃⟨ invEquiv (congEquiv (fibrationEquiv B ℓ₁)) ⟩
        f ≡ g
      ■

  -- Then embed into the above case by lifting the type
  L : Type _ → Type _ -- local synonym fixing the levels of Lift
  L = Lift {i = ℓ₁} {j = ℓ}

  liftFibration : Fibration B ℓ₁ → Fibration′
  liftFibration (A , f) = L A , f ∘ lower

  hasPropFibersLiftFibration : hasPropFibers liftFibration
  hasPropFibersLiftFibration (A , f) =
    Embedding-into-isProp→isProp (Equiv→Embedding fiberChar)
      (isPropΣ (isEmbedding→hasPropFibers (liftEmbedding _ _) A)
               λ _ → isEquiv→hasPropFibers (snd (invEquiv (preCompEquiv LiftEquiv))) _)
    where
    fiberChar : fiber liftFibration (A , f)
              ≃ (Σ[ (E , eq) ∈ fiber L A ] fiber (_∘ lower) (transport⁻ (λ i → eq i → B) f))
    fiberChar =
        fiber liftFibration (A , f)
      ≃⟨ Σ-cong-equiv-snd (λ _ → invEquiv ΣPath≃PathΣ) ⟩
        (Σ[ (E , g) ∈ Fibration B ℓ₁ ] Σ[ eq ∈ (L E ≡ A) ] PathP (λ i → eq i → B) (g ∘ lower) f)
      ≃⟨ boringSwap ⟩
        (Σ[ (E , eq) ∈ fiber L A ] Σ[ g ∈ (E → B) ] PathP (λ i → eq i → B) (g ∘ lower) f)
      ≃⟨ Σ-cong-equiv-snd (λ _ → Σ-cong-equiv-snd λ _ → transportEquiv (PathP≡Path⁻ _ _ _)) ⟩
        (Σ[ (E , eq) ∈ fiber L A ] fiber (_∘ lower) (transport⁻ (λ i → eq i → B) f))
      ■ where
      unquoteDecl boringSwap =
        declStrictEquiv boringSwap
          (λ ((E , g) , (eq , p)) → ((E , eq) , (g , p)))
          (λ ((E , g) , (eq , p)) → ((E , eq) , (g , p)))

  isEmbeddingLiftFibration : isEmbedding liftFibration
  isEmbeddingLiftFibration = hasPropFibers→isEmbedding hasPropFibersLiftFibration

  -- and finish off
  module _ (f g : Fibration B ℓ₁) where
    open Lifted (liftFibration f) (liftFibration g)
    f≃g : Type (ℓ-max ℓ ℓ₁)
    f≃g = ∀ b → fiber (f .snd) b ≃ fiber (g .snd) b

    FibrationIP : f≃g ≃ (f ≡ g)
    FibrationIP =
      f≃g  ≃⟨ equivΠCod (λ b → equivComp (Σ-cong-equiv-fst LiftEquiv)
                                          (Σ-cong-equiv-fst LiftEquiv)) ⟩
      f≃g′ ≃⟨ Fibration′IP ⟩
      (liftFibration f ≡ liftFibration g) ≃⟨ invEquiv (_ , isEmbeddingLiftFibration _ _) ⟩
      (f ≡ g) ■
open FibrationIdentityPrinciple renaming (f≃g to _≃Fib_) using (FibrationIP) public

Embedding : (B : Type ℓ₁) → (ℓ : Level) → Type (ℓ-max ℓ₁ (ℓ-suc ℓ))
Embedding B ℓ = Σ[ A ∈ Type ℓ ] A ↪ B

module EmbeddingIdentityPrinciple {B : Type ℓ} {ℓ₁} (f g : Embedding B ℓ₁) where
  module _ where
    open Σ f renaming (fst to F) public
    open Σ g renaming (fst to G) public
    open Σ (f .snd) renaming (fst to ffun; snd to isEmbF) public
    open Σ (g .snd) renaming (fst to gfun; snd to isEmbG) public
  f≃g : Type _
  f≃g = (∀ b → fiber ffun b → fiber gfun b) ×
         (∀ b → fiber gfun b → fiber ffun b)
  toFibr : Embedding B ℓ₁ → Fibration B ℓ₁
  toFibr (A , (f , _)) = (A , f)

  isEmbeddingToFibr : isEmbedding toFibr
  isEmbeddingToFibr w x = fullEquiv .snd where
    -- carefully managed such that (cong toFibr) is the equivalence
    fullEquiv : (w ≡ x) ≃ (toFibr w ≡ toFibr x)
    fullEquiv = compEquiv (congEquiv (invEquiv Σ-assoc-≃)) (invEquiv (Σ≡PropEquiv (λ _ → isEmbeddingIsProp)))

  EmbeddingIP : f≃g ≃ (f ≡ g)
  EmbeddingIP =
      f≃g
    ≃⟨ strictIsoToEquiv (invIso toProdIso) ⟩
      (∀ b → (fiber ffun b → fiber gfun b) × (fiber gfun b → fiber ffun b))
    ≃⟨ equivΠCod (λ _ → isEquivPropBiimpl→Equiv (isEmbedding→hasPropFibers isEmbF _)
                                                 (isEmbedding→hasPropFibers isEmbG _)) ⟩
      (∀ b → (fiber (f .snd .fst) b) ≃ (fiber (g .snd .fst) b))
    ≃⟨ FibrationIP (toFibr f) (toFibr g) ⟩
      (toFibr f ≡ toFibr g)
    ≃⟨ invEquiv (_ , isEmbeddingToFibr _ _) ⟩
      f ≡ g
    ■
open EmbeddingIdentityPrinciple renaming (f≃g to _≃Emb_) using (EmbeddingIP) public


{-# OPTIONS --without-K --copatterns --sized-types #-}
open import lib.Basics
open import lib.PathGroupoid
open import lib.types.Paths
open import lib.Funext
open import Size

{-
-- | Coinductive delay type. This is the functor νπ̂ : Set → Set arising
-- as the fixed point of π̂(H) = π ∘ ⟨Id, H⟩, where π : Set × Set → Set
-- with π(X, Y) = X.
record D (S : Set) : Set where
  coinductive
  field
    force : S
open D

-- | Action of D on morphisms
D₁ : ∀ {X Y} → (X → Y) → D X → D Y
force (D₁ f x) = f (force x)

-- | D lifted to dependent functions
↑D₁ : ∀ {A} → (B : A → Set) → ((x : A) → B x) → (y : D A) → D (B (force y))
force (↑D₁ B f y) = f (force y)

D-intro : ∀ {H : Set → Set} → (∀ {X} → H X → X) → (∀ {X} → H X → D X)
force (D-intro f x) = f x

D-intro2 : ∀ {X S : Set} → (X → S) → X → D S
force (D-intro2 f x) = f x

postulate
  -- | We'll need coinduction to prove such equalities in the future, or prove
  -- it from univalence.
  D-coind : ∀ {S} {x y : D S} → force x == force y → x == y

D-coind2 : ∀ {S} {x y : D S} → D (force x == force y) → x == y
D-coind2 p = D-coind (force p
-}

module _ where
  private
    mutual
      data #D (A : Set) (P : Set) : Set where
        #p : #D-aux A P → (Unit → Unit) → #D A P

      data #D-aux (A : Set) (P : Set) : Set where
        #now : A → #D-aux A P
        #later : P → #D-aux A P

  D : Set → Set → Set
  D A X = #D A X

  now : ∀ {A X} → A → D A X
  now a = #p (#now a) _

  later : ∀ {A X} → X → D A X
  later x = #p (#later x) _

  D₁ : ∀ {A P₁ P₂} → (P₁ → P₂) → (D A P₁ → D A P₂)
  D₁ f (#p (#now a) _)   = now a
  D₁ f (#p (#later x) _) = later (f x)

  record P {i : Size} (A : Set) : Set where
    coinductive
    field
      #force : ∀ {j : Size< i} → D A (P {j} A)
  open P

  force : ∀ {A} → P A → D A (P A)
  force x = #force x

  P-intro : ∀ {A X : Set} → (X → D A X) → (X → P A)
  P-intro {A} {X} f = P-intro'
    where
      P-intro' : ∀ {i} → X → P {i} A
      #force (P-intro' x) {j} = D₁ (P-intro' {j}) (f x)

  postulate  -- HIT
    weak~ : ∀{A X : Set} → (force* : X → D A X) →
            (x : X) → (later x == force* x)

  -- | Extra module for recursion using sized types.
  -- This is convenient, as we can use the functor D in the definition, which
  -- in turn simplifies proofs.
  module DRec {A B : Set} {P' Y : Set}
    (now* : A → D B Y)
    (later* : P A → D B Y)
    (force* : Y → D B Y)
    (weak~* : (x : P A) → (later* x == force x))
    where
      f : D A P' → D B Y
      f = f-aux phantom where
        f-aux : Phantom weak~* → D A P' → D B Y
        f-aux phantom (#p (#now a) _)   = now* a
        f-aux phantom (#p (#later x) _) = later* x

      postulate      -- HIT
        weak~-β : (x : P') → ap f (weak~ force* x) == weak~* x

{-
  module PElim {A X} {S : D A X → Set}
    (now* : (a : A) → S (now a))
    (later* : (x : X) → S (later x))
    (force*₁ : (x : X) → D A X)
    (force*₂ : (x : X) → S (force*₁ x))
    (weak~* : (x : X) → -- (x_rec : S
              (later* x == (force*₂ x) [ S ↓ (weak~ force*₁ x) ]))
    where
      f : (x : D A X) → S x
      f = f-aux phantom
        where
          f-aux : Phantom weak~* → (x : D A X) → S x
          f-aux phantom (#p (#now a) _)   = now* a
          f-aux phantom (#p (#later x) _) = later* x
-}
--      postulate      -- HIT
--        weak~-β : (x : X) → apd f (weak~ force*₁ x) == weak~* x

{-
      weak~-β₂ : (x : ∞P A) →
                 apd f (weak~ x) == weak~* x (↑D₁ S f x)
                  -- transport (weak~* x) g-is-D₁f (↑D₁ S f x)
      weak~-β₂ = ?
-}

open DRec public renaming (f to D-rec)
{-
open PElim public
  renaming (f to P-elim; g to ∞P-elim; f-homomorphism to P-elim-hom;
           weak~-β to elim-weak~-β)

-}

module Bla where

⊥ : ∀ {A} → P A
⊥ = P-intro later unit

-- | Copairing of morphisms
[_,_] : ∀ {i j k} {A : Type i} {B : Type j} {C : Type k}
  (l : A → C) (r : B → C) → (x : Coprod A B) → C
[ f , g ] x = match x withl f withr g

id-D : ∀ {A} → D A (P A) → D A (P A)
id-D {A} = D-rec now later force (weak~ force)
           --(idf A) (idf (P A)) (λ x → force x) (weak~ (λ x → force x))

D₁-force : ∀ {A P₁ P₂} → (force* : P₁ → D A P₁) → (f : P₁ → P₂) → (x : P₁)
           → later (f x) == D₁ f (force* x)
D₁-force force* f x =
  later (f x)
    =⟨ idp ⟩
  D₁ f (later x)
    =⟨ weak~ force* x |in-ctx (D₁ f) ⟩
  D₁ f (force* x)
    ∎

-- | Direct definition of bind
bind : ∀ {A B} → (A → P B) → (P A → P B)
bind {A} {B} f x = P-intro {X = P A ⊔ P B} [ u , v ] (inl x)
  where
    elim-A : A → D B (P A ⊔ P B)
    elim-A a =
      D-rec now
            (later ∘ inr)
            (D₁ inr ∘ force)
            (D₁-force force inr)
            (force (f a))

    u : P A → D B (P A ⊔ P B)
    u x = D-rec
          elim-A
          (later ∘ inl)
          (later ∘ inl) -- this should be force ...
          (λ _ → idp)
          (force x)

    v : P B → D B (P A ⊔ P B)
    v = D₁ inr ∘ force

{-
-- | Copairing of morphisms
[_,_] : ∀ {i j k} {A : Type i} {B : Type j} {C : Type k}
  (l : A → C) (r : B → C) → (x : Coprod A B) → C
[ f , g ] x = match x withl f withr g

-- | Inverse of [now, later] à la Lambek,
-- given by extending id + D ([now, later]) : A ⊔ D(A ⊔ ∞P A) → A ⊔ ∞P A.
out : ∀ {A} → P A → A ⊔ ∞P A
out {A} = P-rec inl force (λ _ → idp)
    -- (inr ∘ D₁ [ now , later ]) resp-weak~
    where
      resp-weak~ : (x : D (A ⊔ ∞P A)) →
                   (inr ∘ D₁ [ now , later ]) x == force x
      resp-weak~ x =
        (inr ∘ D₁ [ now , later ]) x
          =⟨ {!!} ⟩
        inr (D₁ [ now , later ] x)
          =⟨ {!!} ⟩
        force x
          ∎

⊥' : ∀ {A} → ∞P A

⊥ : ∀ {A} → P A
⊥ = later (D-intro (λ _ → {!!}) unit)

force ⊥' = {!!} -- ⊥

-- | Action of P on morphisms
P₁ : ∀ {A B} → (A → B) → (P A → P B)
P₁ f = P-rec (now ∘ f) later weak~

-- | Unit for the monad
η : ∀ {A} → A → P A
η = now

-- | Monad multiplication
μ : ∀ {A} → P (P A) → P A
μ {A} = P-rec (idf (P A)) later weak~

-- | Direct definition of bind
bind : ∀ {A B} → (A → P B) → (P A → P B)
bind {A} {B} f = P-rec f later weak~

η-natural : ∀ {A B} → (f : A → B) →
            η ∘ f == P₁ f ∘ η
η-natural f = λ=-nondep (λ x → idp)
  where
n    open FunextNonDep

μ-natural : ∀ {A B} → (f : A → B) →
            μ ∘ P₁ (P₁ f) == P₁ f ∘ μ
μ-natural {A} f = λ=-nondep q
  where
    open FunextNonDep

    T : P (P A) → Set
    T x = μ ( P₁ (P₁ f) x) == P₁ f (μ x)

    =-later : (x : ∞P (P A)) → D (T (force x)) → T (later x)
    =-later x p = transport T (! (weak~ x)) (force p)

    r : (x : ∞P (P A)) → (p : D (T (force x))) →
        (=-later x p) == (force p) [ T ↓ (weak~ x) ]
    r x p = trans-↓ T (weak~ x) (force p)

    q : (x : P (P A)) → μ ( P₁ (P₁ f) x) == P₁ f (μ x)
    q = P-elim {S = λ x → μ ( P₁ (P₁ f) x) == P₁ f (μ x)}
        (λ a → idp) =-later r

-- | Termination predicate on P A
data _↓_ {A} (x : P A) : A → Set where
  now↓ : (a : A) → now a == x → x ↓ a
  later↓ : (a : A) → (u : ∞P A) → (later u == x) → (force u) ↓ a → x ↓ a

mutual
  -- | Weak bisimilarity proofs
  data ~proof {A} (x y : P A) : Set where
    terminating : (a : A) → x ↓ a → y ↓ a → ~proof x y
    -- A bit awkward, but otherwise we cannot pattern matching on ~proof
    step : (u v : ∞P A) → (later u == x) → (later v == y) → force u ~ force v →
           ~proof x y

  -- | Weak bisimilarity for P A
  record _~_ {A} (x y : P A) : Set where
    coinductive
    field
      out~ : ~proof x y
open _~_

terminate→=now : ∀{A} → (a : A) → (x : P A) → x ↓ a → now a == x
terminate→=now a x (now↓ .a na=x) = na=x
terminate→=now a x (later↓ .a u lu=x fu↓a) =
  now a
    =⟨ terminate→=now a (force u) fu↓a ⟩
  force u
    =⟨ ! (weak~ u) ⟩
  later u
    =⟨ lu=x ⟩
  x
    ∎

lemma : ∀{A} → (a : A) → (x y : P A) → x ↓ a → y ↓ a → x == y
lemma a x y x↓a y↓a =
  x
    =⟨ ! (terminate→=now a x x↓a) ⟩
  now a
    =⟨ terminate→=now a y y↓a ⟩
  y
    ∎

inr-inj : ∀ {i} {A B : Set i} →
          (x y : B) → Path {i} {A ⊔ B} (inr x) (inr y) → x == y
inr-inj x .x idp = idp

later-inj : ∀ {A} → (u v : ∞P A) → later u == later v → u == v
later-inj u v p = inr-inj u v lem
  where
    lem : inr u == inr v
    lem = transport (λ z → inr u == P-out z) {later u} {later v} p idp

-- | Weak bisimilarity implies equality for P A
~→= : ∀{A} → (x y : P A) → x ~ y → x == y
~→= {A} x y = P-elim {S = λ x' → x' ~ y → x' == y} now-= later-= weak~-= x
  where
    now-= : (a : A) → now a ~ y → now a == y
    now-= a p = lem (out~ p)
      where
        lem : ~proof (now a) y → now a == y
        lem (terminating b (now↓ .b nb=na) y↓b) =
          now a
            =⟨ ! nb=na ⟩
          now b
            =⟨ terminate→=now b y y↓b ⟩
          y
            ∎
        lem (terminating b (later↓ .b u () now_a↓b) y↓b)
        lem (step u v () x₂ x₃)

    later-= : (u : ∞P A) →
              D (force u ~ y → force u == y) → later u ~ y → later u == y
    later-= u p later_u~y = lem (out~ later_u~y)
      where
        lem : ~proof (later u) y → later u == y
        lem (terminating a later_u↓a y↓a) = lemma a (later u) y later_u↓a y↓a
        lem (step u' v later_u'=later_u later_v=y force_u'~force_v) =
          later u
            =⟨ weak~ u ⟩
          force u
            =⟨ force p force_u~y ⟩
          y ∎
          where
            force_u'=force_u : force u' == force u
            force_u'=force_u =
              force u'
                =⟨ later-inj u' u later_u'=later_u |in-ctx force ⟩
              force u
                ∎

            y=force_v : y == force v
            y=force_v =
              y
                =⟨ ! later_v=y ⟩
              later v
                =⟨ weak~ v ⟩
              force v
                ∎

            force_u~y : force u ~ y
            force_u~y = transport
                   (λ z → z ~ y)
                   force_u'=force_u
                   (transport! (λ z → force u' ~ z) y=force_v force_u'~force_v)

    weak~-= : (u : ∞P A) (p : D (force u ~ y → force u == y)) →
              (later-= u p)
                == (force p) [ (λ x' → x' ~ y → x' == y) ↓ (weak~ u) ]
    weak~-= u p = {!!}
-}


{-# OPTIONS --without-K --rewriting #-}

open import HoTT
open import cohomology.Theory

open import cw.CW

module cw.cohomology.ZerothCohomologyGroupOnDiag {i} (OT : OrdinaryTheory i)
  (⊙skel : ⊙Skeleton {i} 0) (ac : ⊙has-cells-with-choice 0 ⊙skel i) where

open OrdinaryTheory OT
open import cw.cohomology.TipAndAugment OT ⊙skel

open import groups.KernelSndImageInl (C2 0) {H = CX₀ 0}
  {K = Lift-group {j = i} Unit-group}
  cst-hom cst-hom (λ _ → idp)
  (C2×CX₀-is-abelian 0)

open import groups.KernelImage
  (cst-hom {G = C2×CX₀ 0} {H = Lift-group {j = i} Unit-group})
  cw-coε (C2×CX₀-is-abelian 0)

C-cw-iso-ker/im : C 0 ⊙⟦ ⊙skel ⟧ ≃ᴳ Ker/Im
C-cw-iso-ker/im =
      Ker-φ-snd-quot-Im-inl
  ∘eᴳ full-subgroup (ker-cst-hom-is-full (CX₀ 0) (Lift-group {j = i} Unit-group)) ⁻¹ᴳ


open import AbstractInterfaces public

module OrdersAndEqualities {{_ : IsProc}} {{_ : IsTime}} {{_ : IsMsg}} {{_ : IsEvent}} where

-- _≡ₑ_ is a decidable equality on events within one process.

data _≡ₑ_ : ∀ {P T T′} → Event P T → Event P T′ → Set where
  refl≡ₑ : ∀ {P T} {a b : Event P T} →
           a ≡ₑ b

_≢ₑ_ : ∀ {P T T′} → Event P T → Event P T′ → Set
a ≢ₑ b = ¬ (a ≡ₑ b)

≡→≡ₑ : ∀ {P T T′} {a : Event P T} {b : Event P T′} →
        T ≡ T′ → a ≡ₑ b
≡→≡ₑ refl = refl≡ₑ

≢→≢ₑ : ∀ {P T T′} {a : Event P T} {b : Event P T′} →
        T ≢ T′ → a ≢ₑ b
≢→≢ₑ T≢T′ refl≡ₑ = refl ↯ T≢T′

_≡ₑ?_ : ∀ {T T′ P} → (a : Event P T) (b : Event P T′) → Dec (a ≡ₑ b)
_≡ₑ?_ {T} {T′} a b with T ≡ₜ? T′
a ≡ₑ? b | yes T≡T′ = yes (≡→≡ₑ T≡T′)
a ≡ₑ? b | no  T≢T′ = no (≢→≢ₑ T≢T′)

-- _≅ₑ_ is a decidable equality on events across all processes.

data _≅ₑ_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → Event Pᵢ Tᵢ → Event Pⱼ Tⱼ → Set where
  refl≅ₑ : ∀ {P T} {a : Event P T} {b : Event P T} →
           a ≅ₑ b

_≇ₑ_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → Event Pᵢ Tᵢ → Event Pⱼ Tⱼ → Set
a ≇ₑ b = ¬ (a ≅ₑ b)

≡ₑ→≅ₑ : ∀ {P T T′} {a : Event P T} {b : Event P T′} →
         a ≡ₑ b → a ≅ₑ b
≡ₑ→≅ₑ refl≡ₑ = refl≅ₑ

≢ₑ→≇ₑ : ∀ {P T T′} {a : Event P T} {b : Event P T′} →
         a ≢ₑ b → a ≇ₑ b
≢ₑ→≇ₑ a≢b refl≅ₑ = refl≡ₑ ↯ a≢b

≢ₚ→≇ₑ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} →
         Pᵢ ≢ Pⱼ → a ≇ₑ b
≢ₚ→≇ₑ P≢P′ refl≅ₑ = refl ↯ P≢P′

≢ₜ→≇ₑ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} →
         Tᵢ ≢ Tⱼ → a ≇ₑ b
≢ₜ→≇ₑ T≢T′ refl≅ₑ = refl ↯ T≢T′

_≅ₑ?_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → (a : Event Pᵢ Tᵢ) (b : Event Pⱼ Tⱼ) → Dec (a ≅ₑ b)
_≅ₑ?_ {Pᵢ} {Pⱼ} a b with Pᵢ ≡ₚ? Pⱼ
a ≅ₑ? b | yes refl  with a ≡ₑ? b
a ≅ₑ? b | yes refl  | yes a≡b = yes (≡ₑ→≅ₑ a≡b)
a ≅ₑ? b | yes refl  | no  a≢b = no (≢ₑ→≇ₑ a≢b)
a ≅ₑ? b | no  Pᵢ≢Pⱼ = no (≢ₚ→≇ₑ Pᵢ≢Pⱼ)

-- _<ₑ_ is a decidable strict total order on events within one process.

_<ₑ_ : ∀ {T T′ P} → Event P T → Event P T′ → Set
_<ₑ_ {T} {T′} a b = T <ₜ T′

_≮ₑ_ : ∀ {P T T′} → Event P T → Event P T′ → Set
a ≮ₑ b = ¬ (a <ₑ b)

trans<ₑ : ∀ {P T T′ T″} {a : Event P T} {b : Event P T′} {c : Event P T″} →
          a <ₑ b → b <ₑ c → a <ₑ c
trans<ₑ = trans<ₜ

tri<ₑ : ∀ {T T′ P} → (a : Event P T) (b : Event P T′) →
        Tri (a <ₑ b) (a ≡ₑ b) (b <ₑ a)
tri<ₑ {T} {T′} a b with tri<ₜ T T′
tri<ₑ a b | τ₍ T<T′ T≢T′ T′≮T = τ₍ T<T′ (≢→≢ₑ T≢T′) T′≮T
tri<ₑ a b | τ₌ T≮T′ T≡T′ T′≮T = τ₌ T≮T′ (≡→≡ₑ T≡T′) T′≮T
tri<ₑ a b | τ₎ T≮T′ T≢T′ T′<T = τ₎ T≮T′ (≢→≢ₑ T≢T′) T′<T

irrefl<ₑ : ∀ {P T} {a : Event P T} → a ≮ₑ a
irrefl<ₑ {a = a} with tri<ₑ a a
irrefl<ₑ | τ₍ a<a a≢a a≮a = a≮a
irrefl<ₑ | τ₌ a≮a a≡a _   = a≮a
irrefl<ₑ | τ₎ a≮a a≢a a<a = a≮a

_<ₑ?_ : ∀ {P T T′} → (a : Event P T) (b : Event P T′) → Dec (a <ₑ b)
a <ₑ? b with tri<ₑ a b
a <ₑ? b | τ₍ a<b a≢b b≮a = yes a<b
a <ₑ? b | τ₌ a≮b a≡b b≮a = no a≮b
a <ₑ? b | τ₎ a≮b a≢b b<a = no a≮b

-- _⊳_ is a strict partial order on events across all processes.

data _⊳_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → Event Pᵢ Tᵢ → Event Pⱼ Tⱼ → Set where
  lift⊳  : ∀ {P T T′} {a : Event P T} {b : Event P T′} →
           a <ₑ b → a ⊳ b

  pass⊳  : ∀ {Cᵢ Cⱼ Pᵢ Pⱼ Tₘ Tⱼ} {{_ : Tₘ ≡ sucₜ Cᵢ}} {{_ : Tⱼ ≡ sucₜ (Tₘ ⊔ₜ Cⱼ)}} →
           {m : Msg Pᵢ Pⱼ Tₘ} {a : Event Pᵢ Tₘ} {b : Event Pⱼ Tⱼ} →
           isSendₑ {Cᵢ} m a → isRecvₑ {Cⱼ} m b → a ⊳ b

  trans⊳ : ∀ {Pᵢ Pⱼ Pₖ Tᵢ Tⱼ Tₖ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} {c : Event Pₖ Tₖ} →
           a ⊳ b → b ⊳ c → a ⊳ c

_⋫_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → Event Pᵢ Tᵢ → Event Pⱼ Tⱼ → Set
a ⋫ b = ¬ (a ⊳ b)

clock⊳ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} →
         a ⊳ b → Tᵢ <ₜ Tⱼ
clock⊳ (lift⊳ Tᵢ<Tⱼ)                           = Tᵢ<Tⱼ
clock⊳ (pass⊳ {Cᵢ} {Cⱼ} {{refl}} {{refl}} _ _) = n<s[n⊔m]ₜ (sucₜ Cᵢ) Cⱼ
clock⊳ (trans⊳ a⊳b b⊳c)                        = trans<ₜ (clock⊳ a⊳b) (clock⊳ b⊳c)

irrefl⊳ : ∀ {P T} {a : Event P T} → a ⋫ a
irrefl⊳ (lift⊳ {a = a} a<a) = a<a ↯ irrefl<ₑ {a = a}
irrefl⊳ (pass⊳ x y)         = (x , y) ↯ absurdₑ
irrefl⊳ (trans⊳ {Tᵢ = Tᵢ} {Tⱼ} a⊳b b⊳a) with tri<ₜ Tᵢ Tⱼ
irrefl⊳ (trans⊳ a⊳b b⊳a) | τ₍ Tᵢ<Tⱼ Tᵢ≢Tⱼ Tⱼ≮Tᵢ = clock⊳ b⊳a ↯ Tⱼ≮Tᵢ
irrefl⊳ (trans⊳ a⊳b b⊳a) | τ₌ Tᵢ≮Tⱼ Tᵢ≡Tⱼ Tⱼ≮Tᵢ = clock⊳ a⊳b ↯ Tᵢ≮Tⱼ
irrefl⊳ (trans⊳ a⊳b b⊳a) | τ₎ Tᵢ≮Tⱼ Tᵢ≢Tⱼ Tⱼ<Tᵢ = clock⊳ a⊳b ↯ Tᵢ≮Tⱼ

asym⊳ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} → a ⊳ b → b ⋫ a
asym⊳ a⊳b b⊳a = irrefl⊳ (trans⊳ a⊳b b⊳a)

-- _⇒_ is a decidable strict total order on events across all processes.

data _⇒_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → Event Pᵢ Tᵢ → Event Pⱼ Tⱼ → Set where
  diff⇒ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} →
           Tᵢ <ₜ Tⱼ → a ⇒ b

  same⇒ : ∀ {Pᵢ Pⱼ T} {a : Event Pᵢ T} {b : Event Pⱼ T} →
           Pᵢ <ₚ Pⱼ → a ⇒ b

_⇏_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → Event Pᵢ Tᵢ → Event Pⱼ Tⱼ → Set
a ⇏ b = ¬ (a ⇒ b)

lift⇒ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} →
         a ⊳ b → a ⇒ b
lift⇒ = diff⇒ ∘ clock⊳

trans⇒ : ∀ {Pᵢ Pⱼ Pₖ Tᵢ Tⱼ Tₖ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} {c : Event Pₖ Tₖ} →
          a ⇒ b → b ⇒ c → a ⇒ c
trans⇒ (diff⇒ Tᵢ<Tⱼ) (diff⇒ Tⱼ<Tₖ) = diff⇒ (trans<ₜ Tᵢ<Tⱼ Tⱼ<Tₖ)
trans⇒ (diff⇒ Tᵢ<Tⱼ) (same⇒ Pⱼ<Pₖ) = diff⇒ Tᵢ<Tⱼ
trans⇒ (same⇒ Pᵢ<Pⱼ) (diff⇒ Tⱼ<Tₖ) = diff⇒ Tⱼ<Tₖ
trans⇒ (same⇒ Pᵢ<Pⱼ) (same⇒ Pⱼ<Pₖ) = same⇒ (trans<ₚ Pᵢ<Pⱼ Pⱼ<Pₖ)

≮→⇏ : ∀ {Pᵢ Pⱼ T} {a : Event Pᵢ T} {b : Event Pⱼ T} →
        Pᵢ ≮ₚ Pⱼ → a ⇏ b
≮→⇏ Pᵢ≮Pⱼ (diff⇒ T<T)   = T<T ↯ irrefl<ₜ
≮→⇏ Pᵢ≮Pⱼ (same⇒ Pᵢ<Pⱼ) = Pᵢ<Pⱼ ↯ Pᵢ≮Pⱼ

≮×≮→⇏ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} →
          Tᵢ ≮ₜ Tⱼ → Pᵢ ≮ₚ Pⱼ → a ⇏ b
≮×≮→⇏ Tᵢ≮Tⱼ Pᵢ≮Pⱼ (diff⇒ Tᵢ<Tⱼ) = Tᵢ<Tⱼ ↯ Tᵢ≮Tⱼ
≮×≮→⇏ Tᵢ≮Tⱼ Pᵢ≮Pⱼ (same⇒ Pᵢ<Pⱼ) = Pᵢ<Pⱼ ↯ Pᵢ≮Pⱼ

≮×≢→⇏ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} {a : Event Pᵢ Tᵢ} {b : Event Pⱼ Tⱼ} →
          Tᵢ ≮ₜ Tⱼ → Tᵢ ≢ Tⱼ → a ⇏ b
≮×≢→⇏ Tᵢ≮Tⱼ Tᵢ≢Tⱼ (diff⇒ Tᵢ<Tⱼ) = Tᵢ<Tⱼ ↯ Tᵢ≮Tⱼ
≮×≢→⇏ Tᵢ≮Tⱼ Tᵢ≢Tⱼ (same⇒ Pᵢ<Pⱼ) = refl ↯ Tᵢ≢Tⱼ

tri⇒₌ : ∀ {Pᵢ Pⱼ T} → (a : Event Pᵢ T) (b : Event Pⱼ T) →
         Tri (a ⇒ b) (a ≅ₑ b) (b ⇒ a)
tri⇒₌ {Pᵢ} {Pⱼ} a b with tri<ₚ Pᵢ Pⱼ
tri⇒₌ a b | τ₍ Pᵢ<Pⱼ Pᵢ≢Pⱼ Pⱼ≮Pᵢ = τ₍ (same⇒ Pᵢ<Pⱼ) (≢ₚ→≇ₑ Pᵢ≢Pⱼ) (≮→⇏ Pⱼ≮Pᵢ)
tri⇒₌ a b | τ₌ Pᵢ≮Pⱼ refl  Pⱼ≮Pᵢ = τ₌ (≮→⇏ Pᵢ≮Pⱼ) refl≅ₑ  (≮→⇏ Pⱼ≮Pᵢ)
tri⇒₌ a b | τ₎ Pᵢ≮Pⱼ Pᵢ≢Pⱼ Pⱼ<Pᵢ = τ₎ (≮→⇏ Pᵢ≮Pⱼ) (≢ₚ→≇ₑ Pᵢ≢Pⱼ) (same⇒ Pⱼ<Pᵢ)

tri⇒ : ∀ {Tᵢ Tⱼ Pᵢ Pⱼ} → (a : Event Pᵢ Tᵢ) (b : Event Pⱼ Tⱼ) →
        Tri (a ⇒ b) (a ≅ₑ b) (b ⇒ a)
tri⇒ {Tᵢ} {Tⱼ} a b with tri<ₜ Tᵢ Tⱼ
tri⇒ a b | τ₍ Tᵢ<Tⱼ Tᵢ≢Tⱼ Tⱼ≮Tᵢ = τ₍ (diff⇒ Tᵢ<Tⱼ) (≢ₜ→≇ₑ Tᵢ≢Tⱼ) (≮×≢→⇏ Tⱼ≮Tᵢ (sym≢ Tᵢ≢Tⱼ))
tri⇒ a b | τ₌ Tᵢ≮Tⱼ refl  Tⱼ≮Tᵢ = tri⇒₌ a b
tri⇒ a b | τ₎ Tᵢ≮Tⱼ Tᵢ≢Tⱼ Tⱼ<Tᵢ = τ₎ (≮×≢→⇏ Tᵢ≮Tⱼ Tᵢ≢Tⱼ) (≢ₜ→≇ₑ Tᵢ≢Tⱼ) (diff⇒ Tⱼ<Tᵢ)

irrefl⇒ : ∀ {P T} {a : Event P T} → a ⇏ a
irrefl⇒ {a = a} with tri⇒ a a
irrefl⇒ | τ₍ a⇒a a≢a a⇏a = a⇏a
irrefl⇒ | τ₌ a⇏a a≢a _    = a⇏a
irrefl⇒ | τ₎ a⇏a a≢a a⇒a = a⇏a

_⇒?_ : ∀ {Pᵢ Pⱼ Tᵢ Tⱼ} → (a : Event Pᵢ Tᵢ) (b : Event Pⱼ Tⱼ) → Dec (a ⇒ b)
a ⇒? b with tri⇒ a b
a ⇒? b | τ₍ a⇒b a≇b b⇏a = yes a⇒b
a ⇒? b | τ₌ a⇏b a≅b b⇏a = no a⇏b
a ⇒? b | τ₎ a⇏b a≇b b⇒a = no a⇏b


data _≡_ {A : Set} (x : A) : A → Set where
  refl : x ≡ x

record R₁ (F : Set → Set) : Set₁ where
  constructor mkR₁
  field
    f₁ : ∀ {A} → A → F A

open R₁ {{...}}

record R₂ (F : Set → Set) : Set₁ where
  constructor mkR₂
  field
    instance
      r₁ : R₁ F

record R₃ (_ : Set) : Set where
  constructor mkR₃

postulate
  instance
    r₃ : R₂ R₃

  A : Set
  a : A

record R₄ : Set where
  constructor c
  field
    f₂ : A

postulate
  F : (r₄ : R₄) → c a ≡ r₄ → Set

G : Set → Set
G _ = F _ (refl {x = f₁ a})


{-# OPTIONS --safe --experimental-lossy-unification #-}
module Cubical.ZCohomology.RingStructure.GradedCommutativity where

open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Function
open import Cubical.Foundations.Transport
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Pointed
open import Cubical.Foundations.Pointed.Homogeneous
open import Cubical.Foundations.GroupoidLaws hiding (assoc)
open import Cubical.Foundations.Path

open import Cubical.Data.Empty as ⊥
open import Cubical.Data.Nat
open import Cubical.Data.Int
  renaming (_+_ to _ℤ+_ ; _·_ to _ℤ∙_ ; +Comm to +ℤ-comm ; ·Comm to ∙-comm ; +Assoc to ℤ+-assoc ; -_ to -ℤ_)
  hiding (_+'_ ; +'≡+)
open import Cubical.Data.Sigma
open import Cubical.Data.Sum

open import Cubical.HITs.SetTruncation as ST
open import Cubical.HITs.Truncation as T
open import Cubical.HITs.S1 hiding (_·_)
open import Cubical.HITs.Sn
open import Cubical.HITs.Susp

open import Cubical.Homotopy.Loopspace

open import Cubical.ZCohomology.Base
open import Cubical.ZCohomology.GroupStructure
open import Cubical.ZCohomology.RingStructure.CupProduct
open import Cubical.ZCohomology.RingStructure.RingLaws
open import Cubical.ZCohomology.Properties

private
  variable
    ℓ : Level

open PlusBis

natTranspLem : ∀ {ℓ} {A B : ℕ → Type ℓ} {n m : ℕ} (a : A n)
  (f : (n : ℕ) → (a : A n) → B n) (p : n ≡ m)
  → f m (subst A p a) ≡ subst B p (f n a)
natTranspLem {A = A} {B = B} a f p = sym (substCommSlice A B f p a)

transp0₁ : (n : ℕ) → subst coHomK (+'-comm 1 (suc n)) (0ₖ _) ≡ 0ₖ _
transp0₁ zero = refl
transp0₁ (suc n) = refl

transp0₂ : (n m : ℕ) → subst coHomK (+'-comm (suc (suc n)) (suc m)) (0ₖ _) ≡ 0ₖ _
transp0₂ n zero = refl
transp0₂ n (suc m) = refl

-- Recurring expressions
private
  ΩKn+1→Ω²Kn+2 : {k : ℕ} → typ (Ω (coHomK-ptd k)) → typ ((Ω^ 2) (coHomK-ptd (suc k)))
  ΩKn+1→Ω²Kn+2 x = sym (Kn→ΩKn+10ₖ _) ∙∙ cong (Kn→ΩKn+1 _) x ∙∙ Kn→ΩKn+10ₖ _

  ΩKn+1→Ω²Kn+2' : {k : ℕ} → Kn→ΩKn+1 k (0ₖ k) ≡ Kn→ΩKn+1 k (0ₖ k) → typ ((Ω^ 2) (coHomK-ptd (suc k)))
  ΩKn+1→Ω²Kn+2' p = sym (Kn→ΩKn+10ₖ _) ∙∙ p ∙∙ Kn→ΩKn+10ₖ _

  Kn→Ω²Kn+2 : {k : ℕ} → coHomK k → typ ((Ω^ 2) (coHomK-ptd (2 + k)))
  Kn→Ω²Kn+2 x = ΩKn+1→Ω²Kn+2 (Kn→ΩKn+1 _ x)

-- Definition of of -ₖ'ⁿ̇*ᵐ
-- This definition is introduced to facilite the proofs
-ₖ'-helper : {k : ℕ} (n m : ℕ)
  → isEvenT n ⊎ isOddT n → isEvenT m ⊎ isOddT m
  → coHomKType k → coHomKType k
-ₖ'-helper {k = zero} n m (inl x₁) q x = x
-ₖ'-helper {k = zero} n m (inr x₁) (inl x₂) x = x
-ₖ'-helper {k = zero} n m (inr x₁) (inr x₂) x = 0 - x
-ₖ'-helper {k = suc zero} n m p q base = base
-ₖ'-helper {k = suc zero} n m (inl x) q (loop i) = loop i
-ₖ'-helper {k = suc zero} n m (inr x) (inl x₁) (loop i) = loop i
-ₖ'-helper {k = suc zero} n m (inr x) (inr x₁) (loop i) = loop (~ i)
-ₖ'-helper {k = suc (suc k)} n m p q north = north
-ₖ'-helper {k = suc (suc k)} n m p q south = north
-ₖ'-helper {k = suc (suc k)} n m (inl x) q (merid a i) =
  (merid a ∙ sym (merid (ptSn (suc k)))) i
-ₖ'-helper {k = suc (suc k)} n m (inr x) (inl x₁) (merid a i) =
  (merid a ∙ sym (merid (ptSn (suc k)))) i
-ₖ'-helper {k = suc (suc k)} n m (inr x) (inr x₁) (merid a i) =
  (merid a ∙ sym (merid (ptSn (suc k)))) (~ i)

-ₖ'-gen : {k : ℕ} (n m : ℕ)
         (p : isEvenT n ⊎ isOddT n)
         (q : isEvenT m ⊎ isOddT m)
       → coHomK k → coHomK k
-ₖ'-gen {k = zero} = -ₖ'-helper {k = zero}
-ₖ'-gen {k = suc k} n m p q = T.map (-ₖ'-helper {k = suc k} n m p q)

-- -ₖ'ⁿ̇*ᵐ
-ₖ'^_·_ : {k : ℕ} (n m : ℕ) → coHomK k → coHomK k
-ₖ'^_·_ {k = k} n m = -ₖ'-gen n m (evenOrOdd n) (evenOrOdd m)

-- cohomology version
-ₕ'^_·_ : {k : ℕ} {A : Type ℓ} (n m : ℕ) → coHom k A → coHom k A
-ₕ'^_·_ n m = ST.map λ f x → (-ₖ'^ n · m) (f x)

-- -ₖ'ⁿ̇*ᵐ = -ₖ' for n m odd
-ₖ'-gen-inr≡-ₖ' : {k : ℕ} (n m : ℕ) (p : _) (q : _) (x : coHomK k)
  → -ₖ'-gen n m (inr p) (inr q) x ≡ (-ₖ x)
-ₖ'-gen-inr≡-ₖ' {k = zero} n m p q _ = refl
-ₖ'-gen-inr≡-ₖ' {k = suc zero} n m p q =
  T.elim ((λ _ → isOfHLevelTruncPath))
         λ { base → refl
          ; (loop i) → refl}
-ₖ'-gen-inr≡-ₖ' {k = suc (suc k)} n m p q =
  T.elim ((λ _ → isOfHLevelTruncPath))
         λ { north → refl
           ; south → refl
           ; (merid a i) k → ∣ symDistr (merid (ptSn _)) (sym (merid a)) (~ k) (~ i) ∣ₕ}

-- -ₖ'ⁿ̇*ᵐ x = x for n even
-ₖ'-gen-inl-left : {k : ℕ} (n m : ℕ) (p : _) (q : _) (x : coHomK k)
  → -ₖ'-gen n m (inl p) q x ≡ x
-ₖ'-gen-inl-left {k = zero} n m p q x = refl
-ₖ'-gen-inl-left {k = suc zero} n m p q =
  T.elim (λ _ → isOfHLevelTruncPath)
         λ { base → refl ; (loop i) → refl}
-ₖ'-gen-inl-left {k = suc (suc k)} n m p q =
  T.elim (λ _ → isOfHLevelPath (4 + k) (isOfHLevelTrunc (4 + k)) _ _)
         λ { north → refl
           ; south → cong ∣_∣ₕ (merid (ptSn _))
           ; (merid a i) k → ∣ compPath-filler (merid a) (sym (merid (ptSn _))) (~ k) i ∣ₕ}

-- -ₖ'ⁿ̇*ᵐ x = x for m even
-ₖ'-gen-inl-right : {k : ℕ} (n m : ℕ) (p : _) (q : _) (x : coHomK k)
  → -ₖ'-gen n m p (inl q) x ≡ x
-ₖ'-gen-inl-right {k = zero} n m (inl x₁) q x = refl
-ₖ'-gen-inl-right {k = zero} n m (inr x₁) q x = refl
-ₖ'-gen-inl-right {k = suc zero} n m (inl x₁) q =
  T.elim (λ _ → isOfHLevelTruncPath)
         λ { base → refl ; (loop i) → refl}
-ₖ'-gen-inl-right {k = suc zero} n m (inr x₁) q =
  T.elim (λ _ → isOfHLevelTruncPath)
         λ { base → refl ; (loop i) → refl}
-ₖ'-gen-inl-right {k = suc (suc k)} n m (inl x₁) q =
  T.elim (λ _ → isOfHLevelTruncPath)
         λ { north → refl
           ; south → cong ∣_∣ₕ (merid (ptSn _))
           ; (merid a i) k → ∣ compPath-filler (merid a) (sym (merid (ptSn _))) (~ k) i  ∣ₕ}
-ₖ'-gen-inl-right {k = suc (suc k)} n m (inr x₁) q =
  T.elim (λ _ → isOfHLevelTruncPath)
         λ { north → refl
           ; south → cong ∣_∣ₕ (merid (ptSn _))
           ; (merid a i) k → ∣ compPath-filler (merid a) (sym (merid (ptSn _))) (~ k) i  ∣ₕ}

-ₖ'-gen² : {k : ℕ} (n m : ℕ)
         (p : isEvenT n ⊎ isOddT n)
         (q : isEvenT m ⊎ isOddT m)
         → (x : coHomK k) → -ₖ'-gen n m p q (-ₖ'-gen n m p q x) ≡ x
-ₖ'-gen² {k = zero} n m (inl x₁) q x = refl
-ₖ'-gen² {k = zero} n m (inr x₁) (inl x₂) x = refl
-ₖ'-gen² {k = zero} n m (inr x₁) (inr x₂) x =
     cong (pos 0 -_) (-AntiComm (pos 0) x)
  ∙∙ -AntiComm (pos 0) (-ℤ (x - pos 0))
  ∙∙ h x
  where
  h : (x : _) →  -ℤ (-ℤ (x - pos 0) - pos 0) ≡ x
  h (pos zero) = refl
  h (pos (suc n)) = refl
  h (negsuc n) = refl
-ₖ'-gen² {k = suc k} n m (inl x₁) q x i =
  -ₖ'-gen-inl-left n m x₁ q (-ₖ'-gen-inl-left n m x₁ q x i) i
-ₖ'-gen² {k = suc k} n m (inr x₁) (inl x₂) x i =
  -ₖ'-gen-inl-right n m (inr x₁) x₂ (-ₖ'-gen-inl-right n m (inr x₁) x₂ x i) i
-ₖ'-gen² {k = suc k} n m (inr x₁) (inr x₂) x =
  (λ i → -ₖ'-gen-inr≡-ₖ' n m x₁ x₂ (-ₖ'-gen-inr≡-ₖ' n m x₁ x₂ x i) i) ∙ -ₖ^2 x

-ₖ'-genIso : {k : ℕ} (n m : ℕ)
         (p : isEvenT n ⊎ isOddT n)
         (q : isEvenT m ⊎ isOddT m)
       → Iso (coHomK k) (coHomK k)
Iso.fun (-ₖ'-genIso {k = k} n m p q) = -ₖ'-gen n m p q
Iso.inv (-ₖ'-genIso {k = k} n m p q) = -ₖ'-gen n m p q
Iso.rightInv (-ₖ'-genIso {k = k} n m p q) = -ₖ'-gen² n m p q
Iso.leftInv (-ₖ'-genIso {k = k} n m p q) = -ₖ'-gen² n m p q

-- action of cong on -ₖ'ⁿ̇*ᵐ
cong-ₖ'-gen-inr : {k : ℕ} (n m : ℕ)  (p : _) (q : _) (P : Path (coHomK (2 + k)) (0ₖ _) (0ₖ _))
     → cong (-ₖ'-gen n m (inr p) (inr q)) P ≡ sym P
cong-ₖ'-gen-inr {k = k} n m p q P = code≡sym (0ₖ _) P
  where
  code : (x : coHomK (2 + k)) → 0ₖ _ ≡ x → x ≡ 0ₖ _
  code = T.elim (λ _ → isOfHLevelΠ (4 + k) λ _ → isOfHLevelTruncPath)
                λ { north → cong (-ₖ'-gen n m (inr p) (inr q))
                  ; south P → cong ∣_∣ₕ (sym (merid (ptSn _))) ∙ (cong (-ₖ'-gen n m (inr p) (inr q)) P)
                  ; (merid a i) → t a i}
    where
    t : (a : S₊ (suc k)) → PathP (λ i → 0ₖ (2 + k) ≡ ∣ merid a i ∣ₕ → ∣ merid a i ∣ₕ ≡ 0ₖ (2 + k))
                                  (cong (-ₖ'-gen n m (inr p) (inr q)))
                                  (λ P → cong ∣_∣ₕ (sym (merid (ptSn _))) ∙ (cong (-ₖ'-gen n m (inr p) (inr q)) P))
    t a = toPathP (funExt λ P → cong (transport (λ i → ∣ merid a i ∣ ≡ 0ₖ (suc (suc k))))
                   (cong (cong (-ₖ'-gen n m (inr p) (inr q))) (λ i → (transp (λ j → 0ₖ (suc (suc k)) ≡ ∣ merid a (~ j ∧ ~ i) ∣) i
                         (compPath-filler P (λ j → ∣ merid a (~ j) ∣ₕ) i))))
        ∙∙ cong (transport (λ i → ∣ merid a i ∣ ≡ 0ₖ (suc (suc k)))) (congFunct (-ₖ'-gen n m (inr p) (inr q)) P (sym (cong ∣_∣ₕ (merid a))))
        ∙∙ (λ j → transp (λ i → ∣ merid a (i ∨ j) ∣ ≡ 0ₖ (suc (suc k))) j
                  (compPath-filler' (cong ∣_∣ₕ (sym (merid a)))
                    (cong (-ₖ'-gen n m (inr p) (inr q)) P
                    ∙ cong (-ₖ'-gen n m (inr p) (inr q)) (sym (cong ∣_∣ₕ (merid a)))) j))
        ∙∙ (λ i → sym (cong ∣_∣ₕ (merid a))
                 ∙ isCommΩK (2 + k) (cong (-ₖ'-gen n m (inr p) (inr q)) P)
                                    (cong (-ₖ'-gen n m (inr p) (inr q)) (sym (cong ∣_∣ₕ (merid a)))) i)
        ∙∙ (λ j → (λ i → ∣ merid a (~ i ∨ j) ∣)
                 ∙ (cong ∣_∣ₕ (compPath-filler' (merid a) (sym (merid (ptSn _))) (~ j)) ∙ (λ i → -ₖ'-gen n m (inr p) (inr q) (P i))))
        ∙ sym (lUnit _))

  code≡sym : (x : coHomK (2 + k)) → (p : 0ₖ _ ≡ x) → code x p ≡ sym p
  code≡sym x = J (λ x p → code x p ≡ sym p) refl

cong-cong-ₖ'-gen-inr : {k : ℕ} (n m : ℕ) (p : _) (q : _)
    (P : Square (refl {x = 0ₖ (suc (suc k))}) refl refl refl)
  → cong (cong (-ₖ'-gen n m (inr p) (inr q))) P ≡ sym P
cong-cong-ₖ'-gen-inr n m p q P =
     rUnit _
  ∙∙ (λ k → (λ i → cong-ₖ'-gen-inr n m p q refl (i ∧ k))
          ∙∙ (λ i → cong-ₖ'-gen-inr n m p q (P i) k)
          ∙∙ λ i → cong-ₖ'-gen-inr n m p q refl (~ i ∧ k))
  ∙∙ (λ k → transportRefl refl k
          ∙∙ cong sym P
          ∙∙ transportRefl refl k)
  ∙∙ sym (rUnit (cong sym P))
  ∙∙ sym (sym≡cong-sym P)

Kn→ΩKn+1-ₖ'' : {k : ℕ} (n m : ℕ) (p : _) (q : _) (x : coHomK k)
  → Kn→ΩKn+1 k (-ₖ'-gen n m (inr p) (inr q) x) ≡ sym (Kn→ΩKn+1 k x)
Kn→ΩKn+1-ₖ'' n m p q x = cong (Kn→ΩKn+1 _) (-ₖ'-gen-inr≡-ₖ' n m p q x) ∙ Kn→ΩKn+1-ₖ _ x

transpΩ² : {n m : ℕ} (p q : n ≡ m) → (P : _)
        → transport (λ i → refl {x = 0ₖ (p i)} ≡ refl {x = 0ₖ (p i)}) P
        ≡ transport (λ i → refl {x = 0ₖ (q i)} ≡ refl {x = 0ₖ (q i)}) P
transpΩ² p q P k = subst (λ n → refl {x = 0ₖ n} ≡ refl {x = 0ₖ n}) (isSetℕ _ _ p q k) P

-- Some technical lemmas about Kn→Ω²Kn+2 and its interaction with -ₖ'ⁿ̇*ᵐ and transports
-- TODO : Check if this can be cleaned up more by having more general lemmas
private
  lem₁ : (n : ℕ) (a : _)
    → (cong (cong (subst coHomK (+'-comm (suc zero) (suc (suc n)))))
          (Kn→Ω²Kn+2 ∣ a ∣ₕ))
     ≡ ΩKn+1→Ω²Kn+2
       (sym (transp0₁ n) ∙∙ cong (subst coHomK (+'-comm (suc zero) (suc n))) (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ) ∙∙ transp0₁ n)
  lem₁ zero a =
       (λ k i j → transportRefl (Kn→Ω²Kn+2 ∣ a ∣ₕ i j) k)
     ∙ cong ΩKn+1→Ω²Kn+2 λ k → rUnit (λ i → transportRefl (Kn→ΩKn+1 1 ∣ a ∣ i) (~ k)) k
  lem₁ (suc n) a =
       (λ k → transp (λ i → refl {x = 0ₖ (+'-comm 1 (suc (suc (suc n))) (i ∨ ~ k))}
                            ≡ refl {x = 0ₖ (+'-comm 1 (suc (suc (suc n))) (i ∨ ~ k))}) (~ k)
                (λ i j → transp (λ i → coHomK (+'-comm 1 (suc (suc (suc n))) (i ∧ ~ k))) k
                (Kn→Ω²Kn+2 ∣ a ∣ₕ i j)))
    ∙∙ transpΩ² (+'-comm 1 (suc (suc (suc n))))
                (cong suc (+'-comm (suc zero) (suc (suc n))))
                (Kn→Ω²Kn+2 ∣ a ∣ₕ)
    ∙∙ sym (natTranspLem {A = λ n → 0ₖ n ≡ 0ₖ n}
             (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣)
              (λ _ → ΩKn+1→Ω²Kn+2)
              (+'-comm 1 (suc (suc n))))
    ∙∙ cong ΩKn+1→Ω²Kn+2
         (λ k → transp (λ i → 0ₖ (+'-comm (suc zero) (suc (suc n)) (i ∨ k))
                              ≡ 0ₖ (+'-comm (suc zero) (suc (suc n)) (i ∨ k))) k
          (λ i → transp (λ i → coHomK (+'-comm (suc zero) (suc (suc n)) (i ∧ k))) (~ k)
           (Kn→ΩKn+1 _ ∣ a ∣ₕ i)))
    ∙∙ cong ΩKn+1→Ω²Kn+2 (rUnit (cong (subst coHomK (+'-comm (suc zero) (suc (suc n))))
                                   (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣ₕ)))

  lem₂ : (n : ℕ) (a : _) (p : _) (q : _)
    → (cong (cong (-ₖ'-gen (suc (suc n)) (suc zero) p q
                  ∘ (subst coHomK (+'-comm 1 (suc (suc n))))))
             (Kn→Ω²Kn+2 (∣ a ∣ₕ)))
     ≡ ΩKn+1→Ω²Kn+2
         (sym (transp0₁ n)
       ∙∙ cong (subst coHomK (+'-comm (suc zero) (suc n)))
                (cong (-ₖ'-gen (suc (suc n)) (suc zero) p q)
                 (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ))
       ∙∙ transp0₁ n)
  lem₂ n a (inl x) (inr y) =
       (λ k i j → (-ₖ'-gen-inl-left (suc (suc n)) 1 x (inr y) (
                    subst coHomK (+'-comm 1 (suc (suc n)))
                  (Kn→Ω²Kn+2 ∣ a ∣ₕ i j))) k)
    ∙∙ lem₁ n a
    ∙∙ cong ΩKn+1→Ω²Kn+2 (cong (sym (transp0₁ n) ∙∙_∙∙ transp0₁ n)
      λ k i → subst coHomK (+'-comm 1 (suc n))
              (-ₖ'-gen-inl-left (suc (suc n)) 1 x (inr y) (Kn→ΩKn+1 (suc n) ∣ a ∣ i) (~ k)))
  lem₂ n a (inr x) (inr y) =
       cong-cong-ₖ'-gen-inr (suc (suc n)) 1 x y
         (cong
        (cong
         (subst coHomK (+'-comm 1 (suc (suc n)))))
        (Kn→Ω²Kn+2 ∣ a ∣ₕ))
    ∙∙ cong sym (lem₁ n a)
    ∙∙ λ k → ΩKn+1→Ω²Kn+2
                (sym (transp0₁ n) ∙∙
                 cong (subst coHomK (+'-comm 1 (suc n)))
                 (cong-ₖ'-gen-inr (suc (suc n)) 1 x y
                  (Kn→ΩKn+1 (suc n) ∣ a ∣) (~ k))
                 ∙∙ transp0₁ n)

  lem₃ : (n m : ℕ) (q : _) (p : isEvenT (suc (suc n)) ⊎ isOddT (suc (suc n))) (x : _)
    → (((sym (cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n))
                                 ∙∙ (λ j → -ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                                (subst coHomK (+'-comm (suc (suc m)) (suc n)) (Kn→ΩKn+1 _ x j)))
                    ∙∙ cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n))))
     ≡ (Kn→ΩKn+1 _ (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                      (subst coHomK (cong suc (+-comm (suc m) n)) x)))
  lem₃ n m q p x =
    sym (cong-∙∙ (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (sym (transp0₂ m n))
        (λ j → subst coHomK (+'-comm (suc (suc m)) (suc n)) (Kn→ΩKn+1 _ x j))
        (transp0₂ m n))
          ∙ h n m p q x
    where
    help : (n m : ℕ) (x : _)
      → ((sym (transp0₂ m n))
         ∙∙ (λ j → subst coHomK (+'-comm (suc (suc m)) (suc n))
                     (Kn→ΩKn+1 (suc (suc (m + n))) x j))
         ∙∙ transp0₂ m n)
         ≡ Kn→ΩKn+1 (suc (n + suc m))
                  (subst coHomK (cong suc (+-comm (suc m) n)) x)
    help zero m x =
         sym (rUnit _)
      ∙∙ (λ k i → transp (λ i → coHomK (+'-comm (suc (suc m)) 1 (i ∨ k))) k
            (Kn→ΩKn+1 _
              (transp (λ i → coHomK (predℕ (+'-comm (suc (suc m)) 1 (i ∧ k)))) (~ k) x) i))
      ∙∙ cong (Kn→ΩKn+1 _)
           λ k → subst coHomK (isSetℕ _ _ (cong predℕ (+'-comm (suc (suc m)) 1))
                   (cong suc (+-comm (suc m) zero)) k) x
    help (suc n) m x =
      sym (rUnit _)
      ∙∙ ((λ k i → transp (λ i → coHomK (+'-comm (suc (suc m)) (suc (suc n)) (i ∨ k))) k
            (Kn→ΩKn+1 _
             (transp (λ i → coHomK (predℕ (+'-comm (suc (suc m)) (suc (suc n)) (i ∧ k)))) (~ k) x) i)))
      ∙∙ cong (Kn→ΩKn+1 _)
          (λ k → subst coHomK (isSetℕ _ _ (cong predℕ (+'-comm (suc (suc m)) (suc (suc n))))
                                            (cong suc (+-comm (suc m) (suc n))) k) x)

    h : (n m : ℕ) (p : isEvenT (suc (suc n)) ⊎ isOddT (suc (suc n))) (q : _) (x : _)
      →  cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q)
           (sym (transp0₂ m n)
            ∙∙ (λ j → subst coHomK (+'-comm (suc (suc m)) (suc n))
                       (Kn→ΩKn+1 (suc (suc (m + n))) x j))
            ∙∙ transp0₂ m n)
        ≡  Kn→ΩKn+1 (suc (n + suc m))
            (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
             (subst coHomK (cong suc (+-comm (suc m) n)) x))
    h n m (inl p) (inl q) x =
         (λ k → cong (-ₖ'-gen (suc n) (suc (suc m))
                  (isPropEvenOrOdd (suc n) (evenOrOdd (suc n)) (inr p) k) (inl q))
                    (help n m x k))
      ∙∙ ((λ k i → -ₖ'-gen-inl-right (suc n) (suc (suc m)) (inr p) q (help n m x i1 i) k))
      ∙∙ λ i → Kn→ΩKn+1 (suc (n + suc m))
                 (-ₖ'-gen-inl-right (suc n) (suc (suc m)) (isPropEvenOrOdd (suc n) (inr p) (evenOrOdd (suc n)) i) q
                  (subst coHomK (cong suc (+-comm (suc m) n)) x) (~ i))
    h n m (inl p) (inr q) x =
       (λ k → cong (-ₖ'-gen (suc n) (suc (suc m)) (isPropEvenOrOdd (suc n) (evenOrOdd (suc n)) (inr p) k) (inr q))
           (help n m x k))
     ∙∙ cong-ₖ'-gen-inr (suc n) (suc (suc m)) p q (help n m x i1)
     ∙∙ sym (Kn→ΩKn+1-ₖ'' (suc n) (suc (suc m)) p q
          (subst coHomK (λ i → suc (+-comm (suc m) n i)) x))
      ∙ λ k → Kn→ΩKn+1 (suc (n + suc m))
        (-ₖ'-gen (suc n) (suc (suc m)) (isPropEvenOrOdd (suc n) (inr p) (evenOrOdd (suc n)) k) (inr q)
         (subst coHomK (cong suc (+-comm (suc m) n)) x))
    h n m (inr p) (inl q) x =
         (λ k → cong (-ₖ'-gen (suc n) (suc (suc m)) (isPropEvenOrOdd (suc n) (evenOrOdd (suc n)) (inl p) k) (inl q))
                   (help n m x k))
      ∙∙ (λ k i → -ₖ'-gen-inl-left (suc n) (suc (suc m)) p (inl q) (help n m x i1 i) k)
      ∙∙ λ k → Kn→ΩKn+1 (suc (n + suc m))
                 (-ₖ'-gen-inl-right (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                  (subst coHomK (cong suc (+-comm (suc m) n)) x) (~ k))
    h n m (inr p) (inr q) x =
         (λ k → cong (-ₖ'-gen (suc n) (suc (suc m)) (isPropEvenOrOdd (suc n) (evenOrOdd (suc n)) (inl p) k) (inr q))
                    (help n m x k))
      ∙∙ (λ k i → -ₖ'-gen-inl-left (suc n) (suc (suc m)) p (inr q) (help n m x i1 i) k)
      ∙∙ cong (Kn→ΩKn+1 (suc (n + suc m)))
           (sym (-ₖ'-gen-inl-left (suc n) (suc (suc m)) p (inr q)
             (subst coHomK (λ i → suc (+-comm (suc m) n i)) x)))
       ∙ λ k → Kn→ΩKn+1 (suc (n + suc m))
        (-ₖ'-gen (suc n) (suc (suc m)) (isPropEvenOrOdd (suc n) (inl p) (evenOrOdd (suc n)) k) (inr q)
         (subst coHomK (cong suc (+-comm (suc m) n)) x))

  lem₄ : (n m : ℕ) (q : _) (p : isEvenT (suc (suc n)) ⊎ isOddT (suc (suc n))) (a : _) (b : _)
          → cong (Kn→ΩKn+1 _) (((sym (cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n))
                                 ∙∙ (λ j → -ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                                (subst coHomK (+'-comm (suc (suc m)) (suc n))
                                  (_⌣ₖ_ {n = suc (suc m)} {m = (suc n)} ∣ merid b j ∣ₕ ∣ a ∣)))
                    ∙∙ cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n))))
           ≡ cong (Kn→ΩKn+1 _) (Kn→ΩKn+1 _ (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                                               (subst coHomK (cong suc (+-comm (suc m) n))
                                               (_⌣ₖ_ {n = suc m} {m = (suc n)} ∣ b ∣ₕ ∣ a ∣))))
  lem₄ n m q p a b = cong (cong (Kn→ΩKn+1 _)) (lem₃ n m q p (_⌣ₖ_ {n = suc m} {m = (suc n)} ∣ b ∣ₕ ∣ a ∣))

  lem₅ : (n m : ℕ) (p : _) (q : _) (a : _) (b : _)
    → cong (cong (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                   ∘ (subst coHomK (+'-comm (suc (suc m)) (suc (suc n))))))
         (ΩKn+1→Ω²Kn+2 (sym (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (transp0₂ n m))
                     ∙∙ (λ i → -ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                                   (subst coHomK (+'-comm (suc (suc n)) (suc m))
                                     (_⌣ₖ_ {n = suc (suc n)} {m = suc m} ∣ merid a i ∣ₕ ∣ b ∣ₕ)))
                     ∙∙ cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (transp0₂ n m)))
        ≡ Kn→Ω²Kn+2 (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                       (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                         (subst coHomK (cong suc (sym (+-suc n m))) (_⌣ₖ_ {n = suc n} {m = suc m} ∣ a ∣ₕ ∣ b ∣ₕ))))
  lem₅ n m p q a b =
       cong (cong (cong (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                        ∘ (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))))))
            (cong (sym (Kn→ΩKn+10ₖ _) ∙∙_∙∙ Kn→ΩKn+10ₖ _)
              (lem₄ m n p q b a))
     ∙ help p q (_⌣ₖ_ {n = suc n} {m = suc m} ∣ a ∣ ∣ b ∣)
    where
    annoying : (x : _)
      → cong (cong (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))))
          (Kn→Ω²Kn+2 (subst coHomK (cong suc (+-comm (suc n) m)) x))
         ≡ Kn→Ω²Kn+2 (subst coHomK (cong suc (sym (+-suc n m))) x)
    annoying x =
        ((λ k → transp (λ i → refl {x = 0ₖ ((+'-comm (suc (suc m)) (suc (suc n))) (i ∨  ~ k))}
                              ≡ refl {x = 0ₖ ((+'-comm (suc (suc m)) (suc (suc n))) (i ∨ ~ k))}) (~ k)

                  λ i j → transp (λ i → coHomK (+'-comm (suc (suc m)) (suc (suc n)) (i ∧ ~ k))) k
                    (Kn→Ω²Kn+2 (subst coHomK (cong suc (+-comm (suc n) m)) x) i j)))
      ∙∙ cong (transport (λ i → refl {x = 0ₖ ((+'-comm (suc (suc m)) (suc (suc n))) i)}
                              ≡ refl {x = 0ₖ ((+'-comm (suc (suc m)) (suc (suc n))) i)}))
              (natTranspLem {A = coHomK} x (λ _ → Kn→Ω²Kn+2) (cong suc (+-comm (suc n) m)))
      ∙∙ sym (substComposite (λ n → refl {x = 0ₖ n} ≡ refl {x = 0ₖ n})
             (cong (suc ∘ suc ∘ suc) (+-comm (suc n) m)) (+'-comm (suc (suc m)) (suc (suc n)))
             (Kn→Ω²Kn+2 x))
      ∙∙ (λ k → subst (λ n → refl {x = 0ₖ n} ≡ refl {x = 0ₖ n})
                       (isSetℕ _ _
                         (cong (suc ∘ suc ∘ suc) (+-comm (suc n) m) ∙ (+'-comm (suc (suc m)) (suc (suc n))))
                         (cong (suc ∘ suc ∘ suc) (sym (+-suc n m))) k)
                 (Kn→Ω²Kn+2 x))
      ∙∙ sym (natTranspLem {A = coHomK} x (λ _ → Kn→Ω²Kn+2) (cong suc (sym (+-suc n m))))

    help : (p : _) (q : _) (x : _) →
      cong (cong (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                ∘ subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))))
           (Kn→Ω²Kn+2 (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                (subst coHomK (cong suc (+-comm (suc n) m)) x)))
        ≡ Kn→Ω²Kn+2
             (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
              (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
               (subst coHomK (cong suc (sym (+-suc n m))) x)))
    help (inl x) (inl y) z =
         (λ k i j →
           -ₖ'-gen-inl-right (suc (suc n)) (suc (suc m)) (inl x) y
             (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
               ((ΩKn+1→Ω²Kn+2
                 (Kn→ΩKn+1 _ (-ₖ'-gen-inl-right (suc m) (suc (suc n)) (evenOrOdd (suc m)) x
                  (subst coHomK (cong suc (+-comm (suc n) m)) z) k))) i j)) k)
      ∙∙ annoying z
      ∙∙ cong Kn→Ω²Kn+2
          λ k → (-ₖ'-gen-inl-right (suc (suc n)) (suc (suc m)) (inl x) y
                   (-ₖ'-gen-inl-right (suc m) (suc (suc n)) (evenOrOdd (suc m)) x
                    (subst coHomK (cong suc (sym (+-suc n m))) z) (~ k)) (~ k))
    help (inl x) (inr y) z =
         (λ k i j →
           -ₖ'-gen-inl-left (suc (suc n)) (suc (suc m)) x (inr y)
            (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
              (Kn→Ω²Kn+2 (-ₖ'-gen-inl-right (suc m) (suc (suc n)) (evenOrOdd (suc m)) x
                           (subst coHomK (cong suc (+-comm (suc n) m)) z) k) i j)) k)
      ∙∙ annoying z
      ∙∙ cong Kn→Ω²Kn+2
               (λ k → (-ₖ'-gen-inl-left (suc (suc n)) (suc (suc m)) x (inr y)
                 (-ₖ'-gen-inl-right (suc m) (suc (suc n)) (evenOrOdd (suc m)) x
                  (subst coHomK (cong suc (sym (+-suc n m))) z) (~ k)) (~ k)))
    help (inr x) (inl y) z =
         (λ k i j → -ₖ'-gen-inl-right (suc (suc n)) (suc (suc m)) (inr x) y
                      (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
                        (Kn→Ω²Kn+2
                          (-ₖ'-gen (suc m) (suc (suc n)) (isPropEvenOrOdd (suc m) (evenOrOdd (suc m)) (inr y) k) (inr x)
                             (subst coHomK (cong suc (+-comm (suc n) m)) z)) i j)) k)
      ∙∙ cong (cong (cong (subst coHomK (+'-comm (suc (suc m)) (suc (suc n))))) ∘  ΩKn+1→Ω²Kn+2)
            (Kn→ΩKn+1-ₖ'' (suc m) (suc (suc n)) y x
                     (subst coHomK (cong suc (+-comm (suc n) m)) z))
      ∙∙ cong sym (annoying z)
      ∙∙ cong ΩKn+1→Ω²Kn+2 (sym (Kn→ΩKn+1-ₖ'' (suc m) (suc (suc n)) y x
                             (subst coHomK (cong suc (sym (+-suc n m))) z)))
      ∙∙ cong Kn→Ω²Kn+2 λ k → (-ₖ'-gen-inl-right (suc (suc n)) (suc (suc m)) (inr x) y
                                  (-ₖ'-gen (suc m) (suc (suc n)) (isPropEvenOrOdd (suc m) (evenOrOdd (suc m)) (inr y) (~ k)) (inr x)
                                   (subst coHomK (cong suc (sym (+-suc n m))) z)) (~ k))
    help (inr x) (inr y) z =
         (λ k → cong-cong-ₖ'-gen-inr (suc (suc n)) (suc (suc m)) x y
                  (λ i j → subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
                     (Kn→Ω²Kn+2
                       (-ₖ'-gen (suc m) (suc (suc n))
                         (isPropEvenOrOdd (suc m) (evenOrOdd (suc m)) (inl y) k) (inr x)
                          (subst coHomK (cong suc (+-comm (suc n) m)) z)) i j)) k)
      ∙∙ cong (sym ∘ cong (cong (subst coHomK (+'-comm (suc (suc m)) (suc (suc n))))) ∘  Kn→Ω²Kn+2)
               (-ₖ'-gen-inl-left (suc m) (suc (suc n)) y (inr x)
                (subst coHomK (cong suc (+-comm (suc n) m)) z))
      ∙∙ cong sym (annoying z)
      ∙∙ cong (sym ∘ Kn→Ω²Kn+2)
                (sym (-ₖ'-gen-inl-left (suc m) (suc (suc n)) y (inr x)
                      (subst coHomK (cong suc (sym (+-suc n m))) z)))
      ∙∙ cong ΩKn+1→Ω²Kn+2
              λ k → (Kn→ΩKn+1-ₖ'' (suc (suc n)) (suc (suc m)) x y
                      (-ₖ'-gen (suc m) (suc (suc n)) (
                         isPropEvenOrOdd (suc m) (evenOrOdd (suc m)) (inl y) (~ k)) (inr x)
                       (subst coHomK (cong suc (sym (+-suc n m))) z))) (~ k)

  lem₆ : (n m : ℕ) (p : _) (q : _) (a : _) (b : _)
    → flipSquare
        (Kn→Ω²Kn+2 (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                     (subst coHomK (cong suc (+-comm (suc m) n))
                     (_⌣ₖ_ {n = suc m} {m = (suc n)} ∣ b ∣ₕ ∣ a ∣))))
       ≡ Kn→Ω²Kn+2
         (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
           (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
             (subst coHomK (cong suc (sym (+-suc n m)))
               (-ₖ'-gen (suc n) (suc m) (evenOrOdd (suc n)) (evenOrOdd (suc m))
                 (subst coHomK (+'-comm (suc m) (suc n)) (∣ b ∣ₕ ⌣ₖ ∣ a ∣ₕ))))))
  lem₆ n m p q a b =
      sym (sym≡flipSquare (Kn→Ω²Kn+2 (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                     (subst coHomK (cong suc (+-comm (suc m) n))
                     (_⌣ₖ_ {n = suc m} {m = (suc n)} ∣ b ∣ₕ ∣ a ∣)))))
     ∙ cong ΩKn+1→Ω²Kn+2
           (help₁
             (subst coHomK (cong suc (+-comm (suc m) n))
               (_⌣ₖ_ {n = suc m} {m = (suc n)} ∣ b ∣ ∣ a ∣)) p q
          ∙ cong (Kn→ΩKn+1 _) (sym (help₂ (∣ b ∣ ⌣ₖ ∣ a ∣))))
    where
    help₁ : (x : _) (p : _) (q : _)
      → sym (Kn→ΩKn+1 (suc (n + suc m)) (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q x))
       ≡ Kn→ΩKn+1 (suc (n + suc m)) ((-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
          (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
           (-ₖ'-gen (suc n) (suc m) (evenOrOdd (suc n)) (evenOrOdd (suc m)) x))))
    help₁ z (inl x) (inl y) =
         cong (λ x → sym (Kn→ΩKn+1 (suc (n + suc m)) x))
           (-ₖ'-gen-inl-right (suc n) (suc (suc m)) (evenOrOdd (suc n)) y z)
      ∙∙ sym (Kn→ΩKn+1-ₖ'' (suc n) (suc m) x y z)
      ∙∙ λ k → Kn→ΩKn+1 (suc (n + suc m))
        (-ₖ'-gen-inl-right (suc (suc n)) (suc (suc m)) (inl x) y
         (-ₖ'-gen-inl-right (suc m) (suc (suc n)) (evenOrOdd (suc m)) x
          (-ₖ'-gen (suc n) (suc m)
            (isPropEvenOrOdd (suc n) (inr x) (evenOrOdd (suc n)) k)
            (isPropEvenOrOdd (suc m) (inr y) (evenOrOdd (suc m)) k) z) (~ k)) (~ k))
    help₁ z (inl x) (inr y) =
         (λ k → sym (Kn→ΩKn+1 (suc (n + suc m))
                      (-ₖ'-gen (suc n) (suc (suc m))
                        (isPropEvenOrOdd (suc n) (evenOrOdd (suc n)) (inr x) k) (inr y) z)))
      ∙∙ cong sym (Kn→ΩKn+1-ₖ'' (suc n) (suc (suc m)) x y z)
      ∙∙ cong (Kn→ΩKn+1 (suc (n + suc m))) (sym (-ₖ'-gen-inl-right (suc n) (suc m) (inr x) y z))
       ∙ λ k → Kn→ΩKn+1 (suc (n + suc m))
        (-ₖ'-gen-inl-left (suc (suc n)) (suc (suc m)) x (inr y)
         (-ₖ'-gen-inl-right (suc m) (suc (suc n)) (evenOrOdd (suc m)) x
          (-ₖ'-gen (suc n) (suc m)
            (isPropEvenOrOdd (suc n) (inr x) (evenOrOdd (suc n)) k)
            (isPropEvenOrOdd (suc m) (inl y) (evenOrOdd (suc m)) k) z) (~ k)) (~ k))
    help₁ z (inr x) (inl y) =
         cong (λ x → sym (Kn→ΩKn+1 (suc (n + suc m)) x))
           (-ₖ'-gen-inl-right (suc n) (suc (suc m)) (evenOrOdd (suc n)) y z)
      ∙∙ (λ k → Kn→ΩKn+1-ₖ'' (suc m) (suc (suc n)) y x
                  (-ₖ'-gen-inl-left (suc n) (suc m) x (inr y) z (~ k)) (~ k))
      ∙∙ λ k → Kn→ΩKn+1 (suc (n + suc m))
                 (-ₖ'-gen-inl-right (suc (suc n)) (suc (suc m)) (inr x) y
                  (-ₖ'-gen (suc m) (suc (suc n))
                    (isPropEvenOrOdd (suc m) (inr y) (evenOrOdd (suc m)) k) (inr x)
                   (-ₖ'-gen (suc n) (suc m)
                     (isPropEvenOrOdd (suc n) (inl x) (evenOrOdd (suc n)) k)
                     (isPropEvenOrOdd (suc m) (inr y) (evenOrOdd (suc m)) k) z)) (~ k))
    help₁ z (inr x) (inr y) =
         ((λ k → sym (Kn→ΩKn+1 (suc (n + suc m))
                      (-ₖ'-gen (suc n) (suc (suc m))
                        (isPropEvenOrOdd (suc n) (evenOrOdd (suc n)) (inl x) k) (inr y) z))))
      ∙∙ cong sym (cong (Kn→ΩKn+1 (suc (n + suc m))) (-ₖ'-gen-inl-left (suc n) (suc (suc m)) x (inr y) z))
      ∙∙ (λ k → sym (Kn→ΩKn+1 (suc (n + suc m))
                     (-ₖ'-gen-inl-left (suc m) (suc (suc n)) y (inr x)
                       (-ₖ'-gen-inl-right (suc n) (suc m) (inl x) y z (~ k)) (~ k))))
       ∙ λ k → Kn→ΩKn+1-ₖ'' (suc (suc n)) (suc (suc m)) x y
                  (-ₖ'-gen (suc m) (suc (suc n)) (isPropEvenOrOdd (suc m) (inl y) (evenOrOdd (suc m)) k) (inr x)
                   (-ₖ'-gen (suc n) (suc m)
                     (isPropEvenOrOdd (suc n) (inl x) (evenOrOdd (suc n)) k)
                     (isPropEvenOrOdd (suc m) (inl y) (evenOrOdd (suc m)) k)  z)) (~ k)

    help₂ : (x : _) →
       (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
         (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
           (subst coHomK (cong suc (sym (+-suc n m)))
             (-ₖ'-gen (suc n) (suc m) (evenOrOdd (suc n)) (evenOrOdd (suc m))
               (subst coHomK (+'-comm (suc m) (suc n)) x)))))
     ≡ -ₖ'-gen (suc (suc n)) (suc (suc m)) p q
        (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
          (-ₖ'-gen (suc n) (suc m) (evenOrOdd (suc n)) (evenOrOdd (suc m))
            (subst coHomK (cong suc (+-comm (suc m) n)) x)))
    help₂ x =
         (λ k → -ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                  (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                    (transp (λ i → coHomK ((cong suc (sym (+-suc n m))) (i ∨ k))) k
                     (-ₖ'-gen (suc n) (suc m) (evenOrOdd (suc n)) (evenOrOdd (suc m))
                       (transp (λ i → coHomK ((cong suc (sym (+-suc n m))) (i ∧ k))) (~ k)
                         (subst coHomK (+'-comm (suc m) (suc n)) x))))))
       ∙ cong (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                 ∘ -ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                 ∘ -ₖ'-gen (suc n) (suc m) (evenOrOdd (suc n)) (evenOrOdd (suc m)))
              (sym (substComposite coHomK (+'-comm (suc m) (suc n)) ((cong suc (sym (+-suc n m)))) x)
              ∙ λ k → subst coHomK (isSetℕ _ _ (+'-comm (suc m) (suc n) ∙ cong suc (sym (+-suc n m)))
                        ((cong suc (+-comm (suc m) n))) k) x)

  lem₇ : (n : ℕ) (a : _) (p : _) (q : _)
    → ((λ i → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) (suc zero) (evenOrOdd (suc n)) (inr tt)
                          (transp0₁ n (~ i))))
    ∙∙ (λ i j → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) (suc zero) (evenOrOdd (suc n)) (inr tt)
                              (subst coHomK (+'-comm (suc zero) (suc n)) (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ i))) j)
    ∙∙ (λ i → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) (suc zero) (evenOrOdd (suc n)) (inr tt)
                          (transp0₁ n i))))
       ≡ (cong (Kn→ΩKn+1 (suc (suc (n + zero))))
           (sym (transp0₁ n)
         ∙∙ sym (cong (subst coHomK (+'-comm (suc zero) (suc n)))
                 (cong (-ₖ'-gen (suc (suc n)) (suc zero) p q) (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ)))
         ∙∙ transp0₁ n))
  lem₇ zero a (inl x) (inr tt) =
      (λ k → rUnit ((cong (Kn→ΩKn+1 _) (cong-ₖ'-gen-inr (suc zero) (suc zero) tt tt
                      (λ i → (subst coHomK (+'-comm (suc zero) (suc zero))
                       (Kn→ΩKn+1 (suc zero) ∣ a ∣ₕ i))) k))) (~ k))
    ∙ λ k → ((cong (Kn→ΩKn+1 (suc (suc zero)))
               (rUnit (λ i → subst coHomK (+'-comm (suc zero) (suc zero))
                 (-ₖ'-gen-inl-left (suc (suc zero)) (suc zero) tt (inr tt)
                  (Kn→ΩKn+1 (suc zero) ∣ a ∣ₕ (~ i)) (~ k))) k)))
  lem₇ (suc n) a (inl x) (inr tt) =
      ((λ k → rUnit (cong (Kn→ΩKn+1 _)
        (λ i → -ₖ'-gen (suc (suc n)) (suc zero)
                 (isPropEvenOrOdd n (evenOrOdd (suc (suc n))) (inr x) k) (inr tt)
                   (subst coHomK (+'-comm (suc zero) (suc (suc n)))
                    (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣ₕ i)))) (~ k)))
    ∙∙ (((λ k → ((cong (Kn→ΩKn+1 _) (cong-ₖ'-gen-inr (suc (suc n)) (suc zero) x tt
           (λ i → (subst coHomK (+'-comm (suc zero) (suc (suc n)))
                     (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣ₕ i))) k))))))
    ∙∙ λ k → ((cong (Kn→ΩKn+1 (suc (suc (suc n + zero))))
               (rUnit (λ i → subst coHomK (+'-comm (suc zero) (suc (suc n)))
                 (-ₖ'-gen-inl-left (suc (suc (suc n))) (suc zero) x (inr tt)
                   (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣ₕ (~ i)) (~ k))) k)))
  lem₇ (suc n) a (inr x) (inr tt) =
       (λ k → rUnit (λ i j → Kn→ΩKn+1 _
                  (-ₖ'-gen (suc (suc n)) (suc zero)
                          (isPropEvenOrOdd (suc (suc n)) (evenOrOdd (suc (suc n))) (inl x) k) (inr tt)
                     (subst coHomK (+'-comm (suc zero) (suc (suc n)))
                       (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣ₕ i))) j) (~ k))
    ∙∙ (λ k i j → Kn→ΩKn+1 _ (-ₖ'-gen-inl-left (suc (suc n)) (suc zero) x (inr tt)
                                (subst coHomK (+'-comm (suc zero) (suc (suc n)))
                                  (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣ₕ i)) k) j)
    ∙∙ λ k → cong (Kn→ΩKn+1 _)
              (rUnit (sym (cong (subst coHomK (+'-comm (suc zero) (suc (suc n))))
                (cong-ₖ'-gen-inr (suc (suc (suc n))) (suc zero) x tt (Kn→ΩKn+1 (suc (suc n)) ∣ a ∣ₕ) (~ k)))) k)

-- ∣ a ∣ ⌣ₖ ∣ b ∣ ≡ -ₖ'ⁿ*ᵐ (∣ b ∣ ⌣ₖ ∣ a ∣) for n ≥ 1, m = 1
gradedComm'-elimCase-left : (n : ℕ) (p : _) (q : _) (a : S₊ (suc n)) (b : S¹) →
      (_⌣ₖ_  {n = suc n} {m = (suc zero)} ∣ a ∣ₕ ∣ b ∣ₕ)
    ≡ (-ₖ'-gen (suc n) (suc zero) p q)
       (subst coHomK (+'-comm (suc zero) (suc n))
        (_⌣ₖ_  {n = suc zero} {m = suc n} ∣ b ∣ₕ ∣ a ∣ₕ))
gradedComm'-elimCase-left zero (inr tt) (inr tt) a b =
    proof a b
  ∙ cong (-ₖ'-gen 1 1 (inr tt) (inr tt))
         (sym (transportRefl ((_⌣ₖ_ {n = suc zero} {m = suc zero} ∣ b ∣ ∣ a ∣))))
  where
  help : flipSquare (ΩKn+1→Ω²Kn+2' (λ j i → _⌣ₖ_ {n = suc zero} {m = suc zero} ∣ loop i ∣ₕ ∣ loop j ∣ₕ)) ≡
                    cong (cong (-ₖ'-gen 1 1 (inr tt) (inr tt)))
                      (ΩKn+1→Ω²Kn+2' (λ i j → _⌣ₖ_ {n = suc zero} {m = suc zero} ∣ loop j ∣ₕ ∣ loop i ∣ₕ))
  help = sym (sym≡flipSquare _)
       ∙ sym (cong-cong-ₖ'-gen-inr 1 1 tt tt
              (ΩKn+1→Ω²Kn+2' (λ i j → _⌣ₖ_ {n = suc zero} {m = suc zero} ∣ loop j ∣ ∣ loop i ∣)))

  proof : (a b : S¹) → _⌣ₖ_ {n = suc zero} {m = suc zero} ∣ a ∣ₕ ∣ b ∣ₕ ≡
      -ₖ'-gen 1 1 (inr tt) (inr tt) (_⌣ₖ_ {n = suc zero} {m = suc zero} ∣ b ∣ ∣ a ∣)
  proof base base = refl
  proof base (loop i) k = -ₖ'-gen 1 1 (inr tt) (inr tt) (Kn→ΩKn+10ₖ _ (~ k) i)
  proof (loop i) base k = Kn→ΩKn+10ₖ _ k i
  proof (loop i) (loop j) k =
    hcomp (λ r →  λ { (i = i0) → -ₖ'-gen 1 1 (inr tt) (inr tt) (Kn→ΩKn+10ₖ _ (~ k ∨ ~ r) j)
                     ; (i = i1) → -ₖ'-gen 1 1 (inr tt) (inr tt) (Kn→ΩKn+10ₖ _ (~ k ∨ ~ r) j)
                     ; (j = i0) → Kn→ΩKn+10ₖ _ (k ∨ ~ r) i
                     ; (j = i1) → Kn→ΩKn+10ₖ _ (k ∨ ~ r) i
                     ; (k = i0) → doubleCompPath-filler
                                    (sym (Kn→ΩKn+10ₖ _))
                                    (λ j i → _⌣ₖ_ {n = suc zero} {m = suc zero} ∣ loop i ∣ₕ ∣ loop j ∣ₕ)
                                    (Kn→ΩKn+10ₖ _) (~ r) j i
                     ; (k = i1) → (-ₖ'-gen 1 1 (inr tt) (inr tt)
                                    (doubleCompPath-filler
                                     (sym (Kn→ΩKn+10ₖ _))
                                     (λ i j → _⌣ₖ_ {n = suc zero} {m = suc zero} ∣ loop j ∣ₕ ∣ loop i ∣ₕ)
                                     (Kn→ΩKn+10ₖ _) (~ r) i j))})
          (help k i j)
gradedComm'-elimCase-left (suc n) p q north b =
  cong (-ₖ'-gen (suc (suc n)) 1 p q ∘
            (subst coHomK (+'-comm 1 (suc (suc n)))))
              (sym (⌣ₖ-0ₖ _ (suc (suc n)) ∣ b ∣ₕ))
gradedComm'-elimCase-left (suc n) p q south b =
  cong (-ₖ'-gen (suc (suc n)) 1 p q ∘
            (subst coHomK (+'-comm 1 (suc (suc n)))))
              ((sym (⌣ₖ-0ₖ _ (suc (suc n)) ∣ b ∣ₕ)) ∙ λ i → ∣ b ∣ ⌣ₖ ∣ merid (ptSn (suc n)) i ∣ₕ)
gradedComm'-elimCase-left (suc n) p q (merid a i) base k =
  hcomp (λ j → λ {(i = i0) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                                  (subst coHomK (+'-comm 1 (suc (suc n)))))
                                    (0ₖ _)
                 ; (i = i1) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                                  (subst coHomK (+'-comm 1 (suc (suc n)))))
                                    (compPath-filler (sym (⌣ₖ-0ₖ _ (suc (suc n)) ∣ base ∣ₕ))
                                                     (λ i → ∣ base ∣ ⌣ₖ ∣ merid a i ∣ₕ) j k)
                 ; (k = i0) → _⌣ₖ_ {n = suc (suc n)} {m = suc zero} ∣ merid a i ∣ₕ ∣ base ∣ₕ
                 ; (k = i1) → -ₖ'-gen (suc (suc n)) 1 p q
                                (subst coHomK (+'-comm 1 (suc (suc n)))
                                 (∣ base ∣ₕ ⌣ₖ ∣ merid a i ∣ₕ))})
        (hcomp (λ j → λ {(i = i0) → ∣ north ∣
                        ; (i = i1) → ∣ north ∣
                        ; (k = i0) → (sym (Kn→ΩKn+10ₖ _)
                                    ∙ (λ j → Kn→ΩKn+1 _
                                         (sym (gradedComm'-elimCase-left n (evenOrOdd (suc n)) (inr tt) a base
                                        ∙ cong (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)) (transp0₁ n)) j))) j i
                        ; (k = i1) → ∣ north ∣})
               ∣ north ∣)
gradedComm'-elimCase-left (suc n) p q (merid a i) (loop j) k =
  hcomp (λ r →
    λ { (i = i0) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                      (subst coHomK (+'-comm 1 (suc (suc n)))))
                        (sym (⌣ₖ-0ₖ _ (suc (suc n)) ∣ (loop j) ∣ₕ) k)
      ; (i = i1) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                      (subst coHomK (+'-comm 1 (suc (suc n)))))
                        (compPath-filler (sym (⌣ₖ-0ₖ _ (suc (suc n)) ∣ (loop j) ∣ₕ))
                          (λ i → ∣ loop j ∣ ⌣ₖ ∣ merid (ptSn (suc n)) i ∣ₕ) r k)
      ; (k = i0) → _⌣ₖ_ {n = suc (suc n)} {m = suc zero} ∣ merid a i ∣ₕ ∣ loop j ∣ₕ
      ; (k = i1) → -ₖ'-gen (suc (suc n)) 1 p q
                     (subst coHomK (+'-comm 1 (suc (suc n)))
                      (_⌣ₖ_ {n = suc zero} {m = suc (suc n)} ∣ loop j ∣ₕ
                        ∣ compPath-filler (merid a) (sym (merid (ptSn (suc n)))) (~ r) i ∣ₕ))})
        (hcomp (λ r →
          λ { (i = i0) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                            (subst coHomK (+'-comm 1 (suc (suc n)))))
                              ∣ rCancel (merid (ptSn (suc (suc n)))) (~ k ∧ r) j ∣
            ; (i = i1) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                            (subst coHomK (+'-comm 1 (suc (suc n)))))
                              ∣ rCancel (merid (ptSn (suc (suc n)))) (~ k ∧ r) j ∣
            ; (k = i0) → help₂ r i j
            ; (k = i1) → -ₖ'-gen (suc (suc n)) 1 p q
                           (subst coHomK (+'-comm 1 (suc (suc n)))
                            (_⌣ₖ_ {n = suc zero} {m = suc (suc n)} ∣ loop j ∣ₕ
                              (Kn→ΩKn+1 _ ∣ a ∣ₕ i)))})
   (-ₖ'-gen (suc (suc n)) 1 p q
                           (subst coHomK (+'-comm 1 (suc (suc n)))
                            (_⌣ₖ_ {n = suc zero} {m = suc (suc n)} ∣ loop j ∣ₕ
                              (Kn→ΩKn+1 _ ∣ a ∣ₕ i)))))
    where
    P : Path _ (Kn→ΩKn+1 (suc (suc (n + 0))) (0ₖ _))
               (Kn→ΩKn+1 (suc (suc (n + 0))) (_⌣ₖ_ {n = (suc n)} {m = suc zero} ∣ a ∣ ∣ base ∣))
    P i = Kn→ΩKn+1 (suc (suc (n + 0)))
            ((sym (gradedComm'-elimCase-left n (evenOrOdd (suc n)) (inr tt) a base
              ∙ cong (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)) (transp0₁ n)) i))

    help₁ : (P ∙∙ ((λ i j → _⌣ₖ_ {n = suc (suc n)} {m = suc zero} ∣ merid a j ∣ₕ ∣ loop i ∣ₕ)) ∙∙ sym P)
         ≡ ((λ i → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)
                                   (transp0₁ n (~ i))))
        ∙∙ (λ i j → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)
                                  (subst coHomK (+'-comm 1 (suc n)) (∣ loop i ∣ₕ ⌣ₖ ∣ a ∣ₕ))) j)
        ∙∙ (λ i → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)
                                   (transp0₁ n i))))
    help₁ k i j =
        ((λ i → (Kn→ΩKn+1 (suc (suc (n + 0))))
                  (compPath-filler'
                    ((gradedComm'-elimCase-left n (evenOrOdd (suc n)) (inr tt) a base))
                   (cong (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt))
                    (transp0₁ n)) (~ k) (~ i)))
       ∙∙ (λ i j → (Kn→ΩKn+1 _
                     (gradedComm'-elimCase-left n (evenOrOdd (suc n)) (inr tt) a (loop i) k) j))
       ∙∙ λ i → (Kn→ΩKn+1 (suc (suc (n + 0))))
                   (compPath-filler'
                     ((gradedComm'-elimCase-left n (evenOrOdd (suc n)) (inr tt) a base))
                    (cong (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt))
                     (transp0₁ n)) (~ k) i)) i j

    help₂ : I → I → I → coHomK _
    help₂ r i j =
      hcomp (λ k →
        λ { (i = i0) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                           subst coHomK (+'-comm 1 (suc (suc n))))
                          ∣ rCancel (merid (ptSn (suc (suc n)))) (~ k ∨ r) j ∣
          ; (i = i1) → (-ₖ'-gen (suc (suc n)) 1 p q ∘
                           subst coHomK (+'-comm 1 (suc (suc n))))
                          ∣ rCancel (merid (ptSn (suc (suc n)))) (~ k ∨ r) j ∣
          ; (j = i0) → compPath-filler (sym (Kn→ΩKn+10ₖ (suc (suc (n + 0)))))
                          P k r i
          ; (j = i1) → compPath-filler (sym (Kn→ΩKn+10ₖ (suc (suc (n + 0)))))
                          P k r i
          ; (r = i0) → -ₖ'-gen (suc (suc n)) 1 p q
                         (subst coHomK (+'-comm 1 (suc (suc n)))
                           (doubleCompPath-filler (sym (Kn→ΩKn+10ₖ _))
                             (λ i j → _⌣ₖ_ {n = suc zero} {m = suc (suc n)} ∣ loop j ∣ₕ
                                         (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ i)) (Kn→ΩKn+10ₖ _) (~ k) i j))
          ; (r = i1) → doubleCompPath-filler P
                         (λ i j → _⌣ₖ_ {n = suc (suc n)} {m = suc zero} ∣ merid a j ∣ₕ ∣ loop i ∣ₕ)
                         (sym P) (~ k) j i})
             (hcomp (λ k →
               λ { (i = i0) → ∣ north ∣
                 ; (i = i1) → ∣ north ∣
                 ; (j = i0) → (Kn→ΩKn+10ₖ (suc (suc (n + 0)))) (~ r) i
                 ; (j = i1) → (Kn→ΩKn+10ₖ (suc (suc (n + 0)))) (~ r) i
                 ; (r = i0) → lem₂ n a p q (~ k) i j
                 ; (r = i1) → help₁ (~ k) j i})
                    (hcomp (λ k →
                      λ { (i = i0) → ∣ north ∣
                        ; (i = i1) → ∣ north ∣
                        ; (j = i0) → Kn→ΩKn+10ₖ (suc (suc (n + 0))) (~ r) i
                        ; (j = i1) → Kn→ΩKn+10ₖ (suc (suc (n + 0))) (~ r) i
                        ; (r = i0) → flipSquare≡cong-sym (flipSquare (ΩKn+1→Ω²Kn+2
                                                (sym (transp0₁ n)
                                              ∙∙ cong (subst coHomK (+'-comm 1 (suc n)))
                                                  (cong (-ₖ'-gen (suc (suc n)) 1 p q)
                                                   (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ))
                                              ∙∙ transp0₁ n))) (~ k) i j
                        ; (r = i1) → ((λ i → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)
                                                 (transp0₁ n (~ i))))
                                    ∙∙ (λ i j → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)
                                                  (subst coHomK (+'-comm 1 (suc n)) (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ i))) j)
                                    ∙∙ (λ i → Kn→ΩKn+1 _ (-ₖ'-gen (suc n) 1 (evenOrOdd (suc n)) (inr tt)
                                                  (transp0₁ n i)))) j i})
                              (hcomp (λ k →
                                λ { (i = i0) → ∣ north ∣
                                  ; (i = i1) → ∣ north ∣
                                  ; (j = i0) → Kn→ΩKn+10ₖ (suc (suc (n + 0))) (~ r ∧ k) i
                                  ; (j = i1) → Kn→ΩKn+10ₖ (suc (suc (n + 0))) (~ r ∧ k) i
                                  ; (r = i0) → doubleCompPath-filler
                                                  (sym (Kn→ΩKn+10ₖ _))
                                                  (cong (Kn→ΩKn+1 (suc (suc (n + 0))))
                                                      (sym (transp0₁ n)
                                                    ∙∙ sym (cong (subst coHomK (+'-comm 1 (suc n)))
                                                             (cong (-ₖ'-gen (suc (suc n)) 1 p q)
                                                               (Kn→ΩKn+1 (suc n) ∣ a ∣ₕ)))
                                                    ∙∙ transp0₁ n))
                                                (Kn→ΩKn+10ₖ _) k j i
                                  ; (r = i1) → lem₇ n a p q (~ k) j i})
                                         (lem₇ n a p q i1 j i))))

-- ∣ a ∣ ⌣ₖ ∣ b ∣ ≡ -ₖ'ⁿ*ᵐ (∣ b ∣ ⌣ₖ ∣ a ∣) for all n, m ≥ 1
gradedComm'-elimCase : (k n m : ℕ) (term : n + m ≡ k) (p : _) (q : _) (a : _) (b : _) →
      (_⌣ₖ_  {n = suc n} {m = (suc m)} ∣ a ∣ₕ ∣ b ∣ₕ)
    ≡ (-ₖ'-gen (suc n) (suc m) p q)
       (subst coHomK (+'-comm (suc m) (suc n))
        (_⌣ₖ_  {n = suc m} {m = suc n} ∣ b ∣ₕ ∣ a ∣ₕ))
gradedComm'-elimCase k zero zero term p q a b = gradedComm'-elimCase-left zero p q a b
gradedComm'-elimCase k zero (suc m) term (inr tt) q a b =
    help q
  ∙ sym (cong (-ₖ'-gen 1 (suc (suc m)) (inr tt) q
             ∘ (subst coHomK (+'-comm (suc (suc m)) 1)))
        (gradedComm'-elimCase-left (suc m) q (inr tt) b a))
  where
  help : (q : _) → ∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ ≡
            -ₖ'-gen 1 (suc (suc m)) (inr tt) q
            (subst coHomK (+'-comm (suc (suc m)) 1)
             (-ₖ'-gen (suc (suc m)) 1 q (inr tt)
              (subst coHomK (+'-comm 1 (suc (suc m))) (∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ))))
  help (inl x) =
      (sym (transportRefl _)
     ∙ (λ i → subst coHomK (isSetℕ _ _ refl (+'-comm 1 (suc (suc m)) ∙ +'-comm (suc (suc m)) 1) i)
               (∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ)))
    ∙∙ substComposite coHomK
         (+'-comm 1 (suc (suc m)))
          (+'-comm (suc (suc m)) 1)
           ((∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ))
    ∙∙ λ i → -ₖ'-gen-inl-right (suc zero) (suc (suc m)) (inr tt) x
            ((subst coHomK (+'-comm (suc (suc m)) 1)
             (-ₖ'-gen-inl-left (suc (suc m)) 1 x (inr tt)
              (subst coHomK (+'-comm 1 (suc (suc m))) (∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ)) (~ i)))) (~ i)
  help (inr x) =
       (sym (transportRefl _)
    ∙∙ (λ k → subst coHomK (isSetℕ _ _ refl (+'-comm 1 (suc (suc m)) ∙ +'-comm (suc (suc m)) 1) k) (∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ))
    ∙∙ sym (-ₖ^2 (subst coHomK (+'-comm 1 (suc (suc m)) ∙ +'-comm (suc (suc m)) 1) (∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ))))
    ∙∙ (λ i → -ₖ'-gen-inr≡-ₖ' 1 (suc (suc m)) tt x
                (-ₖ'-gen-inr≡-ₖ' (suc (suc m)) 1 x tt
                  (substComposite coHomK (+'-comm 1 (suc (suc m))) (+'-comm (suc (suc m)) 1) (∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ) i)
                  (~ i)) (~ i))
    ∙∙ λ i → (-ₖ'-gen 1 (suc (suc m)) (inr tt) (inr x)
                  (transp (λ j → coHomK ((+'-comm (suc (suc m)) 1) (j ∨ ~ i))) (~ i)
                    (-ₖ'-gen (suc (suc m)) 1 (inr x) (inr tt)
                      (transp (λ j → coHomK ((+'-comm (suc (suc m)) 1) (j ∧ ~ i))) i
                              ((subst coHomK (+'-comm 1 (suc (suc m))) (∣ a ∣ₕ ⌣ₖ ∣ b ∣ₕ)))))))
gradedComm'-elimCase k (suc n) zero term p q a b =
  gradedComm'-elimCase-left (suc n) p q a b
gradedComm'-elimCase zero (suc n) (suc m) term p q a b =
  ⊥.rec (snotz (sym (+-suc n m) ∙ cong predℕ term))
gradedComm'-elimCase (suc zero) (suc n) (suc m) term p q a b =
  ⊥.rec (snotz (sym (+-suc n m) ∙ cong predℕ term))
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q north north = refl
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q north south = refl
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q north (merid a i) r =
  -ₖ'-gen (suc (suc n)) (suc (suc m)) p q (
    (subst coHomK (+'-comm (suc (suc m)) (suc (suc n))))
      ((sym (Kn→ΩKn+10ₖ _)
      ∙ cong (Kn→ΩKn+1 _)
          (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (sym (transp0₂ n m))
                 ∙ sym (gradedComm'-elimCase (suc k) m (suc n) (+-suc m n ∙ +-comm (suc m) n ∙ cong predℕ term)
             (evenOrOdd (suc m)) p a north))) r i))
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q south north = refl
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q south south = refl
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q south (merid a i) r =
  -ₖ'-gen (suc (suc n)) (suc (suc m)) p q (
    (subst coHomK (+'-comm (suc (suc m)) (suc (suc n))))
      ((sym (Kn→ΩKn+10ₖ _)
      ∙ cong (Kn→ΩKn+1 _)
          (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (sym (transp0₂ n m))
                  ∙ sym (gradedComm'-elimCase (suc k) m (suc n) (+-suc m n ∙ +-comm (suc m) n ∙ cong predℕ term)
             (evenOrOdd (suc m)) p a south))) r i))
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q (merid a i) north r =
    (cong (Kn→ΩKn+1 (suc (suc (n + suc m))))
      (gradedComm'-elimCase (suc k) n (suc m) (cong predℕ term) (evenOrOdd (suc n)) q a north
       ∙ cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n))
   ∙' Kn→ΩKn+10ₖ _) r i
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q (merid a i) south r =
    (cong (Kn→ΩKn+1 (suc (suc (n + suc m))))
      (gradedComm'-elimCase (suc k) n (suc m) (cong predℕ term) (evenOrOdd (suc n)) q a south
       ∙ cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n))
   ∙' Kn→ΩKn+10ₖ _) r i
gradedComm'-elimCase (suc (suc k)) (suc n) (suc m) term p q (merid a i) (merid b j) r =
  hcomp (λ l →
    λ { (i = i0) → -ₖ'-gen (suc (suc n)) (suc (suc m)) p q (
                     (subst coHomK (+'-comm (suc (suc m)) (suc (suc n))))
                       ((compPath-filler (sym (Kn→ΩKn+10ₖ _))
                        (cong (Kn→ΩKn+1 _)
                          (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (sym (transp0₂ n m))
                                   ∙ sym (gradedComm'-elimCase (suc k) m (suc n) (+-suc m n ∙ +-comm (suc m) n ∙ cong predℕ term)
                               (evenOrOdd (suc m)) p b north))) l r j)))
       ; (i = i1) → -ₖ'-gen (suc (suc n)) (suc (suc m)) p q (
                     (subst coHomK (+'-comm (suc (suc m)) (suc (suc n))))
                       ((compPath-filler (sym (Kn→ΩKn+10ₖ _))
                        (cong (Kn→ΩKn+1 _)
                          (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (sym (transp0₂ n m))
                                  ∙ sym (gradedComm'-elimCase (suc k) m (suc n) (+-suc m n ∙ +-comm (suc m) n ∙ cong predℕ term)
                              (evenOrOdd (suc m)) p b south))) l r j)))
       ; (r = i0) → help₂ l i j
       ; (r = i1) → -ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                       (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
                        (help₁ l i j))})
   (hcomp (λ l →
     λ { (i = i0) → -ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                      (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
                        (Kn→ΩKn+10ₖ _ (~ r ∨ ~ l) j))
       ; (i = i1) → -ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                      (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
                        (Kn→ΩKn+10ₖ _ (~ r ∨ ~ l) j))
       ; (j = i0) → Kn→ΩKn+10ₖ _ r i
       ; (j = i1) → Kn→ΩKn+10ₖ _ r i
       ; (r = i0) → lem₄ n m q p a b (~ l) j i
       ; (r = i1) → -ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                      (subst coHomK (+'-comm (suc (suc m)) (suc (suc n)))
                        (doubleCompPath-filler
                         (sym (Kn→ΩKn+10ₖ _))
                          (λ i j → Kn→ΩKn+1 _ ((sym (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (transp0₂ n m))
                                             ∙∙ (λ i → -ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                                                           (subst coHomK (+'-comm (suc (suc n)) (suc m))
                                                             (_⌣ₖ_ {n = suc (suc n)} {m = suc m} ∣ merid a i ∣ₕ ∣ b ∣ₕ)))
                                             ∙∙ cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (transp0₂ n m)) i) j)
                          (Kn→ΩKn+10ₖ _) (~ l) i j))})
        (hcomp (λ l →
          λ { (i = i0) → ∣ north ∣
            ; (i = i1) → ∣ north ∣
            ; (j = i0) → Kn→ΩKn+10ₖ _ r i
            ; (j = i1) → Kn→ΩKn+10ₖ _ r i
            ; (r = i0) → lem₄ n m q p a b i1 j i
            ; (r = i1) → lem₅ n m p q a b (~ l) i j})
            (hcomp (λ l →
              λ { (i = i0) → ∣ north ∣
                ; (i = i1) → ∣ north ∣
                ; (j = i0) → Kn→ΩKn+10ₖ _ (r ∨ ~ l) i
                ; (j = i1) → Kn→ΩKn+10ₖ _ (r ∨ ~ l) i
                ; (r = i0) → doubleCompPath-filler
                               (sym (Kn→ΩKn+10ₖ _))
                               (lem₄ n m q p a b i1)
                               (Kn→ΩKn+10ₖ _) (~ l) j i
                ; (r = i1) → Kn→Ω²Kn+2 (-ₖ'-gen (suc (suc n)) (suc (suc m)) p q
                                            (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                                              (subst coHomK (cong suc (sym (+-suc n m)))
                                                (gradedComm'-elimCase k n m
                                                  (+-comm n m ∙∙ cong predℕ (+-comm (suc m) n) ∙∙ cong (predℕ ∘ predℕ) term)
                                                  (evenOrOdd (suc n)) (evenOrOdd (suc m)) a b (~ l))))) i j})
                (lem₆ n m p q a b r i j))))
  where
  help₁ : I → I → I → coHomK _
  help₁ l i j =
    Kn→ΩKn+1 _
      (hcomp (λ r
        → λ { (i = i0) → compPath-filler' (cong ((-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p)) (sym (transp0₂ n m)))
                            (sym (gradedComm'-elimCase (suc k) m (suc n) (+-suc m n ∙ +-comm (suc m) n ∙ cong predℕ term)
                                                        (evenOrOdd (suc m)) p b north)) r l
              ; (i = i1) → compPath-filler' (cong ((-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p)) (sym (transp0₂ n m)))
                             (sym (gradedComm'-elimCase (suc k) m (suc n) (+-suc m n ∙ +-comm (suc m) n ∙ cong predℕ term)
                                                        (evenOrOdd (suc m)) p b south)) r l
              ; (l = i0) → doubleCompPath-filler (sym (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (transp0₂ n m)))
                                                  (λ i → -ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p
                                                           (subst coHomK (+'-comm (suc (suc n)) (suc m))
                                                             (_⌣ₖ_ {n = suc (suc n)} {m = suc m} ∣ merid a i ∣ₕ ∣ b ∣ₕ)))
                                                  (cong (-ₖ'-gen (suc m) (suc (suc n)) (evenOrOdd (suc m)) p) (transp0₂ n m)) r i
              ; (l = i1) → _⌣ₖ_ {n = suc m} {m = suc (suc n)} ∣ b ∣ₕ ∣ merid a i ∣ₕ})
          (gradedComm'-elimCase (suc k) m (suc n) (+-suc m n ∙ +-comm (suc m) n ∙ cong predℕ term)
            (evenOrOdd (suc m)) p b (merid a i) (~ l))) j

  help₂ : I → I → I → coHomK _
  help₂ l i j =
    hcomp (λ r →
      λ { (i = i0) → ∣ north ∣
         ; (i = i1) → ∣ north ∣
         ; (j = i0) →
           Kn→ΩKn+1 (suc (suc (n + suc m)))
                (compPath-filler (gradedComm'-elimCase (suc k) n (suc m)
                                  (cong predℕ term) (evenOrOdd (suc n)) q a north)
                  (cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q)  (transp0₂ m n)) r (~ l)) i
         ; (j = i1) →
              Kn→ΩKn+1 (suc (suc (n + suc m)))
                (compPath-filler (gradedComm'-elimCase (suc k) n (suc m)
                                 (cong predℕ term) (evenOrOdd (suc n)) q a south)
                  (cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n)) r (~ l)) i
         ; (l = i0) →
           Kn→ΩKn+1 _
             (doubleCompPath-filler (sym (cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n)))
                                    (λ j → -ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q
                                             (subst coHomK (+'-comm (suc (suc m)) (suc n))
                                               (_⌣ₖ_ {n = suc (suc m)} {m = (suc n)} ∣ merid b j ∣ₕ ∣ a ∣)))
                                    (cong (-ₖ'-gen (suc n) (suc (suc m)) (evenOrOdd (suc n)) q) (transp0₂ m n)) r j) i
         ; (l = i1) → Kn→ΩKn+1 _ (_⌣ₖ_ {n = (suc n)} {m = suc (suc m)} ∣ a ∣ ∣ merid b j ∣ₕ) i})
          (hcomp (λ r →
            λ { (i = i0) → ∣ north ∣
              ; (i = i1) → ∣ north ∣
              ; (j = i0) → Kn→ΩKn+1 (suc (suc (n + suc m)))
                             (gradedComm'-elimCase (suc k) n (suc m)
                               (cong predℕ term) (evenOrOdd (suc n)) q a north (~ l ∨ ~ r)) i
              ; (j = i1) → Kn→ΩKn+1 (suc (suc (n + suc m)))
                             (gradedComm'-elimCase (suc k) n (suc m)
                               (cong predℕ term) (evenOrOdd (suc n)) q a south (~ l ∨ ~ r)) i
              ; (l = i0) → Kn→ΩKn+1 (suc (suc (n + suc m)))
                             (gradedComm'-elimCase (suc k) n (suc m)
                               (cong predℕ term) (evenOrOdd (suc n)) q a (merid b j) i1) i
              ; (l = i1) → Kn→ΩKn+1 _ (gradedComm'-elimCase (suc k) n (suc m) (cong predℕ term)
                                          (evenOrOdd (suc n)) q a (merid b j) (~ r)) i})
               (Kn→ΩKn+1 (suc (suc (n + suc m)))
                 (gradedComm'-elimCase (suc k) n (suc m) (cong predℕ term)
                   (evenOrOdd (suc n)) q a (merid b j) i1) i))

private
  coherence-transp : (n m : ℕ) (p : _) (q : _)
   → -ₖ'-gen (suc n) (suc m) p q
        (subst coHomK (+'-comm (suc m) (suc n)) (0ₖ (suc m +' suc n))) ≡ 0ₖ _
  coherence-transp zero zero p q = refl
  coherence-transp zero (suc m) p q = refl
  coherence-transp (suc n) zero p q = refl
  coherence-transp (suc n) (suc m) p q = refl

gradedComm'-⌣ₖ∙ : (n m : ℕ) (p : _) (q : _) (a : _)
    → ⌣ₖ∙ (suc n) (suc m) a
  ≡ ((λ b → -ₖ'-gen (suc n) (suc m) p q (subst coHomK (+'-comm (suc m) (suc n)) (b ⌣ₖ a)))
    , (cong (-ₖ'-gen (suc n) (suc m) p q)
       (cong (subst coHomK (+'-comm (suc m) (suc n)))
        (0ₖ-⌣ₖ (suc m) (suc n) a))
   ∙ coherence-transp n m p q))
gradedComm'-⌣ₖ∙ n m p q =
  T.elim (λ _ → isOfHLevelPath (3 + n) ((isOfHLevel↑∙ (suc n) m)) _ _)
    λ a → →∙Homogeneous≡ (isHomogeneousKn _) (funExt λ b → funExt⁻ (cong fst (f₁≡f₂ b)) a)
  where
  f₁ : coHomK (suc m) → S₊∙ (suc n) →∙ coHomK-ptd (suc n +' suc m)
  fst (f₁ b) a = _⌣ₖ_ {n = suc n} {m = suc m} ∣ a ∣ₕ b
  snd (f₁ b) = 0ₖ-⌣ₖ (suc n) (suc m) b

  f₂ : coHomK (suc m) → S₊∙ (suc n) →∙ coHomK-ptd (suc n +' suc m)
  fst (f₂ b) a =
    -ₖ'-gen (suc n) (suc m) p q (subst coHomK (+'-comm (suc m) (suc n))
      (_⌣ₖ_ {n = suc m} {m = suc n} b ∣ a ∣ₕ))
  snd (f₂ b) =
    (cong (-ₖ'-gen (suc n) (suc m) p q)
            (cong (subst coHomK (+'-comm (suc m) (suc n)))
             (⌣ₖ-0ₖ (suc m) (suc n) b))
       ∙ coherence-transp n m p q)

  f₁≡f₂ : (b : _) → f₁ b ≡ f₂ b
  f₁≡f₂ =
    T.elim (λ _ → isOfHLevelPath (3 + m)
                    (subst (isOfHLevel (3 + m))
                     (λ i → S₊∙ (suc n) →∙ coHomK-ptd (+'-comm (suc n) (suc m) (~ i)))
                      (isOfHLevel↑∙' (suc m) n)) _ _)
     λ b → →∙Homogeneous≡ (isHomogeneousKn _)
             (funExt λ a → gradedComm'-elimCase (n + m) n m refl p q a b)

-- Finally, graded commutativity:
gradedComm'-⌣ₖ : (n m : ℕ) (a : coHomK n) (b : coHomK m)
  → a ⌣ₖ b ≡ (-ₖ'^ n · m) (subst coHomK (+'-comm m n) (b ⌣ₖ a))
gradedComm'-⌣ₖ zero zero a b = sym (transportRefl _) ∙ cong (transport refl) (comm-·₀ a b)
gradedComm'-⌣ₖ zero (suc m) a b =
      sym (transportRefl _)
  ∙∙ (λ k → subst coHomK (isSetℕ _ _ refl (+'-comm (suc m) zero) k) (b ⌣ₖ a))
  ∙∙ sym (-ₖ'-gen-inl-left zero (suc m) tt (evenOrOdd (suc m))
          (subst coHomK (+'-comm (suc m) zero) (b ⌣ₖ a)))
gradedComm'-⌣ₖ (suc n) zero a b =
     sym (transportRefl _)
  ∙∙ ((λ k → subst coHomK (isSetℕ _ _ refl (+'-comm zero (suc n)) k) (b ⌣ₖ a)))
  ∙∙ sym (-ₖ'-gen-inl-right (suc n) zero (evenOrOdd (suc n)) tt
          (subst coHomK (+'-comm zero (suc n)) (b ⌣ₖ a)))
gradedComm'-⌣ₖ (suc n) (suc m) a b =
  funExt⁻ (cong fst (gradedComm'-⌣ₖ∙ n m (evenOrOdd (suc n)) (evenOrOdd (suc m)) a)) b

gradedComm'-⌣ : {A : Type ℓ} (n m : ℕ) (a : coHom n A) (b : coHom m A)
  → a ⌣ b ≡ (-ₕ'^ n · m) (subst (λ n → coHom n A) (+'-comm m n) (b ⌣ a))
gradedComm'-⌣ n m =
  ST.elim2 (λ _ _ → isOfHLevelPath 2 squash₂ _ _)
    λ f g →
      cong ∣_∣₂ (funExt (λ x →
        gradedComm'-⌣ₖ n m (f x) (g x)
      ∙ cong ((-ₖ'^ n · m) ∘ (subst coHomK (+'-comm m n)))
         λ i → g (transportRefl x (~ i)) ⌣ₖ f (transportRefl x (~ i))))

-----------------------------------------------------------------------------
-- The previous code introduces another - to facilitate proof
-- This a reformulation with the usual -ₕ' definition (the one of the ring) of the results

-ₕ^-gen : {k : ℕ} → {A : Type ℓ} → (n m : ℕ)
         → (p : isEvenT n ⊎ isOddT n)
         → (q : isEvenT m ⊎ isOddT m)
         → (a : coHom k A) → coHom k A
-ₕ^-gen n m (inl p) q a       = a
-ₕ^-gen n m (inr p) (inl q) a = a
-ₕ^-gen n m (inr p) (inr q) a = -ₕ a

-ₕ^_·_ : {k : ℕ} → {A : Type ℓ} → (n m : ℕ) → (a : coHom k A) → coHom k A
-ₕ^_·_ n m a = -ₕ^-gen n m (evenOrOdd n) (evenOrOdd m) a

-ₕ^-gen-eq : ∀ {ℓ} {k : ℕ} {A : Type ℓ} (n m : ℕ)
  → (p : isEvenT n ⊎ isOddT n) (q : isEvenT m ⊎ isOddT m)
  → (x : coHom k A)
  → -ₕ^-gen n m p q x  ≡ (ST.map λ f x → (-ₖ'-gen n m p q) (f x)) x
-ₕ^-gen-eq {k = k} n m (inl p) q = ST.elim (λ _ → isSetPathImplicit) λ f → cong ∣_∣₂ (funExt λ x → sym (-ₖ'-gen-inl-left n m p q (f x)))
-ₕ^-gen-eq {k = k} n m (inr p) (inl q) = ST.elim (λ _ → isSetPathImplicit) λ f → cong ∣_∣₂ (funExt λ z → sym (-ₖ'-gen-inl-right n m (inr p) q (f z)))
-ₕ^-gen-eq {k = k} n m (inr p) (inr q) = ST.elim (λ _ → isSetPathImplicit) λ f → cong ∣_∣₂ (funExt λ z → sym (-ₖ'-gen-inr≡-ₖ' n m p q (f z)))

-ₕ^-eq : ∀ {ℓ} {k : ℕ} {A : Type ℓ} (n m : ℕ) → (a : coHom k A)
             → (-ₕ^ n · m) a  ≡ (-ₕ'^ n · m) a
-ₕ^-eq n m a = -ₕ^-gen-eq n m (evenOrOdd n) (evenOrOdd m) a

gradedComm-⌣ : ∀ {ℓ} {A : Type ℓ} (n m : ℕ) (a : coHom n A) (b : coHom m A)
  → a ⌣ b ≡ (-ₕ^ n · m) (subst (λ n → coHom n A) (+'-comm m n) (b ⌣ a))
gradedComm-⌣ n m a b = (gradedComm'-⌣ n m a b) ∙ (sym (-ₕ^-eq n m (subst (λ n₁ → coHom n₁ _) (+'-comm m n) (b ⌣ a))))