\begin{code} {-# OPTIONS --safe #-} open import Prelude module HITs.Pushout.Properties {A : Type a} {B : Type b} {C : Type c} {f : A → B} {g : A → C} where open import HITs.Pushout.Base f g open import HITs.Pushout.Eliminators {f = f} {g = g} open import Finite open import Data.List open import Data.List.Membership \end{code} %<*push-paths> \begin{code} Push : List A → B ⊎ C → B ⊎ C → Type- Push [] x y = x ≡ y Push (i ∷ is) (inl x) y = x ≡ f i × Push is (inr (g i)) y Push (i ∷ is) (inr x) y = x ≡ g i × Push is (inl (f i)) y \end{code} %</push-paths> \begin{code} private module BackToExample (i j : A) (x x′ : B) where _ : Push (i ∷ j ∷ []) (inl x) (inl x′) ≡ (x ≡ f i × g i ≡ g j × inl (f j) ≡ inl x′) _ = refl _≈*_ : B ⊎ C → B ⊎ C → Type _ \end{code} %<*push-path-ex> \begin{code} x ≈* y = ∃ p × Push p x y \end{code} %</push-path-ex> \begin{code} refl-≈* : ∀ {x} → x ≈* x refl-≈* = [] , refl trans-≈* : ∀ {x y z} → x ≈* y → y ≈* z → x ≈* z trans-≈* ([] , p) rs = subst (_≈* _) (sym p) rs trans-≈* {x = inl x} (l ∷ ls , p , ps) rs = map-Σ (l ∷_) (p ,_) (trans-≈* (ls , ps) rs) trans-≈* {x = inr x} (l ∷ ls , p , ps) rs = map-Σ (l ∷_) (p ,_) (trans-≈* (ls , ps) rs) sym-≈* : ∀ {x y} → x ≈* y → y ≈* x sym-≈* p = go p refl-≈* where go : ∀ {x y z} → x ≈* y → x ≈* z → y ≈* z go ([] , p) rs = subst (_≈* _) p rs go {x = inl x} (i ∷ is , p , ps) (js , rs) = go (is , ps) (i ∷ js , refl , subst (flip (Push js) _) (cong inl p) rs) go {x = inr x} (i ∷ is , p , ps) (js , rs) = go (is , ps) (i ∷ js , refl , subst (flip (Push js) _) (cong inr p) rs) module PushoutQuot where Pushout′ : Type _ Pushout′ = (B ⊎ C) / λ x y → ∥ x ≈* y ∥ pull-struct : (x y : B ⊎ C) → x ≈* y → pull x ≡ pull y pull-struct x y ([] , ps) = cong pull ps pull-struct (inl x) y (i ∷ is , p , ps) = cong inl p ; push i ; pull-struct _ y (is , ps) pull-struct (inr x) y (i ∷ is , p , ps) = cong inr p ; sym (push i) ; pull-struct _ y (is , ps) Pushout⇔quot : Pushout ⇔ Pushout′ Pushout⇔quot .fun = rec squash/ ([_] ∘ inl) ([_] ∘ inr) λ i → eq/ _ _ ∣ (i ∷ []) , refl , refl ∣ Pushout⇔quot .inv = rec/ trunc (inl ▿ inr) λ x y → ∥rec∥ (trunc _ _) (pull-struct x y) Pushout⇔quot .rightInv = elimProp/ (λ _ → squash/ _ _) (either (λ _ → refl) (λ _ → refl)) Pushout⇔quot .leftInv = elimProp _ (λ _ → trunc _ _) (λ _ → refl) λ _ → refl push-struct : (x y : B ⊎ C) → pull x ≡ pull y → ∥ x ≈* y ∥ push-struct x y p = effective/ (λ _ _ → squash) (record { reflexive = λ _ → ∣ refl-≈* ∣ ; symmetric = λ _ _ → ∥map∥ sym-≈* ; transitive = λ _ _ _ → ∥liftA2∥ trans-≈* }) x y (un-pull x y (cong (Pushout⇔quot .fun) p)) where un-pull : (x y : B ⊎ C) → Pushout⇔quot .fun (pull x) ≡ Pushout⇔quot .fun (pull y) → [ x ] ≡ ([ y ] ⦂ Pushout′) un-pull (inl _) (inl _) p = p un-pull (inl _) (inr _) p = p un-pull (inr _) (inl _) p = p un-pull (inr _) (inr _) p = p open PushoutQuot using (push-struct; pull-struct) public module _ (o : ℰ A) (l : Discrete B) (r : Discrete C) where discA : Discrete A discA = ℰ⇒Discrete o trunc-loopₗ : ∀ {x y} i is → i ∈ is → Push is x y → inl (f i) ≈* y trunc-loopₗ {x = inl x} i (j ∷ is) (zero , i∈is) (p , ps) = j ∷ is , cong f (sym i∈is) , ps trunc-loopₗ {x = inr x} i (j ∷ is) (zero , i∈is) (p , ps) = (is , subst (flip (Push is) _ ∘ inl ∘ f) i∈is ps) trunc-loopₗ {x = inl x} i (j ∷ is) (suc k , i∈is) (p , ps) = trunc-loopₗ i is (k , i∈is) ps trunc-loopₗ {x = inr x} i (j ∷ is) (suc k , i∈is) (p , ps) = trunc-loopₗ i is (k , i∈is) ps trunc-loopₗ-loopless : ∀ {x y} i is → (i∈is : i ∈ is) → (x~y : Push is x y) → NoDup is → NoDup (trunc-loopₗ i is i∈is x~y .fst) trunc-loopₗ-loopless {x = inl x} i (j ∷ is) (zero , i∈is) x~y nd = nd trunc-loopₗ-loopless {x = inr x} i (j ∷ is) (zero , i∈is) x~y nd = snd nd trunc-loopₗ-loopless {x = inl x} i (j ∷ is) (suc k , i∈is) (_ , x~y) (_ , nd) = trunc-loopₗ-loopless i is (k , i∈is) x~y nd trunc-loopₗ-loopless {x = inr x} i (j ∷ is) (suc k , i∈is) (_ , x~y) (_ , nd) = trunc-loopₗ-loopless i is (k , i∈is) x~y nd trunc-loopᵣ : ∀ {x y} i is → i ∈ is → Push is x y → inr (g i) ≈* y trunc-loopᵣ {x = inr x} i (j ∷ is) (zero , i∈is) (p , ps) = j ∷ is , cong g (sym i∈is) , ps trunc-loopᵣ {x = inr x} i (j ∷ is) (suc k , i∈is) (p , ps) = trunc-loopᵣ i is (k , i∈is) ps trunc-loopᵣ {x = inl x} i (j ∷ is) (zero , i∈is) (p , ps) = (is , subst (flip (Push is) _ ∘ inr ∘ g) i∈is ps) trunc-loopᵣ {x = inl x} i (j ∷ is) (suc k , i∈is) (p , ps) = trunc-loopᵣ i is (k , i∈is) ps trunc-loopᵣ-loopless : ∀ {x y} i is → (i∈is : i ∈ is) → (x~y : Push is x y) → NoDup is → NoDup (trunc-loopᵣ i is i∈is x~y .fst) trunc-loopᵣ-loopless {x = inr x} i (j ∷ is) (zero , i∈is) x~y nd = nd trunc-loopᵣ-loopless {x = inl x} i (j ∷ is) (zero , i∈is) x~y nd = snd nd trunc-loopᵣ-loopless {x = inr x} i (j ∷ is) (suc k , i∈is) (_ , x~y) (_ , nd) = trunc-loopᵣ-loopless i is (k , i∈is) x~y nd trunc-loopᵣ-loopless {x = inl x} i (j ∷ is) (suc k , i∈is) (_ , x~y) (_ , nd) = trunc-loopᵣ-loopless i is (k , i∈is) x~y nd Loopless : ∀ {x y} → x ≈* y → Type a \end{code} %<*loopless> \begin{code} Loopless = NoDup ∘ fst \end{code} %</loopless> \begin{code} cons-l : ∀ i {x} → (p : inr (g i) ≈* x) → Loopless p → Σ (inl (f i) ≈* x) Loopless cons-l i (is , pt) ls with find discA i is ... | no i∉is = (i ∷ is , refl , pt) , i∉is , ls ... | yes i∈is = trunc-loopₗ i is i∈is pt , trunc-loopₗ-loopless i is i∈is pt ls cons-r : ∀ i {x} → (p : inl (f i) ≈* x) → Loopless p → Σ (inr (g i) ≈* x) Loopless cons-r i ([] , pt) ls = (i ∷ [] , refl , pt) , (λ ()) , Poly-tt cons-r i (is , pt) ls with find discA i is ... | no i∉is = (i ∷ is , refl , pt) , i∉is , ls ... | yes i∈is = trunc-loopᵣ i is i∈is pt , trunc-loopᵣ-loopless i is i∈is pt ls \end{code} %<*deloop> \begin{code} deloop : ∀ {x y} → x ≈* y → Σ[ p ⦂ x ≈* y ] × Loopless p \end{code} %</deloop> \begin{code} deloop ([] , pt) = ([] , pt) , Poly-tt deloop {x = inl x} (i ∷ is , p , pt) = subst (λ e → Σ (inl e ≈* _) Loopless) (sym p) (uncurry (cons-l i) (deloop (is , pt))) deloop {x = inr x} (i ∷ is , p , pt) = subst (λ e → Σ (inr e ≈* _) Loopless) (sym p) (uncurry (cons-r i) (deloop (is , pt))) ℰPush : ∀ {x y} → (is : List A) → ℰ (Push is x y) ℰPush [] = Discrete⇒ℰ (Discrete-⊎ l r) ℰPush {x = inl x} (i ∷ is) = ℰ× (Discrete⇒ℰ l) (ℰPush is) ℰPush {x = inr x} (i ∷ is) = ℰ× (Discrete⇒ℰ r) (ℰPush is) module _ {x y : B ⊎ C} where ℰLoopless′ : ℰ (Σ[ p ⦂ List A ] × NoDup p × Push p x y) ℰLoopless′ = subst ℰ (isoToPath ⇔-Σ-assoc) (ℰΣ (ℰ⟨List⟩ o) (ℰPush ∘′ fst)) ℰLoopless : ℰ (Σ[ p ⦂ x ≈* y ] × Loopless p) ℰLoopless = subst ℰ (cong (Σ (List A)) (funExt λ is → isoToPath ⇔-Σ-swap) ; sym (isoToPath ⇔-Σ-assoc)) ℰLoopless′ fin-disc-pushout : Discrete Pushout fin-disc-pushout = elimProp2 _ (λ _ _ → isPropDec (trunc _ _)) go where go : (x y : B ⊎ C) → Dec (pull x ≡ pull y) go x y = iff-dec (∥rec∥ (trunc _ _) (pull-struct _ _ ∘ fst) , ∥map∥ deloop ∘ push-struct _ _) (ℰ⇒Dec (ℰLoopless {x = x} {y = y})) \end{code}