{-# OPTIONS --universe-polymorphism #-}
module Categories.Equivalence.Strong where

-- Strong equivalence of categories.  Same as ordinary equivalence in Cat.
-- May not include everything we'd like to think of as equivalences, namely
-- the full, faithful functors that are essentially surjective on objects.

open import Level
open import Relation.Binary using (IsEquivalence; module IsEquivalence)
open import Function using () renaming (_∘_ to _∙_)

open import Categories.Category
open import Categories.Functor hiding (equiv)
open import Categories.NaturalIsomorphism as NI hiding (equiv)
open import Categories.NaturalTransformation as NT hiding (id; equiv)
open import Categories.Morphisms using (Iso; module Iso)

record WeakInverse {o ℓ e o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} (F : Functor C D) (G : Functor D C) : Set (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′) where
  field
    F∘G≅id : NaturalIsomorphism (F ∘ G) id
    G∘F≅id : NaturalIsomorphism (G ∘ F) id
  F∘G⇒id = NaturalIsomorphism.F⇒G F∘G≅id
  id⇒F∘G = NaturalIsomorphism.F⇐G F∘G≅id
  G∘F⇒id = NaturalIsomorphism.F⇒G G∘F≅id
  id⇒G∘F = NaturalIsomorphism.F⇐G G∘F≅id
  .F∘G-iso : _
  F∘G-iso = NaturalIsomorphism.iso F∘G≅id
  .F∘G-isoˡ : _
  F∘G-isoˡ = λ x → Iso.isoˡ {C = D} (F∘G-iso x)
  .F∘G-isoʳ : _
  F∘G-isoʳ = λ x → Iso.isoʳ {C = D} (F∘G-iso x)
  .G∘F-iso : _
  G∘F-iso = NaturalIsomorphism.iso G∘F≅id
  .G∘F-isoˡ : _
  G∘F-isoˡ = λ x → Iso.isoˡ {C = C} (G∘F-iso x)
  .G∘F-isoʳ : _
  G∘F-isoʳ = λ x → Iso.isoʳ {C = C} (G∘F-iso x)

record StrongEquivalence {o ℓ e o′ ℓ′ e′} (C : Category o ℓ e) (D : Category o′ ℓ′ e′) : Set (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′) where
  field
    F : Functor C D
    G : Functor D C
    weak-inverse : WeakInverse F G
  open WeakInverse weak-inverse public

module Equiv where
  refl : ∀ {o ℓ e} {C : Category o ℓ e} → StrongEquivalence C C
  refl = record
    { F = id
    ; G = id
    ; weak-inverse = record
      { F∘G≅id = IsEquivalence.refl NI.equiv
      ; G∘F≅id = IsEquivalence.refl NI.equiv
      }
    }

  sym : ∀ {o ℓ e o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} → StrongEquivalence C D → StrongEquivalence D C
  sym Inv = record
    { F = Inv.G
    ; G = Inv.F
    ; weak-inverse = record
      { F∘G≅id = Inv.G∘F≅id
      ; G∘F≅id = Inv.F∘G≅id
      }
    }
    where
    module Inv = StrongEquivalence Inv

  trans : ∀ {o₁ ℓ₁ e₁ o₂ ℓ₂ e₂ o₃ ℓ₃ e₃} {C₁ : Category o₁ ℓ₁ e₁} {C₂ : Category o₂ ℓ₂ e₂} {C₃ : Category o₃ ℓ₃ e₃} → StrongEquivalence C₁ C₂ → StrongEquivalence C₂ C₃ → StrongEquivalence C₁ C₃
  trans {C₁ = C₁} {C₂} {C₃} A B = record
    { F = B.F ∘ A.F
    ; G = A.G ∘ B.G
    ; weak-inverse = record
      { F∘G≅id = IsEquivalence.trans NI.equiv ((B.F ⓘˡ A.F∘G≅id) ⓘʳ B.G) B.F∘G≅id
      ; G∘F≅id = IsEquivalence.trans NI.equiv ((A.G ⓘˡ B.G∘F≅id) ⓘʳ A.F) A.G∘F≅id
      }
    }
    where
    module A = StrongEquivalence A
    module B = StrongEquivalence B

equiv : ∀ {o ℓ e} → IsEquivalence (StrongEquivalence {o} {ℓ} {e})
equiv = record { refl = Equiv.refl; sym = Equiv.sym; trans = Equiv.trans }


{-
This second-order signature was created from the following second-order syntax description:

syntax Empty | E

type
  𝟘 : 0-ary

term
  abort : 𝟘  ->  α

theory
  (𝟘η) e : 𝟘  c : α |> abort(e) = c
-}

module Empty.Signature where

open import SOAS.Context

-- Type declaration
data ET : Set where
  𝟘 : ET

open import SOAS.Syntax.Signature ET public
open import SOAS.Syntax.Build ET public

-- Operator symbols
data Eₒ : Set where
  abortₒ : {α : ET} → Eₒ

-- Term signature
E:Sig : Signature Eₒ
E:Sig = sig λ
  { (abortₒ {α}) → (⊢₀ 𝟘) ⟼₁ α
  }

open Signature E:Sig public


{-# OPTIONS --universe-polymorphism #-}
open import Categories.Category
open import Categories.Object.BinaryProducts
open import Categories.Object.Exponentiating

module Categories.Object.Exponentiating.Adjunction {o ℓ e}
    (C : Category o ℓ e)
    (binary : BinaryProducts C)
    (Σ : Category.Obj C)
    (exponentiating : Exponentiating C binary Σ) where

open Category C
open BinaryProducts binary
open Exponentiating exponentiating

import Categories.Object.Product
open Categories.Object.Product C

import Categories.Object.Product.Morphisms
open Categories.Object.Product.Morphisms C

open Equiv
open HomReasoning

import Categories.Object.Exponentiating.Functor
open Categories.Object.Exponentiating.Functor C binary Σ exponentiating

open import Categories.Functor
  using (Functor; Contravariant)
  renaming (id to idF; _≡_ to _≡F_; _∘_ to _∘F_)

open import Categories.Adjunction hiding (_≡_; id)
open import Categories.NaturalTransformation
  using (NaturalTransformation; module NaturalTransformation)
open import Categories.Monad
  using (Monad)

Σ↑-Self-Adjunction : Adjunction (Functor.op Σ↑-Functor) Σ↑-Functor
Σ↑-Self-Adjunction = record
  { unit    = record
      { η       = λ _ → flip id
      ; commute = unit-commute
      }
  ; counit  = record
      { η       = λ _ → flip id
      ; commute = counit-commute
      }
  ; zig     = zig-zag
  ; zag     = zig-zag
  } where
    .lem₁ : ∀{A B C D}{f : (B × C) ⇒ D}{g : A ⇒ (C × B)}
      → (f ∘ swap ∘ second id) ∘ g
      ≡ f ∘ swap ∘ g
    lem₁ {A}{B}{C}{D}{f}{g} =
      begin
        (f ∘ swap ∘ second id) ∘ g
      ↓⟨ (refl ⟩∘⟨ refl ⟩∘⟨ second-id product) ⟩∘⟨ refl ⟩
        (f ∘ swap ∘ id) ∘ g
      ↓⟨ (refl ⟩∘⟨ identityʳ) ⟩∘⟨ refl ⟩
        (f ∘ swap) ∘ g
      ↓⟨ assoc ⟩
        f ∘ swap ∘ g
      ∎

    .lem₂ : ∀ {X Y}{f : X ⇒ Y}
      → eval {Σ↑ Y} ∘ first (flip id ∘ f)
      ≡ eval {X}    ∘ swap ∘ second [Σ↑ f ]
    lem₂ {X}{Y}{f} =
      begin
        eval {Σ↑ Y} ∘ first (flip id ∘ f)
      ↑⟨ refl ⟩∘⟨ first∘first ⟩
        eval {Σ↑ Y} ∘ first (flip id) ∘ first f
      ↑⟨ assoc ⟩
        (eval {Σ↑ Y} ∘ first (flip id)) ∘ first f
      ↓⟨ β ⟩∘⟨ refl ⟩
        (eval {Y} ∘ swap ∘ second id) ∘ first f
      ↓⟨ lem₁ ⟩
        eval {Y} ∘ swap ∘ first f
      ↓⟨ refl ⟩∘⟨ swap∘⁂ ⟩
        eval {Y} ∘ second f ∘ swap
      ↑⟨ assoc ⟩
        (eval {Y} ∘ second f) ∘ swap
      ↑⟨ β ⟩∘⟨ refl ⟩
        (eval {X} ∘ first (λ-abs X (eval {Y} ∘ second f))) ∘ swap
      ↓⟨ assoc ⟩
        eval {X} ∘ first (λ-abs X (eval {Y} ∘ second f)) ∘ swap
      ↑⟨ refl ⟩∘⟨ swap∘⁂ ⟩
        eval {X} ∘ swap ∘ second (λ-abs X (eval ∘ second f))
      ∎

    .unit-commute : ∀ {X Y} (f : X ⇒ Y)
      → flip id ∘ f ≡ [Σ² f ] ∘ flip id
    unit-commute {X}{Y} f =
      begin
        flip id ∘ f
      ↓⟨ λ-unique lem₂ ⟩
        flip [Σ↑ f ]
      ↑⟨ λ-cong lem₁ ⟩
        λ-abs (Σ↑ Y) ((eval {X} ∘ swap ∘ second id) ∘ second [Σ↑ f ])
      ↓⟨ λ-distrib ⟩
        [Σ↑ [Σ↑ f ] ] ∘ flip id
      ∎

    .counit-commute : ∀ {X Y} (f : X ⇒ Y)
      → [Σ² f ] ∘ flip id ≡ flip id ∘ f
    counit-commute f = sym (unit-commute f)

    .zig-zag : ∀{X}
      → id ≡ [Σ↑ flip id ] ∘ flip id
    zig-zag {X} =
      begin
        id
      ↑⟨ flip² ⟩
        flip (flip id)
      ↑⟨ λ-cong lem₁ ⟩
        λ-abs X ((eval ∘ swap ∘ second id) ∘ second (flip id))
      ↓⟨ λ-distrib ⟩
        [Σ↑ flip id ] ∘ flip id
      ∎


module Numeral.Natural.Decidable where

open import Data
open import Data.Boolean
open import Functional
open import Lang.Inspect
open import Logic.Propositional
open import Numeral.Natural
open import Structure.Function
open import Structure.Function.Domain
open import Structure.Relator.Properties
open import Type.Properties.Decidable

module _ where
  open import Numeral.Natural.Oper.Comparisons
  open import Numeral.Natural.Oper.Proofs
  open import Relator.Equals
  open import Relator.Equals.Proofs.Equiv

  instance
    [≡?]-decider : Decider(2)(_≡_)(_≡?_)
    [≡?]-decider {𝟎}   {𝟎}   = true [≡]-intro
    [≡?]-decider {𝟎}   {𝐒 y} = false \()
    [≡?]-decider {𝐒 x} {𝟎}   = false \()
    [≡?]-decider {𝐒 x} {𝐒 y} with (x ≡? y) | [≡?]-decider {x} {y}
    ... | 𝑇 | true  xy  = true  (congruence₁(𝐒) xy)
    ... | 𝐹 | false nxy = false (nxy ∘ injective(𝐒))

  zero?-decider : Decider(1)(_≡ 𝟎)(zero?)
  zero?-decider {𝟎}   = true [≡]-intro
  zero?-decider {𝐒 x} = false \()

module _ where
  open import Numeral.Natural.Oper.Comparisons
  open import Numeral.Natural.Oper.Proofs
  open import Numeral.Natural.Oper.Divisibility
  open import Numeral.Natural.Oper.Modulo
  open import Numeral.Natural.Oper.Modulo.Proofs
  open import Numeral.Natural.Relation.Divisibility
  open import Numeral.Natural.Relation.Divisibility.Proofs
  open import Relator.Equals
  open import Relator.Equals.Proofs.Equiv

  instance
    [∣]-decider : Decider(2)(_∣_)(_∣₀?_)
    [∣]-decider {𝟎} {𝟎}   = true Div𝟎
    [∣]-decider {𝟎} {𝐒 y} = false [0]-divides-not
    [∣]-decider {𝐒 x} {y} with y mod 𝐒(x) | inspect(\x → y mod 𝐒(x)) x
    ... | 𝟎   | intro eq = true  ([↔]-to-[→] mod-divisibility eq)
    ... | 𝐒 _ | intro eq = false ([𝐒]-not-0 ∘ transitivity(_≡_) (symmetry(_≡_) eq) ∘ [↔]-to-[←] mod-divisibility)

module _ where
  open import Data.Boolean.Stmt
  open import Data.Boolean.Stmt.Proofs
  open import Data.List
  open import Data.List.Decidable as List
  open import Data.List.Equiv.Id
  open import Lang.Inspect
  open import Logic.Classical
  open import Logic.Predicate
  open import Numeral.Natural.LinearSearch
  open import Numeral.Natural.Oper.Divisibility
  open import Numeral.Natural.Prime
  open import Numeral.Natural.Prime.Proofs
  open import Numeral.Natural.Relation.Divisibility
  open import Numeral.Natural.Relation.Divisibility.Proofs
  open import Numeral.Natural.Relation.Order
  open import Numeral.Natural.Relation.Order.Classical
  open import Numeral.Natural.Relation.Order.Proofs
  open import Relator.Equals
  open import Relator.Equals.Proofs.Equiv
  open import Type.Properties.Decidable.Proofs
  open import Syntax.Implication.Dependent
  open import Syntax.Implication using (•_•_⇒₂-[_]_)

  -- A naive primality test using bruteforce.
  -- It checks if there are any divisors between 2 and p.
  -- Note: The performance and space should be terrible on this implementation because it checks whether the list of all divisors is empty.
  prime? : ℕ → Bool
  prime? 0          = 𝐹
  prime? 1          = 𝐹
  prime? n@(𝐒(𝐒 _)) = decide(2)(_≡_) ⦃ [∃]-intro _ ⦃ List.[≡]-decider ⦃ dec = [≡?]-decider ⦄ ⦄ ⦄ (findBoundedAll 2 n (_∣₀? n)) ∅

  instance
    Prime-decider : Decider(1)(Prime)(prime?)
    Prime-decider {𝟎} = false \()
    Prime-decider {𝐒 𝟎} = false \()
    Prime-decider {n@(𝐒(𝐒 x))} with prime? n | inspect prime? n
    ... | 𝑇 | intro eq = true $
      eq ⇒
      (prime? n ≡ 𝑇)                                     ⇒-[ [↔]-to-[←] IsTrue.is-𝑇 ]
      IsTrue(prime? n)                                   ⇒-[ [↔]-to-[←] (decider-true ⦃ List.[≡]-decider ⦃ dec = [≡?]-decider ⦄ ⦄) ]
      findBoundedAll 2 n (_∣₀? n) ≡ ∅                    ⇒-[ (\empty {_} → [↔]-to-[←] (findBoundedAll-emptyness{f = _∣₀? n}) empty) ]
      (∀{d} → (2 ≤ d) → (d < n) → IsFalse(d ∣₀? n))      ⇒-[ (\p {i} → [↔]-to-[←] (decider-false ⦃ [∣]-decider ⦄) ∘₂ p) ]
      (∀{d} → (2 ≤ d) → (d < n) → ¬(d ∣ n))              ⇒-[]
      (∀{d} → (2 ≤ d) → (d < 𝐒(𝐒(x))) → ¬(d ∣ 𝐒(𝐒(x))))  ⇒-[ (\p {d} div 2d dx → p{d} 2d (succ dx) div) ]
      (∀{d} → (d ∣ 𝐒(𝐒(x))) → (2 ≤ d) → ¬(d ≤ 𝐒(x)))     ⇒-[ (\p {d} div → [¬→]-disjunctive-formᵣ ⦃ decider-to-classical ⦃ [≡?]-decider ⦄ ⦄ \ nd0 → antisymmetry(_≤_)(_≡_) ([≤]-without-[𝐒] (divides-upper-limit div)) (sub₂(_≯_)(_≤_) (p{𝐒 d} div (succ ([≢]-to-[<]-of-0ᵣ nd0))))) ]
      (∀{d} → (𝐒(d) ∣ 𝐒(𝐒(x))) → ((d ≡ 0) ∨ (d ≡ 𝐒(x)))) ⇒-[ intro ]
      Prime n                                            ⇒-end
    ... | 𝐹 | intro eq = false \p →
      • (
        p ⇒
        Prime(n)                                      ⇒-[ prime-only-divisors ]
        (∀{d} → (d ∣ n) → ((d ≡ 1) ∨ (d ≡ n)))        ⇒-[ (\p {d} 2d dn div → [∨]-elim (\{[≡]-intro → [≤][0]ᵣ-negation ([≤]-without-[𝐒] 2d)}) (\{[≡]-intro → irreflexivity(_<_) dn}) (p div)) ]
        (∀{d} → (2 ≤ d) → (d < n) → ¬(d ∣ n))         ⇒-[ ((\p {i} → [↔]-to-[→] (decider-false ⦃ [∣]-decider ⦄) ∘₂ p)) ]
        (∀{d} → (2 ≤ d) → (d < n) → IsFalse(d ∣₀? n)) ⇒-[ [↔]-to-[→] findBoundedAll-emptyness ]
        findBoundedAll 2 n (_∣₀? n) ≡ ∅               ⇒-[ [↔]-to-[→] (decider-true ⦃ List.[≡]-decider ⦃ dec = [≡?]-decider ⦄ ⦄) ]
        IsTrue(prime? n)                              ⇒-end
      )
      • (
        eq ⇒
        (prime? n ≡ 𝐹)                    ⇒-[ [↔]-to-[←] IsFalse.is-𝐹 ]
        IsFalse(prime? n)                 ⇒-end
      )
      ⇒₂-[ disjointness ]
      Empty ⇒-end

  import      Data.Either as Either
  open import Data.List.Relation.Membership using (_∈_)
  open import Data.List.Relation.Membership.Proofs
  open import Data.Tuple as Tuple using (_⨯_ ; _,_)
  open import Logic.Propositional.Theorems
  open import Numeral.Natural.Oper
  open import Numeral.Natural.Oper.Proofs
  open import Numeral.Natural.Proofs
  open import Numeral.Natural.Relation.Order.Existence using ([≤]-equivalence)
  open import Structure.Function.Domain
  open import Structure.Operator
  open import Structure.Operator.Properties
  open import Syntax.Transitivity

  prime-composite-not : ∀{n} → Prime(n) → Composite(n) → ⊥
  prime-composite-not {.(𝐒(𝐒(a)) ⋅ 𝐒(𝐒(b)))} p (intro a b) =
    Either.map1
      (\())
      ((\()) ∘ cancellationₗ(_+_) {x = a} ∘ injective(𝐒) ∘ injective(𝐒))
      (prime-only-divisors p {𝐒(𝐒(a))} (divides-with-[⋅] {c = 𝐒(𝐒(b))} ([∨]-introₗ divides-reflexivity)))

  -- Using Numeral.Natural.Decidable.prime?, when it is false, there is a divisor d between 2 and n for n. This means that (d ∣ n). Equivalently ∃(k ↦ d ⋅ k ≡ n). The proof of Composite uses these d and k.
  prime-or-composite : ∀{n} → Prime(𝐒(𝐒(n))) ∨ Composite(𝐒(𝐒(n)))
  prime-or-composite{n} = [¬→]-disjunctive-formᵣ ⦃ decider-to-classical ⦃ Prime-decider ⦄ ⦄ $
    ¬ Prime(𝐒(𝐒(n)))                                                                ⇒-[ [↔]-to-[→] (decider-false ⦃ Prime-decider ⦄) ]
    IsFalse(prime? (𝐒(𝐒(n))))                                                       ⇒-[ [↔]-to-[←] (decider-false ⦃ List.[≡]-decider ⦃ dec = [≡?]-decider ⦄ ⦄) ]
    findBoundedAll 2 (𝐒(𝐒(n))) (_∣₀? 𝐒(𝐒(n))) ≢ ∅                                   ⇒-[ non-empty-inclusion-existence ]
    ∃(_∈ findBoundedAll 2 (𝐒(𝐒(n))) (_∣₀? 𝐒(𝐒(n))))                                 ⇒-[ [∃]-map-proof ([↔]-to-[→] (findBoundedAll-membership {f = _∣₀? 𝐒(𝐒(n))})) ]
    ∃(d ↦ (2 ≤ d) ∧ (d < 𝐒(𝐒(n))) ∧ IsTrue(d ∣₀? 𝐒(𝐒(n))))                          ⇒-[ [∃]-map-proof ([∧]-map id ([↔]-to-[←] (decider-true ⦃ [∣]-decider ⦄))) ]
    ∃(d ↦ (2 ≤ d) ∧ (d < 𝐒(𝐒(n))) ∧ (d ∣ 𝐒(𝐒(n))))                                  ⇒-[ (\{([∃]-intro (𝐒 𝟎) ⦃ [∧]-intro ([∧]-intro (succ()) _) _ ⦄) ; ([∃]-intro (𝐒(𝐒 d)) ⦃ [∧]-intro ([∧]-intro d2 dn) div ⦄) → [∃]-intro d ⦃ [∧]-intro dn div ⦄}) ]
    ∃(d ↦ (𝐒(𝐒(d)) < 𝐒(𝐒(n))) ∧ (𝐒(𝐒(d)) ∣ 𝐒(𝐒(n))))                                ⇒-[ (\{([∃]-intro d ⦃ [∧]-intro dn div ⦄) → [∃]-intro d ⦃ [∧]-intro dn ([∃]-intro div ⦃ divides-quotient-correctness {yx = div} ⦄) ⦄}) ]
    ∃(d ↦ (𝐒(𝐒(d)) < 𝐒(𝐒(n))) ∧ ∃{Obj = 𝐒(𝐒(d)) ∣ 𝐒(𝐒(n))}(q ↦ (𝐒(𝐒(d)) ⋅ divides-quotient q ≡ 𝐒(𝐒(n))))) ⇒-[ (\{([∃]-intro d ⦃ [∧]-intro dn ([∃]-intro q ⦃ prod ⦄) ⦄) → [∃]-intro (d , [∃]-witness ([↔]-to-[←] [≤]-equivalence (divides-quotient-composite (succ (succ min)) dn {q}))) ⦃ congruence₂ᵣ(_⋅_)(𝐒(𝐒(d))) (([∃]-proof ([↔]-to-[←] [≤]-equivalence (divides-quotient-composite (succ (succ min)) dn {q})))) 🝖 prod ⦄}) ]
    ∃{Obj = ℕ ⨯ ℕ}(\(a , b) → (𝐒(𝐒(a)) ⋅ 𝐒(𝐒(b)) ≡ 𝐒(𝐒(n))))                        ⇒-[ [↔]-to-[←] composite-existence ]
    Composite(𝐒(𝐒 n))                                                               ⇒-end

  prime-xor-composite : ∀{n} → Prime(𝐒(𝐒(n))) ⊕ Composite(𝐒(𝐒(n)))
  prime-xor-composite {n} = [⊕]-or-not-both prime-or-composite (Tuple.uncurry prime-composite-not)

  open import Data.Tuple
  -- open import Numeral.Natural.Inductions
  {-# TERMINATING #-}
  -- TODO: Use strong induction. (a < n) because (a ⋅ b = n).
  prime-factor-existence : ∀{n} → ∃(PrimeFactor(𝐒(𝐒(n))))
  prime-factor-existence {n} with prime-or-composite{n}
  ... | Either.Left  p = [∃]-intro (𝐒(𝐒(n))) ⦃ intro ⦃ p ⦄ ⦄
  ... | Either.Right c
    with [∃]-intro(a , b) ⦃ p ⦄ ← [↔]-to-[→] composite-existence c
    with [∃]-intro d ⦃ pa ⦄ ← prime-factor-existence{a}
    = [∃]-intro d ⦃ divisor-primeFactors ([↔]-to-[→] divides-[⋅]-existence ([∃]-intro (𝐒 (𝐒 b)) ⦃ p ⦄)) pa ⦄


------------------------------------------------------------------------
-- INCREMENTAL λ-CALCULUS
--
-- Postulate extensionality of functions.
--
-- Justification on Agda mailing list:
-- http://permalink.gmane.org/gmane.comp.lang.agda/2343
------------------------------------------------------------------------

module Postulate.Extensionality where

open import Relation.Binary.PropositionalEquality

postulate ext : ∀ {a b} → Extensionality a b

-- Convenience of using extensionality 3 times in a row
-- (using it twice in a row is moderately tolerable)
ext³ : ∀
  {A : Set}
  {B : A → Set}
  {C : (a : A) → B a → Set }
  {D : (a : A) → (b : B a) → C a b → Set}
  {f g : (a : A) → (b : B a) → (c : C a b) → D a b c} →
  ((a : A) (b : B a) (c : C a b) → f a b c ≡ g a b c) → f ≡ g

ext³ fabc=gabc = ext (λ a → ext (λ b → ext (λ c → fabc=gabc a b c)))


module Deriv where

open import Relation.Binary.Bundles using (DecSetoid)
open import Algebra.Bundles using (Semiring)
open import Level using (0ℓ)
open import Relation.Nullary using (yes; no)

module _ (S : DecSetoid 0ℓ 0ℓ) (Targ : Set) where

  open DecSetoid S renaming (Carrier to Key)

  infixl 6 _+_
  infixl 7 _*_
  data Expr : Set where
    ↑ : Targ → Expr
    ! : Key → Expr
    _+_ : Expr → Expr → Expr
    _*_ : Expr → Expr → Expr

module _ {S : DecSetoid 0ℓ 0ℓ} (R : Semiring 0ℓ 0ℓ) where

  private module S = DecSetoid S
  open S renaming (Carrier to Key)
  private module R = Semiring R
  open R using (0#; 1#) renaming (Carrier to Targ)

  eval
    : (lookup : Key → Targ)
    → (expr : Expr S Targ)
    → Targ
  eval lookup (↑ x) = x
  eval lookup (! x) = lookup x
  eval lookup (x + x₁) = eval lookup x₁ R.+ eval lookup x₁
  eval lookup (x * x₁) = eval lookup x₁ R.* eval lookup x₁

  deriv : Expr S Targ → Key → Expr S Targ
  deriv (↑ x) k = ↑ 0#
  deriv (! x) k with x ≟ k
  deriv (! x) k | yes _ = ↑ 1#
  deriv (! x) k | no _ = ↑ 0#
  deriv (e + e₁) k = deriv e k + deriv e₁ k
  deriv (e * e₁) k = (deriv e k * e₁) + (e * deriv e₁ k)

open import Data.Nat using (ℕ)
open import Data.Nat.Properties using (+-*-semiring)
open import Data.String
open import Relation.Binary.PropositionalEquality using (decSetoid)

asdf : Expr (decSetoid _≟_) ℕ
asdf = ↑ 2 + (↑ 5 * (! "hello" * ! "goodbye"))

asdf' : Expr (decSetoid _≟_) ℕ
asdf' = deriv +-*-semiring asdf "hello"

normalize : ∀ {D} → Expr D ℕ → Expr D ℕ
normalize (x + y) with normalize x | normalize y
normalize (x + y) | ↑ w | ↑ z   = ↑ (w Data.Nat.+ z)
normalize (x + y) | ↑ 0 | z   = z
normalize (x + y) | w   | ↑ 0 = w
normalize (x + y) | w   | z   = w + z
normalize (x * y) with normalize x | normalize y
normalize (x * y) | ↑ w | ↑ z   = ↑ (w Data.Nat.* z)
normalize (x * y) | ↑ 0 | z   = ↑ 0
normalize (x * y) | w   | ↑ 0 = ↑ 0
normalize (x * y) | ↑ 1 | z   = z
normalize (x * y) | w   | ↑ 1 = w
normalize (x * y) | w   | z   = w * z
normalize z = z

module _ (R : Semiring 0ℓ 0ℓ) where
  open Semiring R
  private module R = Semiring R

  asdf'' : Carrier
  asdf'' = 1# R.+ 0#


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Data.Unit.Polymorphic where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Relation.Nullary using (yes)
open import Cubical.Relation.Binary.Raw using (Decidable)

import Cubical.Data.Unit.Base as ⊤

⊤ : {ℓ : Level} → Type ℓ
⊤ = Lift ⊤.⊤

pattern tt = lift ⊤.tt

infix 4 _≟_

_≟_ : {ℓ : Level} → Decidable {A = ⊤ {ℓ}} _≡_
_ ≟ _ = yes refl

isContr⊤ : {ℓ : Level} → isContr (⊤ {ℓ})
isContr⊤ = tt , λ {tt → refl}

isProp⊤ : {ℓ : Level} → isProp (⊤ {ℓ})
isProp⊤ _ _ i = tt


-- Non-indexed (plain) monads in form of Kleisli triple, presented in point-free style.

module Control.Comonad where

open import Function using (id) renaming (_∘′_ to _∘_)
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

open import Axiom.FunctionExtensionality
open import Control.Functor

record IsComonad (W : Set → Set) : Set₁ where

  -- Methods.

  field
    extract : ∀ {A  } → W A → A
    extend  : ∀ {A B} → (W A → B) → W A → W B

  -- Laws.

  field

    extend-β : ∀ {A B} {k : W A → B} →

      extract ∘ extend k ≡ k

    extend-η : ∀ {A} →

      extend {A = A} extract ≡ id

    extend-∘ : ∀ {A B C} {k : W A → B} {l : W B → C} →

      extend (l ∘ extend k) ≡ extend l ∘ extend k

  -- Comonadic composition.

  comComp : ∀ {A B C : Set} (l : W B → C) (k : W A → B) → (W A → C)
  comComp l k = l ∘ extend k

  -- Functoriality.

  isFunctor : IsFunctor W
  isFunctor = record
    { ops  = record { map = map  }
    ; laws = record { map-id = extend-η ; map-∘ = λ {A B C f g} → sym (map-∘-sym f g) }
    }
    where
      map : ∀ {A B} → (A → B) → W A → W B
      map f = extend (f ∘ extract)

      map-∘-sym : ∀ {A B C} (f : A → B) (g : B → C) → map g ∘ map f ≡ map (g ∘ f)
      map-∘-sym f g = begin
        map g ∘ map f                                ≡⟨⟩
        extend (g ∘ extract) ∘ extend (f ∘ extract)  ≡⟨ sym extend-∘ ⟩
        extend (g ∘ extract ∘ extend (f ∘ extract))  ≡⟨ cong (λ z → extend (g ∘ z)) extend-β ⟩
        extend (g ∘ f ∘ extract)                     ≡⟨⟩
        map (g ∘ f)                                  ∎

  open IsFunctor isFunctor public

-- Monads in Kleisli Triple presentation.

record Comonad : Set₁ where
  constructor comonad
  field
    W  : Set → Set
    W! : IsComonad W

  open IsComonad W! public

-- Casting a Comonad to a Functor

FunctorOfComonad : Comonad → Functor
FunctorOfComonad WW = functor W isFunctor
  where open Comonad WW


{-# OPTIONS --cubical #-}
module _ where

-- Test case by Ulf Norell, 16/09/2020

open import Agda.Primitive.Cubical    renaming (primIMin to _∧_)
open import Agda.Builtin.Cubical.Path using (_≡_)

data Nat : Set where
  zero : Nat
  suc  : Nat → Nat

record Pos : Set where
  constructor 1+_
  field unpos : Nat

open Pos

Pos→Nat : Pos → Nat
Pos→Nat (1+ n) = suc n

variable
  A : Set
  x : A

refl : x ≡ x
refl {x = x} i = x

id : Pos → Pos
id n = n

-- (i ∧ j) in the system caused a mishandling of de Bruijn indexes.
foo : (n : Pos) (i j : I) → Nat
foo n i j = primHComp
              (λ k → primPOr (i ∧ j)                (i ∧ j)
                             (λ _ → suc (n .unpos)) (λ _ → suc (n .unpos)))
              (suc (n .unpos))

-- The test triggers normalization to make sure the `primHComp` in
-- `foo` reduces properly.
                             --  v  foil syntactic equality check
test : ∀ n i j → foo n i j ≡ foo (id n) i j
test n i j = refl


{-# OPTIONS --cubical --safe #-}

module Equality where

open import Cubical.Core.Everything         using (_≡_; Level; Type; Σ; _,_; fst; snd; _≃_; ~_)
open import Cubical.Foundations.Prelude     using (refl; sym; cong; transport; subst; funExt; transp; I; i0; i1)
open import Cubical.Foundations.Function    using (_∘_)
open import Cubical.Foundations.Univalence  using (ua)
open import Cubical.Foundations.Isomorphism using (iso; Iso; isoToPath; section; retract)

open import Data.Bool.Base      using (Bool; true; false; _∧_)
open import Data.Nat.Base       using (ℕ; zero; suc; _+_)
open import Data.Fin            using (Fin; toℕ; fromℕ; #_; opposite) renaming (zero to fz; suc to fs)
open import Data.Product        using (_×_; proj₁; proj₂)

-- mutual recursion
data Γ : ℕ → Type
data U : {n : ℕ} → Γ n → Type

-- context (snoc list of dependent types)
data Γ where
  ε   : Γ 0
  _∙_ : {n : ℕ} → (γ : Γ n) → U γ → Γ (suc n)

tail : {n : ℕ} → Γ (suc n) → Γ n
tail (γ ∙ _) = γ

drop : {n : ℕ} → (k : ℕ) → Γ (k + n) → Γ n
drop zero    γ       = γ
drop (suc k) (γ ∙ x) = drop k γ

head : {n : ℕ} → (γ : Γ (suc n)) → U (tail γ)
head (_ ∙ A) = A

-- lookup a type in a context at position k
lookup : {n : ℕ} → (k : ℕ) → (γ : Γ (k + suc n)) → U (tail (drop k γ))
lookup k γ = head (drop k γ)

-- type universe
data U where
  nat : {n : ℕ} → {γ : Γ n} → U γ
  pi  : {n : ℕ} → {γ : Γ n} → (A : U γ) → U (γ ∙ A) → U γ

data Term : {n : ℕ} → (γ : Γ n) → U γ → Type where
--  v  : {n : ℕ} → (k : ℕ) → {γ : Γ (k + suc n)} → {A : U (tail (drop k γ))} → Term (tail (drop k γ)) A
  v  : {n : ℕ} → (k : ℕ) → {γ : Γ (k + suc n)} → {A : U (tail (drop k γ))} → Term (tail (drop k γ)) A
  tz : {n : ℕ} → {γ : Γ n} → Term γ nat -- zero
  ts : {n : ℕ} → {γ : Γ n} → Term γ nat → Term γ nat -- suc
--  tn : (P : Term nat → U) → Term (P tz) → ((n : Term nat) → Term (P n) → Term (P (ts n))) → (n : Term nat) → Term (P n) -- natrec
  tλ : {n : ℕ} → {γ : Γ n} → {A : U γ} → {B : U (γ ∙ A)} → Term (γ ∙ A) B → Term γ (pi A B)
  ta : {n : ℕ} → {γ : Γ n} → {A : U γ} → {B : U (γ ∙ A)} → Term γ (pi A B) → Term γ A → Term (γ ∙ A) B

--+1 : Term ε (pi nat nat)
--+1 = tλ {!!} --(v {n = 0} 0)

data Eq : Type where
  eq : Eq -- equal
  ne : Eq -- not equal

data Maybe (a : Type) : Type where
  nothing : Maybe a
  just    : a → Maybe a

ℕeq : ℕ → ℕ → Eq
ℕeq zero zero       = eq
ℕeq zero (suc n)    = ne
ℕeq (suc m) zero    = ne
ℕeq (suc m) (suc n) = ℕeq m n

natrec : (P : ℕ → Type) → P 0 → ((n : ℕ) → P n → P (suc n)) → (n : ℕ) → P n
natrec P z s zero    = z
natrec P z s (suc n) = s n (natrec P z s n)

_+'_ : ℕ → ℕ → ℕ
_+'_ = λ m → λ n → natrec (λ _ → ℕ) n (λ _ → suc) m

0=0 : 0 ≡ 0
0=0 = refl

suc=suc : (m n : ℕ) → m ≡ n → suc m ≡ suc n
suc=suc m n e = cong suc e

0+n=n : (n : ℕ) → 0 + n ≡ n
0+n=n = natrec (λ k → 0 + k ≡ k) 0=0 (λ n e → suc=suc n n e)

n=0+n : (n : ℕ) → n + 0 ≡ n
n=0+n = natrec (λ k → k + 0 ≡ k) 0=0 λ n e → suc=suc (n + 0) n e


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

module Math.FormalLanguage where

-- agda-stdlib
import Algebra.FunctionProperties as FP
import Algebra.Structures as Structures
open import Level renaming (zero to lzero; suc to lsuc)
open import Data.List as L using (List; []; _++_)
import Data.List.Properties as Lₚ
open import Data.Nat hiding (_⊔_; _^_)
open import Data.Empty
open import Data.Product using (proj₁; proj₂; _,_; _×_; ∃₂; ∃)
open import Function using (_$_)
import Function as F
open import Relation.Binary.PropositionalEquality
open import Relation.Binary
open import Relation.Unary hiding (∅; ｛_｝)
import Relation.Unary as U
import Relation.Unary.Properties as Uₚ

-- Equivalence of predicate
infix 4 _≡ᴾ_
_≡ᴾ_ : ∀ {a l} {A : Set a} → Rel (Pred A l) (a ⊔ l)
_≡ᴾ_ P Q = (P ⊆ Q) × (Q ⊆ P)

≡ᴾ-refl : ∀ {a l} {A : Set a} → Reflexive {A = Pred A l} _≡ᴾ_
≡ᴾ-refl = F.id , F.id

≡ᴾ-sym : ∀ {a l} {A : Set a} → Symmetric {A = Pred A l} _≡ᴾ_
≡ᴾ-sym = Data.Product.swap

≡ᴾ-trans : ∀ {a l} {A : Set a} → Transitive {A = Pred A l} _≡ᴾ_
≡ᴾ-trans P≡Q Q≡R = proj₁ Q≡R F.∘ proj₁ P≡Q , proj₂ P≡Q F.∘ proj₂ Q≡R

≡ᴾ-isEquivalence : ∀ {a l} {A : Set a} → IsEquivalence {A = Pred A l} _≡ᴾ_
≡ᴾ-isEquivalence = record
  { refl  = ≡ᴾ-refl
  ; sym   = ≡ᴾ-sym
  ; trans = ≡ᴾ-trans
  }

≡ᴾ-setoid : ∀ {a l} {A : Set a} → Setoid _ _
≡ᴾ-setoid {a} {l} {A} = record
  { Carrier       = Pred A l
  ; _≈_           = _≡ᴾ_
  ; isEquivalence = ≡ᴾ-isEquivalence
  }

∅ : ∀ {a l} {A : Set a} → Pred A l
∅ {l = l} = λ _ → Lift l ⊥

｛_｝ : ∀ {a l} {A : Set a} → A → Pred A (a ⊔ l)
｛_｝{l = l} x = λ y → Lift l (y ≡ x)

Lang : ∀ {s} → Set s → (l : Level) → Set _
Lang Σ l = Pred (List Σ) l

-- TODO Move Math.FormalLanguage.Construct.EmptyLang
data EmptyLang {a l} {A : Set a} : Lang A (a ⊔ l) where
  mkEmptyLang : EmptyLang []

-- TODO Move Math.FormalLanguage.Construct.Concat
-- TODO Hetero
-- Lang A l → Lang B l → Lang (A ⊎ B) l
-- map inj₁ xs ++ map inj₂ ys
-- concatenation of formal language
data _<>_ {a l} {A : Set a} (L₁ L₂ : Lang A l) : Lang A (a ⊔ l) where
  mk<> : ∀ {xs ys} → L₁ xs → L₂ ys → (L₁ <> L₂) (xs ++ ys)

-- TODO Move Math.FormalLanguage.Construct.Concat.Properties
module _ {s l} {Σ : Set s} where
  open FP {A = Lang Σ (s ⊔ l)} _≡ᴾ_

  <>-identityˡ : LeftIdentity (EmptyLang {l = l}) _<>_
  <>-identityˡ L = to , from
    where
    to : EmptyLang <> L ⊆ L
    to (mk<> mkEmptyLang x₁) = x₁
    from : L ⊆ EmptyLang <> L
    from Lx = mk<> mkEmptyLang Lx

  <>-identityʳ  : RightIdentity (EmptyLang {l = l}) _<>_
  <>-identityʳ L = to , from
    where
    to : L <> EmptyLang ⊆ L
    to (mk<> Lx mkEmptyLang) = subst L (sym $ Lₚ.++-identityʳ _) Lx
    from : L ⊆ L <> EmptyLang
    from {xs} x = subst (L <> EmptyLang) (Lₚ.++-identityʳ xs) $
      mk<> {xs = xs} {ys = []} x mkEmptyLang

{- TODO move contents of agda-combinatorics to agda-misc
  <>-dec : ∀ {L₁ L₂ : Lang Σ l} →
    U.Decidable L₁ → U.Decidable L₂ → U.Decidable (L₁ <> L₂)
  <>-dec L₁? L₂? zs with L.filter (L₁? Uₚ.×? L₂?) (splits₂ zs)
  ... | x = ?
-}


-- Classical propositional logic, de Bruijn approach, final encoding

module Bf.Cp where

open import Lib using (List; _,_; LMem; lzero; lsuc)

-- Types

infixl 2 _&&_
infixl 1 _||_
infixr 0 _=>_
data Ty : Set where
  UNIT  :             Ty
  _=>_  : Ty -> Ty -> Ty
  _&&_  : Ty -> Ty -> Ty
  _||_  : Ty -> Ty -> Ty
  FALSE :             Ty

infixr 0 _<=>_
_<=>_ : Ty -> Ty -> Ty
a <=> b = (a => b) && (b => a)

NOT : Ty -> Ty
NOT a = a => FALSE

TRUE : Ty
TRUE = FALSE => FALSE

-- Context and truth judgement

Cx : Set
Cx = List Ty

isTrue : Ty -> Cx -> Set
isTrue a tc = LMem a tc

-- Terms

TmRepr : Set1
TmRepr = Cx -> Ty -> Set

module ArrMp where
  record Tm (tr : TmRepr) : Set1 where
    infixl 1 _$_
    infixr 0 lam=>_
    field
      var    : forall {tc a}   -> isTrue a tc               -> tr tc a
      lam=>_ : forall {tc a b} -> tr (tc , a) b             -> tr tc (a => b)
      _$_    : forall {tc a b} -> tr tc (a => b) -> tr tc a -> tr tc b

    v0 : forall {tc a} -> tr (tc , a) a
    v0 = var lzero

    v1 : forall {tc a b} -> tr (tc , a , b) a
    v1 = var (lsuc lzero)

    v2 : forall {tc a b c} -> tr (tc , a , b , c) a
    v2 = var (lsuc (lsuc lzero))
  open Tm {{...}} public

module Mp where
  record Tm (tr : TmRepr) : Set1 where
    field
      pair' : forall {tc a b}   -> tr tc a        -> tr tc b -> tr tc (a && b)
      fst   : forall {tc a b}   -> tr tc (a && b)            -> tr tc a
      snd   : forall {tc a b}   -> tr tc (a && b)            -> tr tc b
      left  : forall {tc a b}   -> tr tc a                   -> tr tc (a || b)
      right : forall {tc a b}   -> tr tc b                   -> tr tc (a || b)
      case' : forall {tc a b c} -> tr tc (a || b) -> tr (tc , a) c -> tr (tc , b) c -> tr tc c

      isArrMp : ArrMp.Tm tr
    open ArrMp.Tm isArrMp public

    syntax pair' x y    = [ x , y ]
    syntax case' xy x y = case xy => x => y
  open Tm {{...}} public

module Cp where
  record Tm (tr : TmRepr) : Set1 where
    infixr 0 abort=>_
    field
      abort=>_ : forall {tc a} -> tr (tc , NOT a) FALSE -> tr tc a

      isMp : Mp.Tm tr
    open Mp.Tm isMp public
  open Tm {{...}} public

  Thm : Ty -> Set1
  Thm a = forall {tr tc} {{_ : Tm tr}} -> tr tc a
open Cp public


{-

An experiment of transporting rev-++-distr from lists to lists where
the arguments to cons have been flipped inspired by section 2 of
https://arxiv.org/abs/2010.00774

Note that Agda doesn't care about the order of constructors so we
can't do exactly the same example.

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Experiments.List where

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

open import Cubical.Data.Sigma

infixr 5 _∷_
infixl 5 _∷'_
infixr 5 _++_

-- Normal lists
data List (A : Type) : Type where
  []  : List A
  _∷_ : (x : A) (xs : List A) → List A

-- Lists where the arguments to cons have been flipped
data List' (A : Type) : Type where
  []  : List' A
  _∷'_ : (xs : List' A) (x : A) → List' A

variable
  A : Type

-- Some operations and properties for List

_++_ : List A → List A → List A
[] ++ ys = ys
(x ∷ xs) ++ ys = x ∷ xs ++ ys

rev : List A → List A
rev [] = []
rev (x ∷ xs) = rev xs ++ (x ∷ [])

++-unit-r : (xs : List A) → xs ++ [] ≡ xs
++-unit-r [] = refl
++-unit-r (x ∷ xs) = cong (_∷_ x) (++-unit-r xs)

++-assoc : (xs ys zs : List A) → (xs ++ ys) ++ zs ≡ xs ++ ys ++ zs
++-assoc [] ys zs = refl
++-assoc (x ∷ xs) ys zs = cong (_∷_ x) (++-assoc xs ys zs)

rev-++-distr : (xs ys : List A) → rev (xs ++ ys) ≡ rev ys ++ rev xs
rev-++-distr [] ys       = sym (++-unit-r (rev ys))
rev-++-distr (x ∷ xs) ys = cong (_++ _) (rev-++-distr xs ys) ∙ ++-assoc (rev ys) (rev xs) (x ∷ [])

-- We now want to transport this to List'. For this we first establish
-- an isomorphism of the types.

toList' : List A → List' A
toList' []       = []
toList' (x ∷ xs) = toList' xs ∷' x

fromList' : List' A → List A
fromList' []        = []
fromList' (xs ∷' x) =  x ∷ fromList' xs

toFrom : (xs : List' A) → toList' (fromList' xs) ≡ xs
toFrom []          = refl
toFrom (xs ∷' x) i = toFrom xs i ∷' x

fromTo : (xs : List A) → fromList' (toList' xs) ≡ xs
fromTo []          = refl
fromTo (x ∷ xs) i =  x ∷ fromTo xs i

ListIso : Iso (List A) (List' A)
ListIso = iso toList' fromList' toFrom fromTo

ListEquiv : List A ≃ List' A
ListEquiv = isoToEquiv ListIso

-- We then use univalence to turn this into a path
ListPath : (A : Type) → List A ≡ List' A
ListPath A = isoToPath (ListIso {A = A})

-- We can now use this path to transport the operations and properties
-- from List to List'
module transport where

  -- First make a suitable Σ-type packaging what we need for the
  -- transport (note that _++_ and rev here are part of the Σ-type).
  -- It should be possible to automatically generate this given a module/file.
  T : Type → Type
  T X = Σ[ _++_ ∈ (X → X → X) ] Σ[ rev ∈ (X → X) ] ((xs ys : X) → rev (xs ++ ys) ≡ rev ys ++ rev xs)

  -- We can now transport the instance of T for List to List'
  T-List' : T (List' A)
  T-List' {A = A} = transport (λ i → T (ListPath A i)) (_++_ , rev , rev-++-distr)

  -- Getting the operations and property for List' is then just a matter of projecting them out
  _++'_ : List' A → List' A → List' A
  _++'_ = T-List' .fst

  rev' : List' A → List' A
  rev' = T-List' .snd .fst

  rev-++-distr' : (xs ys : List' A) → rev' (xs ++' ys) ≡ rev' ys ++' rev' xs
  rev-++-distr' = T-List' .snd .snd

-- To connect this with the Cubical Agda paper consider the following
-- (painfully) manual transport. This is really what the above code
-- unfolds to.
module manualtransport where

  _++'_ : List' A → List' A → List' A
  _++'_ {A = A} = transport (λ i → ListPath A i → ListPath A i → ListPath A i) _++_

  rev' : List' A → List' A
  rev' {A = A} = transport (λ i → ListPath A i → ListPath A i) rev

  rev-++-distr' : (xs ys : List' A) → rev' (xs ++' ys) ≡ rev' ys ++' rev' xs
  rev-++-distr' {A = A} = transport (λ i → (xs ys : ListPath A i)
                                         → revP i (appP i xs ys) ≡ appP i (revP i ys) (revP i xs))
                                    rev-++-distr
    where
    appP : PathP (λ i → ListPath A i → ListPath A i → ListPath A i) _++_ _++'_
    appP i = transp (λ j → ListPath A (i ∧ j) → ListPath A (i ∧ j) → ListPath A (i ∧ j)) (~ i) _++_

    revP : PathP (λ i → ListPath A i → ListPath A i) rev rev'
    revP i = transp (λ j → ListPath A (i ∧ j) → ListPath A (i ∧ j)) (~ i) rev

-- The above operations for List' are derived by going back and
-- forth. With the SIP we can do better and transport properties for
-- user defined operations (assuming that the operations are
-- well-defined wrt to the forward direction of the equivalence).
open import Cubical.Foundations.SIP
open import Cubical.Structures.Axioms
open import Cubical.Structures.Product
open import Cubical.Structures.Pointed
open import Cubical.Structures.Function

-- For illustrative purposes we first apply the SIP manually. This
-- requires quite a bit of boilerplate code which is automated in the
-- next module.
module manualSIP (A : Type) where

  -- First define the raw structure without axioms. This is just the
  -- signature of _++_ and rev.
  RawStruct : Type → Type
  RawStruct X = (X → X → X) × (X → X)

  -- Some boilerplate code which can be automated
  e1 : StrEquiv (λ x → x → x → x) ℓ-zero
  e1 = FunctionEquivStr+ pointedEquivAction
                         (FunctionEquivStr+ pointedEquivAction PointedEquivStr)

  e2 : StrEquiv (λ x → x → x) ℓ-zero
  e2 = FunctionEquivStr+ pointedEquivAction PointedEquivStr

  RawEquivStr : StrEquiv RawStruct _
  RawEquivStr = ProductEquivStr e1 e2

  rawUnivalentStr : UnivalentStr _ RawEquivStr
  rawUnivalentStr = productUnivalentStr e1 he1 e2 he2
    where
    he2 : UnivalentStr (λ z → z → z) e2
    he2 = functionUnivalentStr+ pointedEquivAction pointedTransportStr
                                PointedEquivStr pointedUnivalentStr

    he1 : UnivalentStr (λ z → z → z → z) e1
    he1 = functionUnivalentStr+ pointedEquivAction pointedTransportStr e2 he2

  -- Now the property that we want to transport
  P : (X : Type) → RawStruct X → Type
  P X (_++_ , rev) = ((xs ys : X) → rev (xs ++ ys) ≡ rev ys ++ rev xs)

  -- Package things up for List
  List-Struct : Σ[ X ∈ Type ] (Σ[ s ∈ RawStruct X ] (P X s))
  List-Struct = List A , (_++_ , rev) , rev-++-distr

  -- We now give direct definitions of ++' and rev' for List'
  _++'_ : List' A → List' A → List' A
  [] ++' ys        = ys
  (xs ∷' x) ++' ys = (xs ++' ys) ∷' x

  rev' : List' A → List' A
  rev' [] = []
  rev' (xs ∷' x) = rev' xs ++' ([] ∷' x)

  -- We then package this up into a raw structure on List'
  List'-RawStruct : Σ[ X ∈ Type ] (RawStruct X)
  List'-RawStruct = List' A , (_++'_ , rev')

  -- Finally we prove that toList' commutes with _++_ and rev. Note
  -- that this could be a lot more complex, see for example the Matrix
  -- example (Cubical.Algebra.Matrix).
  toList'-++ : (xs ys : List A) → toList' (xs ++ ys) ≡ toList' xs ++' toList' ys
  toList'-++ [] ys = refl
  toList'-++ (x ∷ xs) ys i = toList'-++ xs ys i ∷' x

  toList'-rev : (xs : List A) → toList' (rev xs) ≡ rev' (toList' xs)
  toList'-rev [] = refl
  toList'-rev (x ∷ xs) = toList'-++ (rev xs) (x ∷ []) ∙ cong (_++' ([] ∷' x)) (toList'-rev xs)

  -- We can now get the property for ++' and rev' via the SIP
  rev-++-distr' : (xs ys : List' A) → rev' (xs ++' ys) ≡ rev' ys ++' rev' xs
  rev-++-distr' = transferAxioms rawUnivalentStr List-Struct List'-RawStruct
                        (ListEquiv , toList'-++ , toList'-rev)

  -- Note that rev-++-distr' is really talking about the direct
  -- definitions of ++' and rev', not the transported operations as in
  -- the previous attempt.

-- We now automate parts of the above construction
open import Cubical.Structures.Auto

module SIP-auto (A : Type) where

  -- First define the raw structure without axioms. This is just the
  -- signature of _++_ and rev.
  RawStruct : Type → Type
  RawStruct X = (X → X → X) × (X → X)

  -- Some automated SIP magic
  RawEquivStr : _
  RawEquivStr = AutoEquivStr RawStruct

  rawUnivalentStr : UnivalentStr _ RawEquivStr
  rawUnivalentStr = autoUnivalentStr RawStruct

  -- Now the property that we want to transport
  P : (X : Type) → RawStruct X → Type
  P X (_++_ , rev) = ((xs ys : X) → rev (xs ++ ys) ≡ rev ys ++ rev xs)

  -- Package things up for List
  List-Struct : Σ[ X ∈ Type ] (Σ[ s ∈ RawStruct X ] (P X s))
  List-Struct = List A , (_++_ , rev) , rev-++-distr

  -- We now give direct definitions of ++' and rev' for List'
  _++'_ : List' A → List' A → List' A
  [] ++' ys        = ys
  (xs ∷' x) ++' ys = (xs ++' ys) ∷' x

  rev' : List' A → List' A
  rev' [] = []
  rev' (xs ∷' x) = rev' xs ++' ([] ∷' x)

  -- We then package this up into a raw structure on List'
  List'-RawStruct : Σ[ X ∈ Type ] (RawStruct X)
  List'-RawStruct = List' A , (_++'_ , rev')

  -- Finally we prove that toList' commutes with _++_ and rev. Note
  -- that this could be a lot more complex, see for example the Matrix
  -- example (Cubical.Algebra.Matrix).
  toList'-++ : (xs ys : List A) → toList' (xs ++ ys) ≡ toList' xs ++' toList' ys
  toList'-++ [] ys = refl
  toList'-++ (x ∷ xs) ys i = toList'-++ xs ys i ∷' x

  toList'-rev : (xs : List A) → toList' (rev xs) ≡ rev' (toList' xs)
  toList'-rev [] = refl
  toList'-rev (x ∷ xs) = toList'-++ (rev xs) (x ∷ []) ∙ cong (_++' ([] ∷' x)) (toList'-rev xs)

  -- We can now get the property for ++' and rev' via the SIP
  rev-++-distr' : (xs ys : List' A) → rev' (xs ++' ys) ≡ rev' ys ++' rev' xs
  rev-++-distr' = transferAxioms rawUnivalentStr List-Struct List'-RawStruct
                        (ListEquiv , toList'-++ , toList'-rev)

  -- Note that rev-++-distr' is really talking about the direct
  -- definitions of ++' and rev', not the transported operations as in
  -- the previous attempt.


{-

This file proves the higher groupoid structure of types
for homogeneous and heterogeneous paths

-}
{-# OPTIONS --cubical --safe #-}
module Cubical.Foundations.GroupoidLaws where

open import Cubical.Foundations.Prelude

private
  variable
    ℓ : Level
    A : Type ℓ
    x y z w : A

_⁻¹ : (x ≡ y) → (y ≡ x)
x≡y ⁻¹ = sym x≡y

infix 40 _⁻¹

-- homogeneous groupoid laws

symInvo : (p : x ≡ y) → p ≡ p ⁻¹ ⁻¹
symInvo p = refl

rUnit : (p : x ≡ y) → p ≡ p ∙ refl
rUnit p j i = compPath-filler p refl j i

-- The filler of left unit: lUnit-filler p =
-- PathP (λ i → PathP (λ j → PathP (λ k → A) x (p (~ j ∨ i)))
-- (refl i) (λ j → compPath-filler refl p i j)) (λ k i → (p (~ k ∧ i ))) (lUnit p)

lUnit-filler : {x y : A} (p : x ≡ y) → I → I → I → A
lUnit-filler {x = x} p j k i =
  hfill (λ j → λ { (i = i0) → x
                  ; (i = i1) → p (~ k ∨ j )
                  ; (k = i0) → p i
               -- ; (k = i1) → compPath-filler refl p j i
                  }) (inS (p (~ k ∧ i ))) j

lUnit : (p : x ≡ y) → p ≡ refl ∙ p
lUnit p j i = lUnit-filler p i1 j i

symRefl : refl {x = x} ≡ refl ⁻¹
symRefl i = refl

compPathRefl : refl {x = x} ≡ refl ∙ refl
compPathRefl = rUnit refl

-- The filler of right cancellation: rCancel-filler p =
-- PathP (λ i → PathP (λ j → PathP (λ k → A) x (p (~ j ∧ ~ i)))
-- (λ j → compPath-filler p (p ⁻¹) i j) (refl i)) (λ j i → (p (i ∧ ~ j))) (rCancel p)

rCancel-filler : ∀ {x y : A} (p : x ≡ y) → (k j i : I) → A
rCancel-filler {x = x} p k j i =
  hfill (λ k → λ { (i = i0) → x
                  ; (i = i1) → p (~ k ∧ ~ j)
               -- ; (j = i0) → compPath-filler p (p ⁻¹) k i
                  ; (j = i1) → x
                  }) (inS (p (i ∧ ~ j))) k

rCancel : (p : x ≡ y) → p ∙ p ⁻¹ ≡ refl
rCancel {x = x} p j i = rCancel-filler p i1 j i

lCancel : (p : x ≡ y) → p ⁻¹ ∙ p ≡ refl
lCancel p = rCancel (p ⁻¹)

-- The filler of the three-out-of-four identification: 3outof4-filler α p β =
-- PathP (λ i → PathP (λ j → PathP (λ k → A) (α i i0) (α i i1))
-- (λ j → α i j) (λ j → β i j)) (λ j i → α i0 i) (3outof4 α p β)

3outof4-filler : (α : I → I → A) → (p : α i1 i0 ≡ α i1 i1) →
  (β : PathP (λ j → Path A (α j i0) (α j i1)) (λ i → α i0 i) p) → I → I → I → A
3outof4-filler α p β k j i =
  hfill (λ k → λ { (i = i0) → α k i0
                  ; (i = i1) → α k i1
                  ; (j = i0) → α k i
                  ; (j = i1) → β k i
                  }) (inS (α i0 i)) k

3outof4 : (α : I → I → A) → (p : α i1 i0 ≡ α i1 i1) →
  (β : PathP (λ j → Path A (α j i0) (α j i1)) (λ i → α i0 i) p) → (λ i → α i1 i) ≡ p
3outof4 α p β j i = 3outof4-filler α p β i1 j i

-- The filler of the pre-associative square: preassoc p q r =
-- PathP (λ i → PathP (λ j → PathP (λ k → A) x (compPath-filler q r i j))
-- (refl i) (λ j → compPath-filler (p ∙ q) r i j)) (λ j i → compPath-filler p q j i) (preassoc p q r)

preassoc-filler : {x y z w : A} (p : x ≡ y) (q : y ≡ z) (r : z ≡ w) → I → I → I → A
preassoc-filler {x = x} p q r k j i =
  hfill (λ k → λ { (i = i0) → x
                  ; (i = i1) → compPath-filler q r k j
                  ; (j = i0) → p i
               -- ; (j = i1) → compPath-filler (p ∙ q) r k i
                  }) (inS (compPath-filler p q j i)) k

preassoc : (p : x ≡ y) (q : y ≡ z) (r : z ≡ w) →
  PathP (λ j → Path A x ((q ∙ r) j)) p ((p ∙ q) ∙ r)
preassoc {x = x} p q r j i = preassoc-filler p q r i1 j i

assoc : (p : x ≡ y) (q : y ≡ z) (r : z ≡ w) →
  p ∙ q ∙ r ≡ (p ∙ q) ∙ r
assoc p q r = 3outof4 (compPath-filler p (q ∙ r)) ((p ∙ q) ∙ r) (preassoc p q r)

-- heterogeneous groupoid laws

symInvoP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
     PathP (λ j → PathP (λ i → symInvo (λ i → A i) j i) x y) p (symP (symP p))
symInvoP p = refl

rUnitP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
  PathP (λ j → PathP (λ i → rUnit (λ i → A i) j i) x y) p (compPathP p refl)
rUnitP p j i = compPathP-filler p refl i j

lUnitP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
  PathP (λ j → PathP (λ i → lUnit (λ i → A i) j i) x y) p (compPathP refl p)
lUnitP {A = A} {x = x} p k i =
  comp (λ j → lUnit-filler (λ i → A i) j k i)
       (λ j → λ { (i = i0) → x
                ; (i = i1) → p (~ k ∨ j )
                ; (k = i0) → p i
                }) (p (~ k ∧ i ))

rCancelP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
   PathP (λ j → PathP (λ i → rCancel (λ i → A i) j i) x x) (compPathP p (symP p)) refl
rCancelP {A = A} {x = x} p j i =
  comp (λ k → rCancel-filler (λ i → A i) k j i)
       (λ k → λ { (i = i0) → x
                ; (i = i1) → p (~ k ∧ ~ j)
                ; (j = i1) → x
                }) (p (i ∧ ~ j))

lCancelP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
   PathP (λ j → PathP (λ i → lCancel (λ i → A i) j i) y y) (compPathP (symP p) p) refl
lCancelP p = rCancelP (symP p)

3outof4P : {A : I → I → Type ℓ} {P : (A i0 i1) ≡ (A i1 i1)}
  {B : PathP (λ j → Path (Type ℓ) (A i0 j) (A i1 j)) (λ i → A i i0) P}
  (α : ∀ (i j : I) → A j i)
  (p : PathP (λ i → P i) (α i1 i0) (α i1 i1)) →
  (β : PathP (λ j → PathP (λ i → B j i) (α j i0) (α j i1)) (λ i → α i0 i) p) →
  PathP (λ j → PathP (λ i → 3outof4 (λ j i → A i j) P B j i) (α i1 i0) (α i1 i1)) (λ i → α i1 i) p
3outof4P {A = A} {P} {B} α p β j i =
  comp (λ k → 3outof4-filler (λ j i → A i j) P B k j i)
       (λ k → λ { (i = i0) → α k i0
                ; (i = i1) → α k i1
                ; (j = i0) → α k i
                ; (j = i1) → β k i
                }) (α i0 i)

preassocP : {A : I → Type ℓ} {x : A i0} {y : A i1} {B_i1 : Type ℓ} {B : (A i1) ≡ B_i1} {z : B i1}
  {C_i1 : Type ℓ} {C : (B i1) ≡ C_i1} {w : C i1} (p : PathP A x y) (q : PathP (λ i → B i) y z) (r : PathP (λ i → C i) z w) →
  PathP (λ j → PathP (λ i → preassoc (λ i → A i) B C j i) x ((compPathP q r) j)) p (compPathP (compPathP p q) r)
preassocP {A = A} {x = x} {B = B} {C = C} p q r j i =
  comp (λ k → preassoc-filler (λ i → A i) B C k j i)
       (λ k → λ { (i = i0) → x
                ; (i = i1) → compPathP-filler q r j k
                ; (j = i0) → p i
             -- ; (j = i1) → compPathP-filler (compPathP p q) r i k
                }) (compPathP-filler p q i j)

assocP : {A : I → Type ℓ} {x : A i0} {y : A i1} {B_i1 : Type ℓ} {B : (A i1) ≡ B_i1} {z : B i1}
  {C_i1 : Type ℓ} {C : (B i1) ≡ C_i1} {w : C i1} (p : PathP A x y) (q : PathP (λ i → B i) y z) (r : PathP (λ i → C i) z w) →
  PathP (λ j → PathP (λ i → assoc (λ i → A i) B C j i) x w) (compPathP p (compPathP q r)) (compPathP (compPathP p q) r)
assocP p q r =
  3outof4P (λ i j → compPathP-filler p (compPathP q r) j i) (compPathP (compPathP p q) r) (preassocP p q r)

-- Loic's code below

-- simultaneaous composition on both sides of a path

doubleCompPath-filler : {ℓ : Level} {A : Type ℓ} {w x y z : A} → w ≡ x → x ≡ y → y ≡ z →
                        I → I → A
doubleCompPath-filler p q r i =
  hfill (λ t → λ { (i = i0) → p (~ t)
                 ; (i = i1) → r t })
        (inS (q i))

doubleCompPath : {ℓ : Level} {A : Type ℓ} {w x y z : A} → w ≡ x → x ≡ y → y ≡ z → w ≡ z
doubleCompPath p q r i = doubleCompPath-filler p q r i i1

_∙∙_∙∙_ : {ℓ : Level} {A : Type ℓ} {w x y z : A} → w ≡ x → x ≡ y → y ≡ z → w ≡ z
p ∙∙ q ∙∙ r = doubleCompPath p q r

-- some exchange law for doubleCompPath and refl

rhombus-filler : {ℓ : Level} {A : Type ℓ} {x y z : A} (p : x ≡ y) (q : y ≡ z) → I → I → A
rhombus-filler p q i j =
  hcomp (λ t → λ { (i = i0) → p (~ t ∨ j)
                 ; (i = i1) → q (t ∧ j)
                 ; (j = i0) → p (~ t ∨ i)
                 ; (j = i1) → q (t ∧ i) })
        (p i1)

leftright : {ℓ : Level} {A : Type ℓ} {x y z : A} (p : x ≡ y) (q : y ≡ z) →
            (refl ∙∙ p ∙∙ q) ≡ (p ∙∙ q ∙∙ refl)
leftright p q i j =
  hcomp (λ t → λ { (j = i0) → p (i ∧ (~ t))
                 ; (j = i1) → q (t ∨ i) })
        (rhombus-filler p q i j)

-- equating doubleCompPath and a succession of two compPath

split-leftright : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y) (r : y ≡ z) →
                  (p ∙∙ q ∙∙ r) ≡ (refl ∙∙ (p ∙∙ q ∙∙ refl) ∙∙ r)
split-leftright p q r i j =
  hcomp (λ t → λ { (j = i0) → p (~ i ∧ ~ t)
                 ; (j = i1) → r t })
        (doubleCompPath-filler p q refl j i)

split-leftright' : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y) (r : y ≡ z) →
                  (p ∙∙ q ∙∙ r) ≡ (p ∙∙ (refl ∙∙ q ∙∙ r) ∙∙ refl)
split-leftright' p q r i j =
  hcomp (λ t → λ { (j = i0) → p (~ t)
                 ; (j = i1) → r (i ∨ t) })
        (doubleCompPath-filler refl q r j i)

doubleCompPath-elim : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y)
                      (r : y ≡ z) → (p ∙∙ q ∙∙ r) ≡ (p ∙ q) ∙ r
doubleCompPath-elim p q r = (split-leftright p q r) ∙ (λ i → (leftright p q (~ i)) ∙ r)

doubleCompPath-elim' : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y)
                       (r : y ≡ z) → (p ∙∙ q ∙∙ r) ≡ p ∙ (q ∙ r)
doubleCompPath-elim' p q r = (split-leftright' p q r) ∙ (sym (leftright p (q ∙ r)))

-- deducing associativity for compPath

-- assoc : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y) (r : y ≡ z) →
--                 (p ∙ q) ∙ r ≡ p ∙ (q ∙ r)
-- assoc p q r = (sym (doubleCompPath-elim p q r)) ∙ (doubleCompPath-elim' p q r)

hcomp-unique : ∀ {ℓ} {A : Set ℓ} {φ} → (u : I → Partial φ A) → (u0 : A [ φ ↦ u i0 ]) →
               (h2 : ∀ i → A [ (φ ∨ ~ i) ↦ (\ { (φ = i1) → u i 1=1; (i = i0) → outS u0}) ])
               → (hcomp u (outS u0) ≡ outS (h2 i1)) [ φ ↦ (\ { (φ = i1) → (\ i → u i1 1=1)}) ]
hcomp-unique {φ = φ} u u0 h2 = inS (\ i → hcomp (\ k → \ { (φ = i1) → u k 1=1
                                                            ; (i = i1) → outS (h2 k) })
                                                   (outS u0))

lid-unique : ∀ {ℓ} {A : Set ℓ} {φ} → (u : I → Partial φ A) → (u0 : A [ φ ↦ u i0 ]) →
               (h1 h2 : ∀ i → A [ (φ ∨ ~ i) ↦ (\ { (φ = i1) → u i 1=1; (i = i0) → outS u0}) ])
               → (outS (h1 i1) ≡ outS (h2 i1)) [ φ ↦ (\ { (φ = i1) → (\ i → u i1 1=1)}) ]
lid-unique {φ = φ} u u0 h1 h2 = inS (\ i → hcomp (\ k → \ { (φ = i1) → u k 1=1
                                                            ; (i = i0) → outS (h1 k)
                                                            ; (i = i1) → outS (h2 k) })
                                                   (outS u0))

transp-hcomp : ∀ {ℓ} (φ : I) {A' : Set ℓ}
                     (A : (i : I) → Set ℓ [ φ ↦ (λ _ → A') ]) (let B = \ (i : I) → outS (A i))
                 → ∀ {ψ} (u : I → Partial ψ (B i0)) → (u0 : B i0 [ ψ ↦ u i0 ]) →
                 (transp B φ (hcomp u (outS u0)) ≡ hcomp (\ i o → transp B φ (u i o)) (transp B φ (outS u0)))
                   [ ψ ↦ (\ { (ψ = i1) → (\ i → transp B φ (u i1 1=1))}) ]
transp-hcomp φ A u u0 = inS (sym (outS (hcomp-unique
               ((\ i o → transp B φ (u i o))) (inS (transp B φ (outS u0)))
                 \ i → inS (transp B φ (hfill u u0 i)))))
  where
    B = \ (i : I) → outS (A i)

hcomp-cong : ∀ {ℓ} {A : Set ℓ} {φ} → (u : I → Partial φ A) → (u0 : A [ φ ↦ u i0 ]) →
                                    (u' : I → Partial φ A) → (u0' : A [ φ ↦ u' i0 ]) →

             (ueq : ∀ i → PartialP φ (\ o → u i o ≡ u' i o)) → (outS u0 ≡ outS u0') [ φ ↦ (\ { (φ = i1) → ueq i0 1=1}) ]
             → (hcomp u (outS u0) ≡ hcomp u' (outS u0')) [ φ ↦ (\ { (φ = i1) → ueq i1 1=1 }) ]
hcomp-cong u u0 u' u0' ueq 0eq = inS (\ j → hcomp (\ i o → ueq i o j) (outS 0eq j))

squeezeSq≡
  : ∀{w x y z : A}
  → (p : w ≡ y) (q : w ≡ x) (r : y ≡ z) (s : x ≡ z)
  → (q ≡ p ∙∙ r ∙∙ sym s) ≡ (Square p q r s)
squeezeSq≡ p q r s k
  = Square
      (λ j → p (j ∧ k))
      q
      (λ j → doubleCompPath-filler p r (sym s) j (~ k))
      (λ j → s (j ∧ k))


------------------------------------------------------------------------
-- The Agda standard library
--
-- Sums (disjoint unions)
------------------------------------------------------------------------

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

module Data.Sum.Base where

open import Function using (_∘_; _-[_]-_ ; id)
open import Relation.Nullary using (Dec; yes; no; ¬_)
open import Level using (_⊔_)

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

infixr 1 _⊎_

data _⊎_ {a b} (A : Set a) (B : Set b) : Set (a ⊔ b) where
  inj₁ : (x : A) → A ⊎ B
  inj₂ : (y : B) → A ⊎ B

------------------------------------------------------------------------
-- Functions

[_,_] : ∀ {a b c} {A : Set a} {B : Set b} {C : A ⊎ B → Set c} →
        ((x : A) → C (inj₁ x)) → ((x : B) → C (inj₂ x)) →
        ((x : A ⊎ B) → C x)
[ f , g ] (inj₁ x) = f x
[ f , g ] (inj₂ y) = g y

[_,_]′ : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c} →
         (A → C) → (B → C) → (A ⊎ B → C)
[_,_]′ = [_,_]

swap : ∀ {a b} {A : Set a} {B : Set b} → A ⊎ B → B ⊎ A
swap (inj₁ x) = inj₂ x
swap (inj₂ x) = inj₁ x

map : ∀ {a b c d} {A : Set a} {B : Set b} {C : Set c} {D : Set d} →
      (A → C) → (B → D) → (A ⊎ B → C ⊎ D)
map f g = [ inj₁ ∘ f , inj₂ ∘ g ]

map₁ : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c}→
       (A → C) → (A ⊎ B → C ⊎ B)
map₁ f = map f id

map₂ : ∀ {a b d} {A : Set a} {B : Set b} {D : Set d} →
       (B → D) → (A ⊎ B → A ⊎ D)
map₂ = map id

infixr 1 _-⊎-_
_-⊎-_ : ∀ {a b c d} {A : Set a} {B : Set b} →
        (A → B → Set c) → (A → B → Set d) → (A → B → Set (c ⊔ d))
f -⊎- g = f -[ _⊎_ ]- g

module _ {p} {P : Set p} where

-- Conversion back and forth with Dec

  fromDec : Dec P → P ⊎ ¬ P
  fromDec (yes p) = inj₁ p
  fromDec (no ¬p) = inj₂ ¬p

  toDec : P ⊎ ¬ P → Dec P
  toDec (inj₁ p)  = yes p
  toDec (inj₂ ¬p) = no ¬p


module Sigma.Renaming.Properties where

open import Data.Nat using (ℕ; _+_; zero; suc)
open import Data.Fin using (Fin; zero; suc)

open import Sigma.Subst.Core
open import Sigma.Renaming.Base

open import Sigma.Subst.Properties using (extensionality)

open import Function using (_∘_)

open import Relation.Binary.PropositionalEquality as Eq
  using (_≡_; refl; cong; cong₂)
open Eq.≡-Reasoning

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

⇑-cong : ∀ { m n } { ρ₁ ρ₂ : Ren m n }
  → ρ₁ ≡ ρ₂
  -- -----------
  → ρ₁ ⇑ ≡ ρ₂ ⇑
⇑-cong ρ₁≡ρ₂ = cong (_⇑) ρ₁≡ρ₂

⇑✶-cong : ∀ { m n } k { ρ₁ ρ₂ : Ren m n }
  → ρ₁ ≡ ρ₂
  -- -----------
  → ρ₁ ⇑✶ k  ≡ ρ₂ ⇑✶ k
⇑✶-cong k ρ₁≡ρ₂ = cong (_⇑✶ k) ρ₁≡ρ₂

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

∘-⇑-distrib : ∀ { m n k } ( ρ₁ : Ren m n ) ( ρ₂ : Ren n k )
  → (ρ₂ ⇑ ∘ ρ₁ ⇑) ≡ (ρ₂ ∘ ρ₁) ⇑
∘-⇑-distrib ρ₁ ρ₂ = extensionality lemma
  where
    lemma : ∀ x → (ρ₂ ⇑ ∘ ρ₁ ⇑) x ≡ ((ρ₂ ∘ ρ₁) ⇑) x
    lemma zero = refl
    lemma (suc x) = refl

-- TODO:
-- generalized for ⇑✶

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

⇑-id : ∀ { n } → (id { n }) ⇑ ≡ id
⇑-id = extensionality lemma
  where
    lemma : ∀ { n } x → (id { n } ⇑) x ≡ x
    lemma zero = refl
    lemma (suc x) = refl


{-# OPTIONS --without-K --safe #-}
-- Take a relation that is already reflexive and transitive
-- and make it symmetric.
--   (Borrowed from Categories/Support/ZigZag from copumpkin's Categories library

module Relation.Binary.Construct.Symmetrize where

open import Level
open import Relation.Binary
open import Relation.Binary.Construct.On using () renaming (isEquivalence to on-preserves-equivalence)

data Direction : Set where
  ↘ ↗ : Direction

rotate : Direction → Direction
rotate ↘ = ↗
rotate ↗ = ↘

private
  variable
    c ℓ₁ ℓ₂ : Level
    Carrier : Set c

data ZigZag′ (_∼_ : Rel Carrier ℓ₂) : (x y : Carrier) (begin end : Direction) → Set (levelOfTerm x ⊔ ℓ₂) where
  zig : ∀ {x y z e} (first : x ∼ y) (rest : ZigZag′ _∼_ y z ↗ e) → ZigZag′ _∼_ x z ↘ e
  zag : ∀ {x y z e} (first : y ∼ x) (rest : ZigZag′ _∼_ y z ↘ e) → ZigZag′ _∼_ x z ↗ e
  slish : ∀ {x y} (last : x ∼ y) → ZigZag′ _∼_ x y ↘ ↘
  slash : ∀ {x y} (last : y ∼ x) → ZigZag′ _∼_ x y ↗ ↗

data Alternating′ (_∼_ : Carrier -> Carrier -> Set ℓ₂) (x y : Carrier) : Set (levelOfTerm x ⊔ ℓ₂) where
  disorient : ∀ {begin end} (zz : ZigZag′ _∼_ x y begin end) → Alternating′ _∼_ x y

module _ (Base : Preorder c ℓ₁ ℓ₂) where

  ZigZag : (x y : Preorder.Carrier Base) (begin end : Direction) → Set (c ⊔ ℓ₂)
  ZigZag = ZigZag′ (Preorder._∼_ Base)

  private
    sym′ : {x y z : Preorder.Carrier Base} {begin middle end : Direction} → ZigZag y z middle end →
           ZigZag y x middle begin → ZigZag z x (rotate end) begin
    sym′ (zig first rest) accum = sym′ rest (zag first accum)
    sym′ (zag first rest) accum = sym′ rest (zig first accum)
    sym′ (slish last) accum     = zag last accum
    sym′ (slash last) accum     = zig last accum

  sym : ∀ {x y begin end} → ZigZag x y begin end → ZigZag y x (rotate end) (rotate begin)
  sym (zig first rest) = sym′ rest (slash first)
  sym (zag first rest) = sym′ rest (slish first)
  sym (slish last)     = slash last
  sym (slash last)     = slish last

  trans : ∀ {x y z begin end begin′ end′} → ZigZag x y begin end → ZigZag y z begin′ end′ → ZigZag x z begin end′
  trans (zig first rest) yz = zig first (trans rest yz)
  trans (zag first rest) yz = zag first (trans rest yz)
  trans (slish last) (zig first rest) = zig (Preorder.trans Base last first) rest
  trans (slish last) (zag first rest) = zig last (zag first rest)
  trans (slish last) (slish only) = slish (Preorder.trans Base last only)
  trans (slish last) (slash only) = zig last (slash only)
  trans (slash last) (zig first rest) = zag last (zig first rest)
  trans (slash last) (zag first rest) = zag (Preorder.trans Base first last) rest
  trans (slash last) (slish only) = zag last (slish only)
  trans (slash last) (slash only) = slash (Preorder.trans Base only last)

  Alternating : (x y : Preorder.Carrier Base) → Set (c ⊔ ℓ₂)
  Alternating = Alternating′ (Preorder._∼_ Base)

  private
    is-equivalence : IsEquivalence Alternating
    is-equivalence = record
      { refl = disorient (slash (Preorder.refl Base))
      ; sym = λ where (disorient zz) → disorient (sym zz)
      ; trans = λ where (disorient ij) (disorient jk) → disorient (trans ij jk)
      }

  setoid : Setoid c (c ⊔ ℓ₂)
  setoid = record
    { Carrier = Preorder.Carrier Base
    ; _≈_ = Alternating
    ; isEquivalence = is-equivalence
    }

  -- the main eliminators for Alternating -- they prove that any equivalence that
  -- respects the base preorder also respects its Alternating completion.
  locally-minimal : ∀ {ℓ′} {_≈_ : Rel (Preorder.Carrier Base) ℓ′} (≈-isEquivalence : IsEquivalence _≈_) →
    (Preorder._∼_ Base ⇒ _≈_) → (Alternating ⇒ _≈_)
  locally-minimal {_} {_≋_} isEq inj (disorient zz) = impl zz
    where
    open IsEquivalence isEq renaming (sym to >sym; trans to _>trans>_)

    impl : {i j : Preorder.Carrier Base} {b e : Direction} → ZigZag i j b e → i ≋ j
    impl (zig first rest) = inj first >trans> impl rest
    impl (zag first rest) = >sym (inj first) >trans> impl rest
    impl (slish last) = inj last
    impl (slash last) = >sym (inj last)

  minimal : ∀ {c′ ℓ′} (Dest : Setoid c′ ℓ′) (f : Preorder.Carrier Base → Setoid.Carrier Dest) →
            (Preorder._∼_ Base =[ f ]⇒ Setoid._≈_ Dest) → (Alternating =[ f ]⇒ Setoid._≈_ Dest)
  minimal Dest f inj = locally-minimal (on-preserves-equivalence f (Setoid.isEquivalence Dest)) inj


-- This module introduces operators.

module Introduction.Operators where

-- Agda has a very flexible mechanism for defining operators, supporting infix,
-- prefix, postfix and mixfix operators.

data Nat : Set where
  zero : Nat
  suc  : Nat -> Nat

-- Any name containing underscores (_) can be used as an operator by writing
-- the arguments where the underscores are. For instance, the function _+_ is
-- the infix addition function. This function can be used either as a normal
-- function: '_+_ zero zero', or as an operator: 'zero + zero'.

_+_ : Nat -> Nat -> Nat
zero  + m = m
suc n + m = suc (n + m)

-- A fixity declaration specifies precedence level (50 in this case) and
-- associativity (left associative here) of an operator. Only infix operators
-- (whose names start and end with _) have associativity.
infixl 50 _+_

-- The only restriction on where _ can appear in a name is that there cannot be
-- two underscores in sequence. For instance, we can define an if-then-else
-- operator:

data Bool : Set where
  false : Bool
  true  : Bool

if_then_else_ : {A : Set} -> Bool -> A -> A -> A
if true  then x else y = x
if false then x else y = y

-- if_then_else_ is treated as a prefix operator (ends, but doesn't begin with
-- an _), so the declared precedence determines how something in an else branch
-- should be parsed. For instance, with the given precedences
--   if x then y else a + b
-- is parsed as
--   if x then y else (a + b)
-- and not
--   (if x then y else a) + b

infix 10 if_then_else_

-- In Agda there is no restriction on what characters are allowed to appear in
-- an operator (as opposed to a function symbol). For instance, it is allowed
-- (but not recommended) to define 'f' to be an infix operator and '+' to be a
-- function symbol.

module BadIdea where

  _f_ : Nat -> Nat -> Nat
  zero  f zero  = zero
  zero  f suc n = suc n
  suc n f zero  = suc n
  suc n f suc m = suc (n f m)

  + : Nat -> Nat
  + n = suc n


{-

This file contains:
  - Pushout-products of two maps;
  - The connectivity of pushout-product maps.

-}
{-# OPTIONS --safe #-}
module Cubical.HITs.Pushout.PushoutProduct where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Equiv.Properties
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels

open import Cubical.Data.Nat
open import Cubical.Data.Sigma

open import Cubical.HITs.Pushout.Base
open import Cubical.HITs.Pushout.Properties

open import Cubical.Homotopy.Connected

private
  variable
    ℓ ℓ' ℓ'' ℓ''' : Level
    A : Type ℓ
    B : Type ℓ'
    X : Type ℓ''
    Y : Type ℓ'''

-- The definition of pushout-product

PushProd : (f : X → A)(g : Y → B) → Type _
PushProd f g = Pushout (map-× (idfun _) g) (map-× f (idfun _))

_×̂_ : (f : X → A)(g : Y → B) → PushProd f g → A × B
(f ×̂ g) (inl (x , b)) = f x , b
(f ×̂ g) (inr (a , y)) = a , g y
(f ×̂ g) (push (x , y) i) = f x , g y

infixr 5 _×̂_

module _
  (m n : ℕ)(f : X → A)(g : Y → B)
  (connf : isConnectedFun m f)
  (conng : isConnectedFun n g)
  (P : A × B → TypeOfHLevel ℓ (m + n)) where

  module _
    (sec : (x : PushProd f g) → P ((f ×̂ g) x) .fst) where

    private
      fam : A → Type _
      fam a = Σ[ k ∈ ((b : B) → P (a , b) .fst) ] ((y : Y) → k (g y) ≡ sec (inr (a , y)))

      open Iso

      fiberEquiv : (a : A)
        → fam a ≃ fiber (λ(s : (b : B) → P (a , b) .fst) → s ∘ g) (λ y → sec (inr (a , y)))
      fiberEquiv a =  isoToEquiv
        (iso (λ (k , p) → k , λ i y → p y i)
             (λ (k , p) → k , λ y i → p i y)
             (λ _ → refl) (λ _ → refl))

      is-m-trunc-fam : (a : A) → isOfHLevel m (fam a)
      is-m-trunc-fam a =
        isOfHLevelRespectEquiv _ (invEquiv (fiberEquiv a))
          (isOfHLevelPrecomposeConnected m n (λ b → P (a , b)) g conng _)

      sec-fam : (x : X) → fam (f x)
      sec-fam x = (λ b → sec (inl (x , b))) , (λ y i → sec (push (x , y) i))

      map-iso = elim.isIsoPrecompose f _ (λ a → fam a , is-m-trunc-fam a) connf

      k = map-iso .inv sec-fam
      ϕ = map-iso .rightInv sec-fam

    ext : (x : A × B) → P x .fst
    ext (a , b) = k a .fst b

    ext-path : (x : PushProd f g) → ext ((f ×̂ g) x) ≡ sec x
    ext-path (inl (x , b)) i = ϕ i x .fst b
    ext-path (inr (a , y)) i = k a .snd y i
    ext-path (push (x , y) i) j =
      hcomp (λ k → λ
        { (i = i0) → ϕ j x .snd y i0
        ; (i = i1) → ϕ i0 x .snd y (j ∨ ~ k)
        ; (j = i0) → ϕ i0 x .snd y (i ∧ ~ k)
        ; (j = i1) → ϕ i1 x .snd y i })
      (ϕ j x .snd y i)

  lifting : hasSection (λ(s : (x : A × B) → P x .fst) → s ∘ (f ×̂ g))
  lifting .fst sec = ext sec
  lifting .snd sec i x = ext-path sec x i

-- The connectivity of pushout-product

isConnected×̂ : {m n : ℕ}{f : A → B}{g : X → Y}
  → isConnectedFun m f → isConnectedFun n g
  → isConnectedFun (m + n) (f ×̂ g)
isConnected×̂ congf congg =
  elim.isConnectedPrecompose _ _ (lifting _ _ _ _ congf congg)


open import Agda.Primitive

open import Equality

module Quotient where

  is-prop : ∀ {ℓ} (A : Set ℓ) → Set ℓ
  is-prop A = ∀ (x y : A) → x ≡ y

  record is-equivalence {ℓ k} {A : Set ℓ} (E : A → A → Set k) : Set (ℓ ⊔ k) where
    field
      equiv-prop : ∀ {x y} → is-prop (E x y)
      equiv-refl : ∀ {x} → E x x
      equiv-symm : ∀ {x y} → E x y → E y x
      equiv-tran : ∀ {x y z} → E x y → E y z → E x z

  record Equivalence {ℓ} (A : Set ℓ) : Set (lsuc ℓ) where
    field
      equiv-relation : A → A → Set ℓ
      equiv-is-equivalence : is-equivalence equiv-relation

  is-set : ∀ {ℓ} (A : Set ℓ) → Set ℓ
  is-set A = ∀ (x y : A) (p q : x ≡ y) → p ≡ q

  record HSet ℓ : Set (lsuc ℓ) where
    field
      hset-type : Set ℓ
      hset-is-set : is-set hset-type

  record Quotient {ℓ} (A : Set ℓ) (E : Equivalence A) : Set (lsuc ℓ) where
    open Equivalence

    field
      quot-type : Set ℓ
      quot-class : ∀ (x : A) → quot-type
      quot-≡ : ∀ {x y : A} → equiv-relation E x y → quot-class x ≡ quot-class y
      quot-is-set : is-set quot-type
      quot-elim :
        ∀ (B : ∀ quot-type → Set ℓ)
          (f : ∀ (x : A) → B (quot-class x)) →
          (∀ (x y : A) {ε : equiv-relation E x y} → transport B (quot-≡ ε) (f x) ≡ f y) →
          ∀ (ξ : quot-type) → B ξ
      quot-compute :
        ∀ (B : ∀ quot-type → Set ℓ)  →
          (f : ∀ (x : A) → B (quot-class x)) →
          (η : ∀ (x y : A) {ε : equiv-relation E x y} → transport B (quot-≡ ε) (f x) ≡ f y) →
          (quot-elim ? quot-class η)


open import Relation.Nullary using (¬_; Dec; yes; no)
open import Relation.Binary using (Decidable)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Relation.Nullary.Decidable using (False; map)
open import Function.Equivalence as FE using ()

module AKS.Nat.Base where

open import Agda.Builtin.FromNat using (Number)
open import Data.Nat using (ℕ; _+_; _∸_; _*_; _≟_; _<ᵇ_; pred) public
open ℕ public
open import Data.Nat.Literals using (number)

instance
  ℕ-number : Number ℕ
  ℕ-number = number

data ℕ⁺ : Set where
  ℕ+ : ℕ → ℕ⁺

_+⁺_ : ℕ⁺ → ℕ⁺ → ℕ⁺
ℕ+ n +⁺ ℕ+ m = ℕ+ (suc (n + m))

_*⁺_ : ℕ⁺ → ℕ⁺ → ℕ⁺
ℕ+ n *⁺ ℕ+ m = ℕ+ (n + m * (suc n))

_≟⁺_ : Decidable {A = ℕ⁺} _≡_
ℕ+ n ≟⁺ ℕ+ m = map (FE.equivalence (λ { refl → refl }) (λ { refl → refl })) (n ≟ m)

⟅_⇑⟆ : ∀ n {≢0 : False (n ≟ zero)} → ℕ⁺
⟅ suc n ⇑⟆ = ℕ+ n

⟅_⇓⟆ : ℕ⁺ → ℕ
⟅ ℕ+ n ⇓⟆ = suc n

instance
  ℕ⁺-number : Number ℕ⁺
  ℕ⁺-number = record
    { Constraint = λ n → False (n ≟ zero)
    ; fromNat = λ n {{≢0}} → ⟅ n ⇑⟆ {≢0}
    }

infix 4 _≤_
record _≤_ (n : ℕ) (m : ℕ) : Set where
  constructor lte
  field
    k : ℕ
    ≤-proof : n + k ≡ m

infix 4 _≥_
_≥_ : ℕ → ℕ → Set
n ≥ m = m ≤ n

infix 4 _≰_
_≰_ : ℕ → ℕ → Set
n ≰ m = ¬ (n ≤ m)

infix 4 _≱_
_≱_ : ℕ → ℕ → Set
n ≱ m = ¬ (m ≤ n)

infix 4 _<_
_<_ : ℕ → ℕ → Set
n < m = suc n ≤ m

infix 4 _≮_
_≮_ : ℕ → ℕ → Set
n ≮ m = ¬ (n < m)

infix 4 _>_
_>_ : ℕ → ℕ → Set
n > m = m < n

infix 4 _≯_
_≯_ : ℕ → ℕ → Set
n ≯ m = m ≮ n


open import Categories
open import Monads

module Monads.Kleisli.Adjunction {a b}{C : Cat {a}{b}}(M : Monad C) where

open Cat C
open Monad M

open import Library
open import Functors
open import Monads.Kleisli M
open import Adjunctions
open import Monads.Kleisli.Functors M
open Fun

KlAdj : Adj C Kl
KlAdj = record {
  L        = KlL;
  R        = KlR;
  left     = id;
  right    = id;
  lawa     = λ _ → refl;
  lawb     = λ _ → refl;
  natleft  = lem;
  natright = lem}
  where
   lem = λ {X}{X'}{Y}{Y'} (f : Hom X' X)(g : Hom Y (T Y')) h →
    proof
    comp (bind g) (comp h f)
    ≅⟨ cong (λ h → comp (bind g) (comp h f)) (sym law2) ⟩
    comp (bind g) (comp (comp (bind h) η) f)
    ≅⟨ cong (comp (bind g)) ass ⟩
    comp (bind g) (comp (bind h) (comp η f))
    ∎


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

module Dodo.Binary.Trichotomous where

-- Stdlib imports
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; _≢_; refl; cong; subst; subst₂) renaming (sym to ≡-sym)
open import Level using (Level)
open import Function using (flip; _∘_; _∘₂_)
open import Data.Empty using (⊥-elim)
open import Data.Product using (_,_)
open import Relation.Unary using (Pred)
open import Relation.Binary using (Rel; Irreflexive; Trichotomous; Tri; tri<; tri≈; tri>)
open import Relation.Binary.Construct.Closure.Transitive using ([_])
-- Local imports
open import Dodo.Unary.Equality
open import Dodo.Binary.Equality
open import Dodo.Binary.Immediate
open import Dodo.Binary.Filter

-- # Definitions

tri-immˡ : {a ℓ₁ ℓ₂ : Level} {A : Set a} {_≈_ : Rel A ℓ₁} {R : Rel A ℓ₂}
  → Trichotomous _≈_ R → {x y z : A}
  → immediate R x z → immediate R y z
    ---------------------------------
  → x ≈ y
tri-immˡ triR {x} {y} {z} (Rxz , ¬∃y) (Ryz , ¬∃x) with triR x y
... | tri<  Rxy x≢y ¬Ryx = ⊥-elim (¬∃y (y , Rxy , [ Ryz ]))
... | tri≈ ¬Rxy x≡y ¬Ryx = x≡y
... | tri> ¬Rxy x≢y  Ryx = ⊥-elim (¬∃x (x , Ryx , [ Rxz ]))

tri-immʳ : {a ℓ₁ ℓ₂ : Level} {A : Set a} {_≈_ : Rel A ℓ₁} {R : Rel A ℓ₂}
  → Trichotomous _≈_ R → {x y z : A}
  → immediate R x y → immediate R x z
    ---------------------------------
  → y ≈ z
tri-immʳ triR {x} {y} {z} (Rxy , ¬∃z) (Rxz , ¬∃y) with triR y z
... | tri<  Ryz y≢z ¬Rzy = ⊥-elim (¬∃y (y , Rxy , [ Ryz ]))
... | tri≈ ¬Ryz y≡z ¬Rzy = y≡z
... | tri> ¬Ryz y≢z  Rzy = ⊥-elim (¬∃z (z , Rxz , [ Rzy ]))

tri-irreflexive : {a ℓ₁ ℓ₂ : Level} {A : Set a} {_≈_ : Rel A ℓ₁} {_<_ : Rel A ℓ₂}
  → Trichotomous _≈_ _<_
    --------------------
  → Irreflexive _≈_ _<_
tri-irreflexive triR {x} {y} x≈y x<y with triR x y
... | tri< x<y x≉y x≯y = x≉y x≈y
... | tri≈ x≮y x≈y x≯y = x≮y x<y
... | tri> x≮y x≉y x>y = x≉y x≈y

tri-flip : ∀ {a ℓ : Level} {A : Set a} {R : Rel A ℓ}
  → {x y : A}
  → Tri (R x y) (x ≡ y) (R y x)
    -------------------------------------
  → Tri (flip R x y) (x ≡ y) (flip R y x)
tri-flip (tri<  Rxy x≢y ¬Ryx) = tri> ¬Ryx x≢y  Rxy
tri-flip (tri≈ ¬Rxy x≡y ¬Ryx) = tri≈ ¬Ryx x≡y ¬Rxy
tri-flip (tri> ¬Rxy x≢y  Ryx) = tri<  Ryx x≢y ¬Rxy

trichotomous-flip : ∀ {a ℓ : Level} {A : Set a} {R : Rel A ℓ}
  → Trichotomous _≡_ R
    -------------------------
  → Trichotomous _≡_ (flip R)
trichotomous-flip {R = R} triR = tri-flip {R = R} ∘₂ triR


module container.m.core where

open import level
open import sum
open import equality.core
open import equality.calculus
open import function.core
open import function.isomorphism
open import function.extensionality
open import container.core
open import container.equality
open import container.fixpoint

infix 1000 ♯_

postulate
  ∞  : ∀ {a} (A : Set a) → Set a
  ♯_ : ∀ {a} {A : Set a} → A → ∞ A
  ♭  : ∀ {a} {A : Set a} → ∞ A → A

{-# BUILTIN INFINITY ∞  #-}
{-# BUILTIN SHARP    ♯_ #-}
{-# BUILTIN FLAT     ♭  #-}

module Definition {li la lb}(c : Container li la lb) where
  open Container c public

  -- definition of indexed M-types using native Agda coinduction
  data M (i : I) : Set (la ⊔ lb) where
    inf : (a : A i) → ((b : B a) → ∞ (M (r b))) → M i

  -- the terminal coalgebra
  out : M →ⁱ F M
  out i (inf a f) = a , ♭ ∘' f

  -- normally, the constructor can be defined in terms of out and unfold, but
  -- Agda provides it natively, together with a definitional β rule
  inM' : F M →ⁱ M
  inM' i (a , f) = inf a (λ x → ♯ (f x))

  inM'-β : {i : I}(x : F M i) → out i (inM' i x) ≡ x
  inM'-β x = refl

  module Elim {lx}{X : I → Set lx}
              (α : X →ⁱ F X) where
    -- anamorphisms
    unfold : X →ⁱ M
    unfold i x = inf a f
      where
        u : F X i
        u = α i x

        a : A i
        a = proj₁ u

        f : (b : B a) → ∞ (M (r b))
        f b = ♯ unfold (r b) (proj₂ u b)

    -- computational rule for anamorphisms
    -- this holds definitionally
    unfold-β : {i : I}(x : X i)
             → out i (unfold i x) ≡ imap unfold i (α i x)
    unfold-β x = refl

    -- the corresponding η rule doesn't hold, so we postulate it
    postulate
      unfold-η : (h : X →ⁱ M)
               → (∀ {i} (x : X i) → out i (h i x) ≡ imap h i (α i x))
               → ∀ {i} (x : X i) → h i x ≡ unfold i x
  open Elim public

  -- using η, we can prove that the unfolding of out is the identity
  unfold-id : ∀ {i} (x : M i) → unfold out i x ≡ x
  unfold-id x = sym (unfold-η out idⁱ (λ _ → refl) x)

  -- the usual definition of the constructor
  inM : F M →ⁱ M
  inM = unfold (imap out)

  -- the constructor is the inverse of the destructor
  inM-η : ∀ {i} (x : M i) → inM i (out i x) ≡ x
  inM-η x = unfold-η out (inM ∘ⁱ out) (λ _ → refl) x · unfold-id x

  inM-β : ∀ {i} (x : F M i) → out i (inM i x) ≡ x
  inM-β {i} x = ap u (funext (λ i → funext inM-η))
    where
      u : (M →ⁱ M) → F M i
      u h = imap h i x

  fixpoint : ∀ i → M i ≅ F M i
  fixpoint i = iso (out i) (inM i) inM-η inM-β

  -- now we can prove that the constructor provided by Agda is equal to the
  -- usual one
  inM-alt : ∀ {i} (x : F M i) → inM' i x ≡ inM i x
  inM-alt {i} x = sym (inM-η (inM' i x))


module Categories.Terminal where

open import Library
open import Categories
open import Categories.Sets
open Cat

record Term {a b} (C : Cat {a}{b})(T : Obj C) : Set (a ⊔ b) where
  constructor term
  field t : ∀{X} → Hom C X T
        law : ∀{X}{f : Hom C X T} → t {X} ≅ f

OneSet : Term Sets ⊤
OneSet = record {t = λ _ → _; law = ext (λ _ → refl)}


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

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

open import LogicalFormulae
open import Functions.Definition

module Orders.Partial.Definition {a : _} (carrier : Set a) where

record PartialOrder {b : _} : Set (a ⊔ lsuc b) where
  field
    _<_ : Rel {a} {b} carrier
    irreflexive : {x : carrier} → (x < x) → False
    <Transitive : {a b c : carrier} → (a < b) → (b < c) → (a < c)
  <WellDefined : {r s t u : carrier} → (r ≡ t) → (s ≡ u) → r < s → t < u
  <WellDefined refl refl r<s = r<s


module Dave.Algebra.Naturals.Monus where
    open import Dave.Algebra.Naturals.Definition
    open import Dave.Algebra.Naturals.Addition

    _∸_ : ℕ → ℕ → ℕ
    m ∸ zero = m
    zero ∸ suc n = zero
    suc m ∸ suc n = m ∸ n

    infixl 6 _∸_

    ∸-zero : ∀ (n : ℕ) → 0 ∸ n ≡ 0
    ∸-zero zero = refl
    ∸-zero (suc n) = refl

    ∸-assoc-+ : ∀ (m n p : ℕ) → m ∸ n ∸ p ≡ m ∸ (n + p)
    ∸-assoc-+ m zero p = refl
    ∸-assoc-+ zero (suc n) p = ∸-zero p
    ∸-assoc-+ (suc m) (suc n) p = begin
        suc m ∸ suc n ∸ p ≡⟨⟩
        m ∸ n ∸ p ≡⟨ ∸-assoc-+ m n p ⟩
        m ∸ (n + p) ≡⟨⟩
        suc m ∸ suc (n + p) ≡⟨⟩
        suc m ∸ (suc n + p) ∎


module Chain
  {U : Set}(T : U -> Set)
  (_==_ : {a b : U} -> T a -> T b -> Set)
  (refl : {a : U}(x : T a) -> x == x)
  (trans : {a b c : U}(x : T a)(y : T b)(z : T c) -> x == y -> y == z -> x == z)
  where

infix 30 _∼_
infix 3 proof_
infixl 2 _≡_by_
infix 1 _qed

data _∼_ {a b : U}(x : T a)(y : T b) : Set where
  prf : x == y -> x ∼ y

proof_ : {a : U}(x : T a) -> x ∼ x
proof x = prf (refl x)

_≡_by_ : {a b c : U}{x : T a}{y : T b} -> x ∼ y -> (z : T c) -> y == z -> x ∼ z
prf p ≡ z by q = prf (trans _ _ _ p q)

_qed : {a b : U}{x : T a}{y : T b} -> x ∼ y -> x == y
prf p qed = p


{-# OPTIONS --cubical --safe #-}

module Data.Integer where

open import Level

open import Data.Nat using (ℕ; suc; zero)
import Data.Nat as ℕ
import Data.Nat.Properties as ℕ
open import Data.Bool

data ℤ : Type where
  ⁺   : ℕ → ℤ
  ⁻suc : ℕ → ℤ

⁻ : ℕ → ℤ
⁻ zero    = ⁺ zero
⁻ (suc n) = ⁻suc n

{-# DISPLAY ⁻suc n = ⁻ suc n #-}

negate : ℤ → ℤ
negate (⁺ x) = ⁻ x
negate (⁻suc x) = ⁺ (suc x)

{-# DISPLAY negate x = ⁻ x #-}

infixl 6 _+_

_-suc_ : ℕ → ℕ → ℤ
x -suc y =
  if y ℕ.<ᴮ x
    then ⁺ (x ℕ.∸ (suc y))
    else ⁻suc (y ℕ.∸ x)

_+_ : ℤ → ℤ → ℤ
⁺    x + ⁺    y = ⁺ (x ℕ.+ y)
⁺    x + ⁻suc y = x -suc y
⁻suc x + ⁺    y = y -suc x
⁻suc x + ⁻suc y = ⁻suc (suc x ℕ.+ y)

_*-suc_ : ℕ → ℕ → ℤ
zero  *-suc m = ⁺ zero
suc n *-suc m = ⁻suc (n ℕ.+ m ℕ.+ n ℕ.* m)

infixl 7 _*_
_*_ : ℤ → ℤ → ℤ
⁺    x * ⁺    y = ⁺ (x ℕ.* y)
⁺    x * ⁻suc y = x *-suc y
⁻suc x * ⁺    y = y *-suc x
⁻suc x * ⁻suc y = ⁺ (suc x ℕ.* suc y)


module L0 where

open import Common

-- Syntax

data Name : Set where
 d n j m : Name

data Pred1 : Set where
 M B : Pred1

data Pred2 : Set where
 K L : Pred2

data Expr : Set where
  _⦅_⦆ : Pred1 -> Name -> Expr
  _⦅_,_⦆ : Pred2 -> Name -> Name -> Expr
  ¬ : Expr -> Expr
  [_∧_] : Expr -> Expr -> Expr
  [_∨_] : Expr -> Expr -> Expr
  [_⇒_] : Expr -> Expr -> Expr
  [_⇔_] : Expr -> Expr -> Expr

example1 : Expr
example1 = [ K ⦅ d , j ⦆ ∧ M ⦅ d ⦆  ]
example2 : Expr
example2 = ¬ [ M ⦅ d ⦆ ∨ B ⦅ m ⦆ ]
example3 : Expr
example3 = [ L ⦅ n , j ⦆ ⇒ [ B ⦅ d ⦆ ∨ ¬ (K ⦅ m , m ⦆) ] ]
example4 : Expr
example4 = [ ¬ (¬ (¬ (B ⦅ n ⦆))) ⇔ ¬ (M ⦅ n ⦆) ]

-- Semantics

data Person : Set where
  Richard_Nixon : Person
  Noam_Chomsky : Person
  John_Mitchell : Person
  Muhammad_Ali : Person

instance
  eqPerson : Eq Person
  -- _==_ ⦃ eqPerson ⦄ x y =  isEq x y (refl {!x y!})
  _==_ ⦃ eqPerson ⦄ Richard_Nixon Richard_Nixon = true
  _==_ ⦃ eqPerson ⦄ Noam_Chomsky Noam_Chomsky = true
  _==_ ⦃ eqPerson ⦄ John_Mitchell John_Mitchell = true
  _==_ ⦃ eqPerson ⦄ Muhammad_Ali Muhammad_Ali = true
  _==_ ⦃ eqPerson ⦄ _ _ = false

_∈_ : {A : Set} {{_ : Eq A}} -> A -> PSet A -> Bool
x ∈ ⦃⦄ = false
x ∈ (x₁ :: xs) = (x == x₁) || (x ∈ xs)

⟦_⟧ₙ : Name -> Person
⟦ d ⟧ₙ = Richard_Nixon
⟦ n ⟧ₙ = Noam_Chomsky
⟦ j ⟧ₙ = John_Mitchell
⟦ m ⟧ₙ = Muhammad_Ali

⟦_⟧ₚ₁ : Pred1 -> PSet Person
⟦ x ⟧ₚ₁ = {!!}

⟦_⟧ₚ₂ : Pred2 -> PSet (Pair Person)
⟦ x ⟧ₚ₂ = {!!}

⟦_⟧ₑ : Expr -> Bool
{-# TERMINATING #-}
⟦ x ⦅ x₁ ⦆ ⟧ₑ = ⟦ x₁ ⟧ₙ ∈ ⟦ x ⟧ₚ₁
⟦ x ⦅ x₁ , x₂ ⦆ ⟧ₑ = < ⟦ x₁ ⟧ₙ , ⟦ x₂ ⟧ₙ > ∈ ⟦ x ⟧ₚ₂
⟦ ¬ x ⟧ₑ = neg ⟦ x ⟧ₑ
⟦ [ x ∧ x₁ ] ⟧ₑ = ⟦ x ⟧ₑ && ⟦ x₁ ⟧ₑ
⟦ [ x ∨ x₁ ] ⟧ₑ = ⟦ x ⟧ₑ || ⟦ x₁ ⟧ₑ
⟦ [ x ⇒ x₁ ] ⟧ₑ = (neg ⟦ x₁ ⟧ₑ) || ⟦ x ⟧ₑ
⟦ [ x ⇔ x₁ ] ⟧ₑ = ⟦ [ x ⇒ x₁ ] ⟧ₑ && ⟦ [ x₁ ⇒ x ] ⟧ₑ


------------------------------------------------------------------------
-- The Agda standard library
--
-- "Finite" sets indexed on coinductive "natural" numbers
------------------------------------------------------------------------

{-# OPTIONS --without-K --sized-types --guardedness #-}

module Codata.Musical.Cofin where

open import Codata.Musical.Notation
open import Codata.Musical.Conat as Conat using (Coℕ; suc; ∞ℕ)
open import Data.Nat.Base using (ℕ; zero; suc)
open import Data.Fin using (Fin; zero; suc)
open import Relation.Binary.PropositionalEquality using (_≡_ ; refl)
open import Function

------------------------------------------------------------------------
-- The type

-- Note that Cofin ∞ℕ is /not/ finite. Note also that this is not a
-- coinductive type, but it is indexed on a coinductive type.

data Cofin : Coℕ → Set where
  zero : ∀ {n} → Cofin (suc n)
  suc  : ∀ {n} (i : Cofin (♭ n)) → Cofin (suc n)

suc-injective : ∀ {m} {p q : Cofin (♭ m)} → (Cofin (suc m) ∋ suc p) ≡ suc q → p ≡ q
suc-injective refl = refl

------------------------------------------------------------------------
-- Some operations

fromℕ : ℕ → Cofin ∞ℕ
fromℕ zero    = zero
fromℕ (suc n) = suc (fromℕ n)

toℕ : ∀ {n} → Cofin n → ℕ
toℕ zero    = zero
toℕ (suc i) = suc (toℕ i)

fromFin : ∀ {n} → Fin n → Cofin (Conat.fromℕ n)
fromFin zero    = zero
fromFin (suc i) = suc (fromFin i)

toFin : ∀ n → Cofin (Conat.fromℕ n) → Fin n
toFin zero    ()
toFin (suc n) zero    = zero
toFin (suc n) (suc i) = suc (toFin n i)

import Codata.Cofin as C

fromMusical : ∀ {n} → Cofin n → C.Cofin (Conat.fromMusical n)
fromMusical zero    = C.zero
fromMusical (suc n) = C.suc (fromMusical n)

toMusical : ∀ {n} → C.Cofin n → Cofin (Conat.toMusical n)
toMusical C.zero    = zero
toMusical (C.suc n) = suc (toMusical n)


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

-- This module provides the basic expression type for polynomials.

module Polynomial.Expr where

open import Data.Nat using (ℕ)
open import Data.Fin using (Fin)

infixl 6 _⊕_
infixl 7 _⊗_
infixr 8 _⊛_
data Expr  {ℓ} (A : Set ℓ) (n : ℕ) : Set ℓ where
  Κ   : A → Expr A n
  Ι   : Fin n → Expr A n
  _⊕_ : Expr A n → Expr A n → Expr A n
  _⊗_ : Expr A n → Expr A n → Expr A n
  _⊛_ : Expr A n → ℕ → Expr A n
  ⊝_  : Expr A n → Expr A n

open import Polynomial.Parameters

module Eval {c r₁ r₂ r₃} (homo : Homomorphism c r₁ r₂ r₃) where
  open Homomorphism homo
  open import Polynomial.Exponentiation rawRing

  open import Data.Vec as Vec using (Vec)

  ⟦_⟧ : ∀ {n} → Expr Raw.Carrier n → Vec Carrier n → Carrier
  ⟦ Κ x ⟧ ρ = ⟦ x ⟧ᵣ
  ⟦ Ι x ⟧ ρ = Vec.lookup ρ x
  ⟦ x ⊕ y ⟧ ρ = ⟦ x ⟧ ρ + ⟦ y ⟧ ρ
  ⟦ x ⊗ y ⟧ ρ = ⟦ x ⟧ ρ * ⟦ y ⟧ ρ
  ⟦ ⊝ x ⟧ ρ = - ⟦ x ⟧ ρ
  ⟦ x ⊛ i ⟧ ρ = ⟦ x ⟧ ρ ^ i


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

open import HoTT
open import cohomology.Theory

open import cw.CW

module cw.cohomology.TipAndAugment {i} (OT : OrdinaryTheory i)
  (⊙skel : ⊙Skeleton {i} 0) where

open OrdinaryTheory OT
open import homotopy.DisjointlyPointedSet
open import cohomology.DisjointlyPointedSet OT

module _ (m : ℤ) where
  CX₀ : Group i
  CX₀ = C m (⊙cw-head ⊙skel)

  CX₀-is-abelian : is-abelian CX₀
  CX₀-is-abelian = C-is-abelian m (⊙cw-head ⊙skel)

  C2×CX₀ : Group i
  C2×CX₀ = C2 m ×ᴳ CX₀

  abstract
    C2×CX₀-is-abelian : is-abelian C2×CX₀
    C2×CX₀-is-abelian = ×ᴳ-is-abelian (C2 m) CX₀ (C2-is-abelian m) CX₀-is-abelian

  C2×CX₀-abgroup : AbGroup i
  C2×CX₀-abgroup = C2×CX₀ , C2×CX₀-is-abelian

  CX₀-β : ⊙has-cells-with-choice 0 ⊙skel i
    → CX₀ ≃ᴳ Πᴳ (MinusPoint (⊙cw-head ⊙skel)) (λ _ → C2 m)
  CX₀-β ac = C-set m (⊙cw-head ⊙skel) (snd (⊙Skeleton.skel ⊙skel)) (⊙Skeleton.pt-dec ⊙skel) ac

abstract
  CX₀-≠-is-trivial : ∀ {m} (m≠0 : m ≠ 0)
    → ⊙has-cells-with-choice 0 ⊙skel i
    → is-trivialᴳ (CX₀ m)
  CX₀-≠-is-trivial {m} m≠0 ac =
    iso-preserves'-trivial (CX₀-β m ac) $
      Πᴳ-is-trivial (MinusPoint (⊙cw-head ⊙skel))
        (λ _ → C2 m) (λ _ → C-dimension m≠0)

cw-coε : C2 0 →ᴳ C2×CX₀ 0
cw-coε = ×ᴳ-inl {G = C2 0} {H = CX₀ 0}


{-

        Agda Implementors' Meeting VI

                  Göteborg
             May 24 - 30, 2007

                Hello Agda!

                Ulf Norell

-}

{-

   Getting your hands on Agda

   http://www.cs.chalmers.se/~ulfn/Agda

   darcs get --partial http://www.cs.chalmers.se/~ulfn/darcs/Agda2

-}

-- Each Agda file contains a top-level module, whose
-- name corresponds to the file name.

module Basics where

{-

  Expressions (types and terms)

-}

-- The expression language of Agda is your favorite dependently
-- typed λ-calculus.

-- For instance:
id₁ : (A : Set) -> A -> A
id₁ = \ A x -> x

id₂ : (A : Set) -> A -> A
id₂ = \ A x -> id₁ A (id₁ A x)

-- Note: Agda likes white space. This is not correct:
--   id:(A:Set)->A->A
-- Why not? In Agda the following strings are valid identifiers:
--   id:
--   A:Set
--   ->A->A

-- Another useful function, featuring telescopes
-- and typed λs.
compose : (A B C : Set)(f : B -> C)(g : A -> B) -> A -> C
compose = \(A B C : Set) -> \ f g x -> f (g x)

{-

  Implicit arguments

-}

-- Writing down type arguments explicitly soon gets old.
-- Enter implicit arguments.

-- Note the curlies in the telescope. And A mysteriously disappeared
-- in the definition.
id₃ : {A : Set} -> A -> A
id₃ = \ x -> x

-- And it's not there when applying the function.
id₄ : {A : Set} -> A -> A
id₄ = \ x -> (id₃ (id₃ x))

-- You can give implicit arguments explicitly.
id₅ : {A : Set} -> A -> A
id₅ {A} x = id₄ {A} x

-- If you want to give a particular implicit argument, you can refer
-- to it by name.
const : {A B : Set} -> A -> B -> A
const = \ x y -> x

const' : (A : Set) -> A -> A -> A
const' = \ A -> const {B = A}

-- It also works the other way around. If you think the type checker
-- should figure out the value of something explicit, you write _.
id₆ : {A : Set} -> A -> A
id₆ x = id₁ _ x

-- Interesting though it is, eventually you'll get bored
-- with the λ-calculus...

-- Move on to: Datatypes.agda


data ⊤ : Set where tt : ⊤

record R : Set where
  constructor r
  field .x : ⊤

f : R → R
R.x (f (r x)) = {!x!}


{-

The James Construction,
  also known as James Reduced Product

A very fundamental and useful construction in classical homotopy theory.
It can be seen as the free A∞-monoid constructed out of a given type,
namely the "correct higher version" of free monoid that is meaningful for all types,
instead of only h-Sets.

Referrence:
  Guillaume Brunerie,
  "The James construction and π₄(𝕊³) in homotopy type theory"
  (https://arxiv.org/abs/1710.10307)

-}
{-# OPTIONS --safe #-}
module Cubical.HITs.James.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Pointed

private
  variable
    ℓ ℓ' : Level

module _
  ((X , x₀) : Pointed ℓ) where

  infixr 5 _∷_

  -- The James Construction

  data James : Type ℓ where
    []   : James
    _∷_  : X → James → James
    unit : (xs : James) → xs ≡ x₀ ∷ xs

  James∙ : Pointed ℓ
  James∙ = James , []

-- Basic operations on James construction, imitating those in Cubical.Data.List.Base

module _
  {X∙@(X , x₀) : Pointed ℓ} where

  infixr 5 _++_
  infixl 5 _∷ʳ_

  [_] : X → James X∙
  [ x ] = x ∷ []

  _++_ : James X∙ → James X∙ → James X∙
  [] ++ ys = ys
  (x ∷ xs) ++ ys = x ∷ xs ++ ys
  (unit xs i) ++ ys = unit (xs ++ ys) i

  ++₀ : (xs : James X∙) → xs ≡ xs ++ [ x₀ ]
  ++₀ [] = unit []
  ++₀ (x ∷ xs) i = x ∷ ++₀ xs i
  ++₀ (unit xs i) j = unit (++₀ xs j) i

  rev : James X∙ → James X∙
  rev [] = []
  rev (x ∷ xs) = rev xs ++ [ x ]
  rev (unit xs i) = ++₀ (rev xs) i

  _∷ʳ_ : James X∙ → X → James X∙
  xs ∷ʳ x = xs ++ x ∷ []

map : {X : Pointed ℓ}{Y : Pointed ℓ'} → (X →∙ Y) → James X → James Y
map f [] = []
map f (x ∷ xs) = f .fst x ∷ map f xs
map f (unit xs i) = (unit (map f xs) ∙ (λ i → f .snd (~ i) ∷ map f xs)) i

map∙ : {X : Pointed ℓ}{Y : Pointed ℓ'} → (X →∙ Y) → James∙ X →∙ James∙ Y
map∙ f .fst = map f
map∙ f .snd = refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Automatic solvers for equations over booleans
------------------------------------------------------------------------

-- See README.Nat for examples of how to use similar solvers

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

module Data.Bool.Solver where

import Algebra.Solver.Ring.Simple as Solver
import Algebra.Solver.Ring.AlmostCommutativeRing as ACR
open import Data.Bool using (_≟_)
open import Data.Bool.Properties

------------------------------------------------------------------------
-- A module for automatically solving propositional equivalences
-- containing _∨_ and _∧_

module ∨-∧-Solver =
  Solver (ACR.fromCommutativeSemiring ∨-∧-commutativeSemiring) _≟_

------------------------------------------------------------------------
-- A module for automatically solving propositional equivalences
-- containing _xor_ and _∧_

module xor-∧-Solver =
  Solver (ACR.fromCommutativeRing xor-∧-commutativeRing) _≟_


{-# OPTIONS --without-K #-}
open import HoTT.Base
open import HoTT.Identity

module HoTT.Homotopy where

open variables
private variable f g : A → B

-- Lemma 2.4.3
~-natural : (α : f ~ g) {x y : A} (p : x == y) → α x ∙ ap g p == ap f p ∙ α y
~-natural α {x} refl rewrite α x = refl

~-natural-id : (α : f ~ id) {x y : A} (p : x == y) → α x ∙ p == ap f p ∙ α y
~-natural-id α {x} refl rewrite α x = refl

-- Corollary 2.4.4
~-natural-comm : {f : A → A} (α : f ~ id) → α ∘ f ~ ap f ∘ α
~-natural-comm {f = f} α x = cancelᵣ (α (f x) ∙ₗ ap-id (α x) ⁻¹ ∙ ~-natural α (α x))

module ~-Reasoning where
  _~⟨_⟩_ : (f : Π A P) {g h : Π A P} → f ~ g → g ~ h → f ~ h
  x ~⟨ α ⟩ β = α ∙ₕ β
  infixr 2 _~⟨_⟩_

  _∎ : (f : Π A P) → f ~ f
  _ ∎ = reflₕ
  infix 3 _∎


-- Some basic stuff for Conor's talk.
module SomeBasicStuff where

infixr 40 _::_ _↦_∣_
infix 30 _∈_ _==_
infixr 10 _,_

data _==_ {A : Set}(x : A) : A -> Set where
  refl : x == x

data Σ (A : Set)(B : A -> Set) : Set where
  _,_ : (x : A) -> B x -> Σ A B

_×_ : Set -> Set -> Set
A × B = Σ A \_ -> B

fst : {A : Set}{B : A -> Set} -> Σ A B -> A
fst (x , y) = x

snd : {A : Set}{B : A -> Set}(p : Σ A B) -> B (fst p)
snd (x , y) = y

data   False : Set where
record True  : Set where

data Nat : Set where
  zero : Nat
  suc  : Nat -> Nat

data [_] (A : Set) : Set where
  []   : [ A ]
  _::_ : A -> [ A ] -> [ A ]

data _∈_ {A : Set} : A -> [ A ] -> Set where
  zero : forall {x xs} -> x ∈ x :: xs
  suc  : forall {x y xs} -> x ∈ xs -> x ∈ y :: xs

postulate Tag : Set
{-# BUILTIN STRING Tag #-}

Enumeration = [ Tag ]

data Enum (ts : Enumeration) : Set where
  enum : (t : Tag) -> t ∈ ts -> Enum ts

data Table (A : Set1) : Enumeration -> Set1 where
  []    : Table A []
  _↦_∣_ : forall {ts} -> (t : Tag) -> A -> Table A ts ->
          Table A (t :: ts)

lookup : forall {A ts} -> Table A ts -> Enum ts -> A
lookup []             (enum _ ())
lookup (.t ↦ v ∣ tbl) (enum t zero)    = v
lookup (_  ↦ v ∣ tbl) (enum t (suc p)) = lookup tbl (enum t p)


{-# OPTIONS --without-K #-}
open import Type
open import Type.Identities
open import Level.NP
open import Explore.Core
open import Explore.Properties
open import Explore.Explorable
open import Data.Zero
open import Function.NP
open import Function.Extensionality
open import Data.Product
open import Relation.Binary.PropositionalEquality.NP using (_≡_; refl; _∙_; !_)
open import HoTT
open Equivalences

import Explore.Monad
open import Explore.Isomorphism

module Explore.Zero where

module _ {ℓ} where
    𝟘ᵉ : Explore ℓ 𝟘
    𝟘ᵉ = empty-explore
    {- or
    𝟘ᵉ ε _ _ = ε
    -}

    𝟘ⁱ : ∀ {p} → ExploreInd p 𝟘ᵉ
    𝟘ⁱ = empty-explore-ind
    {- or
    𝟘ⁱ _ Pε _ _ = Pε
    -}

module _ {ℓ₁ ℓ₂ ℓᵣ} {R : 𝟘 → 𝟘 → ★₀} where
    ⟦𝟘ᵉ⟧ : ⟦Explore⟧ {ℓ₁} {ℓ₂} ℓᵣ R 𝟘ᵉ 𝟘ᵉ
    ⟦𝟘ᵉ⟧ _ εᵣ _ _ = εᵣ

module 𝟘ⁱ = FromExploreInd 𝟘ⁱ
open 𝟘ⁱ public using ()
  renaming (sum to 𝟘ˢ
           ;product to 𝟘ᵖ
           ;reify to 𝟘ʳ
           ;unfocus to 𝟘ᵘ
           )

module _ {ℓ} where

    𝟘ˡ : Lookup {ℓ} 𝟘ᵉ
    𝟘ˡ _ ()

    𝟘ᶠ : Focus {ℓ} 𝟘ᵉ
    𝟘ᶠ ((), _)

    module _ {{_ : UA}} where
        Σᵉ𝟘-ok : Adequate-Σ {ℓ} (Σᵉ 𝟘ᵉ)
        Σᵉ𝟘-ok _ = ! Σ𝟘-lift∘fst

    module _ {{_ : UA}}{{_ : FunExt}} where
        Πᵉ𝟘-ok : Adequate-Π {ℓ} (Πᵉ 𝟘ᵉ)
        Πᵉ𝟘-ok _ = ! Π𝟘-uniq _

open Adequacy _≡_
module _ {{_ : UA}} where
    𝟘ˢ-ok : Adequate-sum 𝟘ˢ
    𝟘ˢ-ok _ = Fin0≡𝟘 ∙ ! Σ𝟘-fst

    adequate-sum𝟘     = 𝟘ˢ-ok

module _ {{_ : UA}}{{_ : FunExt}} where
    𝟘ᵖ-ok : Adequate-product 𝟘ᵖ
    𝟘ᵖ-ok _ = Fin1≡𝟙 ∙ ! (Π𝟘-uniq₀ _)

    adequate-product𝟘 = 𝟘ᵖ-ok

explore𝟘          = 𝟘ᵉ
explore𝟘-ind      = 𝟘ⁱ
lookup𝟘           = 𝟘ˡ
reify𝟘            = 𝟘ʳ
focus𝟘            = 𝟘ᶠ
unfocus𝟘          = 𝟘ᵘ
sum𝟘              = 𝟘ˢ
product𝟘          = 𝟘ᵖ

Lift𝟘ᵉ : ∀ {m} → Explore m (Lift 𝟘)
Lift𝟘ᵉ = explore-iso (≃-sym Lift≃id) 𝟘ᵉ

ΣᵉLift𝟘-ok : ∀ {{_ : UA}}{{_ : FunExt}}{m} → Adequate-Σ {m} (Σᵉ Lift𝟘ᵉ)
ΣᵉLift𝟘-ok = Σ-iso-ok (≃-sym Lift≃id) {Aᵉ = 𝟘ᵉ} Σᵉ𝟘-ok

-- -}


{-# OPTIONS --safe #-}
module Cubical.Algebra.Group.Instances.NProd where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels

open import Cubical.Data.Nat using (ℕ)

open import Cubical.Algebra.Group

private variable
  ℓ : Level

open GroupStr

NProd-Group : (G : (n : ℕ) → Type ℓ) → (Gstr : (n : ℕ) → GroupStr (G n)) → Group ℓ
fst (NProd-Group G Gstr) = (n : ℕ) → G n
1g (snd (NProd-Group G Gstr)) = λ n → 1g (Gstr n)
GroupStr._·_ (snd (NProd-Group G Gstr)) = λ f g n → Gstr n ._·_ (f n) (g n)
inv (snd (NProd-Group G Gstr)) = λ f n → (Gstr n).inv (f n)
isGroup (snd (NProd-Group G Gstr)) = makeIsGroup (isSetΠ (λ _ → is-set (Gstr _)))
                                                 (λ f g h → funExt λ n → ·Assoc (Gstr n) _ _ _)
                                                 (λ f → funExt λ n → ·IdR (Gstr n) _)
                                                 (λ f → funExt λ n → ·IdL (Gstr n) _)
                                                 (λ f → funExt λ n → ·InvR (Gstr n) _)
                                                  λ f → funExt λ n → ·InvL (Gstr n) _


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

module Cubical.Categories.Equivalence.Base where

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

open Precategory
open Functor

private
  variable
    ℓC ℓC' ℓD ℓD' : Level

-- Definition

record isEquivalence {C : Precategory ℓC ℓC'} {D : Precategory ℓD ℓD'}
                     (func : Functor C D) : Type (ℓ-max (ℓ-max ℓC ℓC') (ℓ-max ℓD ℓD')) where
  field
    invFunc : Functor D C

    η : 𝟙⟨ C ⟩ ≅ᶜ invFunc ∘F func
    ε : func ∘F invFunc ≅ᶜ 𝟙⟨ D ⟩

record _≃ᶜ_ (C : Precategory ℓC ℓC') (D : Precategory ℓD ℓD') : Type (ℓ-max (ℓ-max ℓC ℓC') (ℓ-max ℓD ℓD')) where
  field
    func : Functor C D
    isEquiv : isEquivalence func


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

open import lib.Basics
open import lib.NType2
open import lib.Function2
open import lib.types.Group
open import lib.types.Sigma
open import lib.types.Truncation
open import lib.groups.Homomorphism
open import lib.groups.Isomorphism
open import lib.groups.SubgroupProp

module lib.groups.Subgroup where

module _ {i j} {G : Group i} (P : SubgroupProp G j) where
  private
    module G = Group G
    module P = SubgroupProp P

  subgroup-struct : GroupStructure P.SubEl
  subgroup-struct = record {M} where
    module M where
      ident : P.SubEl
      ident = G.ident , P.ident

      inv : P.SubEl → P.SubEl
      inv (g , p) = G.inv g , P.inv p

      comp : P.SubEl → P.SubEl → P.SubEl
      comp (g₁ , p₁) (g₂ , p₂) = G.comp g₁ g₂ , P.comp p₁ p₂

      abstract
        unit-l : ∀ g → comp ident g == g
        unit-l (g , _) = Subtype=-out P.subEl-prop (G.unit-l g)

        assoc : ∀ g₁ g₂ g₃ → comp (comp g₁ g₂) g₃ == comp g₁ (comp g₂ g₃)
        assoc (g₁ , _) (g₂ , _) (g₃ , _) = Subtype=-out P.subEl-prop (G.assoc g₁ g₂ g₃)

        inv-l : ∀ g → comp (inv g) g == ident
        inv-l (g , _) = Subtype=-out P.subEl-prop (G.inv-l g)

  Subgroup : Group (lmax i j)
  Subgroup = group _ SubEl-level subgroup-struct
    where abstract SubEl-level = Subtype-level P.subEl-prop G.El-level

module Subgroup {i j} {G : Group i} (P : SubgroupProp G j) where
  private
    module P = SubgroupProp P
    module G = Group G

  grp = Subgroup P
  open Group grp public

  El=-out : ∀ {s₁ s₂ : El} → fst s₁ == fst s₂ → s₁ == s₂
  El=-out = Subtype=-out P.subEl-prop

  inject : Subgroup P →ᴳ G
  inject = record {f = fst; pres-comp = λ _ _ → idp}

  inject-lift : ∀ {j} {H : Group j} (φ : H →ᴳ G)
    → Π (Group.El H) (P.prop ∘ GroupHom.f φ)
    → (H →ᴳ Subgroup P)
  inject-lift {H = H} φ P-all = record {M} where
    module H = Group H
    module φ = GroupHom φ
    module M where
      f : H.El → P.SubEl
      f h = φ.f h , P-all h

      abstract
        pres-comp : ∀ h₁ h₂ → f (H.comp h₁ h₂) == Group.comp (Subgroup P) (f h₁) (f h₂)
        pres-comp h₁ h₂ = Subtype=-out P.subEl-prop (φ.pres-comp h₁ h₂)

full-subgroup : ∀ {i j} {G : Group i} {P : SubgroupProp G j}
  → is-fullᴳ P → Subgroup P ≃ᴳ G
full-subgroup {G = G} {P} full = Subgroup.inject P , is-eq _ from to-from from-to where
  from : Group.El G → Subgroup.El P
  from g = g , full g

  abstract
    from-to : ∀ p → from (fst p) == p
    from-to p = Subtype=-out (SubgroupProp.subEl-prop P) idp

    to-from : ∀ g → fst (from g) == g
    to-from g = idp

module _ {i} {j} {G : Group i} {H : Group j} (φ : G →ᴳ H) where

  private
    module G = Group G
    module H = Group H
    module φ = GroupHom φ

  module Ker = Subgroup (ker-propᴳ φ)
  Ker = Ker.grp

  module Im = Subgroup (im-propᴳ φ)
  Im = Im.grp

  im-lift : G →ᴳ Im
  im-lift = Im.inject-lift φ (λ g → [ g , idp ])

  im-lift-is-surj : is-surjᴳ im-lift
  im-lift-is-surj (_ , s) = Trunc-fmap
    (λ {(g , p) → (g , Subtype=-out (_ , λ _ → Trunc-level) p)}) s

module _ {i j k} {G : Group i} (P : SubgroupProp G j)
  (Q : SubgroupProp G k) where

  -- FIXME looks like a bad name
  Subgroup-fmap-r : P ⊆ᴳ Q → Subgroup P →ᴳ Subgroup Q
  Subgroup-fmap-r P⊆Q = group-hom (Σ-fmap-r P⊆Q)
    (λ _ _ → Subtype=-out (SubgroupProp.subEl-prop Q) idp)

  Subgroup-emap-r : P ⊆ᴳ Q → Q ⊆ᴳ P → Subgroup P ≃ᴳ Subgroup Q
  Subgroup-emap-r P⊆Q Q⊆P = Subgroup-fmap-r P⊆Q ,
    is-eq _ (Σ-fmap-r Q⊆P)
      (λ _ → Subtype=-out (SubgroupProp.subEl-prop Q) idp)
      (λ _ → Subtype=-out (SubgroupProp.subEl-prop P) idp)


{- Basic definitions using Σ-types

Σ-types are defined in Core/Primitives as they are needed for Glue types.

The file contains:

- Non-dependent pair types: A × B
- Mere existence: ∃[x ∈ A] B
- Unique existence: ∃![x ∈ A] B

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Data.Sigma.Base where

open import Cubical.Core.Primitives public

open import Cubical.Foundations.Prelude
open import Cubical.HITs.PropositionalTruncation.Base

-- Non-dependent pair types

_×_ : ∀ {ℓ ℓ'} (A : Type ℓ) (B : Type ℓ') → Type (ℓ-max ℓ ℓ')
A × B = Σ A (λ _ → B)

infixr 5 _×_

-- Mere existence

∃ : ∀ {ℓ ℓ'} (A : Type ℓ) (B : A → Type ℓ') → Type (ℓ-max ℓ ℓ')
∃ A B = ∥ Σ A B ∥

infix 2 ∃-syntax

∃-syntax : ∀ {ℓ ℓ'} (A : Type ℓ) (B : A → Type ℓ') → Type (ℓ-max ℓ ℓ')
∃-syntax = ∃

syntax ∃-syntax A (λ x → B) = ∃[ x ∈ A ] B

-- Unique existence

∃! : ∀ {ℓ ℓ'} (A : Type ℓ) (B : A → Type ℓ') → Type (ℓ-max ℓ ℓ')
∃! A B = isContr (Σ A B)

infix 2 ∃!-syntax

∃!-syntax : ∀ {ℓ ℓ'} (A : Type ℓ) (B : A → Type ℓ') → Type (ℓ-max ℓ ℓ')
∃!-syntax = ∃!

syntax ∃!-syntax A (λ x → B) = ∃![ x ∈ A ] B


------------------------------------------------------------------------
-- The Agda standard library
--
-- Products of nullary relations
------------------------------------------------------------------------

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

module Relation.Nullary.Product where

open import Data.Bool.Base
open import Data.Product
open import Function
open import Level
open import Relation.Nullary.Reflects
open import Relation.Nullary

private
  variable
    p q : Level
    P : Set p
    Q : Set q

------------------------------------------------------------------------
-- Some properties which are preserved by _×_.

infixr 2 _×-reflects_ _×-dec_

_×-reflects_ : ∀ {bp bq} → Reflects P bp → Reflects Q bq →
                           Reflects (P × Q) (bp ∧ bq)
ofʸ  p ×-reflects ofʸ  q = ofʸ (p , q)
ofʸ  p ×-reflects ofⁿ ¬q = ofⁿ (¬q ∘ proj₂)
ofⁿ ¬p ×-reflects _      = ofⁿ (¬p ∘ proj₁)

_×-dec_ : Dec P → Dec Q → Dec (P × Q)
does  (p? ×-dec q?) = does p? ∧ does q?
proof (p? ×-dec q?) = proof p? ×-reflects proof q?


module RMonads.CatofRMonads where

open import Categories
open import Functors
open import RMonads
open import RMonads.RMonadMorphs

CatofRMonads : ∀{a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}(J : Fun C D) → Cat
CatofRMonads J = record
                 { Obj  = RMonad J
                 ; Hom  = RMonadMorph
                 ; iden = IdRMonadMorph _
                 ; comp = CompRMonadMorph
                 ; idl  = idl _
                 ; idr  = idr _
                 ; ass  = λ{_ _ _ _ f g h} → ass f g h
                 }