Derivative.Isolated.Grafting

{-# OPTIONS --safe #-}
module Derivative.Isolated.Grafting where

open import Derivative.Prelude
open import Derivative.Isolated.Base
open import Derivative.Basics.Decidable as Dec
open import Derivative.Remove

private
  variable
     : Level
    A B : Type 

graft : ( : A °)  (((A   .fst)  B) × B)  (A  B)
graft  (f , b₀) = elimIsolated   _ _  b₀) f

graft-β-yes : ( : A °) (f : (A   .fst)  B) {b₀ : B}  graft  (f , b₀) ( .fst)  b₀
graft-β-yes  f {b₀} = elimIsolated-β-refl   _ _  b₀) f

graft-β-no : ( : A °) (f : (A   .fst)  B) {b₀ : B} (a : A   .fst)  graft  (f , b₀) (a .fst)  f a
graft-β-no  f {b₀} = uncurry $ elimIsolated-β-no   _ _  b₀) f

graft-eval : ( : A °)  (f : A  B) (b₀ : B)
   (p : b₀  f ( .fst))
   graft  (f  fst , b₀)  f
graft-eval  f b₀ p using (a₀ , a₀≟_) = funExt λ a  eval-dec a (a₀≟ a) module graft-eval where
  eval-dec :  a  Dec (a₀  a)  graft  (f  fst , b₀) a  f a
  eval-dec a (yes a₀≡a) = elimIsolated-β-yes   _ _  b₀) (f  fst) a a₀≡a ∙∙ p ∙∙ cong f a₀≡a
  eval-dec a (no ¬a₀≡a) = graft-β-no  (f  fst) (a , ¬a₀≡a)

graft-eval-yes-filler : ( : A °)  (f : A  B) (b₀ : B)
   (p : b₀  f ( .fst))
   Square (graft-β-yes  (f  fst) {b₀ = b₀}) (refl′ (f ( .fst))) (graft-eval  f b₀ p ≡$  .fst) p
graft-eval-yes-filler  f b₀ p using (a₀ , a₀≟_) = λ i j  eval-dec-filler (a₀≟ a₀) (~ j) i module graft-eval-yes-filler where
  open graft-eval  f b₀ p

  eval-dec-filler : (a₀≟a₀ : Dec (a₀  a₀))  Square p (eval-dec a₀ a₀≟a₀) (sym $ graft-β-yes  (f  fst) {b₀}) (refl′ (f a₀))
  eval-dec-filler (yes a₀≡a₀) = goal
    where
      filler : Square p (eval-dec a₀ (yes a₀≡a₀)) _ (cong f a₀≡a₀)
      filler = doubleCompPath-filler (elimIsolated-β-yes   _ _  b₀) (f  fst) a₀ a₀≡a₀) p (cong f a₀≡a₀)

      adjust₁ : cong f a₀≡a₀  refl
      adjust₁ i j = f (isIsolated→K  a₀≡a₀ i j)

      adjust₂ : elimIsolated-β-yes   _ _  b₀) (f  fst) a₀ a₀≡a₀  graft-β-yes  (f  fst) {b₀}
      adjust₂ = cong (elimIsolated-β-yes  _ (f  fst) a₀) (isIsolated→K  a₀≡a₀)

      goal : Square p (eval-dec a₀ (yes a₀≡a₀)) (sym $ graft-β-yes  (f  fst)) (refl′ (f a₀))
      goal = subst2  r s  Square p (eval-dec a₀ (yes a₀≡a₀)) (sym r) s) adjust₂ adjust₁ filler

  eval-dec-filler (no ¬a₀≡a₀) = ex-falso $ ¬a₀≡a₀ refl

ungraft : ( : A °)  (A  B)  (((A   .fst)  B) × B)
ungraft (a₀ , _) f .fst = f  fst
ungraft (a₀ , _) f .snd = f a₀

isEquiv-graft : ( : A °)  isEquiv (graft {B = B} )
isEquiv-graft {A} {B} @(a₀ , a₀≟_) = isoToIsEquiv graft-iso module isEquivgraft where

  graft-iso : Iso (((A  a₀)  B) × B) (A  B)
  graft-iso .Iso.fun = graft 
  graft-iso .Iso.inv = ungraft 
  graft-iso .Iso.rightInv f = funExt λ a  goal a (a₀≟ a) where
    goal : (a : A)  Dec (a₀  a)  graft  (ungraft  f) a  f a
    goal a (yes p) = elimIsolated-β-yes   _ _  f a₀) (f  fst) a p  cong f p
    goal a (no ¬p) = elimIsolated-β-no   _ _  f a₀) (f  fst) a ¬p
  graft-iso .Iso.leftInv ( , b) = ΣPathP λ where
    .fst  funExt λ (a , a₀≢a)  elimIsolated-β-no   _ _  b)  a a₀≢a
    .snd  elimIsolated-β-refl   _ _  b) 

graftEquiv : ( : A °)  ((A   .fst  B) × B)  (A  B)
graftEquiv  .fst = graft 
graftEquiv  .snd = isEquiv-graft 

ungraftEquiv : ( : A °)  (A  B)  ((A   .fst  B) × B)
ungraftEquiv  .fst = ungraft 
ungraftEquiv  .snd = isoToIsEquiv $ invIso $ isEquivgraft.graft-iso _ ( .snd)