module Numeric.Nat.Prime.Properties where

open import Prelude
open import Control.WellFounded
open import Numeric.Nat.Properties
open import Numeric.Nat.Divide
open import Numeric.Nat.Divide.Properties
open import Numeric.Nat.GCD
open import Numeric.Nat.GCD.Extended
open import Numeric.Nat.GCD.Properties
open import Numeric.Nat.Prime
open import Tactic.Nat

prime-nonzero : ∀ {p} → Prime p → NonZero p
prime-nonzero {0} (prime p>1 _) = refute p>1
prime-nonzero {suc _} _ = _

prime-coprime/divide : ∀ p a → Prime p → Either (Coprime p a) (p Divides a)
prime-coprime/divide p a (prime _ isp) with gcd p a
prime-coprime/divide p a (prime _ isp) | gcd-res d isGCD =
  case isp d (IsGCD.d|a isGCD) of λ where
    (left d=1)   → left  d=1
    (right refl) → right (IsGCD.d|b isGCD)

prime-divide-prime : ∀ {p q} → Prime p → Prime q → p Divides q → p ≡ q
prime-divide-prime {p} (prime p>1 _) (prime _ dq) p|q =
  case dq p p|q of λ where
    (left refl) → refute p>1
    (right p=q) → p=q

prime-split : ∀ {p} a b → Prime p → p Divides (a * b) → Either (p Divides a) (p Divides b)
prime-split a b isP p|ab =
  case prime-coprime/divide _ a isP of λ where
    (left p/a)  → right (coprime-divide-mul-l _ a b p/a p|ab)
    (right p|a) → left p|a

-- It's enough to check prime divisors when checking coprimality.
module _ (a b : Nat) (f : ∀ p → Prime p → p Divides a → p Divides b → p Divides 1) where

  private
    coprimeByPrimes′ : (k : Nat) → Acc _<_ k → k Divides a → k Divides b → k Divides 1
    coprimeByPrimes′ k (acc wf) k|a k|b =
      case isPrime k of λ where
        (yes isP) → f k isP k|a k|b
        (no (composite i j i>1 j>1 refl)) →
          let i|1 : i Divides 1
              i|1 = coprimeByPrimes′ i (wf i (less-mul-l i>1 j>1))
                                       (mul-divides-l i j a k|a) (mul-divides-l i j b k|b)
              j|1 : j Divides 1
              j|1 = coprimeByPrimes′ j (wf j (less-mul-r i>1 j>1))
                                       (mul-divides-r i j a k|a) (mul-divides-r i j b k|b)
          in case₂ divides-one i|1 , divides-one j|1 of λ where
               refl refl → factor! 1
        (tiny (diff! 0)) → factor! 1
        (tiny (diff! 1)) →
          case₂ divides-zero k|a , divides-zero k|b of λ where
            refl refl →
              let 2∤1 = fromDec (2 divides? 1)
                  2|0 = fromDec (2 divides? 0) in
              ⊥-elim (2∤1 (f 2 (fromDec (decPrime 2)) 2|0 2|0))
        (tiny (diff (suc (suc _)) eq)) → refute eq

  coprimeByPrimes : Coprime a b
  coprimeByPrimes = coprimeByDivide a b λ k → coprimeByPrimes′ k (wfNat k)

coprime-mul-r : ∀ a b c → Coprime a b → Coprime a c → Coprime a (b * c)
coprime-mul-r a b c a/b a/c =
  coprimeByPrimes a (b * c) λ p isP p|a p|bc →
  case prime-split b c isP p|bc of λ where
    (left  p|b) → divide-coprime p a b a/b p|a p|b
    (right p|c) → divide-coprime p a c a/c p|a p|c

coprime-mul-l : ∀ a b c → Coprime a c → Coprime b c → Coprime (a * b) c
coprime-mul-l a b c a/c b/c =
  coprime-sym c _ (coprime-mul-r c a b (coprime-sym a _ a/c) (coprime-sym b _ b/c))

prime-divide-coprime : ∀ p a b → Prime p → Coprime a b → p Divides a → p Divides b → ⊥
prime-divide-coprime p a b isP a/b p|a p|b =
  case divides-one {p} (divide-coprime p a b a/b p|a p|b) of λ where
    refl → fromDec (decPrime 1) isP


module Cats.Category.Arrow where

open import Level
open import Relation.Binary using (IsEquivalence ; _Preserves₂_⟶_⟶_)

open import Cats.Category

module _ {lo la l≈} (C : Category lo la l≈) where

  infixr 9 _∘_
  infixr 4 _≈_

  private
    module C = Category C
    module ≈ = C.≈

  record Obj : Set (lo ⊔ la) where
    field
      Dom : C.Obj
      Cod : C.Obj
      arr : Dom C.⇒ Cod

  open Obj

  record _⇒_ (f g : Obj) : Set (la ⊔ l≈) where
    field
      dom : Dom f C.⇒ Dom g
      cod : Cod f C.⇒ Cod g
      commute : arr g C.∘ dom C.≈ cod C.∘ arr f

  open _⇒_

  record _≈_ {A B} (F G : A ⇒ B) : Set l≈ where
    field
      dom : dom F C.≈ dom G
      cod : cod F C.≈ cod G

  id : ∀ {A} → A ⇒ A
  id {record { Dom = Dom ; Cod = Cod ; arr = arr }}
      = record
      { dom = C.id
      ; cod = C.id
      ; commute = ≈.trans C.id-r (≈.sym C.id-l)
      }

  _∘_ : ∀ {A B C} → (B ⇒ C) → (A ⇒ B) → (A ⇒ C)
  _∘_ {F} {G} {H}
    record { dom = F-dom ; cod = F-cod ; commute = F-commute }
    record { dom = G-dom ; cod = G-cod ; commute = G-commute }
      = record
      { dom = F-dom C.∘ G-dom
      ; cod = F-cod C.∘ G-cod
      ; commute
          = begin
              arr H C.∘ F-dom C.∘ G-dom
            ≈⟨ C.unassoc ⟩
              (arr H C.∘ F-dom) C.∘ G-dom
            ≈⟨ C.∘-resp-l F-commute ⟩
              (F-cod C.∘ arr G) C.∘ G-dom
            ≈⟨ C.assoc ⟩
              F-cod C.∘ arr G C.∘ G-dom
            ≈⟨ C.∘-resp-r G-commute ⟩
              F-cod C.∘ G-cod C.∘ arr F
            ≈⟨ C.unassoc ⟩
              (F-cod C.∘ G-cod) C.∘ arr F
            ∎
      }
    where
      open C.≈-Reasoning

  equiv : ∀ {A B} → IsEquivalence (_≈_ {A} {B})
  equiv = record
      { refl = record { dom = ≈.refl ; cod = ≈.refl }
      ; sym = λ where
          record { dom = dom ; cod = cod } → record
            { dom = ≈.sym dom
            ; cod = ≈.sym cod
            }
      ; trans = λ where
          record { dom = dom₁ ; cod = cod₁ } record { dom = dom₂ ; cod = cod₂ }
            → record
            { dom = ≈.trans dom₁ dom₂
            ; cod = ≈.trans cod₁ cod₂
            }
      }

  ∘-resp : ∀ {A B C} → (_∘_ {A} {B} {C}) Preserves₂ _≈_ ⟶ _≈_ ⟶ _≈_
  ∘-resp
    record { dom = dom-FG ; cod = cod-FG }
    record { dom = dom-HI ; cod = cod-HI }
      = record
      { dom = C.∘-resp dom-FG dom-HI
      ; cod = C.∘-resp cod-FG cod-HI
      }

  id-r : ∀ {A B} {F : A ⇒ B} → F ∘ id ≈ F
  id-r = record
      { dom = C.id-r
      ; cod = C.id-r
      }

  id-l : ∀ {A B} {F : A ⇒ B} → id ∘ F ≈ F
  id-l = record
      { dom = C.id-l
      ; cod = C.id-l
      }

  assoc : ∀ {A B C D} {F : C ⇒ D} {G : B ⇒ C} {H : A ⇒ B}
    → (F ∘ G) ∘ H ≈ F ∘ (G ∘ H)
  assoc = record
      { dom = C.assoc
      ; cod = C.assoc
      }

  _⃗ : Category (la ⊔ lo) (l≈ ⊔ la) l≈
  _⃗ = record
      { Obj = Obj
      ; _⇒_ = _⇒_
      ; _≈_ = _≈_
      ; id = id
      ; _∘_ = _∘_
      ; equiv = equiv
      ; ∘-resp = ∘-resp
      ; id-r = id-r
      ; id-l = id-l
      ; assoc = assoc
      }


-- Free category over a directed graph/quiver
{-# OPTIONS --safe #-}

module Cubical.Categories.Constructions.Free where

open import Cubical.Categories.Category.Base
open import Cubical.Data.Graph.Base
open import Cubical.Data.Graph.Path
open import Cubical.Foundations.Prelude hiding (Path)

module _ {ℓv ℓe : Level} where

  module _ (G : Graph ℓv ℓe)
          (isSetNode : isSet (Node G))
          (isSetEdge : ∀ v w → isSet (Edge G v w)) where
    open Category

    FreeCategory : Category ℓv (ℓ-max ℓv ℓe)
    FreeCategory .ob = Node G
    FreeCategory .Hom[_,_] = Path G
    FreeCategory .id = pnil
    FreeCategory ._⋆_ = ccat G
    FreeCategory .⋆IdL = pnil++ G
    FreeCategory .⋆IdR P = refl
    FreeCategory .⋆Assoc = ++assoc G
    FreeCategory .isSetHom = isSetPath G isSetNode isSetEdge _ _


open import Relation.Binary.Core

module BBHeap.Insert.Properties {A : Set}
                  (_≤_ : A → A → Set)
                  (tot≤ : Total _≤_)
                  (trans≤ : Transitive _≤_) where

open import BBHeap _≤_
open import BBHeap.Insert _≤_ tot≤ trans≤
open import BBHeap.Subtyping.Properties _≤_ trans≤
open import Bound.Lower A
open import Bound.Lower.Order _≤_
open import Data.List
open import Data.Sum
open import List.Permutation.Base A
open import List.Permutation.Base.Concatenation A
open import List.Permutation.Base.Equivalence A
open import Order.Total _≤_ tot≤

lemma-insert∼ : {b : Bound}{x : A}(b≤x : LeB b (val x))(h : BBHeap b) → (x ∷ flatten h) ∼ (flatten (insert b≤x h))
lemma-insert∼ b≤x leaf = refl∼
lemma-insert∼ {x = x} b≤x (left {x = y} {l = l} {r = r} b≤y l⋘r)
    with tot≤ x y
... | inj₁ x≤y
    with lemma-insert⋘ (lexy refl≤) l⋘r
... | inj₁ lᵢ⋘r
           rewrite lemma-subtyping≡ {val y} {val x} (lexy x≤y) (insert {val y} {y} (lexy refl≤) l)
                     | lemma-subtyping≡ {val y} {val x} (lexy x≤y) r
                     = ∼x /head /head (lemma++∼r (lemma-insert∼ (lexy refl≤) l))
... | inj₂ lᵢ⋗r
           rewrite  lemma-subtyping≡ {val y} {val x} (lexy x≤y) (insert {val y} {y} (lexy refl≤) l)
                      | lemma-subtyping≡ {val y} {val x} (lexy x≤y) r
                      = ∼x /head /head (lemma++∼r (lemma-insert∼ (lexy refl≤) l))
lemma-insert∼ {x = x} b≤x (left {x = y} {l = l} {r = r} b≤y l⋘r) | inj₂ y≤x
    with lemma-insert⋘ (lexy y≤x) l⋘r
... | inj₁ lᵢ⋘r = ∼x (/tail /head) /head (lemma++∼r (lemma-insert∼ (lexy y≤x) l))
... | inj₂ lᵢ⋗r = ∼x (/tail /head) /head (lemma++∼r (lemma-insert∼ (lexy y≤x) l))
lemma-insert∼ {x = x} b≤x (right {x = y} {l = l} {r = r} b≤y l⋙r)
    with tot≤ x y
... | inj₁ x≤y
    with lemma-insert⋙ (lexy refl≤) l⋙r
... | inj₁ l⋙rᵢ
           rewrite lemma-subtyping≡ {val y} {val x} (lexy x≤y) (insert {val y} {y} (lexy refl≤) r)
                     | lemma-subtyping≡ {val y} {val x} (lexy x≤y) l
                     = ∼x /head /head (trans∼ (∼x /head (lemma++/ {xs = flatten l}) refl∼) (lemma++∼l {xs = flatten l} (lemma-insert∼ (lexy refl≤) r)))
... | inj₂ l≃rᵢ
           rewrite lemma-subtyping≡ {val y} {val x} (lexy x≤y) (insert {val y} {y} (lexy refl≤) r)
                     | lemma-subtyping≡ {val y} {val x} (lexy x≤y) l
                     = ∼x /head /head (trans∼ (∼x /head (lemma++/ {xs = flatten l}) refl∼) (lemma++∼l {xs = flatten l} (lemma-insert∼ (lexy refl≤) r)))
lemma-insert∼ {x = x} b≤x (right {x = y} {l = l} {r = r} b≤y l⋙r) | inj₂ y≤x
    with lemma-insert⋙ (lexy y≤x) l⋙r
... | inj₁ l⋙rᵢ = ∼x (/tail /head) /head (trans∼ (∼x /head (lemma++/ {xs = flatten l}) refl∼) (lemma++∼l {xs = flatten l} (lemma-insert∼ (lexy y≤x) r)))
... | inj₂ l≃rᵢ = ∼x (/tail /head) /head (trans∼ (∼x /head (lemma++/ {xs = flatten l}) refl∼) (lemma++∼l {xs = flatten l} (lemma-insert∼ (lexy y≤x) r)))


------------------------------------------------------------------------
-- The Agda standard library
--
-- The basic code for equational reasoning with a partial relation
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

open import Relation.Binary

module Relation.Binary.Reasoning.Base.Partial
  {a ℓ} {A : Set a} (_∼_ : Rel A ℓ) (trans : Transitive _∼_)
  where

open import Level using (_⊔_)
open import Relation.Binary.PropositionalEquality.Core as P
  using (_≡_)

infix  4 _IsRelatedTo_
infix  3 _∎⟨_⟩
infixr 2 step-∼ step-≡ step-≡˘
infixr 2 _≡⟨⟩_
infix  1 begin_

------------------------------------------------------------------------
-- Definition of "related to"

-- This seemingly unnecessary type is used to make it possible to
-- infer arguments even if the underlying equality evaluates.

data _IsRelatedTo_ (x y : A) : Set ℓ where
  relTo : (x∼y : x ∼ y) → x IsRelatedTo y

------------------------------------------------------------------------
-- Reasoning combinators

-- Note that the arguments to the `step`s are not provided in their
-- "natural" order and syntax declarations are later used to re-order
-- them. This is because the `step` ordering allows the type-checker to
-- better infer the middle argument `y` from the `_IsRelatedTo_`
-- argument (see issue 622).
--
-- This has two practical benefits. First it speeds up type-checking by
-- approximately a factor of 5. Secondly it allows the combinators to be
-- used with macros that use reflection, e.g. `Tactic.RingSolver`, where
-- they need to be able to extract `y` using reflection.

-- Beginning of a proof

begin_ : ∀ {x y} → x IsRelatedTo y → x ∼ y
begin relTo x∼y = x∼y

-- Standard step with the relation

step-∼ : ∀ x {y z} → y IsRelatedTo z → x ∼ y → x IsRelatedTo z
step-∼ _ (relTo y∼z) x∼y = relTo (trans x∼y y∼z)

-- Step with a non-trivial propositional equality

step-≡ : ∀ x {y z} → y IsRelatedTo z → x ≡ y → x IsRelatedTo z
step-≡ _ x∼z P.refl = x∼z

-- Step with a flipped non-trivial propositional equality

step-≡˘ : ∀ x {y z} → y IsRelatedTo z → y ≡ x → x IsRelatedTo z
step-≡˘ _ x∼z P.refl = x∼z

-- Step with a trivial propositional equality

_≡⟨⟩_ : ∀ x {y} → x IsRelatedTo y → x IsRelatedTo y
_ ≡⟨⟩ x∼y = x∼y

-- Termination step

_∎⟨_⟩ : ∀ x → x ∼ x → x IsRelatedTo x
_ ∎⟨ x∼x ⟩  = relTo x∼x

-- Syntax declarations

syntax step-∼  x y∼z x∼y = x ∼⟨  x∼y ⟩ y∼z
syntax step-≡  x y≡z x≡y = x ≡⟨  x≡y ⟩ y≡z
syntax step-≡˘ x y≡z y≡x = x ≡˘⟨ y≡x ⟩ y≡z


----------------------------------------------------------------
-- This file contains the definition of isomorphisms.         --
----------------------------------------------------------------
module Category.Iso where

open import Category.Category

record Iso {l : Level}{ℂ : Cat {l}}{A B : Obj ℂ} (f : el (Hom ℂ A B)) : Set l where
  field
    inv : el (Hom ℂ B A)

    left-inv-ax  : ⟨ Hom ℂ A A ⟩[ f ○[ comp ℂ ] inv ≡ id ℂ ]
    right-inv-ax : ⟨ Hom ℂ B B ⟩[ inv ○[ comp ℂ ] f ≡ id ℂ ]

open Iso public


{-# OPTIONS --omega-in-omega --no-termination-check --overlapping-instances #-}

module Light.Library.Relation.Binary where

open import Light.Level using (Setω ; Level)
open import Light.Variable.Levels
open import Light.Variable.Sets
open import Light.Library.Relation using (Base ; Index ; Proposition ; True ; _⇢_)

module _ ⦃ base : Base ⦄ where
      record Binary (𝕒 : Set aℓ) (𝕓 : Set bℓ) : Setω where
            field if : 𝕒 → 𝕓 → Index
            field are : ∀ a b → Proposition (if a b)

      SelfBinary : Set aℓ → Setω
      SelfBinary 𝕒 = Binary 𝕒 𝕒

      open Binary using (are)

      private variable a : 𝕒
      private variable b : 𝕓
      private variable c : 𝕔

      record Transitive
            (a‐b‐valid : Binary 𝕒 𝕓)
            (b‐c‐valid : Binary 𝕓 𝕔)
            (a‐c‐valid : Binary 𝕒 𝕔)
            : Setω where

            field transitivity : True (are a‐b‐valid a b ⇢ (are b‐c‐valid b c ⇢ are a‐c‐valid a c))

      record Symmetric
            (a‐b‐valid : Binary 𝕒 𝕓)
            (b‐a‐valid : Binary 𝕓 𝕒)
            : Setω where

            field symmetry : True (are a‐b‐valid a b ⇢ are b‐a‐valid b a)

      record Reflexive (valid : SelfBinary 𝕒) : Setω where
            field reflexivity : True (are valid a a)

      SelfTransitive : ∀ (valid : SelfBinary 𝕒) → Setω
      SelfTransitive valid = Transitive valid valid valid

      SelfSymmetric : ∀ (valid : SelfBinary 𝕒) → Setω
      SelfSymmetric valid = Symmetric valid valid

      record Preserved
            (f : 𝕒 → 𝕓) (g : 𝕔 → 𝕕)
            (a‐c‐valid : Binary 𝕒 𝕔)
            (b‐d‐valid : Binary 𝕓 𝕕)
            : Setω where

            field preservation : True (are a‐c‐valid a c ⇢ are b‐d‐valid (f a) (g c))
            congruence = preservation

      CongruentFor :
            (𝕒 → 𝕓)
            → SelfBinary 𝕒
            → SelfBinary 𝕓
            → Setω
      CongruentFor f = Preserved f f

      SelfCongruentFor :
            (𝕒 → 𝕒)
            → SelfBinary 𝕒
            → Setω
      SelfCongruentFor f 𝕒 = CongruentFor f 𝕒 𝕒

      record Bijective
            (f : 𝕒 → 𝕓) (g : 𝕔 → 𝕕)
            (b‐d‐valid : Binary 𝕓 𝕕)
            (a‐c‐valid : Binary 𝕒 𝕔)
            : Setω where

            field bijectivity : True (are b‐d‐valid (f a) (g c) ⇢ are a‐c‐valid a c)
            injectivity = bijectivity

      Injective :
            (𝕒 → 𝕓)
            → SelfBinary 𝕓
            → SelfBinary 𝕒
            → Setω
      Injective f = Bijective f f

      SelfInjective :
            (𝕒 → 𝕒)
            → SelfBinary 𝕒
            → Setω
      SelfInjective f 𝕒 = Injective f 𝕒 𝕒

open Transitive ⦃ ... ⦄ public
open Symmetric ⦃ ... ⦄ public
open Reflexive ⦃ ... ⦄ public
open Preserved ⦃ ... ⦄ public
open Bijective ⦃ ... ⦄ public


module Iff where

infix 20 _⇔_
record _⇔_ (A B : Set) : Set where
  field
    to   : A → B
    from : B → A


open import Agda.Primitive using (lzero; lsuc; _⊔_)

open import Relation.Binary.PropositionalEquality
import Relation.Binary.Reasoning.Setoid as SetoidR

import Categories.Category as Category
import Categories.Category.Cartesian as Cartesian
open import Categories.Object.Terminal using (Terminal)
open import Categories.Object.Product using (Product)

open import MultiSorted.AlgebraicTheory
import MultiSorted.Substitution as Substitution
import MultiSorted.Product as Product

module MultiSorted.SyntacticCategory
  {ℓt}
  {𝓈 ℴ}
  {Σ : Signature {𝓈} {ℴ}}
  (T : Theory ℓt Σ) where

  open Theory T
  open Substitution T

  -- The syntactic category

  𝒮 : Category.Category 𝓈 (lsuc ℴ) (lsuc (ℓt ⊔ 𝓈 ⊔ ℴ))
  𝒮 =
    record
      { Obj = Context
      ; _⇒_ = _⇒s_
      ; _≈_ = _≈s_
      ; id =  id-s
      ; _∘_ =  _∘s_
      ; assoc = λ {_ _ _ _ _ _ σ} x → subst-∘s (σ x)
      ; sym-assoc =  λ {_ _ _ _ _ _ σ} x → eq-symm (subst-∘s (σ x))
      ; identityˡ = λ x → eq-refl
      ; identityʳ = λ {A B f} x → tm-var-id
      ; identity² = λ x → eq-refl
      ; equiv = record
                 { refl = λ x → eq-refl
                 ; sym = λ ξ y → eq-symm (ξ y)
                 ; trans = λ ζ ξ y → eq-tran (ζ y) (ξ y)}
      ; ∘-resp-≈ = ∘s-resp-≈s
      }

  -- We use the product structure which gives back the context directly
  prod-𝒮 : Context → Context
  prod-𝒮 Γ = Γ

  π-𝒮 : ∀ {Γ} (x : var Γ) → Γ ⇒s ctx-slot (sort-of Γ x)
  π-𝒮 x _ = tm-var x

  tuple-𝒮 : ∀ Γ {Δ} → (∀ (x : var Γ) → Δ ⇒s ctx-slot (sort-of Γ x)) → Δ ⇒s Γ
  tuple-𝒮 Γ ts = λ x → ts x var-var

  project-𝒮 : ∀ {Γ Δ} {x : var Γ} {ts : ∀ (y : var Γ) → Δ ⇒s ctx-slot (sort-of Γ y)} →
              π-𝒮 x ∘s tuple-𝒮 Γ ts ≈s ts x
  project-𝒮 {Γ} {Δ} {x} {ts} var-var = eq-refl

  unique-𝒮 : ∀ {Γ Δ} {ts : ∀ (x : var Γ) → Δ ⇒s ctx-slot (sort-of Γ x)} {g : Δ ⇒s Γ} →
             (∀ x → π-𝒮 x ∘s g ≈s ts x) → tuple-𝒮 Γ ts ≈s g
  unique-𝒮 ξ x = eq-symm (ξ x var-var)

  producted-𝒮 : Product.Producted 𝒮 {Σ = Σ} ctx-slot
  producted-𝒮 =
    record
      { prod = prod-𝒮
      ; π =  π-𝒮
      ; tuple = tuple-𝒮
      ; project = λ {Γ Δ x ts} → project-𝒮 {ts = ts}
      ; unique = unique-𝒮
      }

  -- The terminal object is the empty context
  ⊤-𝒮 : Context
  ⊤-𝒮 = ctx-empty

  !-𝒮 : ∀ {Γ} → Γ ⇒s ⊤-𝒮
  !-𝒮 ()

  !-unique-𝒮 : ∀ {Γ} (σ : Γ ⇒s ⊤-𝒮) → !-𝒮 ≈s σ
  !-unique-𝒮 σ ()

  terminal-𝒮 : Terminal 𝒮
  terminal-𝒮 =
    record
      { ⊤ = ⊤-𝒮
      ; ⊤-is-terminal =
          record { ! = !-𝒮
                 ; !-unique = !-unique-𝒮 } }

  -- Binary product is context contatenation
  product-𝒮 : ∀ {Γ Δ} → Product 𝒮 Γ Δ
  product-𝒮 {Γ} {Δ} =
    record
      { A×B =  ctx-concat Γ Δ
      ; π₁ = λ x → tm-var (var-inl x)
      ; π₂ = λ x → tm-var (var-inr x)
      ; ⟨_,_⟩ = ⟨_,_⟩s
      ; project₁ = λ x → eq-refl
      ; project₂ = λ x → eq-refl
      ; unique = λ {Θ σ σ₁ σ₂} ξ₁ ξ₂ z → u Θ σ σ₁ σ₂ ξ₁ ξ₂ z
      }
    where u : ∀ Θ (σ : Θ ⇒s ctx-concat Γ Δ) (σ₁ : Θ ⇒s Γ) (σ₂ : Θ ⇒s Δ) →
                  ((λ x → σ (var-inl x)) ≈s σ₁) → ((λ y → σ (var-inr y)) ≈s σ₂) → ⟨ σ₁ , σ₂ ⟩s ≈s σ
          u Θ σ σ₁ σ₂ ξ₁ ξ₂ (var-inl z) = eq-symm (ξ₁ z)
          u Θ σ σ₁ σ₂ ξ₁ ξ₂ (var-inr z) = eq-symm (ξ₂ z)

  -- The cartesian structure of the syntactic category
  cartesian-𝒮 : Cartesian.Cartesian 𝒮
  cartesian-𝒮 =
    record
      { terminal = terminal-𝒮
      ; products = record { product = product-𝒮 } }


{-# OPTIONS --cubical --safe --no-sized-types --no-guardedness #-}
module Agda.Builtin.Cubical.Path where

  open import Agda.Primitive.Cubical

  postulate
    PathP : ∀ {ℓ} (A : I → Set ℓ) → A i0 → A i1 → Set ℓ

  {-# BUILTIN PATHP        PathP     #-}

  infix 4 _≡_
  _≡_ : ∀ {ℓ} {A : Set ℓ} → A → A → Set ℓ
  _≡_ {A = A} = PathP (λ _ → A)

  {-# BUILTIN PATH         _≡_     #-}


{-# OPTIONS --without-K --safe #-}

open import Categories.Category using (Category; module Commutation)
open import Categories.Category.Monoidal.Core using (Monoidal)
open import Categories.Category.Monoidal.Braided using (Braided)

-- Braided monoidal categories satisfy the "four middle interchange"

module Categories.Category.Monoidal.Interchange.Braided
  {o ℓ e} {C : Category o ℓ e} {M : Monoidal C} (B : Braided M) where

open import Level using (_⊔_)
open import Data.Product using (_,_)

import Categories.Category.Construction.Core C as Core
import Categories.Category.Monoidal.Construction.Product as MonoidalProduct
open import Categories.Category.Monoidal.Braided.Properties as BraidedProps
  using (braiding-coherence; inv-Braided; inv-braiding-coherence)
open import Categories.Category.Monoidal.Interchange using (HasInterchange)
open import Categories.Category.Monoidal.Properties using (module Kelly's)
import Categories.Category.Monoidal.Reasoning as MonoidalReasoning
import Categories.Category.Monoidal.Utilities as MonoidalUtilities
open import Categories.Category.Product using (_⁂_; assocˡ)
open import Categories.Functor using (_∘F_)
open import Categories.NaturalTransformation.NaturalIsomorphism
  using (_≃_; niHelper)
open import Categories.Morphism.Reasoning C

open Category C
open Commutation C

private
  variable
    W W₁ W₂ X X₁ X₂ Y Y₁ Y₂ Z Z₁ Z₂ : Obj
    f g h i : X ⇒ Y

-- Braided monoidal categories have an interchange map.

open MonoidalReasoning M
open MonoidalUtilities M
open Braided B renaming (associator to α)
open Core.Shorthands            -- for idᵢ, _∘ᵢ_, ...
open Shorthands                 -- for λ⇒, ρ⇒, α⇒, ...
open BraidedProps.Shorthands B  -- for σ⇒, ...

-- The "four middle interchange" for braided tensor products.

swapInner : (W ⊗₀ X) ⊗₀ (Y ⊗₀ Z) ≅ (W ⊗₀ Y) ⊗₀ (X ⊗₀ Z)
swapInner = α ⁻¹ ∘ᵢ idᵢ ⊗ᵢ (α ∘ᵢ σ ⊗ᵢ idᵢ ∘ᵢ α ⁻¹) ∘ᵢ α

module swapInner {W X Y Z} = _≅_ (swapInner {W} {X} {Y} {Z})
private
  i⇒ = swapInner.from
  i⇐ = swapInner.to

-- to shorten things, it is convenient to name some items that recur
-- swapˡ is the inner part of 'swapInner'
private
  swapˡ : X ⊗₀ (Y ⊗₀ Z) ⇒ Y ⊗₀ (X ⊗₀ Z)
  swapˡ = α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐

  swapˡ-act :  swapˡ ∘ g ⊗₁ (h ⊗₁ i) ≈ h ⊗₁ (g ⊗₁ i) ∘ swapˡ
  swapˡ-act {g = g} {h = h} {i = i} = begin
    (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ g ⊗₁ (h ⊗₁ i)    ≈⟨ pullʳ (pullʳ assoc-commute-to) ⟩
    α⇒ ∘ σ⇒ ⊗₁ id ∘ (g ⊗₁ h) ⊗₁ i ∘ α⇐      ≈⟨ refl⟩∘⟨ extendʳ (parallel (braiding.⇒.commute _) id-comm-sym) ⟩
    α⇒ ∘ (h ⊗₁ g) ⊗₁ i ∘ σ⇒ ⊗₁ id ∘ α⇐      ≈⟨ extendʳ assoc-commute-from ⟩
    h ⊗₁ (g ⊗₁ i) ∘ α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐      ∎

swapInner-natural : i⇒ ∘ (f ⊗₁ g) ⊗₁ (h ⊗₁ i) ≈ (f ⊗₁ h) ⊗₁ (g ⊗₁ i) ∘ i⇒
swapInner-natural {f = f} {g = g} {h = h} {i = i} = begin
    (α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒) ∘ (f ⊗₁ g) ⊗₁ (h ⊗₁ i)  ≈⟨ pullʳ (pullʳ assoc-commute-from) ⟩
    α⇐ ∘ id ⊗₁ swapˡ ∘ f ⊗₁ g ⊗₁ (h ⊗₁ i) ∘ α⇒      ≈⟨ refl⟩∘⟨ extendʳ (parallel id-comm-sym swapˡ-act) ⟩
    α⇐ ∘ f ⊗₁ h ⊗₁ (g ⊗₁ i) ∘ id ⊗₁ swapˡ ∘ α⇒      ≈⟨ extendʳ assoc-commute-to ⟩
    (f ⊗₁ h) ⊗₁ (g ⊗₁ i) ∘ α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒    ∎

swapInner-naturalIsomorphism : ⊗ ∘F (⊗ ⁂ ⊗) ≃ ⊗ ∘F MonoidalProduct.⊗ M M
swapInner-naturalIsomorphism = niHelper (record
  { η       = λ _ → i⇒
  ; η⁻¹     = λ _ → i⇐
  ; commute = λ _ → swapInner-natural
  ; iso     = λ _ → swapInner.iso
  })

-- Another version of the interchange that associates differently.
--
-- Why are there two versions and what's the difference? The domain
-- (X₁ ⊗ X₂) ⊗₀ (Y₁ ⊗ Y₂) and codomain (X₁ ⊗ Y₁) ⊗₀ (X₁ ⊗ Y₂) of the
-- interchange map are perfectly symmetric/balanced. But in order to
-- apply the braiding to the middle X₂ and Y₁, we need to
-- re-associate and that breaks the symmetry. We must first
-- re-associate the whole expression in one direction and then the
-- larger subterm in the other. This can be done in two ways,
-- associate to the right first, then to the left, resulting in X₁ ⊗
-- ((Y₂ ⊗₀ X₁) ⊗ Y₂), or vice versa, resulting in (X₁ ⊗ (Y₂ ⊗₀ X₁))
-- ⊗ Y₂. The choice is arbitrary and results in two distinct
-- interchange maps that behave the same way (as witnessed by
-- swapInner-coherent below).
--
-- Why define both? Because the proofs of some coherence laws become
-- easier when the core of the expression is associated in one
-- direction vs. the other. For example swapInner-unitˡ is easier to
-- prove for the second definition, while swapInner-unitʳ is easier
-- to prove for the first; swapInner-assoc uses both.

swapInner′ : (W ⊗₀ X) ⊗₀ (Y ⊗₀ Z) ≅ (W ⊗₀ Y) ⊗₀ (X ⊗₀ Z)
swapInner′ = α ∘ᵢ (α ⁻¹ ∘ᵢ idᵢ ⊗ᵢ σ ∘ᵢ α) ⊗ᵢ idᵢ ∘ᵢ α ⁻¹

module swapInner′ {W X Y Z} = _≅_ (swapInner′ {W} {X} {Y} {Z})
private
  j⇒ = swapInner′.from
  j⇐ = swapInner′.to

  swapʳ : (X ⊗₀ Y) ⊗₀ Z ⇒ (X ⊗₀ Z) ⊗₀ Y
  swapʳ = α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒

-- Derived coherence laws.

swapInner-coherent : [ (X₁ ⊗₀ X₂) ⊗₀ (Y₁ ⊗₀ Y₂) ⇒ (X₁ ⊗₀ Y₁) ⊗₀ (X₂ ⊗₀ Y₂) ]⟨
                       i⇒
                     ≈ j⇒
                     ⟩
swapInner-coherent = begin
    α⇐ ∘ id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒                       ≈⟨ refl⟩∘⟨ pushˡ split₂ˡ ⟩
    α⇐ ∘ id ⊗₁ α⇒ ∘ id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒                 ≈⟨ refl⟩∘⟨ refl⟩∘⟨ pushˡ split₂ˡ ⟩
    α⇐ ∘ id ⊗₁ α⇒ ∘ id ⊗₁ (σ⇒ ⊗₁ id) ∘ id ⊗₁ α⇐ ∘ α⇒          ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ conjugate-from α (idᵢ ⊗ᵢ α) (⟺ pentagon) ⟩
    α⇐ ∘ id ⊗₁ α⇒ ∘ id ⊗₁ (σ⇒ ⊗₁ id) ∘ (α⇒ ∘ α⇒ ⊗₁ id) ∘ α⇐   ≈˘⟨ pullʳ (pullʳ (extendʳ (pushˡ assoc-commute-from))) ⟩
    (α⇐ ∘ id ⊗₁ α⇒ ∘ α⇒ ∘ (id ⊗₁ σ⇒) ⊗₁ id) ∘ α⇒ ⊗₁ id ∘ α⇐   ≈⟨ pushʳ sym-assoc ⟩∘⟨refl ⟩
    ((α⇐ ∘ id ⊗₁ α⇒ ∘ α⇒) ∘ (id ⊗₁ σ⇒) ⊗₁ id) ∘ α⇒ ⊗₁ id ∘ α⇐ ≈⟨ pushˡ (conjugate-from (α ⊗ᵢ idᵢ) α (assoc ○ pentagon)) ⟩∘⟨refl ⟩
    (α⇒ ∘ α⇐ ⊗₁ id ∘ (id ⊗₁ σ⇒) ⊗₁ id) ∘ α⇒ ⊗₁ id ∘ α⇐         ≈˘⟨ pushʳ (pushʳ (pushˡ split₁ˡ)) ⟩
    α⇒ ∘ α⇐ ⊗₁ id ∘ (id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐                 ≈˘⟨ refl⟩∘⟨ pushˡ split₁ˡ ⟩
    α⇒ ∘ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐                       ∎

private
  α-mid : ∀ {X} {Y} {Z} {W} → X ⊗₀ ((Y ⊗₀ Z) ⊗₀ W) ⇒ (X ⊗₀ Y) ⊗₀ (Z ⊗₀ W)
  α-mid = α⇒ ∘ α⇐ ⊗₁ id ∘ α⇐

private
  serialize-assoc : α⇒ {X₁} {Y₁} {Z₁} ⊗₁ α⇒ {X₂} {Y₂} {Z₂} ≈ id ⊗₁ α⇒ ∘ α⇐ ∘ id ⊗₁ (α⇒ ∘ α⇐ ⊗₁ id ∘ α⇐) ∘ α⇒ ∘ id ⊗₁ α⇐ ∘ α⇒
  serialize-assoc = begin
    α⇒ ⊗₁ α⇒                                           ≈⟨ serialize₂₁ ⟩
    id ⊗₁ α⇒ ∘ α⇒ ⊗₁ id                                ≈⟨ refl⟩∘⟨ (begin
      α⇒ ⊗₁ id                                             ≈⟨ switch-fromtoˡ α (switch-fromtoˡ (idᵢ ⊗ᵢ α) pentagon) ⟩
      α⇐ ∘ id ⊗₁ α⇐ ∘ α⇒ ∘ α⇒                             ≈˘⟨ refl⟩∘⟨ refl⟩⊗⟨ cancelˡ α.isoʳ ⟩∘⟨refl ⟩
      α⇐ ∘ id ⊗₁ (α⇒ ∘ α⇐ ∘ α⇐) ∘ α⇒ ∘ α⇒                 ≈˘⟨ refl⟩∘⟨ refl⟩⊗⟨ pullʳ pentagon-inv ⟩∘⟨refl ⟩
      α⇐ ∘ id ⊗₁ (α-mid ∘ id ⊗₁ α⇐) ∘ α⇒ ∘ α⇒             ≈⟨ refl⟩∘⟨ pushˡ split₂ˡ ⟩
      α⇐ ∘ id ⊗₁ α-mid ∘ id ⊗₁ (id ⊗₁ α⇐) ∘ α⇒ ∘ α⇒       ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ extendʳ assoc-commute-from ⟩
      α⇐ ∘ id ⊗₁ α-mid ∘ α⇒ ∘ (id ⊗₁ id) ⊗₁ α⇐ ∘ α⇒       ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ ⊗.identity ⟩⊗⟨refl ⟩∘⟨refl ⟩
      α⇐ ∘ id ⊗₁ α-mid ∘ α⇒ ∘ id ⊗₁ α⇐ ∘ α⇒               ∎) ⟩
    id ⊗₁ α⇒ ∘ α⇐ ∘ id ⊗₁ α-mid ∘ α⇒ ∘ id ⊗₁ α⇐ ∘ α⇒  ∎

swapInner-assoc : [ ((X₁ ⊗₀ X₂) ⊗₀ (Y₁ ⊗₀ Y₂)) ⊗₀ (Z₁ ⊗₀ Z₂) ⇒
                    (X₁ ⊗₀ (Y₁ ⊗₀ Z₁)) ⊗₀ (X₂ ⊗₀ (Y₂ ⊗₀ Z₂)) ]⟨
                    i⇒ ⊗₁ id    ⇒⟨ ((X₁ ⊗₀ Y₁) ⊗₀ (X₂ ⊗₀ Y₂)) ⊗₀ (Z₁ ⊗₀ Z₂) ⟩
                    i⇒          ⇒⟨ ((X₁ ⊗₀ Y₁) ⊗₀ Z₁) ⊗₀ ((X₂ ⊗₀ Y₂) ⊗₀ Z₂) ⟩
                    α⇒ ⊗₁ α⇒
                  ≈ α⇒          ⇒⟨ (X₁ ⊗₀ X₂) ⊗₀ ((Y₁ ⊗₀ Y₂) ⊗₀ (Z₁ ⊗₀ Z₂)) ⟩
                    id ⊗₁ i⇒    ⇒⟨ (X₁ ⊗₀ X₂) ⊗₀ ((Y₁ ⊗₀ Z₁) ⊗₀ (Y₂ ⊗₀ Z₂)) ⟩
                    i⇒
                  ⟩
swapInner-assoc = begin
    α⇒ ⊗₁ α⇒ ∘ i⇒ ∘ i⇒ ⊗₁ id                                   ≈⟨ serialize-assoc ⟩∘⟨refl ⟩
    (id ⊗₁ α⇒ ∘ α⇐ ∘ id ⊗₁ α-mid ∘ α⇒ ∘ id ⊗₁ α⇐ ∘ α⇒) ∘ i⇒ ∘ i⇒ ⊗₁ id  ≈˘⟨ pullˡ (pushˡ (⊗.identity ⟩⊗⟨refl ⟩∘⟨refl)) ⟩
    ((id ⊗₁ id) ⊗₁ α⇒ ∘ α⇐) ∘ (id ⊗₁ α-mid ∘ α⇒ ∘ id ⊗₁ α⇐ ∘ α⇒) ∘ i⇒ ∘ i⇒ ⊗₁ id
                                                                  ≈⟨ ⟺ assoc-commute-to ⟩∘⟨ pullʳ (pullʳ (pushʳ (pushˡ (pushʳ (pushˡ split₂ˡ))))) ⟩
    (α⇐ ∘ id ⊗₁ (id ⊗₁ α⇒)) ∘ id ⊗₁ α-mid ∘ α⇒ ∘
    ((id ⊗₁ α⇐ ∘ α⇒) ∘ α⇐ ∘ id ⊗₁ α⇒) ∘
    (id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ∘ i⇒ ⊗₁ id
                                                                  ≈⟨ pullʳ (refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ elimˡ (_≅_.isoˡ (α ⁻¹ ∘ᵢ idᵢ ⊗ᵢ α))) ⟩
    α⇐ ∘ id ⊗₁ (id ⊗₁ α⇒) ∘ id ⊗₁ α-mid ∘ α⇒ ∘
    (id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ∘
    i⇒ ⊗₁ id
                                                                  ≈⟨ refl⟩∘⟨ merge₂ sym-assoc ⟩∘⟨ pushʳ ((⟺ ⊗.identity ⟩⊗⟨refl) ⟩∘⟨refl ⟩∘⟨ split₁ˡ) ⟩
    α⇐ ∘ id ⊗₁ ((id ⊗₁ α⇒ ∘ α⇒) ∘ α⇐ ⊗₁ id ∘ α⇐) ∘
    (α⇒ ∘ (id ⊗₁ id) ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ∘
    α⇐ ⊗₁ id ∘ (id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ⊗₁ id
                                                                  ≈⟨ refl⟩∘⟨ refl⟩⊗⟨
                                                                       extendʳ (pushˡ (switch-fromtoʳ (α ⊗ᵢ idᵢ) (assoc ○ pentagon))) ⟩∘⟨
                                                                       extendʳ assoc-commute-from ⟩∘⟨refl ⟩
    α⇐ ∘ id ⊗₁ ((α⇒ ∘ α⇒) ∘ (α⇐ ⊗₁ id ∘ α⇐ ⊗₁ id) ∘ α⇐) ∘
    (id ⊗₁ (id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐)) ∘ (α⇒ ∘ α⇒)) ∘ α⇐ ⊗₁ id ∘
    (id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ⊗₁ id
                                                                  ≈˘⟨ refl⟩∘⟨ refl⟩⊗⟨ pushʳ (refl⟩∘⟨ split₁ˡ ⟩∘⟨refl) ⟩∘⟨
                                                                       pushʳ (extendʳ (switch-fromtoʳ (α ⊗ᵢ idᵢ) (assoc ○ pentagon))) ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘ α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐) ∘
    id ⊗₁ (id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐)) ∘ id ⊗₁ α⇒ ∘ α⇒ ∘
    (id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ⊗₁ id
                                                                  ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ split₁ˡ ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘ α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐) ∘
    id ⊗₁ (id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐)) ∘ id ⊗₁ α⇒ ∘ α⇒ ∘
    (id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐)) ⊗₁ id ∘ α⇒ ⊗₁ id
                                                                  ≈⟨ refl⟩∘⟨ merge₂ assoc²' ○ (refl⟩∘⟨ refl⟩∘⟨ assoc) ⟩∘⟨
                                                                       refl⟩∘⟨ extendʳ assoc-commute-from ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘ α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐)) ∘
    id ⊗₁ α⇒ ∘
    id ⊗₁ ((α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id) ∘ α⇒ ∘ α⇒ ⊗₁ id
                                                                  ≈⟨ refl⟩∘⟨ merge₂ (assoc²' ○ (refl⟩∘⟨ refl⟩∘⟨ assoc²')) ⟩∘⟨
                                                                       refl⟩∘⟨ switch-fromtoˡ (idᵢ ⊗ᵢ α) pentagon ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘ α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ∘
    id ⊗₁ ((α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id) ∘ id ⊗₁ α⇐ ∘ α⇒ ∘ α⇒
                                                                  ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ pushˡ split₂ˡ ⟩
    α⇐ ∘ id ⊗₁
      (α⇒ ∘ α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒) ∘
    id ⊗₁ ((α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐) ∘ α⇒ ∘ α⇒
                                                                  ≈⟨ refl⟩∘⟨ merge₂ assoc²' ○ (refl⟩∘⟨ refl⟩∘⟨ (assoc²' ○
                                                                      (refl⟩∘⟨ refl⟩∘⟨ assoc))) ⟩∘⟨ Equiv.refl ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘
      α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒ ∘
      (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐) ∘ α⇒ ∘ α⇒
                                                                  ≈⟨ refl⟩∘⟨ refl⟩⊗⟨ pushʳ (begin
      α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒ ∘
      (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐
                                                                  ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ extendʳ (pushˡ split₂ˡ) ⟩
      α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (σ⇒ ⊗₁ id) ∘ (id ⊗₁ α⇐ ∘ α⇒) ∘
      (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐
                                                                  ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (extendʳ assoc-commute-to ○ (refl⟩∘⟨ sym-assoc)) ⟩
      α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ (id ⊗₁ σ⇒) ⊗₁ id ∘ (α⇐ ∘ (id ⊗₁ α⇐ ∘ α⇒)) ∘
      (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐
                                                                  ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ (sym-assoc ○
                                                                         (conjugate-to α (α ⊗ᵢ idᵢ) (sym-assoc ○ pentagon-inv))) ⟩∘⟨refl ⟩
      α⇒ ∘ (α⇐ ∘ α⇐) ⊗₁ id ∘ (id ⊗₁ σ⇒) ⊗₁ id ∘ (α⇒ ⊗₁ id ∘ α⇐) ∘
      (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐
                                                                  ≈˘⟨ refl⟩∘⟨ split₁ Equiv.refl ⟩∘⟨
                                                                          pushʳ (refl⟩∘⟨ refl⟩⊗⟨ ⊗.identity ⟩∘⟨refl) ⟩
      α⇒ ∘ ((α⇐ ∘ α⇐) ∘ id ⊗₁ σ⇒) ⊗₁ id ∘ α⇒ ⊗₁ id ∘ α⇐ ∘
      (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ (id ⊗₁ id) ∘ α⇐
                                                                  ≈⟨ refl⟩∘⟨ merge₁ assoc² ⟩∘⟨ extendʳ assoc-commute-to ⟩
      α⇒ ∘ (α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘
      ((α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id) ⊗₁ id ∘ α⇐ ∘ α⇐
                                                                  ≈˘⟨ refl⟩∘⟨ pushˡ split₁ˡ ⟩
      α⇒ ∘ ((α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ∘ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id) ⊗₁ id ∘
      α⇐ ∘ α⇐
                                                                  ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ (sym-assoc ○ pentagon-inv) ⟩
      α⇒ ∘ ((α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ∘ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id) ⊗₁ id ∘
      α⇐ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇐
                                                                  ≈⟨ refl⟩∘⟨ pullˡ (⟺ split₁ˡ ○ (assoc ⟩⊗⟨refl)) ⟩
      α⇒ ∘
      ((α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ∘ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐) ⊗₁ id ∘
      α⇐ ∘ id ⊗₁ α⇐
                                                                  ≈⟨ refl⟩∘⟨ (begin
        (α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ∘ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐            ≈⟨ pushˡ (pushʳ sym-assoc) ⟩
        (α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒) ∘ α⇒ ∘ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐            ≈⟨ (refl⟩∘⟨ extendʳ (pushʳ split₁ˡ)) ⟩
        (α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒) ∘ (α⇒ ∘ α⇒ ⊗₁ id) ∘ (σ⇒ ⊗₁ id ∘ α⇐) ⊗₁ id ∘ α⇐    ≈⟨ pushʳ (switch-fromtoˡ (idᵢ ⊗ᵢ α) pentagon ⟩∘⟨ pushˡ split₁ˡ) ⟩
        ((α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒) ∘ (id ⊗₁ α⇐ ∘ α⇒ ∘ α⇒)) ∘
        (σ⇒ ⊗₁ id) ⊗₁ id ∘ α⇐ ⊗₁ id ∘ α⇐                                         ≈⟨ pushˡ (sym-assoc ○ (pullˡ (pullʳ assoc ⟩∘⟨refl))) ⟩
        ((α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ id ⊗₁ α⇐) ∘ α⇒) ∘
        α⇒ ∘ (σ⇒ ⊗₁ id) ⊗₁ id ∘ α⇐ ⊗₁ id ∘ α⇐                                   ≈⟨ pullʳ (refl⟩∘⟨ extendʳ assoc-commute-from) ⟩
        (α⇐ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ id ⊗₁ α⇐) ∘ α⇒ ∘
        σ⇒ ⊗₁ (id ⊗₁ id) ∘ α⇒ ∘ α⇐ ⊗₁ id ∘ α⇐                                   ≈⟨ (refl⟩∘⟨ refl⟩∘⟨ ⟺ split₂ˡ) ⟩∘⟨ refl⟩∘⟨ (refl⟩⊗⟨ ⊗.identity ⟩∘⟨
           conjugate-from (idᵢ ⊗ᵢ (α ⁻¹)) (α ⁻¹) pentagon-inv) ⟩
        (α⇐ ∘ α⇐ ∘ id ⊗₁ (σ⇒ ∘ α⇐)) ∘ α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒            ≈˘⟨ extendʳ (sym-assoc ○ pentagon-inv) ⟩∘⟨refl ⟩
        (α⇐ ⊗₁ id ∘ (α⇐ ∘ id ⊗₁ α⇐) ∘ id ⊗₁ (σ⇒ ∘ α⇐)) ∘
        α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                                           ≈˘⟨ (refl⟩∘⟨ pushʳ split₂ˡ) ⟩∘⟨refl ⟩
        (α⇐ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (α⇐ ∘ σ⇒ ∘ α⇐)) ∘
        α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                                           ≈˘⟨ pushˡ ((refl⟩∘⟨ refl⟩∘⟨ refl⟩⊗⟨ (sym-assoc ○ hexagon₂ ○ assoc)) ⟩∘⟨refl) ⟩
        ((α⇐ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ σ⇒)) ∘ α⇒) ∘
        σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                                                ≈⟨ pushˡ (pushʳ (pushʳ split₂ˡ)) ⟩∘⟨refl ⟩
        ((α⇐ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ σ⇒ ⊗₁ id) ∘ id ⊗₁ (α⇐ ∘ id ⊗₁ σ⇒) ∘ α⇒) ∘
        σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                                                ≈⟨ pushʳ (pushˡ split₂ˡ) ⟩∘⟨refl ⟩
        (((α⇐ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ σ⇒ ⊗₁ id) ∘ id ⊗₁ α⇐) ∘
          id ⊗₁ id ⊗₁ σ⇒ ∘ α⇒) ∘ σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                      ≈⟨ ((pushˡ (pushʳ assoc-commute-to) ⟩∘⟨
                                                                                ⟺ assoc-commute-from) ○ (pullʳ sym-assoc)) ⟩∘⟨refl ⟩
        ((α⇐ ⊗₁ id ∘ (id ⊗₁ σ⇒) ⊗₁ id) ∘ ((α⇐ ∘ id ⊗₁ α⇐) ∘ α⇒) ∘
          (id ⊗₁ id) ⊗₁ σ⇒) ∘ σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                         ≈⟨ pullˡ (⟺ split₁ˡ ⟩∘⟨
                                                                                conjugate-from α (idᵢ ⊗ᵢ α ∘ᵢ α) (⟺ (assoc ○ pentagon)))
                                                                                ⟩∘⟨refl ⟩
        (((α⇐ ∘ id ⊗₁ σ⇒) ⊗₁ id ∘ α⇒ ⊗₁ id ∘ α⇐) ∘ (id ⊗₁ id) ⊗₁ σ⇒) ∘
        σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                                                ≈⟨ (pullˡ (⟺ split₁ˡ) ⟩∘⟨ ⊗.identity ⟩⊗⟨refl) ⟩∘⟨refl ⟩
        ((((α⇐ ∘ id ⊗₁ σ⇒) ∘ α⇒) ⊗₁ id ∘ α⇐) ∘ id ⊗₁ σ⇒) ∘
        σ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇒                                                ≈⟨ extend² (⟺ serialize₂₁ ○ serialize₁₂) ⟩
        ((((α⇐ ∘ id ⊗₁ σ⇒) ∘ α⇒) ⊗₁ id ∘ α⇐) ∘ σ⇒ ⊗₁ id) ∘
        id ⊗₁ σ⇒ ∘ α⇐ ∘ id ⊗₁ α⇒                                                ≈˘⟨ pushʳ (refl⟩∘⟨ refl⟩⊗⟨ ⊗.identity) ⟩∘⟨ ⊗.identity ⟩⊗⟨refl ⟩∘⟨refl ⟩
        (((α⇐ ∘ id ⊗₁ σ⇒) ∘ α⇒) ⊗₁ id ∘ α⇐ ∘ σ⇒ ⊗₁ id ⊗₁ id) ∘
        (id ⊗₁ id) ⊗₁ σ⇒ ∘ α⇐ ∘ id ⊗₁ α⇒                                        ≈⟨ pushʳ assoc-commute-to ⟩∘⟨ extendʳ (⟺ assoc-commute-to) ⟩
        ((((α⇐ ∘ id ⊗₁ σ⇒) ∘ α⇒) ⊗₁ id ∘ (σ⇒ ⊗₁ id) ⊗₁ id) ∘ α⇐) ∘
        α⇐ ∘ id ⊗₁ id ⊗₁ σ⇒ ∘ id ⊗₁ α⇒                                          ≈˘⟨ ((sym-assoc ○ sym-assoc) ⟩⊗⟨refl ○ split₁ˡ) ⟩∘⟨refl ⟩∘⟨ refl⟩∘⟨ split₂ˡ ⟩
        (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ⊗₁ id) ∘ α⇐) ∘
        α⇐ ∘ id ⊗₁ (id ⊗₁ σ⇒ ∘ α⇒)                                              ≈˘⟨ extend² (sym-assoc ○ pentagon-inv) ⟩
        (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ⊗₁ id) ∘ α⇐ ⊗₁ id) ∘
        (α⇐ ∘ id ⊗₁ α⇐) ∘ id ⊗₁ (id ⊗₁ σ⇒ ∘ α⇒)                                ≈˘⟨ split₁ˡ ⟩∘⟨ pushʳ split₂ˡ ⟩
        ((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ id ∘
        α⇐ ∘ id ⊗₁ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒)                                         ∎) ⟩⊗⟨refl ⟩∘⟨refl ⟩
      α⇒ ∘ (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ id ∘ α⇐ ∘
        id ⊗₁ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒)) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇐               ≈⟨ (refl⟩∘⟨ pushˡ ((sym-assoc ⟩⊗⟨refl) ○ split₁ˡ)) ⟩
      α⇒ ∘ (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ id ∘ α⇐) ⊗₁ id ∘
      (id ⊗₁ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒)) ⊗₁ id ∘ α⇐ ∘ id ⊗₁ α⇐                ≈⟨ (refl⟩∘⟨ split₁ˡ ⟩∘⟨ extendʳ (⟺ assoc-commute-to)) ○ pushʳ assoc ⟩
      (α⇒ ∘ (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ id) ⊗₁ id) ∘
      α⇐ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ id ⊗₁ α⇐      ≈⟨ pushˡ assoc-commute-from ⟩
      ((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ (id ⊗₁ id) ∘ α⇒ ∘
      α⇐ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ id ⊗₁ α⇐      ≈˘⟨ refl⟩∘⟨ pullʳ (pullʳ (refl⟩∘⟨ split₂ˡ)) ⟩
      ((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ (id ⊗₁ id) ∘
      (α⇒ ∘ α⇐ ⊗₁ id ∘ α⇐) ∘ id ⊗₁ ((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐)   ≈˘⟨ pullʳ (pullˡ (conjugate-from (α ∘ᵢ α ⊗ᵢ idᵢ) α pentagon)) ⟩
      (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ (id ⊗₁ id) ∘ α⇐) ∘
      id ⊗₁ α⇒ ∘ id ⊗₁ ((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐)                ≈⟨ refl⟩⊗⟨ ⊗.identity ⟩∘⟨refl ⟩∘⟨ ⟺ split₂ˡ ⟩
      (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ id ∘ α⇐) ∘
      id ⊗₁ (α⇒ ∘ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐)                      ≡⟨⟩
      (((α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐) ⊗₁ id ∘ α⇐) ∘ id ⊗₁ j⇒   ≈˘⟨ switch-fromtoʳ α (switch-fromtoˡ α (⟺ hexagon₁))
                                                                                ⟩⊗⟨refl ⟩∘⟨refl ⟩∘⟨refl ⟩
      (σ⇒ ⊗₁ id ∘ α⇐) ∘ id ⊗₁ j⇒
    ∎) ⟩∘⟨refl ⟩
    α⇐ ∘ id ⊗₁ ((α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ id ⊗₁ j⇒) ∘ α⇒ ∘ α⇒       ≈⟨ refl⟩∘⟨ pushˡ split₂ˡ ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ id ⊗₁ id ⊗₁ j⇒ ∘ α⇒ ∘ α⇒   ≈˘⟨ pullʳ (pullʳ (extendʳ assoc-commute-from)) ⟩
    (α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒) ∘ (id ⊗₁ id) ⊗₁ j⇒ ∘ α⇒               ≡⟨⟩
    i⇒ ∘ (id ⊗₁ id) ⊗₁ j⇒ ∘ α⇒                                     ≈⟨ refl⟩∘⟨ ⊗.identity ⟩⊗⟨ ⟺ swapInner-coherent ⟩∘⟨refl ⟩
    i⇒ ∘ id ⊗₁ i⇒ ∘ α⇒
  ∎

private
  mid-1-elim-coh : [ X ⊗₀ (unit ⊗₀ Y) ⇒ X ⊗₀ Y ]⟨ λ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐ ≈ id ⊗₁ λ⇒ ⟩
  mid-1-elim-coh = begin
    λ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐  ≈⟨ pullˡ (Kelly's.coherence₁ M) ⟩
    λ⇒ ⊗₁ id ∘ σ⇒ ⊗₁ id ∘ α⇐ ≈˘⟨  pushˡ split₁ˡ ⟩
    (λ⇒ ∘ σ⇒) ⊗₁ id ∘ α⇐     ≈⟨ braiding-coherence B ⟩⊗⟨refl ⟩∘⟨refl ⟩
    ρ⇒ ⊗₁ id ∘ α⇐             ≈˘⟨ switch-fromtoʳ α triangle ⟩
    id ⊗₁ λ⇒                  ∎

  Kelly₁′ :  [ unit ⊗₀ (X ⊗₀ Y) ⇒ X ⊗₀ Y ]⟨ λ⇒ ⊗₁ id ∘ α⇐ ≈ λ⇒ ⟩
  Kelly₁′ = ⟺ (switch-fromtoʳ α (Kelly's.coherence₁ M))

  Kelly₂′ : [  X ⊗₀ (Y ⊗₀ unit) ⇒ X ⊗₀ Y ]⟨ ρ⇒ ∘ α⇐ ≈ id ⊗₁ ρ⇒ ⟩
  Kelly₂′ = ⟺ (switch-fromtoʳ α (Kelly's.coherence₂ M))

  σ⁻¹-coherence : [ unit ⊗₀ X ⇒ X ]⟨ ρ⇒ ∘ σ⇒ ≈ λ⇒ ⟩
  σ⁻¹-coherence = inv-braiding-coherence (inv-Braided B)

swapInner-unitˡ : [ unit ⊗₀ (X ⊗₀ Y) ⇒ (X ⊗₀ Y) ]⟨
                    λ⇐ ⊗₁ id         ⇒⟨ (unit ⊗₀ unit) ⊗₀ (X ⊗₀ Y) ⟩
                    i⇒               ⇒⟨ (unit ⊗₀ X) ⊗₀ (unit ⊗₀ Y) ⟩
                    λ⇒ ⊗₁ λ⇒
                  ≈ λ⇒
                  ⟩
swapInner-unitˡ = begin
    λ⇒ ⊗₁ λ⇒ ∘ i⇒ ∘ λ⇐ ⊗₁ id      ≈⟨ refl⟩∘⟨ swapInner-coherent ⟩∘⟨ (Kelly's.coherence-inv₃ M ⟩⊗⟨refl) ⟩
    λ⇒ ⊗₁ λ⇒ ∘ j⇒ ∘ ρ⇐ ⊗₁ id      ≈⟨ pullˡ (pushˡ serialize₁₂) ⟩
    (λ⇒ ⊗₁ id ∘ id ⊗₁ λ⇒ ∘ α⇒ ∘ swapʳ ⊗₁ id ∘ α⇐) ∘ ρ⇐ ⊗₁ id
  ≈⟨ (refl⟩∘⟨ (begin
      id ⊗₁ λ⇒ ∘ α⇒ ∘ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐  ≈⟨ pullˡ triangle ⟩
      ρ⇒ ⊗₁ id ∘ (α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐       ≈˘⟨ pushˡ split₁ˡ ⟩
      (ρ⇒ ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐             ≈⟨ (pullˡ Kelly₂′ ⟩⊗⟨refl ⟩∘⟨refl) ⟩
      (id ⊗₁ ρ⇒ ∘ id ⊗₁ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐            ≈˘⟨ pushˡ split₂ˡ ⟩⊗⟨refl ⟩∘⟨refl ⟩
      (id ⊗₁ (ρ⇒ ∘ σ⇒) ∘ α⇒) ⊗₁ id ∘ α⇐                ≈⟨ (refl⟩⊗⟨ σ⁻¹-coherence ⟩∘⟨refl) ⟩⊗⟨refl ⟩∘⟨refl ⟩
      (id ⊗₁ λ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐                        ≈⟨ triangle ⟩⊗⟨refl ⟩∘⟨refl ⟩
      (ρ⇒ ⊗₁ id) ⊗₁ id ∘ α⇐                             ≈˘⟨ assoc-commute-to ⟩
      α⇐ ∘ ρ⇒ ⊗₁ (id ⊗₁ id)
    ∎)) ⟩∘⟨refl ⟩
    (λ⇒ ⊗₁ id ∘ α⇐ ∘ ρ⇒ ⊗₁ (id ⊗₁ id)) ∘ ρ⇐ ⊗₁ id   ≈⟨ (sym-assoc ○ (Kelly₁′ ⟩∘⟨ refl⟩⊗⟨ ⊗.identity)) ⟩∘⟨refl ⟩
    (λ⇒ ∘ ρ⇒ ⊗₁ id) ∘ ρ⇐ ⊗₁ id                       ≈⟨ cancelʳ (_≅_.isoʳ (unitorʳ ⊗ᵢ idᵢ)) ⟩
    λ⇒
  ∎

swapInner-unitʳ : [ (X ⊗₀ Y) ⊗₀ unit ⇒ (X ⊗₀ Y) ]⟨
                    id ⊗₁ λ⇐         ⇒⟨ (X ⊗₀ Y) ⊗₀ (unit ⊗₀ unit) ⟩
                    i⇒               ⇒⟨ (X ⊗₀ unit) ⊗₀ (Y ⊗₀ unit) ⟩
                    ρ⇒ ⊗₁ ρ⇒
                  ≈ ρ⇒
                  ⟩
swapInner-unitʳ = begin
    ρ⇒ ⊗₁ ρ⇒ ∘ i⇒ ∘ id ⊗₁ λ⇐                                  ≡⟨⟩
    ρ⇒ ⊗₁ ρ⇒ ∘ (α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒) ∘ id ⊗₁ λ⇐            ≈⟨ pullˡ (pushˡ serialize₂₁) ⟩
    (id ⊗₁ ρ⇒ ∘ ρ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒) ∘ id ⊗₁ λ⇐ ≈⟨ (refl⟩∘⟨ (begin
      ρ⇒ ⊗₁ id ∘ α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒                                  ≈˘⟨ pushˡ (switch-fromtoʳ α triangle) ⟩
      id ⊗₁ λ⇒ ∘ id ⊗₁ swapˡ ∘ α⇒                                       ≈˘⟨ pushˡ split₂ˡ ⟩
      id ⊗₁ (λ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒                             ≈⟨ refl⟩⊗⟨ mid-1-elim-coh ⟩∘⟨refl ⟩
      id ⊗₁ (id ⊗₁ λ⇒) ∘ α⇒                                             ≈˘⟨ assoc-commute-from ⟩
      α⇒ ∘ (id ⊗₁ id) ⊗₁ λ⇒                                             ≈⟨ refl⟩∘⟨ ⊗.identity ⟩⊗⟨refl ⟩
      α⇒ ∘ id ⊗₁ λ⇒                                                     ∎)) ⟩∘⟨refl ⟩
    (id ⊗₁ ρ⇒ ∘ α⇒ ∘ id ⊗₁ λ⇒) ∘ id ⊗₁ λ⇐                    ≈⟨ (sym-assoc ○ (Kelly's.coherence₂ M ⟩∘⟨refl )) ⟩∘⟨refl ⟩
    (ρ⇒ ∘ id ⊗₁ λ⇒) ∘ id ⊗₁ λ⇐                                ≈⟨ cancelʳ (_≅_.isoʳ (idᵢ ⊗ᵢ unitorˡ)) ⟩
    ρ⇒                                                         ∎

-- Two different ways of swapping things around are the same
private
  [23][14]ʳ : [ (X ⊗₀ Y) ⊗₀ (Z ⊗₀ W) ⇒ (Y ⊗₀ Z) ⊗₀ (X ⊗₀ W) ]⟨ α⇒ ∘ swapʳ ⊗₁ id ∘ (σ⇒ ⊗₁ id) ⊗₁ id ∘ α⇐ ≈ (α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇒ ⊗₁ id ∘ α⇐ ⟩
  [23][14]ʳ = begin
    (α⇒ ∘ swapʳ ⊗₁ id ∘ (σ⇒ ⊗₁ id) ⊗₁ id ∘ α⇐)  ≈˘⟨ refl⟩∘⟨ pushˡ split₁ˡ ⟩
    (α⇒ ∘ (swapʳ ∘ σ⇒ ⊗₁ id) ⊗₁ id ∘ α⇐)        ≈⟨ refl⟩∘⟨ pullʳ (assoc ○ hexagon₁) ⟩⊗⟨refl ⟩∘⟨refl ⟩
    (α⇒ ∘ (α⇐ ∘ α⇒ ∘ σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐)       ≈⟨ refl⟩∘⟨ cancelˡ α.isoˡ ⟩⊗⟨refl ⟩∘⟨refl ⟩
    (α⇒ ∘ (σ⇒ ∘ α⇒) ⊗₁ id ∘ α⇐)                 ≈⟨ extendʳ (pushʳ split₁ˡ) ⟩
    ((α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇒ ⊗₁ id ∘ α⇐)           ∎

  [13][42]ˡ : [ (X ⊗₀ Y) ⊗₀ (Z ⊗₀ W) ⇒ (X ⊗₀ Z)  ⊗₀ (W ⊗₀ Y) ]⟨ α⇐ ∘ id ⊗₁ (id ⊗₁ σ⇒) ∘ id ⊗₁ swapˡ ∘ α⇒ ≈ (α⇐ ∘ id ⊗₁ α⇒) ∘ id ⊗₁ σ⇒ ∘ α⇒ ⟩
  [13][42]ˡ = begin
    α⇐ ∘ id ⊗₁ (id ⊗₁ σ⇒) ∘ id ⊗₁ swapˡ ∘ α⇒         ≈˘⟨  refl⟩∘⟨ pushˡ split₂ˡ ⟩
    α⇐ ∘ id ⊗₁ (id ⊗₁ σ⇒ ∘ α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒ ≈⟨ refl⟩∘⟨ refl⟩⊗⟨ (⟺ assoc ○ (pullˡ (assoc ○ hexagon₁))) ⟩∘⟨refl ⟩
    α⇐ ∘ id ⊗₁ ((α⇒ ∘ σ⇒ ∘ α⇒) ∘ α⇐) ∘ α⇒            ≈⟨ refl⟩∘⟨ refl⟩⊗⟨ pullʳ (cancelʳ α.isoʳ) ⟩∘⟨refl ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘ σ⇒) ∘ α⇒                         ≈⟨ extendʳ (pushʳ split₂ˡ) ⟩
    (α⇐ ∘ id ⊗₁ α⇒) ∘ id ⊗₁ σ⇒ ∘ α⇒                  ∎

swapInner-braiding : [ (W ⊗₀ X) ⊗₀ (Y ⊗₀ Z) ⇒ (Y ⊗₀ Z) ⊗₀ (W ⊗₀ X) ]⟨
                       i⇒         ⇒⟨ (W ⊗₀ Y) ⊗₀ (X ⊗₀ Z) ⟩
                       σ⇒ ⊗₁ σ⇒   ⇒⟨ (Y ⊗₀ W) ⊗₀ (Z ⊗₀ X) ⟩
                       i⇒
                     ≈ σ⇒
                     ⟩
swapInner-braiding = begin
    i⇒ ∘ σ⇒ ⊗₁ σ⇒ ∘ i⇒                                  ≡⟨⟩
    i⇒ ∘ σ⇒ ⊗₁ σ⇒ ∘ α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒              ≈⟨ swapInner-coherent ⟩∘⟨ pushˡ serialize₁₂ ⟩
    j⇒ ∘ σ⇒ ⊗₁ id ∘ id ⊗₁ σ⇒ ∘ α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒  ≈˘⟨ ((refl⟩∘⟨ refl⟩⊗⟨ ⊗.identity) ⟩∘⟨ ⊗.identity ⟩⊗⟨refl ⟩∘⟨refl) ○ assoc ⟩
    ((α⇒ ∘ swapʳ ⊗₁ id ∘ α⇐) ∘ σ⇒ ⊗₁ (id ⊗₁ id)) ∘
    (id ⊗₁ id) ⊗₁ σ⇒ ∘ α⇐ ∘ id ⊗₁ swapˡ ∘ α⇒           ≈⟨ pullʳ (pullʳ assoc-commute-to) ⟩∘⟨ extendʳ (⟺ assoc-commute-to) ⟩
    (α⇒ ∘ swapʳ ⊗₁ id ∘ (σ⇒ ⊗₁ id) ⊗₁ id ∘ α⇐) ∘
    α⇐ ∘ id ⊗₁ (id ⊗₁ σ⇒) ∘ id ⊗₁ swapˡ ∘ α⇒           ≈⟨ [23][14]ʳ ⟩∘⟨ [13][42]ˡ ⟩
    ((α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇒ ⊗₁ id ∘ α⇐) ∘ (α⇐ ∘ id ⊗₁ α⇒) ∘ id ⊗₁ σ⇒ ∘ α⇒  ≈˘⟨ extendʳ (pushʳ (pushʳ assoc)) ⟩
    (α⇒ ∘ σ⇒ ⊗₁ id) ∘ (α⇒ ⊗₁ id ∘ (α⇐ ∘ α⇐) ∘ id ⊗₁ α⇒) ∘ id ⊗₁ σ⇒ ∘ α⇒  ≈˘⟨ refl⟩∘⟨ switch-tofromˡ (α ⊗ᵢ idᵢ)
                                                                                (switch-tofromʳ (idᵢ ⊗ᵢ α) pentagon-inv) ⟩∘⟨refl ⟩
    (α⇒ ∘ σ⇒ ⊗₁ id) ∘ α⇐ ∘ id ⊗₁ σ⇒ ∘ α⇒               ≈⟨ pullʳ (sym-assoc ○ pullˡ hexagon₂) ⟩
    α⇒ ∘ ((α⇐ ∘ σ⇒) ∘ α⇐) ∘ α⇒                          ≈⟨ (refl⟩∘⟨ cancelʳ α.isoˡ) ⟩
    α⇒ ∘ (α⇐ ∘ σ⇒)                                       ≈⟨ cancelˡ α.isoʳ ⟩
    σ⇒                                                   ∎

-- Braided monoidal categories have an interchange.

hasInterchange : HasInterchange M
hasInterchange = record
  { swapInner  = swapInner
  ; natural    = swapInner-natural
  ; assoc      = swapInner-assoc
  ; unitˡ      = swapInner-unitˡ
  ; unitʳ      = swapInner-unitʳ
  }
open HasInterchange hasInterchange public using (naturalIso)


{-# OPTIONS --cubical --no-import-sorts --safe #-}

module Cubical.Data.SumFin.Properties where

open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Univalence

open import Cubical.Data.Empty as ⊥
import Cubical.Data.Fin as Fin
open import Cubical.Data.Nat
open import Cubical.Data.SumFin.Base as SumFin

private
  variable
    ℓ : Level
    k : ℕ

SumFin→Fin : Fin k → Fin.Fin k
SumFin→Fin = SumFin.elim (λ {k} _ → Fin.Fin k) Fin.fzero Fin.fsuc

Fin→SumFin : Fin.Fin k → Fin k
Fin→SumFin = Fin.elim (λ {k} _ → Fin k) fzero fsuc

Fin→SumFin-fsuc : (fk : Fin.Fin k) → Fin→SumFin (Fin.fsuc fk) ≡ fsuc (Fin→SumFin fk)
Fin→SumFin-fsuc = Fin.elim-fsuc (λ {k} _ → Fin k) fzero fsuc

SumFin→Fin→SumFin : (fk : Fin k) → Fin→SumFin (SumFin→Fin fk) ≡ fk
SumFin→Fin→SumFin = SumFin.elim (λ fk → Fin→SumFin (SumFin→Fin fk) ≡ fk)
                                refl λ {k} {fk} eq →
  Fin→SumFin (Fin.fsuc (SumFin→Fin fk)) ≡⟨ Fin→SumFin-fsuc (SumFin→Fin fk) ⟩
  fsuc (Fin→SumFin (SumFin→Fin fk))     ≡⟨ cong fsuc eq ⟩
  fsuc fk                               ∎

Fin→SumFin→Fin : (fk : Fin.Fin k) → SumFin→Fin (Fin→SumFin fk) ≡ fk
Fin→SumFin→Fin = Fin.elim (λ fk → SumFin→Fin (Fin→SumFin fk) ≡ fk)
                          refl λ {k} {fk} eq →
  SumFin→Fin (Fin→SumFin (Fin.fsuc fk)) ≡⟨ cong SumFin→Fin (Fin→SumFin-fsuc fk) ⟩
  Fin.fsuc (SumFin→Fin (Fin→SumFin fk)) ≡⟨ cong Fin.fsuc eq ⟩
  Fin.fsuc fk                           ∎

SumFin≃Fin : ∀ k → Fin k ≃ Fin.Fin k
SumFin≃Fin _ =
  isoToEquiv (iso SumFin→Fin Fin→SumFin Fin→SumFin→Fin SumFin→Fin→SumFin)

SumFin≡Fin : ∀ k → Fin k ≡ Fin.Fin k
SumFin≡Fin k = ua (SumFin≃Fin k)


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Relation.Binary.Reasoning.Equality where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude

private
  variable
    ℓ : Level
    A : Type ℓ

infixr 1 _≡⟨⟩_ _≡⟨_⟩_ _≡˘⟨_⟩_
infix 2 _∎

-- Step with a non-trivial propositional equality

_≡⟨_⟩_ : ∀ x {y z : A} → x ≡ y → y ≡ z → x ≡ z
_≡⟨_⟩_ x = _∙_

-- Step with a flipped non-trivial propositional equality

_≡˘⟨_⟩_ : ∀ x {y z : A} → y ≡ x → y ≡ z → x ≡ z
x ≡˘⟨ y≡x ⟩ y≡z = x ≡⟨ sym y≡x ⟩ y≡z

-- Step with a trivial propositional equality

_≡⟨⟩_ : ∀ x {y : A} → x ≡ y → x ≡ y
_ ≡⟨⟩ x≡y = x≡y

-- Syntax for path definition

≡⟨⟩-syntax : ∀ x {y z : A} → x ≡ y → y ≡ z → x ≡ z
≡⟨⟩-syntax = _≡⟨_⟩_
infixr 1 ≡⟨⟩-syntax
syntax ≡⟨⟩-syntax x (λ i → B) y = x ≡[ i ]⟨ B ⟩ y

≡˘⟨⟩-syntax : ∀ x {y z : A} → y ≡ x → y ≡ z → x ≡ z
≡˘⟨⟩-syntax = _≡˘⟨_⟩_
infixr 1 ≡˘⟨⟩-syntax
syntax ≡˘⟨⟩-syntax x (λ i → B) y = x ≡˘[ i ]⟨ B ⟩ y

-- Termination step

_∎ : ∀ (x : A) → x ≡ x
x ∎ = refl


------------------------------------------------------------------------------
-- Totality properties respect to Bool
------------------------------------------------------------------------------

{-# OPTIONS --exact-split              #-}
{-# OPTIONS --no-sized-types           #-}
{-# OPTIONS --no-universe-polymorphism #-}
{-# OPTIONS --without-K                #-}

module FOTC.Program.SortList.Properties.Totality.BoolI where

open import FOTC.Base
open import FOTC.Data.Bool.Type
open import FOTC.Data.Bool.PropertiesI
open import FOTC.Data.Nat.List.Type
open import FOTC.Data.Nat.Type
open import FOTC.Program.SortList.SortList

------------------------------------------------------------------------------

le-ItemList-Bool : ∀ {item is} → N item → ListN is → Bool (le-ItemList item is)
le-ItemList-Bool {item} Nitem lnnil = subst Bool (sym (le-ItemList-[] item)) btrue
le-ItemList-Bool {item} Nitem (lncons {i} {is} Ni Lis) =
  subst Bool
        (sym (le-ItemList-∷ item i is))
        (&&-Bool (le-Bool Nitem Ni) (le-ItemList-Bool Nitem Lis))

-- See the ATP version.
postulate le-Lists-Bool : ∀ {is js} → ListN is → ListN js → Bool (le-Lists is js)

-- See the ATP version.
postulate ordList-Bool : ∀ {is} → ListN is → Bool (ordList is)

le-ItemTree-Bool : ∀ {item t} → N item → Tree t →
                  Bool (le-ItemTree item t)
le-ItemTree-Bool {item} _ tnil = subst Bool (sym (le-ItemTree-nil item)) btrue
le-ItemTree-Bool {item} Nitem (ttip {i} Ni) =
  subst Bool (sym (le-ItemTree-tip item i)) (le-Bool Nitem Ni)
le-ItemTree-Bool {item} Nitem  (tnode {t₁} {i} {t₂} Tt₁ Ni Tt₂) =
    subst Bool
          (sym (le-ItemTree-node item t₁ i t₂))
          (&&-Bool (le-ItemTree-Bool Nitem Tt₁) (le-ItemTree-Bool Nitem Tt₂))

le-TreeItem-Bool : ∀ {t item} → Tree t → N item → Bool (le-TreeItem t item)
le-TreeItem-Bool {item = item} tnil _ =
  subst Bool (sym (le-TreeItem-nil item)) btrue
le-TreeItem-Bool {item = item} (ttip {i} Ni) Nitem =
  subst Bool (sym (le-TreeItem-tip i item)) (le-Bool Ni Nitem)
le-TreeItem-Bool {item = item} (tnode {t₁} {i} {t₂} Tt₁ Ni Tt₂) Nitem =
  subst Bool
        (sym (le-TreeItem-node t₁ i t₂ item))
        (&&-Bool (le-TreeItem-Bool Tt₁ Nitem) (le-TreeItem-Bool Tt₂ Nitem))

ordTree-Bool : ∀ {t} → Tree t → Bool (ordTree t)
ordTree-Bool tnil          = subst Bool (sym ordTree-nil) btrue
ordTree-Bool (ttip {i} Ni) = subst Bool (sym (ordTree-tip i)) btrue
ordTree-Bool (tnode {t₁} {i} {t₂} Tt₁ Ni Tt₂) =
  subst Bool
        (sym (ordTree-node t₁ i t₂))
        (&&-Bool (ordTree-Bool Tt₁)
                 (&&-Bool (ordTree-Bool Tt₂)
                          (&&-Bool (le-TreeItem-Bool Tt₁ Ni)
                                   (le-ItemTree-Bool Ni Tt₂))))


{-# OPTIONS --without-K #-}
module pointed.equality where

open import sum
open import equality.core
open import function.extensionality
open import function.isomorphism.core
open import function.isomorphism.utils
open import pointed.core

pmap-eq : ∀ {i j}{X : Set i}{Y : Set j}{x₀ : X}{y₀ : Y}
        → {f : X → Y}{p : f x₀ ≡ y₀}
        → {g : X → Y}{q : g x₀ ≡ y₀}
        → (Σ ((x : X) → f x ≡ g x) λ γ → p ≡ γ x₀ · q)
        ≅ _≡_ {A = PMap (X , x₀) (Y , y₀)} (f , p) (g , q)
pmap-eq {X = X}{Y}{x₀}{y₀} = Σ-ap-iso' strong-funext-iso lem ·≅ Σ-split-iso
  where
    lem : {f : X → Y}{p : f x₀ ≡ y₀}
        → {g : X → Y}{q : g x₀ ≡ y₀}
        → (h : f ≡ g)
        → (p ≡ funext-inv h x₀ · q)
        ≅ (subst (λ u → u x₀ ≡ y₀) h p ≡ q)
    lem refl = refl≅


open import Agda.Builtin.Nat

data Vec (A : Set) : Nat → Set where
  []  : Vec A 0
  _∷_ : ∀ {n} → A → Vec A n → Vec A (suc n)

infixr 5 _∷_ _++_

_++_ : ∀ {A m n} → Vec A m → Vec A n → Vec A (m + n)
[]       ++ ys = ys
(x ∷ xs) ++ ys = x ∷ xs ++ ys

T : ∀ {A n} → Vec A n → Set
T [] = Nat
T (x ∷ xs) = Vec Nat 0

foo : ∀ {A} m n (xs : Vec A m) (ys : Vec A n) → T (xs ++ ys)
foo m n xs ys with {m + n} | xs ++ ys
... | []     = 0
... | z ∷ zs = []


{-# OPTIONS --warning=error --safe --without-K #-}

open import LogicalFormulae
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Functions
open import Setoids.Setoids
open import Setoids.Subset
open import Graphs.Definition
open import Sets.FinSet.Definition
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Sets.EquivalenceRelations
open import Graphs.CompleteGraph
open import Graphs.Colouring

module Graphs.RamseyTriangle where

hasMonochromaticTriangle : {a : _} {n : ℕ} (G : Graph a (reflSetoid (FinSet n))) → Set (lsuc lzero)
hasMonochromaticTriangle {n = n} G = Sg (FinSet n → Set) λ pred → (subset (reflSetoid (FinSet n)) pred) && {!!}

ramseyForTriangle : (k : ℕ) → Sg ℕ (λ N → (n : ℕ) → (N <N n) → (c : Colouring k (Kn n)) → {!!})
ramseyForTriangle k = {!!}


{-# OPTIONS --without-K --exact-split --safe #-}

module Fragment.Setoid.Morphism.Base where

open import Level using (Level; _⊔_)
open import Function using (_∘_; Congruent)

import Relation.Binary.PropositionalEquality as PE
open import Relation.Binary using (Setoid)

private
  variable
    a b c ℓ₁ ℓ₂ ℓ₃ : Level

module _ (S : Setoid a ℓ₁) (T : Setoid b ℓ₂) where

  open Setoid S renaming (Carrier to A; _≈_ to _≈₁_)
  open Setoid T renaming (Carrier to B; _≈_ to _≈₂_)

  infixr 1 _↝_

  record _↝_ : Set (a ⊔ b ⊔ ℓ₁ ⊔ ℓ₂) where
    field
      ∣_∣      : A → B
      ∣_∣-cong : Congruent _≈₁_ _≈₂_ ∣_∣

open _↝_ public

lift : ∀ {A : Set a} {B : Setoid b ℓ₂}
       → (A → Setoid.Carrier B)
       → (PE.setoid A ↝ B)
lift {B = B} f
  = record { ∣_∣ = f
           ; ∣_∣-cong = reflexive ∘ (PE.cong f)
           }
     where open Setoid B

id : ∀ {A : Setoid a ℓ₁} → A ↝ A
id = record { ∣_∣ = λ x → x ; ∣_∣-cong = λ x → x }

_·_ : ∀ {A : Setoid a ℓ₁} {B : Setoid b ℓ₂} {C : Setoid c ℓ₃}
      → B ↝ C → A ↝ B → A ↝ C
g · f = record { ∣_∣      = ∣ g ∣ ∘ ∣ f ∣
               ; ∣_∣-cong = ∣ g ∣-cong ∘ ∣ f ∣-cong
               }


{-# OPTIONS --without-K #-}
module hott.equivalence.inverse where

open import level
open import sum
open import function.core
open import function.isomorphism.core
open import function.isomorphism.utils
open import function.isomorphism.properties
open import function.extensionality
open import function.overloading
open import equality.core
open import sets.unit
open import sets.nat.core using (suc)
open import hott.level
open import hott.equivalence.core
open import hott.equivalence.alternative
open import hott.univalence

module _ {i j}{A : Set i}{B : Set j} where
  record inverse (f : A → B) : Set (i ⊔ j) where
    constructor mk-inverse
    field
      g : B → A
      α : (x : A) → g (f x) ≡ x
      β : (y : B) → f (g y) ≡ y

    isom : A ≅ B
    isom = iso f g α β

  iso⇒inv : (f : A ≅ B) → inverse (apply f)
  iso⇒inv (iso f g α β) = mk-inverse g α β

  inverse-struct-iso : (f : A → B)
                     → inverse f
                     ≅ ( Σ (B → A) λ g
                       → Σ ((x : A) → g (f x) ≡ x) λ α
                       → ((y : B) → f (g y) ≡ y) )
  inverse-struct-iso f = record
    { to = λ { (mk-inverse g α β) → (g , α , β) }
    ; from = λ { (g , α , β) → (mk-inverse g α β) }
    ; iso₁ = λ _ → refl
    ; iso₂ = λ _ → refl }

  ≅-inv-struct-iso : (A ≅ B) ≅ Σ (A → B) inverse
  ≅-inv-struct-iso = trans≅ ≅-struct-iso
    (Σ-ap-iso₂ (λ f → sym≅ (inverse-struct-iso f)))

ind-≈ : (P : ∀ {i}{A B : Set i} → A ≈ B → Set i)
      → (∀ {i}{A : Set i} → P {A = A} (≡⇒≈ refl))
      → ∀ {i}{A B : Set i}(eq : A ≈ B) → P eq
ind-≈ P d {A = A} eq = subst P (_≅_.iso₂ uni-iso eq)
                               (lem (≈⇒≡ eq))
  where
    lem : ∀ {i}{A B : Set i}
        → (p : A ≡ B)
        → P (≡⇒≈ p)
    lem refl = d

inverse-nonprop' : ∀ {i}{A : Set i}
                 → inverse (λ (x : A) → x)
                 ≅ ((x : A) → x ≡ x)
inverse-nonprop' {i}{A} = begin
    inverse id'
  ≅⟨ inverse-struct-iso id' ⟩
    ( Σ (A → A) λ g
    → Σ ((x : A) → g x ≡ x) λ α
    → ((y : A) → g y  ≡ y) )
  ≅⟨ ( Σ-ap-iso₂ λ g
      → Σ-ap-iso₁ strong-funext-iso ) ⟩
    ( Σ (A → A) λ g
    → Σ (g ≡ id') λ α
    → ((y : A) → g y ≡ y) )
  ≅⟨ sym≅ Σ-assoc-iso ⟩
    ( Σ (singleton' id') λ { (g , α)
    → ((y : A) → g y ≡ y) } )
  ≅⟨ trans≅ (Σ-ap-iso' (contr-⊤-iso (singl-contr' id'))
                       (λ _ → refl≅))
            ×-left-unit ⟩
    ((x : A) → x ≡ x)
  ∎
  where
    open ≅-Reasoning
    id' : A → A
    id' x = x

inverse-nonprop : ∀ {i}{A B : Set i}
                → (f : A → B)
                → weak-equiv f
                → inverse f
                ≅ ((x : A) → x ≡ x)
inverse-nonprop {i}{A} f we = ind-≈ P inverse-nonprop' (f , we)
  where
    P : ∀ {i}{A B : Set i} → A ≈ B → Set _
    P {A = A} (f , we) = inverse f ≅ ((x : A) → x ≡ x)


module Control.Monad.Except where

open import Prelude
open import Control.Monad.Zero
open import Control.Monad.Identity
open import Control.Monad.Transformer

record ExceptT {a} (E : Set a) (M : Set a → Set a) (A : Set a) : Set a where
  no-eta-equality
  constructor maybeT
  field runExceptT : M (Either E A)

open ExceptT public

module _ {a} {E : Set a} {M : Set a → Set a} where

  instance
    FunctorExceptT : {{_ : Functor M}} → Functor {a = a} (ExceptT E M)
    runExceptT (fmap {{FunctorExceptT}} f m) = fmap f <$> runExceptT m

    FunctorZeroExceptT : {{_ : Monad M}} {{_ : Monoid E}} → FunctorZero {a = a} (ExceptT E M)
    runExceptT (empty {{FunctorZeroExceptT}}) = return (left mempty)

    AlternativeExceptT : {{_ : Monad M}} {{_ : Monoid E}} → Alternative {a = a} (ExceptT E M)
    runExceptT (_<|>_ {{AlternativeExceptT {{monadM}}}} mx my) = do
      right x ← runExceptT mx
        where
          left e₁ → do
            right y ← runExceptT my
              where left e₂ → return (left (e₁ <> e₂))
            return (right y)
      return (right x)

  module _ {{_ : Monad M}} where

    private
      bindExceptT : ∀ {A B} → ExceptT E M A → (A → ExceptT E M B) → ExceptT E M B
      runExceptT (bindExceptT m f) = do
        right x ← runExceptT m
          where left e → return (left e)
        runExceptT (f x)

    instance
      ApplicativeExceptT : Applicative {a = a} (ExceptT E M)
      runExceptT (pure {{ApplicativeExceptT}} x) = pure (right x)
      _<*>_ {{ApplicativeExceptT}} = monadAp bindExceptT

      MonadExceptT : Monad {a = a} (ExceptT E M)
      _>>=_  {{MonadExceptT}} = bindExceptT

    liftExceptT : {A : Set a} → M A → ExceptT E M A
    runExceptT (liftExceptT m) = right <$> m

instance
  TransformerExceptT : ∀ {a} {E : Set a} → Transformer {a} (ExceptT E)
  lift {{TransformerExceptT}} = liftExceptT

Except : ∀ {a} (E : Set a) (A : Set a) → Set a
Except R = ExceptT R Identity

runExcept : ∀ {a} {E : Set a} {A : Set a} → Except E A → Either E A
runExcept m = runIdentity (runExceptT m)


{-# OPTIONS --disable-positivity-check #-}

module univ where

import Logic.ChainReasoning
module Chain {A : Set}
             ( _==_ : A -> A -> Set)
             (refl : {x : A} -> x == x)
             (trans : {x y z : A} -> x == y -> y == z -> x == z) =
             Logic.ChainReasoning.Mono.Homogenous _==_ (\x -> refl) (\x y z -> trans)

data N1 : Set where
  T : N1

data N0 : Set where

data Sigma (A:Set)(B : A -> Set) : Set where
 Pair : (x:A) -> B x -> Sigma A B

rel : Set -> Set1

rel A = A -> A -> Set

pred : Set -> Set1

pred A = A -> Set

Refl : {A:Set} -> rel A -> Set
Refl {A} R = {x : A} -> R x x

Sym : {A:Set} -> rel A -> Set
Sym {A} R = {x y : A} -> R x y -> R y x

Trans : {A:Set} -> rel A -> Set
Trans {A} R = {x y z : A} -> R x y -> R y z -> R x z

Map : (A:Set) -> rel A -> (B:Set) -> rel B -> pred (A -> B)
Map A _R_ B _S_ f = {x y : A} -> x R y -> f x S f y

postulate
  N : Set
  _=N_ : rel N
  refN : Refl _=N_
  symN : Sym _=N_
  transN : Trans _=N_

-- mutual inductive recursive definition of S and the functions _=S_, El, eq, and all the
-- proofs on these functions

mutual

  infix 40 _==_ _=S_
  infixr 80 _<<_

  data S : Set where
    nat : S
    pi  : (A:S) -> (f:El A -> S) -> Map (El A) _==_ S _=S_ f -> S

  _=S'_ : rel S
  nat       =S' nat       = N1
  nat       =S' pi A f pf = N0
  pi _ _ _  =S' nat       = N0
  pi A F pF =S' pi B G pG =
      Sigma (A =S B) \ A=B -> (x : El B) -> F (A=B << x) =S G x

  data _=S_ (A B : S) : Set where
    eqS : A =S' B -> A =S B

  El' : S -> Set
  El' nat = N
  El' (pi A F pF) =
   Sigma ((x : El A) -> El (F x))
         \f -> {x y : El A}(x=y : x == y) ->
               f x == pF x=y << f y

  data El (A : S) : Set where
    el : El' A -> El A

  _=='_ : {A : S} -> rel (El A)
  _=='_ {nat} (el x) (el y) = x =N y
  _=='_ {pi A F pF} (el (Pair f pf)) (el (Pair g pg)) =
        (x : El A) -> f x == g x

  data _==_ {A : S}(x y : El A) : Set where
    eq : x ==' y -> x == y

  _<<_ : {A B : S} -> A =S B -> El B -> El A
  _<<_ {nat} {nat} p x = x
  _<<_ {pi A F pF} {pi B G pG} (eqS (Pair A=B F=G)) (el (Pair g pg)) =
    el (Pair f (\{x}{y} -> pf x y))
    where
      B=A = symS A=B

      F=Gc : (x : El A) -> F x =S G (B=A << x)
      F=Gc x =
        transS (transS refS (symS (pF (castlem A=B (symS A=B) x))))
        (F=G (symS A=B << x))

--         chain> F x
--            === F (A=B << B=A << x)  by symS (pF (castlem A=B B=A x))
--            === G (B=A << x)         by F=G (B=A << x)
--         where
--           open module C = Chain _=S_ refS transS

      f : (x : El A) -> El (F x)
      f x = F=Gc x << g (B=A << x)

      pf : (x y : El A)(p : x == y) -> f x == pF p << f y
      pf x y x=y = trans fx=ccgy ccgy=cfy
        where
          cx = B=A << x
          cy = B=A << y

          cx=cy : cx == cy
          cx=cy = p<< B=A x=y

          cgy : El (G cx)
          cgy = pG cx=cy << g cy

          gx=gy : g cx == cgy
          gx=gy = pg cx=cy

          ccgy : El (F x)
          ccgy = F=Gc x << cgy

          fx=ccgy : f x == ccgy
          fx=ccgy = p<< (F=Gc x) gx=gy

          cfy : El (F x)
          cfy = pF x=y << f y

          ccgy=cfy : ccgy == cfy
          ccgy=cfy = castlem2 (F=Gc x) (pF x=y)
                              (pG cx=cy) (F=Gc y)
                              (g cy)

  p<< : {A B : S}(A=B : A =S B) -> Map (El B) _==_ (El A) _==_ (_<<_ A=B)
  p<< {nat}{nat} _ x=y = x=y
  p<< {pi A F pF} {pi B G pG} (eqS (Pair A=B F=G))
        {el (Pair f pf)} {el (Pair g pg)} (eq f=g) = eq cf=cg
    where
      open module C = Logic.ChainReasoning.Mono.Homogenous _=S_ (\x -> refS) (\x y z -> transS)
      B=A = symS A=B

      F=Gc : (x : El A) -> F x =S G (B=A << x)
      F=Gc x =
        chain> F x
           === F (A=B << B=A << x)  by symS (pF (castlem A=B B=A x))
           === G (B=A << x)         by F=G _

      cf=cg : (x : El A) -> F=Gc x << f (B=A << x)
                         == F=Gc x << g (B=A << x)
      cf=cg x = p<< (F=Gc x) (f=g (B=A << x))

  p<< {nat}      {pi _ _ _} (eqS ()) _
  p<< {pi _ _ _} {nat}      (eqS ()) _

  refS : Refl _=S_
  refS {nat}       = eqS T
  refS {pi A F pF} = eqS (Pair refS \(x : El A) -> pF (castref refS x))

  transS : Trans _=S_
  transS {nat}{nat}{nat} p q = p
  transS {nat}{nat}{pi _ _ _}      _      (eqS ())
  transS {nat}{pi _ _ _}{_}       (eqS ()) _
  transS {pi _ _ _}{nat}{_}       (eqS ()) _
  transS {pi _ _ _}{pi _ _ _}{nat} _      (eqS ())
  transS {pi A F pF}{pi B G pG}{pi C H pH}
         (eqS (Pair A=B F=G)) (eqS (Pair B=C G=H)) =
         eqS (Pair A=C F=H)
    where
      open module C = Chain _=S_ refS transS
      A=C = transS A=B B=C
      F=H : (x : El C) -> F (A=C << x) =S H x
      F=H x =
        chain> F (A=C << x)
           === F (A=B << B=C << x) by symS (pF (casttrans A=B B=C A=C x))
           === G (B=C << x)        by F=G (B=C << x)
           === H x                 by G=H x

  symS : Sym _=S_
  symS {nat}{nat} p                 = p
  symS {pi _ _ _}{nat} (eqS ())
  symS {nat}{pi _ _ _} (eqS ())
  symS {pi A F pF}{pi B G pg} (eqS (Pair A=B F=G)) = eqS (Pair B=A G=F)
    where
      open module C = Chain _=S_ refS transS
      B=A = symS A=B
      G=F : (x : El A) -> G (B=A << x) =S F x
      G=F x =
        chain> G (B=A << x)
           === F (A=B << B=A << x) by symS (F=G (B=A << x))
           === F x                 by pF (castlem A=B B=A x)

  pfi : {A B : S}(p q : A =S B)(x : El B) -> p << x == q << x
  pfi {nat}{nat} _ _ x = ref
  pfi {nat}{pi _ _ _} (eqS ()) _ _
  pfi {pi _ _ _}{nat} (eqS ()) _ _
  pfi {pi A F pF}{pi B G pG} (eqS (Pair A=B1 F=G1)) (eqS (Pair A=B2 F=G2))
      (el (Pair f pf)) = eq f1=f2
    where
      B=A1 = symS A=B1
      B=A2 = symS A=B2

      f1=f2 : (x : El A) -> _ << f (B=A1 << x) == _ << f (B=A2 << x)
      f1=f2 x =
        chain> _ << f (B=A1 << x)
           === _ << _ << f (B=A2 << x) by p<< _ lem2
           === _ << f (B=A2 << x)      by casttrans _ _ _ _
        where
          open module C = Chain _==_ (ref {F x}) (trans {F x})
          lem1 : B=A1 << x == B=A2 << x
          lem1 = pfi B=A1 B=A2 x

          lem2 : f (B=A1 << x) == _ << f (B=A2 << x)
          lem2 = pf lem1

  castref : {A : S}(p : A =S A)(x : El A) -> p << x == x
  castref {nat} p x = ref
  castref {pi A F pF} (eqS (Pair A=A F=F)) (el (Pair f pf)) = eq cf=f
    where
      A=A' = symS A=A
      cf=f : (x : El A) -> _ << f (A=A' << x) == f x
      cf=f x =
        chain> Fx=Fcx << f (A=A' << x)
           === Fx=Fcx << _ << f x by p<< Fx=Fcx lem2
           === refS << f x        by casttrans _ _ _ (f x)
           === f x                by castref _ (f x)
        where
          Fx=Fcx = _
          open module C = Chain _==_ (ref {F x}) (trans {F x})
          lem1 : A=A' << x == x
          lem1 = castref A=A' x

          lem2 : f (A=A' << x) == _ << f x
          lem2 = pf lem1

  casttrans : {A B C : S}(A=B : A =S B)(B=C : B =S C)(A=C : A =S C)(x : El C) ->
               A=B << B=C << x == A=C << x
  casttrans {nat}{nat}{nat} _ _ _ x = ref
  casttrans {nat}{nat}{pi _ _ _}      _      (eqS ()) _ _
  casttrans {nat}{pi _ _ _}{_}       (eqS ()) _ _ _
  casttrans {pi _ _ _}{nat}{_}       (eqS ()) _ _ _
  casttrans {pi _ _ _}{pi _ _ _}{nat} _      (eqS ()) _ _
  casttrans {pi A F pF}{pi B G pG}{pi C H pH}
            (eqS (Pair A=B F=G))(eqS (Pair B=C G=H))(eqS (Pair A=C F=H))
            (el (Pair h ph)) = eq prf
    where
      B=A = symS A=B
      C=B = symS B=C
      C=A = symS A=C

      prf : (x : El A) -> _ << _ << h (C=B << B=A << x) == _ << h (C=A << x)
      prf x =
        chain> Fx=Gcx << Gcx=Hccx << h (C=B << B=A << x)
           === Fx=Hccx << h (C=B << B=A << x) by casttrans _ _ _ _
           === Fx=Hccx << _ << h (C=A << x) by p<< _ (ph (casttrans C=B B=A C=A x))
           === Fx=Hcx << h (C=A << x)  by casttrans _ _ _ _
        where
          Fx=Gcx   = _
          Gcx=Hccx = _
          Fx=Hccx  = transS (lemF=Gc A=B pF pG F=G _)
                            (lemF=Gc B=C pG pH G=H _)
          Fx=Hcx   = _
          open module C = Chain _==_ (ref {F x}) (trans {F x})

  lemF=Gc : {A B : S}(A=B : A =S B)
            {F : El A -> S}(pF : Map (El A) _==_ S _=S_ F)
            {G : El B -> S}(pG : Map (El B) _==_ S _=S_ G)
            (F=G : (x : El B) -> F (A=B << x) =S G x)
            (x : El A) -> F x =S G (symS A=B << x)
  lemF=Gc A=B {F} pF {G} pG F=G x =
    chain> F x
       === F (A=B << B=A << x)  by symS (pF (castlem A=B B=A x))
       === G (B=A << x)         by F=G _
    where
      open module C = Chain _=S_ refS transS
      B=A = symS A=B

  castlem : {A B : S}(p : A =S B)(q : B =S A)(x : El A) ->
            p << q << x == x
  castlem {A}{B} p q x =
    chain> p << q << x
       === refS << x  by casttrans p q refS x
       === x          by castref refS x
    where open module C = Chain _==_ (ref {A}) (trans {A})

  castlem2 : {A B B' C : S}(A=B : A =S B)(A=B' : A =S B')(B=C : B =S C)(B'=C : B' =S C)
             (x : El C) ->
             A=B << B=C << x == A=B' << B'=C << x
  castlem2 {A} p p' q q' x =
    chain> p << q       << x
       === transS p  q  << x  by casttrans _ _ _ x
       === transS p' q' << x  by pfi _ _ _
       === p' << q'     << x  by sym (casttrans _ _ _ x)
    where open module C = Chain _==_ (ref {A}) (trans {A})

  ref : {A:S} -> Refl {El A} _==_
  ref {nat}      {el n}           = eq refN
  ref {pi A F pF}{el (Pair f pf)} = eq f=f
    where
      f=f : (x : El A) -> f x == f x
      f=f x = ref

  trans : {A:S} -> Trans {El A} _==_
  trans {nat}{el x}{el y}{el z} (eq p) (eq q) = eq (transN p q)
  trans {pi A F pF}{el (Pair f pf)}{el (Pair g pg)}{el (Pair h ph)}
        (eq f=g)(eq g=h) = eq f=h
    where
      f=h : (x : El A) -> f x == h x
      f=h x = trans (f=g x) (g=h x)

  sym : {A:S} -> Sym {El A} _==_
  sym {nat}{el x}{el y} (eq p)  = eq (symN p)
  sym {pi A F pF}{el (Pair f pf)}{el (Pair g pg)}
        (eq f=g) = eq g=f
    where
      g=f : (x : El A) -> g x == f x
      g=f x = sym (f=g x)


{-# OPTIONS --safe #-}

module Cubical.Categories.Instances.Sets where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Categories.Category
open import Cubical.Categories.Functor
open import Cubical.Categories.NaturalTransformation

open Category

module _ ℓ where
  SET : Category (ℓ-suc ℓ) ℓ
  ob SET = hSet ℓ
  Hom[_,_] SET (A , _) (B , _) = A → B
  id SET x = x
  _⋆_ SET f g x = g (f x)
  ⋆IdL SET f = refl
  ⋆IdR SET f = refl
  ⋆Assoc SET f g h = refl
  isSetHom SET {A} {B} = isSetΠ (λ _ → snd B)

private
  variable
    ℓ ℓ' : Level

open Functor

-- Hom functors
_[-,_] : (C : Category ℓ ℓ') → (c : C .ob) → Functor (C ^op) (SET ℓ')
(C [-, c ]) .F-ob x    = (C [ x , c ]) , C .isSetHom
(C [-, c ]) .F-hom f k = f ⋆⟨ C ⟩ k
(C [-, c ]) .F-id      = funExt λ _ → C .⋆IdL _
(C [-, c ]) .F-seq _ _ = funExt λ _ → C .⋆Assoc _ _ _

_[_,-] : (C : Category ℓ ℓ') → (c : C .ob)→ Functor C (SET ℓ')
(C [ c ,-]) .F-ob x    = (C [ c , x ]) , C .isSetHom
(C [ c ,-]) .F-hom f k = k ⋆⟨ C ⟩ f
(C [ c ,-]) .F-id      = funExt λ _ → C .⋆IdR _
(C [ c ,-]) .F-seq _ _ = funExt λ _ → sym (C .⋆Assoc _ _ _)

module _ {C : Category ℓ ℓ'} {F : Functor C (SET ℓ')} where
  open NatTrans

  -- natural transformations by pre/post composition
  preComp : {x y : C .ob}
          → (f : C [ x , y ])
          → C [ x ,-] ⇒ F
          → C [ y ,-] ⇒ F
  preComp f α .N-ob c k = (α ⟦ c ⟧) (f ⋆⟨ C ⟩ k)
  preComp f α .N-hom {x = c} {d} k
    = (λ l → (α ⟦ d ⟧) (f ⋆⟨ C ⟩ (l ⋆⟨ C ⟩ k)))
    ≡[ i ]⟨ (λ l → (α ⟦ d ⟧) (⋆Assoc C f l k (~ i))) ⟩
      (λ l → (α ⟦ d ⟧) (f ⋆⟨ C ⟩ l ⋆⟨ C ⟩ k))
    ≡[ i ]⟨ (λ l → (α .N-hom k) i (f ⋆⟨ C ⟩ l)) ⟩
      (λ l → (F ⟪ k ⟫) ((α ⟦ c ⟧) (f ⋆⟨ C ⟩ l)))
    ∎

-- properties
-- TODO: move to own file
open CatIso renaming (inv to cInv)
open Iso

Iso→CatIso : ∀ {A B : (SET ℓ) .ob}
           → Iso (fst A) (fst B)
           → CatIso (SET ℓ) A B
Iso→CatIso is .mor = is .fun
Iso→CatIso is .cInv = is .inv
Iso→CatIso is .sec = funExt λ b → is .rightInv b -- is .rightInv
Iso→CatIso is .ret = funExt λ b → is .leftInv b -- is .rightInv


open import Data.Product using (∃; ∃-syntax; _×_; _,_)

open import DeBruijn
open import Parallel
open import Beta
open import Takahashi

par-triangle : ∀ {n} {M N : Term n}
  → M ⇉ N
    -------
  → N ⇉ M *
par-triangle {M = # x} ⇉-c = ⇉-c
par-triangle {M = ƛ M} (⇉-ƛ M⇉N) = ⇉-ƛ (par-triangle M⇉N)
par-triangle {M = (ƛ M) · N} (⇉-β M⇉M′ N⇉N′) = sub-par (par-triangle M⇉M′) (par-triangle N⇉N′)
par-triangle {M = # _   · N} (⇉-ξ M⇉M′ N⇉N′)       = ⇉-ξ (par-triangle M⇉M′) (par-triangle N⇉N′)
par-triangle {M = _ · _ · N} (⇉-ξ M⇉M′ N⇉N′)       = ⇉-ξ (par-triangle M⇉M′) (par-triangle N⇉N′)
par-triangle {M = (ƛ _) · N} (⇉-ξ (⇉-ƛ M⇉M′) N⇉N′) = ⇉-β (par-triangle M⇉M′) (par-triangle N⇉N′)

par-diamond : ∀ {n} {M A B : Term n}
  →         M ⇉ A → M ⇉ B
    ----------------------
  → ∃[ N ] (A ⇉ N × B ⇉ N)
par-diamond {M = M} M⇉A M⇉B = M * , par-triangle M⇉A , par-triangle M⇉B

strip : ∀ {n} {M A B : Term n}
  →         M ⇉  A → M ⇉* B
    ------------------------
  → ∃[ N ] (A ⇉* N × B ⇉  N)
strip {A = A} M⇉A (M ∎) = A , (A ∎) , M⇉A
strip {A = A} M⇉A (M ⇉⟨　M⇉M′ ⟩ M′⇉*B)
    with par-diamond M⇉A M⇉M′
... | N , A⇉N , M′⇉N
      with strip M′⇉N M′⇉*B
...   | N′ , N⇉*N′              , B⇉N′ =
        N′ , (A ⇉⟨ A⇉N ⟩ N⇉*N′) , B⇉N′

par-confluence : ∀ {n} {M A B : Term n}
  →         M ⇉* A → M ⇉* B
    ------------------------
  → ∃[ N ] (A ⇉* N × B ⇉* N)
par-confluence {B = B} (M ∎) M⇉*B = B , M⇉*B , (B ∎)
par-confluence {B = B} (M ⇉⟨ M⇉A ⟩ A⇉*A′) M⇉*B
    with strip M⇉A M⇉*B
... | N , A⇉*N , B⇉N
      with par-confluence A⇉*A′ A⇉*N
...   | N′ , A′⇉*N′ , N⇉*N′ =
        N′ , A′⇉*N′ , (B ⇉⟨ B⇉N ⟩ N⇉*N′)

confluence : ∀ {n} {M A B : Term n}
  →         M —↠ A → M —↠ B
    ------------------------
  → ∃[ N ] (A —↠ N × B —↠ N)
confluence M—↠A M—↠B
    with par-confluence (betas-pars M—↠A) (betas-pars M—↠B)
... | N , A⇉*N , B⇉*N =
      N , pars-betas A⇉*N , pars-betas B⇉*N


open import Structure.Setoid
open import Structure.Category
open import Type

module Structure.Category.CoMonad
  {ℓₒ ℓₘ ℓₑ}
  {cat : CategoryObject{ℓₒ}{ℓₘ}{ℓₑ}}
  where

import      Function.Equals
open        Function.Equals.Dependent
open import Functional.Dependent using () renaming (_∘_ to _∘ᶠⁿ_)
import      Lvl
open import Logic.Predicate
open import Structure.Category.Functor
open import Structure.Category.Functor.Functors as Functors
open import Structure.Category.NaturalTransformation
open import Structure.Category.NaturalTransformation.NaturalTransformations as NaturalTransformations

open CategoryObject(cat)
open Category.ArrowNotation(category)
open Category(category)
open Functors.Wrapped
open NaturalTransformations.Raw(intro category)(intro category)
private instance _ = cat

record CoMonad (T : Object → Object) ⦃ functor : Functor(category)(category)(T) ⦄ : Type{Lvl.of(Type.of(cat))} where
  open Functor(functor)

  functor-object : cat →ᶠᵘⁿᶜᵗᵒʳ cat
  functor-object = [∃]-intro T ⦃ functor ⦄
  private Tᶠᵘⁿᶜᵗᵒʳ = functor-object

  field
    Η : (Tᶠᵘⁿᶜᵗᵒʳ →ᴺᵀ idᶠᵘⁿᶜᵗᵒʳ)
    Μ : (Tᶠᵘⁿᶜᵗᵒʳ →ᴺᵀ (Tᶠᵘⁿᶜᵗᵒʳ ∘ᶠᵘⁿᶜᵗᵒʳ Tᶠᵘⁿᶜᵗᵒʳ))

  η = [∃]-witness Η
  μ = [∃]-witness Μ

  η-natural : ∀{x y}{f} → (η(y) ∘ map f ≡ f ∘ η(x))
  η-natural = NaturalTransformation.natural([∃]-proof Η)

  μ-natural : ∀{x y}{f} → (μ(y) ∘ map f ≡ map(map f) ∘ μ(x))
  μ-natural = NaturalTransformation.natural([∃]-proof Μ)

  field
    μ-functor-[∘]-commutativity : ((μ ∘ᶠⁿ T) ∘ᴺᵀ μ ⊜ (map ∘ᶠⁿ μ) ∘ᴺᵀ μ)
    μ-functor-[∘]-identityₗ     : ((map ∘ᶠⁿ η) ∘ᴺᵀ μ ⊜ idᴺᵀ)
    μ-functor-[∘]-identityᵣ     : ((η   ∘ᶠⁿ T) ∘ᴺᵀ μ ⊜ idᴺᵀ)

  module FunctionalNames where
    extract : ∀{x} → (T(x) ⟶ x)
    extract{x} = [∃]-witness Η(x)

    duplicate : ∀{x} → (T(x) ⟶ T(T(x)))
    duplicate{x} = [∃]-witness Μ(x)


{-# OPTIONS --without-K --safe #-}
module Categories.Category.Instance.Globe where

open import Level using (Level; zero)
open import Relation.Binary using (IsEquivalence; module IsEquivalence)
open import Relation.Binary.PropositionalEquality using (isEquivalence)
open import Data.Nat using (ℕ; zero; suc; _<_; _≤_; z≤n; s≤s)

open import Categories.Category

data GlobeHom : (m n : ℕ) → Set where
  I : ∀ {place : ℕ} → GlobeHom place place
  σ : ∀ {n m : ℕ} → GlobeHom (suc n) m → GlobeHom n m
  τ : ∀ {n m : ℕ} → GlobeHom (suc n) m → GlobeHom n m

data GlobeEq : {m n : ℕ} → GlobeHom m n → GlobeHom m n → Set where
  both-I : ∀ {m} → GlobeEq {m} {m} I I
  both-σ : ∀ {m n x y} → GlobeEq {m} {n} (σ x) (σ y)
  both-τ : ∀ {m n x y} → GlobeEq {m} {n} (τ x) (τ y)

GlobeEquiv : ∀ {m n} → IsEquivalence (GlobeEq {m} {n})
GlobeEquiv = record { refl = refl; sym = sym; trans = trans }
  where
  refl : ∀ {m n} {x : GlobeHom m n} → GlobeEq x x
  refl {x = I} = both-I
  refl {x = σ y} = both-σ
  refl {x = τ y} = both-τ
  sym : ∀ {m n} {x y : GlobeHom m n} → GlobeEq x y → GlobeEq y x
  sym both-I = both-I
  sym both-σ = both-σ
  sym both-τ = both-τ
  trans : ∀ {m n} {x y z : GlobeHom m n} → GlobeEq x y → GlobeEq y z → GlobeEq x z
  trans both-I y∼z = y∼z
  trans both-σ both-σ = both-σ
  trans both-τ both-τ = both-τ

infixl 7 _⊚_

_⊚_ : ∀ {l m n} → GlobeHom m n → GlobeHom l m → GlobeHom l n
x ⊚ I = x
x ⊚ σ y = σ (x ⊚ y)
x ⊚ τ y = τ (x ⊚ y)

Globe : Category Level.zero Level.zero Level.zero
Globe = record
  { Obj       = ℕ
  ; _⇒_       = GlobeHom
  ; _≈_       = GlobeEq
  ; id        = I
  ; _∘_       = _⊚_
  ; assoc     = λ {_ _ _ _ f g h} → assoc {f = f} {g} {h}
  ; sym-assoc = λ {_ _ _ _ f g h} → GlobeEquiv.sym (assoc {f = f} {g} {h})
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; identity² = identity²
  ; equiv     = GlobeEquiv
  ; ∘-resp-≈  = ∘-resp-≡
  }
  where
  module GlobeEquiv {m n} = IsEquivalence (GlobeEquiv {m} {n})
  assoc : ∀ {A B C D} {f : GlobeHom A B} {g : GlobeHom B C} {h : GlobeHom C D} → GlobeEq ((h ⊚ g) ⊚ f) (h ⊚ (g ⊚ f))
  assoc {f = I} = refl
    where open IsEquivalence GlobeEquiv
  assoc {f = σ y} = both-σ
  assoc {f = τ y} = both-τ
  identityˡ : ∀ {A B} {f : GlobeHom A B} → GlobeEq (I ⊚ f) f
  identityˡ {f = I} = both-I
  identityˡ {f = σ y} = both-σ
  identityˡ {f = τ y} = both-τ
  identityʳ : ∀ {A B} {f : GlobeHom A B} → GlobeEq (f ⊚ I) f
  identityʳ = IsEquivalence.refl GlobeEquiv
  identity² : {m : ℕ} → GlobeEq {m} (I ⊚ I) I
  identity² = both-I
  ∘-resp-≡ : ∀ {A B C} {f h : GlobeHom B C} {g i : GlobeHom A B} → GlobeEq f h → GlobeEq g i → GlobeEq (f ⊚ g) (h ⊚ i)
  ∘-resp-≡ f∼h both-I = f∼h
  ∘-resp-≡ f∼h both-σ = both-σ
  ∘-resp-≡ f∼h both-τ = both-τ


{-# OPTIONS --cubical --no-import-sorts --no-exact-split --safe #-}
module Cubical.Data.NatMinusOne.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.Data.Nat
open import Cubical.Data.NatMinusOne.Base

-1+Path : ℕ ≡ ℕ₋₁
-1+Path = isoToPath (iso -1+_ 1+_ (λ _ → refl) (λ _ → refl))


------------------------------------------------------------------------------
-- Abelian group theory properties
------------------------------------------------------------------------------

{-# OPTIONS --exact-split              #-}
{-# OPTIONS --no-sized-types           #-}
{-# OPTIONS --no-universe-polymorphism #-}
{-# OPTIONS --without-K                #-}

module GroupTheory.AbelianGroup.PropertiesATP where

open import GroupTheory.AbelianGroup.Base

------------------------------------------------------------------------------

postulate xyx⁻¹≡y : ∀ a b → a · b · a ⁻¹ ≡ b
{-# ATP prove xyx⁻¹≡y #-}

postulate x⁻¹y⁻¹≡[xy]⁻¹ : ∀ a b → a ⁻¹ · b ⁻¹ ≡ (a · b) ⁻¹
{-# ATP prove x⁻¹y⁻¹≡[xy]⁻¹ #-}


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Relation.Binary.Raw.Construct.Constant where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels using (hProp)

open import Cubical.Relation.Binary.Raw

------------------------------------------------------------------------
-- Definition

Const : ∀ {a b c} {A : Type a} {B : Type b} → Type c → RawREL A B c
Const I = λ _ _ → I

------------------------------------------------------------------------
-- Properties

module _ {a c} {A : Type a} {C : Type c} where

  reflexive : C → Reflexive {A = A} (Const C)
  reflexive c = c

  symmetric : Symmetric {A = A} (Const C)
  symmetric c = c

  transitive : Transitive {A = A} (Const C)
  transitive c d = c

  isPartialEquivalence : IsPartialEquivalence {A = A} (Const C)
  isPartialEquivalence = record
    { symmetric  = λ {x} {y} → symmetric {x} {y}
    ; transitive = λ {x} {y} {z} → transitive {x} {y} {z}
    }

  partialEquivalence : PartialEquivalence A c
  partialEquivalence = record { isPartialEquivalence = isPartialEquivalence }

  isEquivalence : C → IsEquivalence {A = A} (Const C)
  isEquivalence c = record
    { isPartialEquivalence = isPartialEquivalence
    ; reflexive            = λ {x} → reflexive c {x}
    }

  equivalence : C → Equivalence A c
  equivalence x = record { isEquivalence = isEquivalence x }


------------------------------------------------------------------------------
-- Arithmetic properties (using induction on the FOTC natural numbers type)
------------------------------------------------------------------------------

{-# OPTIONS --exact-split              #-}
{-# OPTIONS --no-sized-types           #-}
{-# OPTIONS --no-universe-polymorphism #-}
{-# OPTIONS --without-K                #-}

-- Usually our proofs use pattern matching instead of the induction
-- principle associated with the FOTC natural numbers. The following
-- examples show some proofs using it.

module FOTC.Data.Nat.PropertiesByInductionI where

open import Common.FOL.Relation.Binary.EqReasoning

open import FOTC.Base
open import FOTC.Base.PropertiesI
open import FOTC.Data.Nat
open import FOTC.Data.Nat.UnaryNumbers

------------------------------------------------------------------------------
-- Congruence properties

+-leftCong : ∀ {a b c} → a ≡ b → a + c ≡ b + c
+-leftCong refl = refl

+-rightCong : ∀ {a b c} → b ≡ c → a + b ≡ a + c
+-rightCong refl = refl

------------------------------------------------------------------------------

N→0∨S : ∀ {n} → N n → n ≡ zero ∨ (∃[ n' ] n ≡ succ₁ n' ∧ N n')
N→0∨S = N-ind A A0 is
  where
  A : D → Set
  A i = i ≡ zero ∨ (∃[ i' ] i ≡ succ₁ i' ∧ N i')

  A0 : A zero
  A0 = inj₁ refl

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = case prf₁ prf₂ Ai
    where
    prf₁ : i ≡ zero → succ₁ i ≡ zero ∨ (∃[ i' ] succ₁ i ≡ succ₁ i' ∧ N i')
    prf₁ h' = inj₂ (i , refl , (subst N (sym h') nzero))

    prf₂ : ∃[ i' ] i ≡ succ₁ i' ∧ N i' →
           succ₁ i ≡ zero ∨ (∃[ i' ] succ₁ i ≡ succ₁ i' ∧ N i')
    prf₂ (i' , prf , Ni') = inj₂ (i , refl , subst N (sym prf) (nsucc Ni'))

Sx≢x : ∀ {n} → N n → succ₁ n ≢ n
Sx≢x = N-ind A A0 is
  where
  A : D → Set
  A i = succ₁ i ≢ i

  A0 : A zero
  A0 = S≢0

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = →-trans succInjective Ai

+-leftIdentity : ∀ n → zero + n ≡ n
+-leftIdentity n = +-0x n

+-rightIdentity : ∀ {n} → N n → n + zero ≡ n
+-rightIdentity = N-ind A A0 is
  where
  A : D → Set
  A i = i + zero ≡ i

  A0 : A zero
  A0 = +-leftIdentity zero

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = trans (+-Sx i zero) (succCong Ai)

pred-N : ∀ {n} → N n → N (pred₁ n)
pred-N {n} Nn = case h₁ h₂ (N→0∨S Nn)
  where
  h₁ : n ≡ zero → N (pred₁ n)
  h₁ n≡0 = subst N (sym (trans (predCong n≡0) pred-0)) nzero

  h₂ : ∃[ n' ] n ≡ succ₁ n' ∧ N n' → N (pred₁ n)
  h₂ (n' , prf , Nn') = subst N (sym (trans (predCong prf) (pred-S n'))) Nn'

+-N : ∀ {m n} → N m → N n → N (m + n)
+-N {n = n} Nm Nn = N-ind A A0 is Nm
  where
  A : D → Set
  A i = N (i + n)

  A0 : A zero
  A0 = subst N (sym (+-leftIdentity n)) Nn

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = subst N (sym (+-Sx i n)) (nsucc Ai)

∸-N : ∀ {m n} → N m → N n → N (m ∸ n)
∸-N {m} Nm Nn = N-ind A A0 is Nn
  where
  A : D → Set
  A i = N (m ∸ i)

  A0 : A zero
  A0 = subst N (sym (∸-x0 m)) Nm

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = subst N (sym (∸-xS m i)) (pred-N Ai)

+-assoc : ∀ {m} → N m → ∀ n o → m + n + o ≡ m + (n + o)
+-assoc Nm n o = N-ind A A0 is Nm
  where
  A : D → Set
  A i = i + n + o ≡ i + (n + o)

  A0 : A zero
  A0 = zero + n + o   ≡⟨ +-leftCong (+-leftIdentity n) ⟩
       n + o          ≡⟨ sym (+-leftIdentity (n + o)) ⟩
       zero + (n + o) ∎

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = succ₁ i + n + o     ≡⟨ +-leftCong (+-Sx i n) ⟩
              succ₁ (i + n) + o   ≡⟨ +-Sx (i + n) o ⟩
              succ₁ (i + n + o)   ≡⟨ succCong Ai ⟩
              succ₁ (i + (n + o)) ≡⟨ sym (+-Sx i (n + o)) ⟩
              succ₁ i + (n + o)   ∎

x+Sy≡S[x+y] : ∀ {m} → N m → ∀ n → m + succ₁ n ≡ succ₁ (m + n)
x+Sy≡S[x+y] Nm n = N-ind A A0 is Nm
  where
  A : D → Set
  A i = i + succ₁ n ≡ succ₁ (i + n)

  A0 : A zero
  A0 = zero + succ₁ n   ≡⟨ +-leftIdentity (succ₁ n) ⟩
       succ₁ n          ≡⟨ succCong (sym (+-leftIdentity n)) ⟩
       succ₁ (zero + n) ∎

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = succ₁ i + succ₁ n     ≡⟨ +-Sx i (succ₁ n) ⟩
              succ₁ (i + succ₁ n)   ≡⟨ succCong Ai ⟩
              succ₁ (succ₁ (i + n)) ≡⟨ succCong (sym (+-Sx i n)) ⟩
              succ₁ (succ₁ i + n)   ∎

+-comm : ∀ {m n} → N m → N n → m + n ≡ n + m
+-comm {n = n} Nm Nn = N-ind A A0 is Nm
  where
  A : D → Set
  A i = i + n ≡ n + i

  A0 : A zero
  A0 = zero + n ≡⟨ +-leftIdentity n ⟩
       n        ≡⟨ sym (+-rightIdentity Nn) ⟩
       n + zero ∎

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = succ₁ i + n   ≡⟨ +-Sx i n ⟩
              succ₁ (i + n) ≡⟨ succCong Ai ⟩
              succ₁ (n + i) ≡⟨ sym (x+Sy≡S[x+y] Nn i) ⟩
              n + succ₁ i   ∎

0∸x : ∀ {n} → N n → zero ∸ n ≡ zero
0∸x = N-ind A A0 is
  where
  A : D → Set
  A i = zero ∸ i ≡ zero

  A0 : A zero
  A0 = ∸-x0 zero

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = zero ∸ succ₁ i   ≡⟨ ∸-xS zero i ⟩
              pred₁ (zero ∸ i) ≡⟨ predCong Ai ⟩
              pred₁ zero       ≡⟨ pred-0 ⟩
              zero ∎

S∸S : ∀ {m n} → N m → N n → succ₁ m ∸ succ₁ n ≡ m ∸ n
S∸S {m} Nm = N-ind A A0 is
  where
  A : D → Set
  A i = succ₁ m ∸ succ₁ i ≡ m ∸ i

  A0 : A zero
  A0 = succ₁ m ∸ succ₁ zero   ≡⟨ ∸-xS (succ₁ m) zero ⟩
       pred₁ (succ₁ m ∸ zero) ≡⟨ predCong (∸-x0 (succ₁ m)) ⟩
       pred₁ (succ₁ m)        ≡⟨ pred-S m ⟩
       m                      ≡⟨ sym (∸-x0 m) ⟩
       m ∸ zero               ∎

  is : ∀ {i} → A i → A (succ₁ i)
  is {i} Ai = succ₁ m ∸ succ₁ (succ₁ i) ≡⟨ ∸-xS (succ₁ m) (succ₁ i) ⟩
              pred₁ (succ₁ m ∸ succ₁ i) ≡⟨ predCong Ai ⟩
              pred₁ (m ∸ i)             ≡⟨ sym (∸-xS m i) ⟩
              m ∸ succ₁ i               ∎


{-# OPTIONS --safe --without-K #-}
module Data.Fin.Subset.Properties.Dec where

open import Data.Nat as ℕ
open import Data.Fin as Fin
open import Data.Empty using (⊥-elim)
open import Data.Fin.Subset
open import Data.Fin.Subset.Dec
open import Data.Fin.Subset.Properties using (⊆⊤; p⊆p∪q; q⊆p∪q ; p∩q⊆p ; p∩q⊆q ; ⊆-poset)
open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Unary renaming (Decidable to Decidable₁) using ()
open import Data.Vec
open import Function using (_∘_)
open import Function.Equivalence using (_⇔_ ; equivalence)
open import Relation.Nullary.Negation using (¬?)

subset¬⊆∁subset : ∀ {n}{p} {P : Fin n → Set p}(P? : Decidable₁ P) → subset (¬? ∘ P?) ⊆ ∁ (subset P?)
subset¬⊆∁subset {zero} P? ()
subset¬⊆∁subset {suc n} P? x∈s with P? (# 0)
subset¬⊆∁subset {suc n} P? here | no ¬p0 = here
subset¬⊆∁subset {suc n} P? (there x∈s) | no ¬p0 = there (subset¬⊆∁subset (P? ∘ suc) x∈s)
subset¬⊆∁subset {suc n} P? (there x∈s) | yes p0 = there (subset¬⊆∁subset (P? ∘ suc) x∈s)

∁subset⊆subset¬ : ∀ {n}{p}{P : Fin n → Set p}(P? : Decidable₁ P) →  ∁ (subset P?) ⊆ subset (¬? ∘ P?)
∁subset⊆subset¬  {zero} P? ()
∁subset⊆subset¬ {suc n} P? x∈s with P? (# 0)
∁subset⊆subset¬ {suc n} P? here | no ¬p0 = here
∁subset⊆subset¬ {suc n} P? (there x∈s) | yes p0 = there (∁subset⊆subset¬ (P? ∘ suc) x∈s)
∁subset⊆subset¬ {suc n} P? (there x∈s) | no ¬p0 = there (∁subset⊆subset¬ (P? ∘ suc) x∈s)

subset¬≡∁subset  : ∀ {n}{p}{P : Fin n → Set p}(P? : Decidable₁ P) → subset (¬? ∘ P?) ≡ ∁ (subset P?)
subset¬≡∁subset {n} P? = ⊆-antisym (subset¬⊆∁subset P?) (∁subset⊆subset¬ P?)
  where
    open Poset (⊆-poset n) renaming (antisym to ⊆-antisym) using ()

∈subset⁺ : ∀ {n}{p}{P : Fin n → Set p}(P? : Decidable₁ P){x} → P x → x ∈ subset P?
∈subset⁺ {zero} P? {()} Px
∈subset⁺ {suc n} P? {x} Px with P? (# 0)
∈subset⁺ {suc n} P? {zero} Px | yes p0 = here
∈subset⁺ {suc n} P? {suc x} Px | yes p0 = there (∈subset⁺ (P? ∘ suc) Px)
∈subset⁺ {suc n} P? {zero} Px | no ¬p0 = ⊥-elim (¬p0 Px)
∈subset⁺ {suc n} P? {suc x} Px | no ¬p0 = there (∈subset⁺ (P? ∘ suc) Px)

∈subset⁻ : ∀ {n}{p} {P : Fin n → Set p}(P? : Decidable₁ P){x} → x ∈ subset P? → P x
∈subset⁻ {zero} P? {()} x∈s
∈subset⁻ {suc n} P? {x} x∈s with P? (# 0)
∈subset⁻ {suc n} P? {zero} here | yes p0 = p0
∈subset⁻ {suc n} P? {suc x} (there x∈s) | yes p0 = ∈subset⁻ (P? ∘ suc) x∈s
∈subset⁻ {suc n} P? {.(suc _)} (there x∈s) | no ¬p0 = ∈subset⁻ (P? ∘ suc) x∈s

⇔∈subset : ∀ {n}{p}{P : Fin n → Set p}(P? : Decidable₁ P) {x} → x ∈ subset P? ⇔ P x
⇔∈subset P? = equivalence (∈subset⁻ P?) (∈subset⁺ P?)

∈∁subset⁺ : ∀ {n}{p}{P : Fin n → Set p}(P? : Decidable₁ P){x} → ¬ P x → x ∈ ∁ (subset P?)
∈∁subset⁺ P?  = subset¬⊆∁subset P? ∘ (∈subset⁺ (¬? ∘ P? ))
∈∁subset⁻ : ∀ {n}{p}{P : Fin n → Set p}(P? : Decidable₁ P){x} → x ∈ ∁ (subset P?) → ¬ P x
∈∁subset⁻ P? = ∈subset⁻ (¬? ∘ P?) ∘ ∁subset⊆subset¬ P?

⇔∈∁subset : ∀ {n}{p}{P : Fin n → Set p}(P? : Decidable₁ P) {x} → x ∈ ∁ (subset P?) ⇔ (¬ P x)
⇔∈∁subset P? = equivalence (∈∁subset⁻ P?) (∈∁subset⁺ P?)


------------------------------------------------------------------------
-- The unit type
------------------------------------------------------------------------

module Data.Unit where

open import Data.Sum
open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as PropEq
  using (_≡_; refl)

------------------------------------------------------------------------
-- Types

-- Note that the name of this type is "\top", not T.

record ⊤ : Set where

tt : ⊤
tt = record {}

record _≤_ (x y : ⊤) : Set where

------------------------------------------------------------------------
-- Operations

_≟_ : Decidable {⊤} _≡_
_ ≟ _ = yes refl

_≤?_ : Decidable _≤_
_ ≤? _ = yes _

total : Total _≤_
total _ _ = inj₁ _

------------------------------------------------------------------------
-- Properties

preorder : Preorder
preorder = PropEq.preorder ⊤

setoid : Setoid
setoid = PropEq.setoid ⊤

decTotalOrder : DecTotalOrder
decTotalOrder = record
  { carrier         = ⊤
  ; _≈_             = _≡_
  ; _≤_             = _≤_
  ; isDecTotalOrder = record
      { isTotalOrder = record
          { isPartialOrder = record
              { isPreorder = record
                  { isEquivalence = PropEq.isEquivalence
                  ; reflexive     = λ _ → _
                  ; trans         = λ _ _ → _
                  ; ∼-resp-≈      = PropEq.resp₂ _≤_
                  }
              ; antisym  = antisym
              }
          ; total = total
          }
      ; _≟_  = _≟_
      ; _≤?_ = _≤?_
      }
  }
  where
  antisym : Antisymmetric _≡_ _≤_
  antisym _ _ = refl

decSetoid : DecSetoid
decSetoid = DecTotalOrder.Eq.decSetoid decTotalOrder

poset : Poset
poset = DecTotalOrder.poset decTotalOrder