Skip to content

The chain rule

For any pair of containers, we can define a cartesian morphism chain-rule : ∂ F [ G ] ⊗ ∂ G ⊸ ∂ (F [ G ]), a lax chain rule. Under some circumstances, this morphism will be invertible, that is a strong chain rule.

module _ (F G : Container  ) where
  open Container F renaming (Shape to S ; Pos to P)
  open Container G renaming (Shape to T ; Pos to Q)
  chain-rule : Cart ( F [ G ]   G) ( (F [ G ]))

The chain rule is defined by first using ungraftEquiv to adjust shapes and positions via an equivalence of containers (η₀), and then distributing isolated points over Σ-types by means of Σ-isolate (η₁).

  chain-rule =
     F [ G ]   G
      ⊸⟨ Equiv→Cart η₀ 
    H
      ⊸⟨ η₁ 
     (F [ G ])
      ⊸∎
    module chain-rule where
      equiv-left :
        (Σ[ (s , p)  Σ[ s  S ] (P s °) ] (P s ∖° p  T)) × (Σ[ t  T ] Q t °)
          
        (Σ[ (s , f)  Σ[ s  S ] (P s  T) ] Σ[   (P s) ° ] Q (f ( .fst)) °)
      equiv-left =
        (Σ[ (s , )  (Σ[ s  S ] (P s °)) ] (P s ∖°   T)) × (Σ[ t  T ] Q t °)
          ≃⟨ step-I 
        Σ[ (s , )  Σ[ s  S ] (P s °) ] Σ[ (_ , t)  (P s ∖°   T) × T ] Q t °
          ≃⟨ Σ-cong-equiv-snd  (s , )  invEquiv $ Σ-cong-equiv-fst $ ungraftEquiv ) 
        Σ[ (s , )  Σ[ s  S ] (P s °) ] Σ[ f  (P s  T) ] Q (f ( .fst)) °
          ≃⟨ step-II 
        Σ[ (s , f)  Σ[ s  S ] (P s  T) ] Σ[   P s ° ] Q (f ( .fst)) °
          ≃∎ where
          step-I = strictEquiv
             (((s , ) , f) , t , )  ((s , ) , (f , t) , ))
             ((s , ) , (f , t) , )  (((s , ) , f) , t , ))
          step-II = strictEquiv
             ((s , ) , (f , q))  ((s , f) ,  , q))
             ((s , f) ,  , q)  ((s , ) , (f , q)))

      H : Container _ _
      H .Shape = Σ[ (s , f)  Σ[ s  S ] (P s  T) ] Σ[   (P s) ° ] Q (f ( .fst)) °
      H .Pos ((s , f) , ( , )) = (Σ[ (p , _)  P s ∖°  ] Q (f p))  (Q (f ( .fst)) ∖° )

      η₀ : Equiv ( F [ G ]   G) H
      η₀ = Equiv-inv $ Equiv-fst $ invEquiv equiv-left

      η₁ : Cart H ( (F [ G ]))
      η₁ .shape = Σ-map-snd λ (s , f)  Σ-isolate (P s) (Q  f)
      η₁ .pos ((s , f) , ( , )) = invEquiv (isIsolatedFst→Σ-remove-equiv ( .snd))

The map of shapes of the chain rule is always an embedding.

  chain-shape-map :
    (Σ[ (s , p)  Σ[ s  S ] (P s °) ] (P s  (p .fst)  T)) × (Σ[ t  T ] Q t °)
      
    Σ[ (s , f)  Σ[ s  S ] (P s  T) ] (Σ[ p  (P s) ] Q (f p)) °
  chain-shape-map = chain-rule .shape

  isEmbedding-chain-shape-map : isEmbedding chain-shape-map
  isEmbedding-chain-shape-map = isEmbedding-∘
    {f = Σ-map-snd λ (s , f)  Σ-isolate (P s) (Q  f)}
    {h = equivFun $ chain-rule.η₀ .Equiv.shape}
    (isEmbedding-Σ-map-snd λ (s , f)  isEmbedding-Σ-isolate (P s) (Q  f))
    (isEquiv→isEmbedding $ equivIsEquiv $ chain-rule.η₀ .Equiv.shape)

It is an equivalence of shapes if and only if Σ-isolate (P s) (Q ∘ f) is an equivalence.

  isEquivChainRule→isEquiv-Σ-isolated :
    isEquiv (chain-rule .shape)  (∀ s  (f : P s  T)  isEquiv (Σ-isolate (P s) (Q  f)))
  isEquivChainRule→isEquiv-Σ-isolated is-equiv-chain-shape-map = is-equiv-Σ-isolate where
    is-equiv-Σ-Σ-isolate : isEquiv (Σ-map-snd {A = Σ[ s  S ] (P s  T)}  (s , f)  Σ-isolate (P s) (Q  f)))
    is-equiv-Σ-Σ-isolate = isEquiv[f∘equivFunA≃B]→isEquiv[f]
      (Σ-map-snd _)
      chain-rule.equiv-left
      is-equiv-chain-shape-map

    is-equiv-Σ-isolate :  s f  isEquiv (Σ-isolate (P s) (Q  f))
    is-equiv-Σ-isolate = curry $ isEquiv-Σ-map-snd→isEquiv is-equiv-Σ-Σ-isolate

  isEquiv-Σ-isolated→isEquivChainRule :
    (∀ s  (f : P s  T)  isEquiv (Σ-isolate (P s) (Q  f)))
      
    isEquiv (chain-rule .shape)
  isEquiv-Σ-isolated→isEquivChainRule is-equiv-Σ-isolate = isEquiv-∘
    {f = equivFun $ chain-rule.η₀ .Equiv.shape}
    {g = Σ-map-snd λ ((s , f))  Σ-isolate (P s) (Q  f)}
    (isEquiv-Σ-map-snd $ uncurry is-equiv-Σ-isolate)
    (equivIsEquiv $ chain-rule.η₀ .Equiv.shape)

  isEquivChainRule≃isEquiv-Σ-isolated :
    isEquiv (chain-rule .shape)  (∀ s  (f : P s  T)  isEquiv (Σ-isolate (P s) (Q  f)))
  isEquivChainRule≃isEquiv-Σ-isolated = propBiimpl→Equiv
    (isPropIsEquiv _) (isPropΠ2 λ s f  isPropIsEquiv _)
    isEquivChainRule→isEquiv-Σ-isolated
    isEquiv-Σ-isolated→isEquivChainRule

The chain rule is strong if it is an equivalence of containers, that is, whenever its shape map is an equivalence.

isStrong : (F G : Container  )  Type _
isStrong F G = isEquiv (chain-shape-map F G)

It is globally strong if this is the case for any choice of containers.

isGloballyStrong : ( : Level)  Type (ℓ-suc )
isGloballyStrong  = (F G : Container  )  isStrong F G

isPropIsGloballyStrong : isProp (isGloballyStrong )
isPropIsGloballyStrong = isPropΠ2 λ F G  isPropIsEquiv _

For discrete containers, the chain rule is strong.

DiscreteContainer→isStrong : (F G : DiscreteContainer  )  isStrong (F .fst) (G .fst)
DiscreteContainer→isStrong (F , disc-F) (G , disc-G) = isEquiv-Σ-isolated→isEquivChainRule F G is-equiv-Σ-isolate where
  open Container F renaming (Shape to S ; Pos to P)
  open Container G renaming (Shape to T ; Pos to Q)

  is-equiv-Σ-isolate :  s f  isEquiv (Σ-isolate (P s) (Q  f))
  is-equiv-Σ-isolate s f = Discrete→isEquiv-Σ-isolate (disc-F s) (disc-G  f)

Having a globally strong chain rule is an inconsistent assumption. A globally strong chain rule is equivalent to assuming that any type is discrete.

isGloballyStrong→AllTypesDiscrete : isGloballyStrong   (A : Type )  Discrete A
isGloballyStrong→AllTypesDiscrete {} is-equiv-chain-shape-map A = discrete-A where
  F : Container  
  F .Shape = 𝟙*
  F .Pos _ = A

  G : (a₀ : A)  Container  
  G a₀ .Shape = A
  G a₀ .Pos = a₀ ≡_

  is-equiv-Σ-isolate-singl : (a₀ : A)  isEquiv (Σ-isolate A (a₀ ≡_))
  is-equiv-Σ-isolate-singl a₀ = isEquivChainRule→isEquiv-Σ-isolated F (G a₀)
    (is-equiv-chain-shape-map F (G a₀))
    
    (idfun A)

  discrete-A : Discrete A
  discrete-A = isEquiv-Σ-isolate-singl→Discrete is-equiv-Σ-isolate-singl

AllTypesDiscrete→isGloballyStrong : ((A : Type )  Discrete A)  isGloballyStrong 
AllTypesDiscrete→isGloballyStrong discrete F G = DiscreteContainer→isStrong (F , discrete  Pos F) (G , discrete  Pos G)

isGloballyStrong≃AllTypesDiscrete : isGloballyStrong   ((A : Type )  Discrete A)
isGloballyStrong≃AllTypesDiscrete = propBiimpl→Equiv isPropIsGloballyStrong (isPropΠ λ A  isPropDiscrete)
  isGloballyStrong→AllTypesDiscrete
  AllTypesDiscrete→isGloballyStrong

Of course, there are non-discrete types (for example, the circle ), hence a globally strong chain rule cannot hold.

¬isGloballyStrong : ¬ isGloballyStrong ℓ-zero
¬isGloballyStrong is-equiv-chain-shape-map = S1.¬isIsolated-base $ Discrete→isIsolated discrete-S¹ base where
  open import Cubical.HITs.S1.Base

  discrete-S¹ : Discrete 
  discrete-S¹ = isGloballyStrong→AllTypesDiscrete is-equiv-chain-shape-map 

Restricted to h-sets, the assumption is less strong: The chain rule is strong for all set-truncated containers if and only if all h-sets are discrete.

isStrongSets→AllSetsDiscrete :
  ((F G : SetContainer  )  isStrong (F .fst) (G .fst))
    
  ((A : hSet )  Discrete  A )
isStrongSets→AllSetsDiscrete {} is-equiv-chain-shape-map (A , is-set-A) = discrete-A where
  F : SetContainer  
  F .fst .Shape = 𝟙*
  F .fst .Pos _ = A
  F .snd .fst = isSet-𝟙*
  F .snd .snd _ = is-set-A

  G : (a₀ : A)  SetContainer  
  G a₀ .fst .Shape = A
  G a₀ .fst .Pos = a₀ ≡_
  G a₀ .snd .fst = is-set-A
  G a₀ .snd .snd a = isOfHLevelPath 1 (is-set-A a₀ a)

  is-equiv-Σ-isolate-singl : (a₀ : A)  isEquiv (Σ-isolate A (a₀ ≡_))
  is-equiv-Σ-isolate-singl a₀ = isEquivChainRule→isEquiv-Σ-isolated _ _
    (is-equiv-chain-shape-map F (G a₀))
    
    (idfun A)

  discrete-A : Discrete A
  discrete-A = isEquiv-Σ-isolate-singl→Discrete is-equiv-Σ-isolate-singl

AllSetsDiscrete→isStrongSets :
  ((A : hSet )  Discrete  A )
    
  ((F G : SetContainer  )  isEquiv (chain-rule (F .fst) (G .fst) .shape))
AllSetsDiscrete→isStrongSets discrete (F , is-set-F) (G , is-set-G) = DiscreteContainer→isStrong
  (F , disc-F)
  (G , disc-G)
  where
    disc-F :  s  Discrete (F .Pos s)
    disc-F s = discrete (F .Pos s , is-set-F .snd s)

    disc-G :  t  Discrete (G .Pos t)
    disc-G t = discrete (G .Pos t , is-set-G .snd t)

isStrongSets≃AllSetsDiscrete :
  ((F G : SetContainer  )  isEquiv (chain-rule (F .fst) (G .fst) .shape))
    
  ((A : hSet )  Discrete  A )
isStrongSets≃AllSetsDiscrete = propBiimpl→Equiv
  (isPropΠ2 λ F G  isPropIsEquiv _)
  (isPropΠ λ A  isPropDiscrete)
  isStrongSets→AllSetsDiscrete
  AllSetsDiscrete→isStrongSets

In the presences of a small replacement Ω of hProp, a strong chain rule for h-sets would let us decide arbitrary propositions (a form of LEM).

impredicativeProp→isGloballyStrong→LEM : ( : Level)
   (Ω : Type )
   (resize : Ω  hProp )
   isGloballyStrong 
   (P : hProp )  Dec  P 
impredicativeProp→isGloballyStrong→LEM  Ω resize has-chain-equiv = dec-prop where
  open import Cubical.Relation.Nullary.Properties using (EquivPresDiscrete)

  all-types-discrete : (A : Type )  Discrete A
  all-types-discrete = isGloballyStrong→AllTypesDiscrete has-chain-equiv

  Ω-discrete : Discrete Ω
  Ω-discrete = all-types-discrete Ω

  hProp-discrete : Discrete (hProp )
  hProp-discrete = EquivPresDiscrete resize Ω-discrete

  𝟙ᴾ : hProp 
  𝟙ᴾ .fst = 𝟙*
  𝟙ᴾ .snd _ _ = refl

  dec-equal-𝟙 : (P : hProp )  Dec (P  𝟙ᴾ)
  dec-equal-𝟙 P = hProp-discrete P 𝟙ᴾ

  dec-prop :  P  Dec  P 
  dec-prop P = Dec.map
     P≡𝟙  subst ⟨_⟩ (sym P≡𝟙) )
     P≢𝟙 p  P≢𝟙 $ Σ≡Prop  _  isPropIsProp) (isContr→≡𝟙* (inhProp→isContr p (str P))))
    (dec-equal-𝟙 P)