module Data.Boolean.Stmt.Proofs where

import      Lvl
open import Data.Boolean
open import Data.Boolean.Proofs hiding (bivalence ; disjointness)
import      Data.Boolean.Operators
open        Data.Boolean.Operators.Programming
open import Data.Boolean.Stmt
open import Functional
open import Logic.Propositional as Logic using (⊥ ; _∨_ ; _∧_ ; ¬_ ; _↔_ ; [⊤]-intro ; [↔]-intro ; [⊥]-elim)
open import Relator.Equals
open import Type

-- A boolean operation is either true or false
bivalence : ∀{a} → (IsTrue(a) ∨ IsFalse(a))
bivalence {𝑇} = Logic.[∨]-introₗ [⊤]-intro
bivalence {𝐹} = Logic.[∨]-introᵣ [⊤]-intro

-- A boolean operation is not both true and false at the same time
disjointness : ∀{a} → IsTrue(a) → IsFalse(a) → ⊥
disjointness {𝑇} [⊤]-intro ()
disjointness {𝐹} () [⊤]-intro

module IsTrue where
  [𝑇]-intro : IsTrue(𝑇)
  [𝑇]-intro = [⊤]-intro

  [𝐹]-elim : ¬ IsTrue(𝐹)
  [𝐹]-elim ()

  [∧]-intro : ∀{a b} → IsTrue(a) → IsTrue(b) → IsTrue(a && b)
  [∧]-intro {𝑇} {b} ta tb = tb
  [∧]-intro {𝐹} {b} ta tb = ta

  [∨]-introₗ : ∀{a b} → IsTrue(a) → IsTrue(a || b)
  [∨]-introₗ {_}{𝑇} _ = [⊤]-intro
  [∨]-introₗ {_}{𝐹} = id

  [∨]-introᵣ : ∀{a b} → IsTrue(b) → IsTrue(a || b)
  [∨]-introᵣ {𝑇}{_} _ = [⊤]-intro
  [∨]-introᵣ {𝐹}{_} = id

  [∧]-elimₗ : ∀{a b} → IsTrue(a && b) → IsTrue(a)
  [∧]-elimₗ {𝑇}{𝑇} [⊤]-intro = [⊤]-intro
  [∧]-elimₗ {𝑇}{𝐹} ()
  [∧]-elimₗ {𝐹}{𝑇} ()
  [∧]-elimₗ {𝐹}{𝐹} ()

  [∧]-elimᵣ : ∀{a b} → IsTrue(a && b) → IsTrue(b)
  [∧]-elimᵣ {𝑇}{𝑇} [⊤]-intro = [⊤]-intro
  [∧]-elimᵣ {𝑇}{𝐹} ()
  [∧]-elimᵣ {𝐹}{𝑇} ()
  [∧]-elimᵣ {𝐹}{𝐹} ()

  [∨]-elim : ∀{ℓ₂}{φ : Type{ℓ₂}}{a b} → (IsTrue(a) → φ) → (IsTrue(b) → φ) → IsTrue(a || b) → φ
  [∨]-elim {_}{_}{𝑇}{𝑇} f _ [⊤]-intro = f [⊤]-intro
  [∨]-elim {_}{_}{𝑇}{𝐹} f _ [⊤]-intro = f [⊤]-intro
  [∨]-elim {_}{_}{𝐹}{𝑇} _ f [⊤]-intro = f [⊤]-intro
  [∨]-elim {_}{_}{𝐹}{𝐹} _ f ()

  [¬]-intro : ∀{a} → IsFalse(a) → IsTrue(! a)
  [¬]-intro {𝐹} fa = [⊤]-intro

  [¬]-elim : ∀{a} → IsTrue(! a) → IsFalse(a)
  [¬]-elim {𝑇} ()
  [¬]-elim {𝐹} [⊤]-intro = [⊤]-intro

  [→?]-intro : ∀{a b} → (IsTrue a → IsTrue b) → IsTrue (a →? b)
  [→?]-intro {𝑇} {𝑇} _   = [⊤]-intro
  [→?]-intro {𝑇} {𝐹} tab = tab [⊤]-intro
  [→?]-intro {𝐹} {𝑇} _   = [⊤]-intro
  [→?]-intro {𝐹} {𝐹} _   = [⊤]-intro

  [→?]-elim : ∀{a b} → IsTrue (a →? b) → (IsTrue a → IsTrue b)
  [→?]-elim {𝑇} {𝑇} tab ta = [⊤]-intro

  [←?]-intro : ∀{a b} → (IsTrue b → IsTrue a) → IsTrue (a ←? b)
  [←?]-intro {𝑇} {𝑇} tba = [⊤]-intro
  [←?]-intro {𝑇} {𝐹} tba = [⊤]-intro
  [←?]-intro {𝐹} {𝑇} tba = tba [⊤]-intro
  [←?]-intro {𝐹} {𝐹} tba = [⊤]-intro

  [←?]-elim : ∀{a b} → IsTrue (a ←? b) → (IsTrue b → IsTrue a)
  [←?]-elim {𝑇} {𝑇} tab tb = [⊤]-intro

  [==]-intro : ∀{a b} → (IsTrue b → IsTrue a) → (IsTrue a → IsTrue b) → IsTrue(a == b)
  [==]-intro {𝑇} {𝑇} ba ab = [⊤]-intro
  [==]-intro {𝑇} {𝐹} ba ab = ab [⊤]-intro
  [==]-intro {𝐹} {𝑇} ba ab = ba [⊤]-intro
  [==]-intro {𝐹} {𝐹} ba ab = [⊤]-intro

  [==]-elimₗ : ∀{a b} → IsTrue(a == b) → (IsTrue b → IsTrue a)
  [==]-elimₗ {𝑇} {𝑇} tab tb = [⊤]-intro

  [==]-elimᵣ : ∀{a b} → IsTrue(a == b) → (IsTrue a → IsTrue b)
  [==]-elimᵣ {𝑇} {𝑇} tab ta = [⊤]-intro

  [!]-intro : ∀{a b} → (IsTrue a → IsTrue b) → (IsTrue a → IsTrue(not b)) → IsTrue(not a)
  [!]-intro {𝑇} {𝑇} tab tanb = tanb [⊤]-intro
  [!]-intro {𝑇} {𝐹} tab tanb = tab [⊤]-intro
  [!]-intro {𝐹} {𝑇} tab tanb = [⊤]-intro
  [!]-intro {𝐹} {𝐹} tab tanb = [⊤]-intro

  [!]-elim : ∀{a b} → IsTrue a → IsTrue(not a) → IsTrue b
  [!]-elim {𝑇} {𝑇} ta tnb = [⊤]-intro
  [!]-elim {𝑇} {𝐹} ta tnb = tnb
  [!]-elim {𝐹} {𝑇} ta tnb = [⊤]-intro
  [!]-elim {𝐹} {𝐹} ta tnb = ta

  is-𝑇 : ∀{a} → IsTrue(a) ↔ (a ≡ 𝑇)
  is-𝑇 {a} = [↔]-intro (l{a}) (r{a}) where
    r : ∀ {a} → IsTrue(a) → (a ≡ 𝑇)
    r {𝑇} _ = [≡]-intro
    r {𝐹} ()

    l : ∀ {a} → IsTrue(a) ← (a ≡ 𝑇)
    l [≡]-intro = [⊤]-intro

  preserves-[&&][∧] : ∀{a b} → IsTrue(a && b) ↔ IsTrue(a) ∧ IsTrue(b)
  preserves-[&&][∧] = [↔]-intro
    (\{(Logic.[∧]-intro l r) → [∧]-intro l r})
    (proof ↦ Logic.[∧]-intro ([∧]-elimₗ proof) ([∧]-elimᵣ proof))

  preserves-[||][∨] : ∀{a b} → IsTrue(a || b) ↔ IsTrue(a) ∨ IsTrue(b)
  preserves-[||][∨] = [↔]-intro
    (Logic.[∨]-elim [∨]-introₗ [∨]-introᵣ)
    ([∨]-elim Logic.[∨]-introₗ Logic.[∨]-introᵣ)

  preserves-[!][¬] : ∀{a} → IsTrue(! a) ↔ (¬ IsTrue(a))
  preserves-[!][¬] {a} = [↔]-intro (l{a}) (r{a}) where
    l : ∀{a} → IsTrue(! a) ← (¬ IsTrue(a))
    l {𝐹} _ = [⊤]-intro
    l {𝑇} f = [⊥]-elim (f [⊤]-intro)

    r : ∀{a} → IsTrue(! a) → (¬ IsTrue(a))
    r {𝑇} () _
    r {𝐹} _ ()

module IsFalse where
  [∧]-introₗ : ∀{a b} → IsFalse(a) → IsFalse(a && b)
  [∧]-introₗ {_}{𝑇} = id
  [∧]-introₗ {_}{𝐹} _ = [⊤]-intro

  [∧]-introᵣ : ∀{a b} → IsFalse(b) → IsFalse(a && b)
  [∧]-introᵣ {𝑇}{_} = id
  [∧]-introᵣ {𝐹}{_} _ = [⊤]-intro

  [∨]-intro : ∀{a b} → IsFalse(a) → IsFalse(b) → IsFalse(a || b)
  [∨]-intro {𝑇} fa fb = fa
  [∨]-intro {𝐹} fa fb = fb

  [¬]-intro : ∀{a} → IsTrue(a) → IsFalse(! a)
  [¬]-intro = id

  [¬]-elim : ∀{a} → IsFalse(! a) → IsTrue(a)
  [¬]-elim = id

  is-𝐹 : ∀{a} → IsFalse(a) ↔ (a ≡ 𝐹)
  is-𝐹 {a} = [↔]-intro (l{a}) (r{a}) where
    r : ∀{a} → IsFalse(a) → (a ≡ 𝐹)
    r {𝑇} ()
    r {𝐹} _ = [≡]-intro

    l : ∀{a} → IsFalse(a) ← (a ≡ 𝐹)
    l [≡]-intro = [⊤]-intro

true-false-opposites : ∀{a} → IsTrue(a) ↔ (¬ IsFalse(a))
true-false-opposites {𝑇} = [↔]-intro (const [⊤]-intro) (const id)
true-false-opposites {𝐹} = [↔]-intro (_$    [⊤]-intro) const

false-true-opposites : ∀{a} → IsFalse(a) ↔ (¬ IsTrue(a))
false-true-opposites {𝑇} = [↔]-intro (_$    [⊤]-intro) const
false-true-opposites {𝐹} = [↔]-intro (const [⊤]-intro) (const id)


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

module Categories.Adjoint.Instance.01-Truncation where

-- The adjunction between (0,1)-truncation and the inclusion functor
-- from Posets to Categories.

open import Data.Product using (_,_)
import Function
open import Relation.Binary using (Poset)
open import Relation.Binary.OrderMorphism using (_⇒-Poset_)

open import Categories.Adjoint using (_⊣_)
open import Categories.Category.Construction.Thin using (Thin)
open import Categories.Category using (Category)
open import Categories.Category.Instance.Cats using (Cats)
open import Categories.Category.Instance.Posets using (Posets)
open import Categories.Functor renaming (id to idF)
open import Categories.Functor.Instance.01-Truncation using (Trunc)
open import Categories.NaturalTransformation
  using (NaturalTransformation; ntHelper)
open import Categories.NaturalTransformation.NaturalIsomorphism using (refl)

open _⇒-Poset_

-- The inclusion functor from Posets to Categories

Inclusion : ∀ {c ℓ₁ ℓ₂} e → Functor (Posets c ℓ₁ ℓ₂) (Cats c ℓ₂ e)
Inclusion {c} {ℓ₁} e = record
  { F₀           = Thin e
  ; F₁           = λ f → record { F₀ = fun f ; F₁ = monotone f }
  ; identity     = refl
  ; homomorphism = refl
  ; F-resp-≈     = λ {A B f g} f≗g →
    let open Poset B
    in record
    { F⇒G = record { η = λ _ → reflexive f≗g          }
    ; F⇐G = record { η = λ _ → reflexive (Eq.sym f≗g) }
    }
  }

-- Trunc is left-adjoint to the inclusion functor from Setoids to Groupoids

TruncAdj : ∀ {o ℓ e} → Trunc ⊣ Inclusion {o} {ℓ} e
TruncAdj {o} {ℓ} {e} = record
  { unit   = unit
  ; counit = counit
  ; zig    = λ {C} → id C , id C
  ; zag    = refl
  }
  where
    open Category

    unit : NaturalTransformation idF (Inclusion e ∘F Trunc)
    unit = record
      { η           = λ _ → record { F₀ = Function.id ; F₁ = Function.id }
      ; commute     = λ _ → refl
      ; sym-commute = λ _ → refl
      }

    counit : NaturalTransformation (Trunc ∘F Inclusion e) idF
    counit = ntHelper record
      { η       = λ _ → record { fun = Function.id ; monotone = Function.id }
      ; commute = λ {_ D} _ → Poset.Eq.refl D
      }


{-# 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.One
open import Data.Fin
open import Function.NP
open import Data.Product
open import HoTT
open import Relation.Binary.PropositionalEquality.NP using (refl; _≡_; !_)
import Explore.Monad

module Explore.One where

module _ {ℓ} where
    open Explore.Monad {₀} ℓ

    𝟙ᵉ : Explore ℓ 𝟙
    𝟙ᵉ = return _
    {- or
    𝟙ᵉ _ f = f _
    -}

    𝟙ⁱ : ∀ {p} → ExploreInd p 𝟙ᵉ
    𝟙ⁱ = return-ind _
    {- or
    𝟙ⁱ _ _ Pf = Pf _
    -}

module _ {ℓ₁ ℓ₂ ℓᵣ} {R : 𝟙 → 𝟙 → ★₀} {r : R _ _} where
    ⟦𝟙ᵉ⟧ : ⟦Explore⟧ {ℓ₁} {ℓ₂} ℓᵣ R 𝟙ᵉ 𝟙ᵉ
    ⟦𝟙ᵉ⟧ _ _ _∙ᵣ_ fᵣ = fᵣ r

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

open Adequacy _≡_
module _ {{_ : UA}} where
    Σᵉ𝟙-ok : ∀ {ℓ} → Adequate-Σ {ℓ} (Σᵉ 𝟙ᵉ)
    Σᵉ𝟙-ok _ = ! Σ𝟙-snd

    Πᵉ𝟙-ok : ∀ {ℓ} → Adequate-Π {ℓ} (Πᵉ 𝟙ᵉ)
    Πᵉ𝟙-ok _ = ! Π𝟙-uniq _

    𝟙ˢ-ok : Adequate-sum 𝟙ˢ
    𝟙ˢ-ok _ = ! 𝟙×-snd

    𝟙ᵖ-ok : Adequate-product 𝟙ᵖ
    𝟙ᵖ-ok _ = ! Π𝟙-uniq _

    adequate-sum𝟙     = 𝟙ˢ-ok
    adequate-product𝟙 = 𝟙ᵖ-ok

module _ {ℓ} where
    𝟙ˡ : Lookup {ℓ} 𝟙ᵉ
    𝟙ˡ = const

    𝟙ᶠ : Focus {ℓ} 𝟙ᵉ
    𝟙ᶠ = proj₂

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


{-# OPTIONS --allow-unsolved-metas #-}

open import bool
open import bool-thms2
open import eq
open import maybe
open import product
open import product-thms
open import bool-relations using (transitive ; total)

module z05-01-hc-sorted-list
  (A : Set)                    -- type of elements
  (_≤A_ : A → A → 𝔹)           -- ordering function
  (≤A-trans : transitive _≤A_) -- proof of transitivity of given ordering
  (≤A-total : total      _≤A_) -- proof of totality     of given ordering
  where

open import bool-relations _≤A_ hiding (transitive ; total)
open import minmax _≤A_ ≤A-trans ≤A-total

data slist : A → A → Set where
  snil  : ∀ {l u : A}
        → l ≤A u ≡ tt
        → slist l u
  scons : ∀ {l u : A}
        → (d : A)      -- value stored at head
        → slist l u    -- elements to the right ≥ stored value
        → d ≤A l ≡ tt
        → slist (min d l) (max d u)

slist-insert : ∀ {l u : A}
             → (d : A)                   -- insert 'd'
             → slist l u                 -- into this 'bst'
             → d ≤A l ≡ tt
             → slist (min d l) (max d u) -- type might change
slist-insert d (snil l≤Au) d≤Al≡tt = scons d (snil l≤Au) d≤Al≡tt

slist-insert d   (scons d' xs d'≤Al≡tt) d≤Al≡tt  with keep (d ≤A d')

slist-insert d L@(scons d' xs d'≤Al≡tt) d≤Al≡tt | tt , p = scons d L d≤Al≡tt

slist-insert d L@(scons d' xs d'≤Al≡tt) d≤Al≡tt | ff , p = {!!}


module Definitions where

data _∨_ (A B : Set) : Set where
  inl : A → A ∨ B
  inr : B → A ∨ B

data _∧_ (A B : Set) : Set where
  _,_ : A → B → A ∧ B

data ⊥ : Set where

¬_ : Set → Set
¬ A = A → ⊥


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

module Algebra.Structures.Bundles.Field where

open import Algebra
open import Level using (suc; _⊔_)
open import Relation.Binary using (Rel)

open import Algebra.Structures.Field

record Field c ℓ : Set (suc (c ⊔ ℓ)) where
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _+_     : Carrier -> Carrier -> Carrier
    _*_     : Carrier -> Carrier -> Carrier
    0#      : Carrier
    1#      : Carrier
    -_      : Carrier -> Carrier
    _⁻¹      : MultiplicativeInverse _≈_ 0#
    isField : IsField _≈_ _+_ _*_ 0# 1# -_ _⁻¹

  open IsField isField public


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

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

open import Setoids.Setoids
open import Rings.Definition
open import Rings.Orders.Partial.Definition
open import Sets.EquivalenceRelations
open import Sequences
open import Setoids.Orders.Partial.Definition
open import Functions.Definition
open import LogicalFormulae
open import Numbers.Naturals.Semiring
open import Groups.Definition

module Rings.Orders.Partial.Bounded {m n o : _} {A : Set m} {S : Setoid {m} {n} A} {_+_ : A → A → A} {_*_ : A → A → A} {_<_ : Rel {m} {o} A} {pOrder : SetoidPartialOrder S _<_} {R : Ring S _+_ _*_} (pRing : PartiallyOrderedRing R pOrder) where

open Group (Ring.additiveGroup R)
open import Groups.Lemmas (Ring.additiveGroup R)
open Setoid S
open Equivalence eq
open SetoidPartialOrder pOrder

BoundedAbove : Sequence A → Set (m ⊔ o)
BoundedAbove x = Sg A (λ K → (n : ℕ) → index x n < K)

BoundedBelow : Sequence A → Set (m ⊔ o)
BoundedBelow x = Sg A (λ K → (n : ℕ) → K < index x n)

Bounded : Sequence A → Set (m ⊔ o)
Bounded x = Sg A (λ K → (n : ℕ) → ((Group.inverse (Ring.additiveGroup R) K) < index x n) && (index x n < K))

boundNonzero : {s : Sequence A} → (b : Bounded s) → underlying b ∼ 0G → False
boundNonzero {s} (a , b) isEq with b 0
... | bad1 ,, bad2 = irreflexive (<Transitive bad1 (<WellDefined reflexive (transitive isEq (symmetric (transitive (inverseWellDefined isEq) invIdent))) bad2))


module Oscar.Property.Transitivity where

open import Oscar.Level

record Transitivity {𝔬} {⋆ : Set 𝔬} {𝔮} (_↦_ : ⋆ → ⋆ → Set 𝔮) : Set (𝔬 ⊔ 𝔮) where
  field
    transitivity : ∀ {x y} → x ↦ y → ∀ {z} → y ↦ z → x ↦ z

open Transitivity ⦃ … ⦄ public


-- Andreas, 2016-07-29 issue #707, comment of 2012-10-31

open import Common.Nat

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

v0 v1 v2 : Vec Nat _
v0 = []
v1 = 0 ∷ v0
v2 = 1 ∷ v1

-- Works, but maybe questionable.
-- The _ is triplicated into three different internal metas.


open import MLib.Prelude
open import MLib.Algebra.PropertyCode
open import MLib.Algebra.PropertyCode.Structures

module MLib.Matrix.Plus {c ℓ} (struct : Struct bimonoidCode c ℓ) {m n : ℕ} where

open import MLib.Matrix.Core
open import MLib.Matrix.Equality struct

open FunctionProperties

-- Pointwise addition --

infixl 6 _⊕_

_⊕_ : Matrix S m n → Matrix S m n → Matrix S m n
(A ⊕ B) i j = A i j ⟨ + ⟩ B i j

⊕-cong : Congruent₂ _⊕_
⊕-cong p q = λ i j → S.cong + (p i j) (q i j)

⊕-assoc : ⦃ props : Has₁ (associative on +) ⦄ → Associative _⊕_
⊕-assoc ⦃ props ⦄ A B C i j = from props (associative on +) (A i j) (B i j) (C i j)

0● : Matrix S m n
0● _ _ = ⟦ 0# ⟧

⊕-identityˡ : ⦃ props : Has₁ (0# is leftIdentity for +) ⦄ → LeftIdentity 0● _⊕_
⊕-identityˡ ⦃ props ⦄ A i j = from props (0# is leftIdentity for +) (A i j)

⊕-identityʳ : ⦃ props : Has₁ (0# is rightIdentity for +) ⦄ → RightIdentity 0● _⊕_
⊕-identityʳ ⦃ props ⦄ A i j = from props (0# is rightIdentity for +) (A i j)

⊕-comm : ⦃ props : Has₁ (commutative on +) ⦄ → Commutative _⊕_
⊕-comm ⦃ props ⦄ A B i j = from props (commutative on +) (A i j) (B i j)


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

open import Categories.Category

-- Some basic facts about Spans in some category 𝒞.
--
-- For the Category instances for these, you can look at the following modules
--    Categories.Category.Construction.Spans
--    Categories.Bicategory.Construction.Spans
module Categories.Category.Diagram.Span {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level
open import Function using (_$_)

open import Categories.Diagram.Pullback 𝒞
open import Categories.Morphism.Reasoning 𝒞

open Category 𝒞
open HomReasoning
open Equiv

open Pullback

private
  variable
    A B C D E : Obj

--------------------------------------------------------------------------------
-- Spans, and Span morphisms

infixr 9 _∘ₛ_

record Span (X Y : Obj) : Set (o ⊔ ℓ) where
  field
    M : Obj
    dom : M ⇒ X
    cod : M ⇒ Y

open Span

id-span : Span A A
id-span {A} = record
  { M = A
  ; dom = id
  ; cod = id
  }

record Span⇒ {X Y} (f g : Span X Y) : Set (o ⊔ ℓ ⊔ e) where
  field
    arr : M f ⇒ M g
    commute-dom : dom g ∘ arr ≈ dom f
    commute-cod : cod g ∘ arr ≈ cod f

open Span⇒

id-span⇒ : ∀ {f : Span A B} → Span⇒ f f
id-span⇒ = record
  { arr = id
  ; commute-dom = identityʳ
  ; commute-cod = identityʳ
  }

_∘ₛ_ : ∀ {f g h : Span A B} → (α : Span⇒ g h) → (β : Span⇒ f g) → Span⇒ f h
_∘ₛ_ {f = f} {g = g} {h = h} α β = record
  { arr = arr α ∘ arr β
  ; commute-dom = begin
    dom h ∘ arr α ∘ arr β ≈⟨ pullˡ (commute-dom α) ⟩
    dom g ∘ arr β ≈⟨ commute-dom β ⟩
    dom f ∎
  ; commute-cod = begin
    cod h ∘ arr α ∘ arr β ≈⟨ pullˡ (commute-cod α) ⟩
    cod g ∘ arr β ≈⟨ commute-cod β ⟩
    cod f ∎
  }

--------------------------------------------------------------------------------
-- Span Compositions

module Compositions (_×ₚ_ : ∀ {X Y Z} (f : X ⇒ Z) → (g : Y ⇒ Z) → Pullback f g) where

  _⊚₀_ : Span B C → Span A B → Span A C
  f ⊚₀ g =
    let g×ₚf = (cod g) ×ₚ (dom f)
    in record
        { M = P g×ₚf
        ; dom = dom g ∘ p₁ g×ₚf
        ; cod = cod f ∘ p₂ g×ₚf
        }

  _⊚₁_ : {f f′ : Span B C} {g g′ : Span A B} → Span⇒ f f′ → Span⇒ g g′ → Span⇒ (f ⊚₀ g) (f′ ⊚₀ g′)
  _⊚₁_  {f = f} {f′ = f′} {g = g} {g′ = g′} α β =
    let pullback = (cod g) ×ₚ (dom f)
        pullback′ = (cod g′) ×ₚ (dom f′)
    in record
      { arr = universal pullback′ {h₁ = arr β ∘ p₁ pullback} {h₂ = arr α ∘ p₂ pullback} $ begin
          cod g′ ∘ arr β ∘ p₁ pullback ≈⟨ pullˡ (commute-cod β) ⟩
          cod g ∘ p₁ pullback          ≈⟨ commute pullback ⟩
          dom f ∘ p₂ pullback          ≈⟨ pushˡ (⟺ (commute-dom α)) ⟩
          dom f′ ∘ arr α ∘ p₂ pullback ∎
      ; commute-dom = begin
          (dom g′ ∘ p₁ pullback′) ∘ universal pullback′ _ ≈⟨ pullʳ (p₁∘universal≈h₁ pullback′) ⟩
          dom g′ ∘ arr β ∘ p₁ pullback                    ≈⟨ pullˡ (commute-dom β) ⟩
          dom g ∘ p₁ pullback                             ∎
      ; commute-cod = begin
          (cod f′ ∘ p₂ pullback′) ∘ universal pullback′ _ ≈⟨ pullʳ (p₂∘universal≈h₂ pullback′) ⟩
          cod f′ ∘ arr α ∘ p₂ pullback                    ≈⟨ pullˡ (commute-cod α) ⟩
          cod f ∘ p₂ pullback                             ∎
      }


module Relations where

open import Level as Level using (zero)
open import Size
open import Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P
open ≡-Reasoning

RelTrans : Set → Set₁
RelTrans B = Rel B Level.zero → Rel B Level.zero

Monotone : ∀{B} → RelTrans B → Set₁
Monotone F = ∀ {R S} → R ⇒ S → F R ⇒ F S

-- | Useful example of a compatible up-to technique: equivalence closure.
data EquivCls {B : Set} (R : Rel B Level.zero) : Rel B Level.zero where
  cls-incl : {a b : B} → R a b → EquivCls R a b
  cls-refl : {b : B} → EquivCls R b b
  cls-sym  : {a b : B} → EquivCls R a b → EquivCls R b a
  cls-trans : {a b c : B} → EquivCls R a b → EquivCls R b c → EquivCls R a c

-- | The operation of taking the equivalence closure is monotone.
equivCls-monotone : ∀{B} → Monotone {B} EquivCls
equivCls-monotone R≤S (cls-incl xRy)  = cls-incl (R≤S xRy)
equivCls-monotone R≤S cls-refl        = cls-refl
equivCls-monotone R≤S (cls-sym p)     = cls-sym (equivCls-monotone R≤S p)
equivCls-monotone R≤S (cls-trans p q) =
  cls-trans (equivCls-monotone R≤S p) (equivCls-monotone R≤S q)

-- | The equivalence closure is indeed a closure operator.
equivCls-expanding : ∀{B R} → R ⇒ EquivCls {B} R
equivCls-expanding p = cls-incl p

equivCls-idempotent : ∀{B R} → EquivCls (EquivCls R) ⇒ EquivCls {B} R
equivCls-idempotent (cls-incl p)    = p
equivCls-idempotent cls-refl        = cls-refl
equivCls-idempotent (cls-sym p)     = cls-sym (equivCls-idempotent p)
equivCls-idempotent (cls-trans p q) =
  cls-trans (equivCls-idempotent p) (equivCls-idempotent q)

-- | Equivalence closure gives indeed equivalence relation
equivCls-equiv : ∀{A} → (R : Rel A _) → IsEquivalence (EquivCls R)
equivCls-equiv R = record
  { refl  = cls-refl
  ; sym   = cls-sym
  ; trans = cls-trans
  }


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

module Categories.Morphism.Cartesian where

open import Level

open import Categories.Category
open import Categories.Functor

private
  variable
    o ℓ e : Level
    C D : Category o ℓ e

record Cartesian (F : Functor C D) {X Y} (f : C [ X , Y ]) : Set (levelOfTerm F) where
  private
    module C = Category C
    module D = Category D
    open Functor F
    open D

  field
    universal : ∀ {A} {u : F₀ A ⇒ F₀ X} (h : C [ A , Y ]) →
                  F₁ f ∘ u ≈ F₁ h →  C [ A , X ]
    commute   : ∀ {A} {u : F₀ A ⇒ F₀ X} {h : C [ A , Y ]}
                  (eq : F₁ f ∘ u ≈ F₁ h) →
                  C [ C [ f ∘ universal h eq ] ≈ h ]
    compat    : ∀ {A} {u : F₀ A ⇒ F₀ X} {h : C [ A , Y ]}
                  (eq : F₁ f ∘ u ≈ F₁ h) →
                  F₁ (universal h eq) ≈ u


{-# OPTIONS --verbose=10 #-}

module inorderF where

  open import Data.Nat
  open import Data.Vec
  open import Agda.Builtin.Sigma
  open import Data.Product
  open import Data.Fin using (fromℕ)

  open import trees
  open import optics
  open import lemmas

  inorderTreeF : {A : Set} -> (t : Tree A) -> Vec A (#nodes t) × (Vec A (#nodes t) -> Tree A)
  inorderTreeF empty = ([] , λ _ -> empty)
  inorderTreeF {A} (node t₁ x t₂) with inorderTreeF t₁ | inorderTreeF t₂
  ...                                | (g₁ , p₁)       | (g₂ , p₂) =
    (g₁ ++ (x ∷ g₂) , λ v -> node (p₁ (take n₁ v)) (head (drop n₁ v)) (righttree v))
    where
      n  = #nodes (node t₁ x t₂)
      n₁ = #nodes t₁
      n₂ = #nodes t₂
      righttree :  Vec A n -> Tree A
      righttree v rewrite +-suc n₁ n₂ = p₂ (drop (1 + n₁) v)

  inorderF : {A : Set} -> TraversalF (Tree A) (Tree A) A A
  inorderF = record{ extract = (#nodes , inorderTreeF) }

  module tests where
    tree1 : Tree ℕ
    tree1 = node (node empty 1 empty) 3 empty

    open Traversal


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

-- Formalization of internal relations
-- (=congruences: https://ncatlab.org/nlab/show/congruence)

open import Categories.Category
module Categories.Object.InternalRelation {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level hiding (zero)
open import Data.Unit
open import Data.Fin using (Fin; zero) renaming (suc to nzero)

import Categories.Morphism as Mor
import Categories.Morphism.Reasoning as MR
open import Categories.Morphism.Notation

open import Categories.Diagram.Pullback
open import Categories.Diagram.KernelPair
open import Categories.Category.Cartesian

open import Categories.Category.BinaryProducts 𝒞 using (BinaryProducts; module BinaryProducts)

private
  module 𝒞 = Category 𝒞

open Category 𝒞
open Mor 𝒞

-- A relation is a span, "which is (-1)-truncated as a morphism into the cartesian product."
-- (https://ncatlab.org/nlab/show/span#correspondences)
isRelation : {X Y R : 𝒞.Obj} (f : R ⇒ X) (g : R ⇒ Y) → Set (o ⊔ ℓ ⊔ e)
isRelation{X}{Y}{R} f g = JointMono
     (Fin 2)
     (λ{zero → X; (nzero _) → Y})
     (λ{zero → f; (nzero _) → g})

record Relation (X Y : 𝒞.Obj) : Set (suc (o ⊔ ℓ ⊔ e)) where
  open Mor 𝒞

  field
    dom : 𝒞.Obj
    p₁ : dom ⇒ X
    p₂ : dom ⇒ Y

  field
    relation : isRelation p₁ p₂

record isEqSpan {X R : 𝒞.Obj} (f : R ⇒ X) (g : R ⇒ X) : Set (suc (o ⊔ ℓ ⊔ e)) where
  field
     R×R : Pullback 𝒞 f g

  module R×R = Pullback R×R renaming (P to dom)

  field
     refl  : X ⇒ R
     sym   : R ⇒ R
     trans : R×R.dom ⇒ R

     is-refl₁ : f ∘ refl ≈ id
     is-refl₂ : g ∘ refl ≈ id

     is-sym₁ : f ∘ sym ≈ g
     is-sym₂ : g ∘ sym ≈ f

     is-trans₁ : f ∘ trans ≈ f ∘ R×R.p₁
     is-trans₂ : g ∘ trans ≈ g ∘ R×R.p₂

-- Internal equivalence
record Equivalence (X : 𝒞.Obj) : Set (suc (o ⊔ ℓ ⊔ e)) where
  open Mor 𝒞
  open BinaryProducts

  field
     R : Relation X X

  open Relation R
  module R = Relation R

  field
    eqspan : isEqSpan R.p₁ R.p₂

module _ where
  open Pullback hiding (P)

  KP⇒EqSpan : {X Y : 𝒞.Obj} (f : X ⇒ Y) → (kp : KernelPair 𝒞 f) → (p : Pullback 𝒞 (p₁ kp) (p₂ kp)) → isEqSpan (p₁ kp) (p₂ kp)
  KP⇒EqSpan f kp p = record
    { R×R = p
    ; refl = universal kp {_} {id}{id} 𝒞.Equiv.refl
    ; sym  = universal kp {_} {p₂ kp}{p₁ kp} (𝒞.Equiv.sym (commute kp))
    ; trans = universal kp {_}{p₁ kp ∘ p₁ p}{p₂ kp ∘ p₂ p} (∘-resp-≈ʳ (commute p))
    ; is-refl₁  = p₁∘universal≈h₁ kp
    ; is-refl₂  = p₂∘universal≈h₂ kp
    ; is-sym₁   = p₁∘universal≈h₁ kp
    ; is-sym₂   = p₂∘universal≈h₂ kp
    ; is-trans₁ = p₁∘universal≈h₁ kp
    ; is-trans₂ = p₂∘universal≈h₂ kp
    }

  KP⇒Relation : {X Y : 𝒞.Obj} (f : X ⇒ Y) → (kp : KernelPair 𝒞 f) → (p : Pullback 𝒞 (p₁ kp) (p₂ kp)) → isRelation (p₁ kp) (p₂ kp)
  KP⇒Relation f kp _ _ _ eq = unique-diagram kp (eq zero) (eq (nzero zero))


-- Andreas, 2011-04-07

module IrrelevantFamilyIndex where

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

-- irrelevant index
data Fin : .Nat -> Set where
  zero : .(n : Nat) -> Fin (suc n)
  suc  : .(n : Nat) -> Fin n -> Fin (suc n)

t : Fin zero
t = zero zero

-- the following is ok, since Fin _ is really just Nat
toNat : Fin zero -> Nat
toNat (zero _)  = zero
toNat (suc _ i) = suc (toNat i)

data Pos : Nat -> Set where
  pos : (n : Nat) -> Pos (suc n)

f : (n : Nat) -> Fin n -> Pos n
f .(suc n) (zero n)  = pos n
f .(suc n) (suc n i) = pos n
-- cannot infer value of dot pattern

{-
f : (n : Nat) -> Fin n -> Pos n
f .(suc _) (zero _)  = pos _
f .(suc _) (suc _ _) = pos _

f' : (n : Nat) -> Fin n -> Pos n
f' _ (zero _)  = pos _
f' _ (suc _ _) = pos _
-}


-- This module introduces parameterised datatypes.

module DataParameterised where

-- First some of our old friends.

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

data Bool : Set where
  false : Bool
  true  : Bool

-- A datatype can be parameterised over a telescope, (A : Set) in the case of
-- lists. The parameters are bound in the types of the constructors.

data List (A : Set) : Set where
  nil  : List A
  cons : A -> List A -> List A

-- When using the constructors the parameters to the datatype becomes implicit
-- arguments. In this case, the types of the constructors are :

--  nil  : {A : Set} -> List A
--  cons : {A : Set} -> A -> List A -> List A

-- So, we can write

--nilNat = nil {Nat}  -- the type of this will be List Nat

-- When pattern matching on elements of a parameterised datatype you cannot
-- refer to the parameters--it wouldn't make sense to pattern match on the
-- element type of the list. So you can say

null : {A : Set} -> List A -> Bool
null  nil       = true
null (cons _ _) = false

-- but not

-- null (nil  {A})     = true
-- null (cons {A} _ _) = false


----------------------------------------------------------------------
-- This file contains constructions of new categories from existing --
-- categories.                                                      --
----------------------------------------------------------------------
module Category.CategoryCons where

open import Level
open import Data.Product

open import Setoid.Total
open import Category.Category

open SetoidFun

-- The product of two categories.
_●_ : {l₁ l₂ : Level} → (ℂ₁ : Cat {l₁}) → (ℂ₂ : Cat {l₂}) → Cat {l₁ ⊔ l₂}
ℂ₁ ● ℂ₂ = record {
            Obj = (Obj ℂ₁) × (Obj ℂ₂);
            Hom = λ A B → (Hom ℂ₁ (proj₁ A) (proj₁ B)) ●ₛ ((Hom ℂ₂ (proj₂ A) (proj₂ B)));
            comp = λ {A} {B} {C} → (comp ℂ₁) ●b (comp ℂ₂);
            id = λ {A} → (id ℂ₁) , (id ℂ₂);
            assocPf = λ {A} {B} {C} {D} {f} {g} {h} → (assocPf ℂ₁) , (assocPf ℂ₂);
            idPf = λ {A} {B} {f} → (idPf ℂ₁) , (idPf ℂ₂) }


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

module SubstLemmas where

open import Level using (Level)
open import Relation.Binary.PropositionalEquality
  using (_≡_; refl; sym; trans; subst; cong₂)
open import Data.Nat using (ℕ; _+_; _*_)

------------------------------------------------------------------------------
-- Lemmas about subst (and a couple about trans)

subst-dist :
  {a b : Level} {A : Set a} {B : A → Set b}
  (f : {x : A} → B x → B x → B x) →
  {x₁ x₂ : A} → (x₂≡x₁ : x₂ ≡ x₁) → (v₁ v₂ : B x₂) →
  subst B x₂≡x₁ (f v₁ v₂) ≡ f (subst B x₂≡x₁ v₁) (subst B x₂≡x₁ v₂)
subst-dist f refl v₁ v₂ = refl

subst-trans :
  {a b : Level} {A : Set a} {B : A → Set b} {x₁ x₂ x₃ : A} →
  (x₂≡x₁ : x₂ ≡ x₁) → (x₃≡x₂ : x₃ ≡ x₂) → (v : B x₃) →
  subst B x₂≡x₁ (subst B x₃≡x₂ v) ≡ subst B (trans x₃≡x₂ x₂≡x₁) v
subst-trans refl refl v = refl

subst₂+ : {b : Level} {B : ℕ → Set b} {x₁ x₂ x₃ x₄ : ℕ} →
  (x₂≡x₁ : x₂ ≡ x₁) → (x₄≡x₃ : x₄ ≡ x₃) → (v₁ : B x₂) → (v₂ : B x₄) →
  (f : {x₁ x₂ : ℕ} → B x₁ → B x₂ → B (x₁ + x₂)) →
  subst B (cong₂ _+_ x₂≡x₁ x₄≡x₃) (f v₁ v₂) ≡
  f (subst B x₂≡x₁ v₁) (subst B x₄≡x₃ v₂)
subst₂+ refl refl v₁ v₂ f = refl

subst₂* : {b : Level} {B : ℕ → Set b} {x₁ x₂ x₃ x₄ : ℕ} →
  (x₂≡x₁ : x₂ ≡ x₁) → (x₄≡x₃ : x₄ ≡ x₃) → (v₁ : B x₂) → (v₂ : B x₄) →
  (f : {x₁ x₂ : ℕ} → B x₁ → B x₂ → B (x₁ * x₂)) →
  subst B (cong₂ _*_ x₂≡x₁ x₄≡x₃) (f v₁ v₂) ≡
  f (subst B x₂≡x₁ v₁) (subst B x₄≡x₃ v₂)
subst₂* refl refl v₁ v₂ f = refl

trans-syml : {A : Set} {x y : A} → (p : x ≡ y) → trans (sym p) p ≡ refl
trans-syml refl = refl

trans-symr : {A : Set} {x y : A} → (p : x ≡ y) → trans p (sym p) ≡ refl
trans-symr refl = refl

subst-subst :
  {a b : Level} {A : Set a} {B : A → Set b}
  {x y : A} → (eq : x ≡ y) → (eq' : y ≡ x) → (irr : sym eq ≡ eq') → (v : B y) →
  subst B eq (subst B eq' v) ≡ v
subst-subst refl .refl refl v = refl


{-# OPTIONS --universe-polymorphism #-}
module Categories.Monoidal.Traced where

open import Level

open import Data.Product
open import Data.Fin

open import Categories.Category
open import Categories.Monoidal
open import Categories.Functor hiding (id; _∘_; identityʳ; assoc)
open import Categories.Monoidal.Braided
open import Categories.Monoidal.Helpers
open import Categories.Monoidal.Braided.Helpers
open import Categories.Monoidal.Symmetric
open import Categories.NaturalIsomorphism
open import Categories.NaturalTransformation hiding (id)

------------------------------------------------------------------------------
-- Helpers

unary : ∀ {o ℓ e} → (C : Category o ℓ e) → (A : Category.Obj C) →
          Fin 1 → Category.Obj C
unary C A zero = A
unary C A (suc ())

binary : ∀ {o ℓ e} → (C : Category o ℓ e) → (A B : Category.Obj C) →
          Fin 2 → Category.Obj C
binary C A B zero = A
binary C A B (suc zero) = B
binary C A B (suc (suc ()))

ternary : ∀ {o ℓ e} → (C : Category o ℓ e) → (A X Y : Category.Obj C) →
          Fin 3 → Category.Obj C
ternary C A X Y zero = A
ternary C A X Y (suc zero) = X
ternary C A X Y (suc (suc zero)) = Y
ternary C A X Y (suc (suc (suc ())))

------------------------------------------------------------------------------
-- Def from http://ncatlab.org/nlab/show/traced+monoidal+category
--
-- A symmetric monoidal category (C,⊗,1,b) (where b is the symmetry) is
-- said to be traced if it is equipped with a natural family of functions
--
-- TrXA,B:C(A⊗X,B⊗X)→C(A,B)
-- satisfying three axioms:
--
-- Vanishing: Tr1A,B(f)=f (for all f:A→B) and
-- TrX⊗YA,B=TrXA,B(TrYA⊗X,B⊗X(f)) (for all f:A⊗X⊗Y→B⊗X⊗Y)
--
-- Superposing: TrXC⊗A,C⊗B(idC⊗f)=idC⊗TrXA,B(f) (for all f:A⊗X→B⊗X)
--
-- Yanking: TrXX,X(bX,X)=idX

record Traced {o ℓ e} {C : Category o ℓ e} {M : Monoidal C} {B : Braided M}
  (S : Symmetric B) : Set (o ⊔ ℓ ⊔ e) where

  private module C = Category C
  open C using (Obj; id; _∘_)

  private module M = Monoidal M
  open M using (⊗; identityʳ; assoc) renaming (id to 𝟙)

  private module F = Functor ⊗
  open F using () renaming (F₀ to ⊗ₒ; F₁ to ⊗ₘ)

  private module NIʳ = NaturalIsomorphism identityʳ
  open NaturalTransformation NIʳ.F⇒G renaming (η to ηidr⇒)
  open NaturalTransformation NIʳ.F⇐G renaming (η to ηidr⇐)

  private module NIassoc = NaturalIsomorphism assoc
  open NaturalTransformation NIassoc.F⇒G renaming (η to ηassoc⇒)
  open NaturalTransformation NIassoc.F⇐G renaming (η to ηassoc⇐)

  private module B = Braided B
  open B using (braid)

  private module NIbraid = NaturalIsomorphism braid
  open NaturalTransformation NIbraid.F⇒G renaming (η to ηbraid⇒)

  field
    trace : ∀ {X A B} → C [ ⊗ₒ (A , X)  , ⊗ₒ (B , X) ] → C [ A , B ]

    vanish_id : ∀ {A B f} →
                C [
                    trace {𝟙} {A} {B} f
                  ≡
                    (ηidr⇒ (unary C B) ∘ f ∘ ηidr⇐ (unary C A))
                  ]

    vanish_⊗ : ∀ {X Y A B f} →
               C [
                    trace {⊗ₒ (X , Y)} {A} {B} f
                  ≡
                    trace {X} {A} {B}
                      (trace {Y} {⊗ₒ (A , X)} {⊗ₒ (B , X)}
                        ((ηassoc⇐ (ternary C B X Y)) ∘ f ∘ (ηassoc⇒ (ternary C A X Y))))
                 ]

    superpose : ∀ {X Y A B} {f : C [ ⊗ₒ (A , X) , ⊗ₒ (B , X) ]} →
                C [
                    trace {X} {⊗ₒ (Y , A)} {⊗ₒ (Y , B)}
                      (ηassoc⇐ (ternary C Y B X) ∘ ⊗ₘ (id , f) ∘ ηassoc⇒ (ternary C Y A X))
                   ≡
                    ⊗ₘ (id , (trace {X} {A} {B} f))
                  ]

    yank : ∀ {X} →
           C [
               trace {X} {X} {X} (ηbraid⇒ (binary C X X))
              ≡
               id
             ]

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


{-# OPTIONS --rewriting #-}

module RewritingNat where

open import Common.Equality

{-# BUILTIN REWRITE _≡_ #-}

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

_+_ : Nat → Nat → Nat
zero + n = n
(suc m) + n = suc (m + n)

plus0T : Set
plus0T = ∀{x} → (x + zero) ≡ x

plusSucT : Set
plusSucT = ∀{x y} → (x + (suc y)) ≡ suc (x + y)

postulate
  plus0p : plus0T
  {-# REWRITE plus0p #-}

  plusSucp : plusSucT

{-# REWRITE plusSucp #-}

plus0 : plus0T
plus0 = refl

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

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


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

open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import LogicalFormulae
open import Sets.EquivalenceRelations
open import Setoids.Setoids

module Setoids.Subset {a b : _} {A : Set a} (S : Setoid {a} {b} A) where

open Setoid S
open Equivalence eq

subset : {c : _} (pred : A → Set c) → Set (a ⊔ b ⊔ c)
subset pred = ({x y : A} → x ∼ y → pred x → pred y)

subsetSetoid : {c : _} {pred : A → Set c} → (subs : subset pred) → Setoid (Sg A pred)
Setoid._∼_ (subsetSetoid subs) (x , predX) (y , predY) = Setoid._∼_ S x y
Equivalence.reflexive (Setoid.eq (subsetSetoid subs)) {a , b} = reflexive
Equivalence.symmetric (Setoid.eq (subsetSetoid subs)) {a , prA} {b , prB} x = symmetric x
Equivalence.transitive (Setoid.eq (subsetSetoid subs)) {a , prA} {b , prB} {c , prC} x y = transitive x y


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

open import Categories.Category using (Category; _[_≈_])

-- Karoubi Envelopes. These are the free completions of categories under split idempotents
module Categories.Category.Construction.KaroubiEnvelope {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level

open import Categories.Morphism.Idempotent.Bundles 𝒞
open import Categories.Morphism.Reasoning 𝒞

private
  module 𝒞 = Category 𝒞
  open 𝒞.HomReasoning
  open 𝒞.Equiv

  open Idempotent
  open Idempotent⇒

KaroubiEnvelope : Category (o ⊔ ℓ ⊔ e) (ℓ ⊔ e) e
KaroubiEnvelope = record
  { Obj = Idempotent
  ; _⇒_ = Idempotent⇒
  ; _≈_ = λ f g → 𝒞 [ Idempotent⇒.hom f ≈ Idempotent⇒.hom g ]
  ; id = id
  ; _∘_ = _∘_
  ; assoc = 𝒞.assoc
  ; sym-assoc = 𝒞.sym-assoc
  ; identityˡ = λ {I} {J} {f} → absorbˡ f
  ; identityʳ = λ {I} {J} {f} → absorbʳ f
  ; identity² = λ {I} → idempotent I
  ; equiv = record
    { refl = refl
    ; sym = sym
    ; trans = trans
    }
  ; ∘-resp-≈ = 𝒞.∘-resp-≈
  }


module BBSTree  {A : Set}(_≤_ : A → A → Set) where

open import Bound.Total A
open import Bound.Total.Order _≤_
open import Data.List
open import List.Order.Simple _≤_

data BBSTree : Bound → Bound → Set where
  bslf : {b t : Bound}
                   → LeB b t
                   → BBSTree b t
  bsnd : {x : A}{b t : Bound}
                   → LeB b (val x)
                   → LeB (val x) t
                   → BBSTree b (val x)
                   → BBSTree (val x) t
                   → BBSTree b t

flatten : {b t : Bound} → BBSTree b t → List A
flatten (bslf _) = []
flatten (bsnd {x = x} b≤x x≤t l r) = flatten l ++ (x ∷ flatten r)


open import Agda.Builtin.Nat

record _×_ (A B : Set) : Set where
  constructor _,_
  field fst : A
        snd : B

open _×_

Δ : ∀ {A} → A → A × A
Δ x = x , x

foo : Nat → Nat
foo n = let x , y = Δ n in x + y

bar : Nat → Nat
bar n = let _!_ : Nat → Nat → Nat
            x ! y = 2 * x + y
        in n ! n


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Structures.Group.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Data.Sigma
open import Cubical.Structures.Monoid hiding (⟨_⟩)

private
  variable
    ℓ : Level

record IsGroup {G : Type ℓ}
               (0g : G) (_+_ : G → G → G) (-_ : G → G) : Type ℓ where

  constructor isgroup

  field
    isMonoid  : IsMonoid 0g _+_
    inverse   : (x : G) → (x + (- x) ≡ 0g) × ((- x) + x ≡ 0g)

  open IsMonoid isMonoid public

  infixl 6 _-_

  _-_ : G → G → G
  x - y = x + (- y)

  invl : (x : G) → (- x) + x ≡ 0g
  invl x = inverse x .snd

  invr : (x : G) → x + (- x) ≡ 0g
  invr x = inverse x .fst

record Group : Type (ℓ-suc ℓ) where

  constructor group

  field
    Carrier : Type ℓ
    0g      : Carrier
    _+_     : Carrier → Carrier → Carrier
    -_      : Carrier → Carrier
    isGroup : IsGroup 0g _+_ -_

  infix  8 -_
  infixr 7 _+_

  open IsGroup isGroup public

-- Extractor for the carrier type
⟨_⟩ : Group → Type ℓ
⟨_⟩ = Group.Carrier

makeIsGroup : {G : Type ℓ} {0g : G} {_+_ : G → G → G} { -_ : G → G}
              (is-setG : isSet G)
              (assoc : (x y z : G) → x + (y + z) ≡ (x + y) + z)
              (rid : (x : G) → x + 0g ≡ x)
              (lid : (x : G) → 0g + x ≡ x)
              (rinv : (x : G) → x + (- x) ≡ 0g)
              (linv : (x : G) → (- x) + x ≡ 0g)
            → IsGroup 0g _+_ -_
makeIsGroup is-setG assoc rid lid rinv linv =
   isgroup (makeIsMonoid is-setG assoc rid lid) λ x → rinv x , linv x

makeGroup : {G : Type ℓ} (0g : G) (_+_ : G → G → G) (-_ : G → G)
            (is-setG : isSet G)
            (assoc : (x y z : G) → x + (y + z) ≡ (x + y) + z)
            (rid : (x : G) → x + 0g ≡ x)
            (lid : (x : G) → 0g + x ≡ x)
            (rinv : (x : G) → x + (- x) ≡ 0g)
            (linv : (x : G) → (- x) + x ≡ 0g)
          → Group
makeGroup 0g _+_ -_ is-setG assoc rid lid rinv linv =
  group _ 0g _+_ -_ (makeIsGroup is-setG assoc rid lid rinv linv)

makeGroup-right : ∀ {ℓ} {A : Type ℓ}
  → (id : A)
  → (comp : A → A → A)
  → (inv : A → A)
  → (set : isSet A)
  → (assoc : ∀ a b c → comp a (comp b c) ≡ comp (comp a b) c)
  → (rUnit : ∀ a → comp a id ≡ a)
  → (rCancel : ∀ a → comp a (inv a) ≡ id)
  → Group
makeGroup-right {A = A} id comp inv set assoc rUnit rCancel =
  makeGroup id comp inv set assoc rUnit lUnit rCancel lCancel
  where
    _⨀_ = comp
    abstract
      lCancel : ∀ a → comp (inv a) a ≡ id
      lCancel a =
        inv a ⨀ a
          ≡⟨ sym (rUnit (comp (inv a) a))  ⟩
        (inv a ⨀ a) ⨀ id
          ≡⟨ cong (comp (comp (inv a) a)) (sym (rCancel (inv a))) ⟩
        (inv a ⨀ a) ⨀ (inv a ⨀ (inv (inv a)))
          ≡⟨ assoc _ _ _ ⟩
        ((inv a ⨀ a) ⨀ (inv a)) ⨀ (inv (inv a))
          ≡⟨ cong (λ □ → □ ⨀ _) (sym (assoc _ _ _)) ⟩
        (inv a ⨀ (a ⨀ inv a)) ⨀ (inv (inv a))
          ≡⟨ cong (λ □ → (inv a ⨀ □) ⨀ (inv (inv a))) (rCancel a) ⟩
        (inv a ⨀ id) ⨀ (inv (inv a))
          ≡⟨ cong (λ □ → □ ⨀ (inv (inv a))) (rUnit (inv a)) ⟩
        inv a ⨀ (inv (inv a))
          ≡⟨ rCancel (inv a) ⟩
        id
          ∎

      lUnit : ∀ a → comp id a ≡ a
      lUnit a =
        id ⨀ a
          ≡⟨ cong (λ b → comp b a) (sym (rCancel a)) ⟩
        (a ⨀ inv a) ⨀ a
          ≡⟨ sym (assoc _ _ _) ⟩
        a ⨀ (inv a ⨀ a)
          ≡⟨ cong (comp a) (lCancel a) ⟩
        a ⨀ id
          ≡⟨ rUnit a ⟩
        a
          ∎

makeGroup-left : ∀ {ℓ} {A : Type ℓ}
  → (id : A)
  → (comp : A → A → A)
  → (inv : A → A)
  → (set : isSet A)
  → (assoc : ∀ a b c → comp a (comp b c) ≡ comp (comp a b) c)
  → (lUnit : ∀ a → comp id a ≡ a)
  → (lCancel : ∀ a → comp (inv a) a ≡ id)
  → Group
makeGroup-left {A = A} id comp inv set assoc lUnit lCancel =
  makeGroup id comp inv set assoc rUnit lUnit rCancel lCancel
  where
    abstract
      rCancel : ∀ a → comp a (inv a) ≡ id
      rCancel a =
        comp a (inv a)
          ≡⟨ sym (lUnit (comp a (inv a)))  ⟩
        comp id (comp a (inv a))
          ≡⟨ cong (λ b → comp b (comp a (inv a))) (sym (lCancel (inv a))) ⟩
        comp (comp (inv (inv a)) (inv a)) (comp a (inv a))
          ≡⟨ sym (assoc (inv (inv a)) (inv a) (comp a (inv a))) ⟩
        comp (inv (inv a)) (comp (inv a) (comp a (inv a)))
          ≡⟨ cong (comp (inv (inv a))) (assoc (inv a) a (inv a)) ⟩
        comp (inv (inv a)) (comp (comp (inv a) a) (inv a))
          ≡⟨ cong (λ b → comp (inv (inv a)) (comp b (inv a))) (lCancel a) ⟩
        comp (inv (inv a)) (comp id (inv a))
          ≡⟨ cong (comp (inv (inv a))) (lUnit (inv a)) ⟩
        comp (inv (inv a)) (inv a)
          ≡⟨ lCancel (inv a) ⟩
        id
          ∎

      rUnit : ∀ a → comp a id ≡ a
      rUnit a =
        comp a id
          ≡⟨ cong (comp a) (sym (lCancel a)) ⟩
        comp a (comp (inv a) a)
          ≡⟨ assoc a (inv a) a ⟩
        comp (comp a (inv a)) a
          ≡⟨ cong (λ b → comp b a) (rCancel a) ⟩
        comp id a
          ≡⟨ lUnit a ⟩
        a
          ∎


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

----------------------------------------------------------------------
-- Gaps
----------------------------------------------------------------------
-- Polynomials can be represented as lists of their coefficients,
-- stored in increasing powers of x:
--
--   3 + 2x² + 4x⁵ + 2x⁷
-- ≡⟨ making the missing xs explicit ⟩
--   3x⁰ + 0x¹ + 2x² + 0x³ + 0x⁴ + 4x⁵ + 0x⁶ + 2x⁷
-- ≡⟨ in list notation ⟩
--   [3,0,2,0,0,4,0,2]
--
-- This approach is wasteful with space. Instead, we will pair each
-- coefficient with the size of the preceding gap, meaning that the
-- above expression is instead written as:
--
--   [(3,0),(2,1),(4,2),(2,1)]
--
-- Which can be thought of as a representation of the expression:
--
--   x⁰ * (3 + x * x¹ * (2 + x * x² * (4 + x * x¹ * (2 + x * 0))))
--
-- To add multiple variables to a polynomial, you can *nest* them,
-- making the coefficients of the outer polynomial polynomials
-- themselves. However, this is *also* wasteful, in a similar way to
-- above: the constant polynomial, for instance, will be represented
-- as many nestings of constant polynomials around a final variable.
-- However, this approach presents a difficulty: the polynomial will
-- have the kind ℕ → Set (...). In other words, it's indexed by the
-- number of variables it contains. The gap we store, then, has to
-- be accomanied with some information about how it relates to that
-- index.
--
-- The first approach I tried was to forget about storing the gaps,
-- and instead store the number of variables in the nested coefficient,
-- along with a proof that the number was smaller than the outer. The
-- proof was _≤_ from Data.Nat:
--
-- data _≤_ : Rel ℕ 0ℓ where
--   z≤n : ∀ {n}                 → zero  ≤ n
--   s≤s : ∀ {m n} (m≤n : m ≤ n) → suc m ≤ suc n
--
-- While this worked, this will actually give you a worse complexity
-- than the naive encoding without gaps.
--
-- For any of the binary operations, you need to be able to "line up"
-- the two arguments in terms of the gaps. For addition, for instance,
-- the argument with fewer variables should be added to the constant
-- term of the argument with more. To do this, you need to compare the
-- gaps.
--
-- To see why that's a problem, consider the following sequence of
-- nestings:
--
--   (5 ≤ 6), (4 ≤ 5), (3 ≤ 4), (1 ≤ 3), (0 ≤ 1)
--
-- The outer polynomial has 6 variables, but it has a gap to its inner
-- polynomial of 5, and so on. What we compare in this case is the
-- number of variables in the tail: like repeatedly taking the length of
-- the tail of a list, it's quadratic.
--
-- The second approach was to try and mimic the powers structure
-- (which only compared the gaps, which is linear), and store the gaps
-- in a proof like the following:
--
-- record _≤″_ (m n : ℕ) : Set where
--   constructor less-than-or-equal
--   field
--     {k}   : ℕ
--     proof : m + k ≡ n
--
-- Here, k is the size of the gap. The problem of this approach was
-- twofold: it was difficult to show that comparisons on the k
-- corresponded to comparisons on the m, and working with ≡ instead of
-- some inductive structure was messy. However, it had the advantage
-- of being erasable: both proofs of the correspondence and the
-- equality proof itself. That said, I'm not very familiar with the
-- soundness of erasure, and in particular how it interacts with axiom
-- K (which I'd managed to avoid up until this point, but started to
-- creep in).
--
-- I may have had more luck if I swapped the arguments too +:
--
-- record _≤″_ (m n : ℕ) : Set where
--   constructor less-than-or-equal
--   field
--     {k}   : ℕ
--     proof : k + m ≡ n
--
-- But I did not try it. The solution I ended up with was superior,
-- regardless:
--
-- infix 4 _≤_
-- data _≤_ (m : ℕ) : ℕ → Set where
--   m≤m : m ≤ m
--   ≤-s : ∀ {n} → (m≤n : m ≤ n) → m ≤ suc n
--
-- (This is a rewritten version of _≤′_ from Data.Nat.Base).
--
-- While this structure stores the same information as ≤, it does so
-- by induction on the *gap*. This became apparent when I realised you
-- could use it to write a comparison function which was linear in the
-- size of the gap (even though it was comparing the length of the
-- tail):

-- data Ordering : ℕ → ℕ → Set where
--   less    : ∀ {n m} → n ≤ m → Ordering n (suc m)
--   greater : ∀ {n m} → m ≤ n → Ordering (suc n) m
--   equal   : ∀ {n}           → Ordering n n

-- ≤-compare : ∀ {i j n}
--           → (i≤n : i ≤ n)
--           → (j≤n : j ≤ n)
--           → Ordering i j
-- ≤-compare m≤m m≤m = equal
-- ≤-compare m≤m (≤-s m≤n) = greater m≤n
-- ≤-compare (≤-s m≤n) m≤m = less m≤n
-- ≤-compare (≤-s i≤n) (≤-s j≤n) = ≤-compare i≤n j≤n
--
-- A few things to note here:
--
-- 1. The ≤-compare function is one of those reassuring ones for which
--    Agda can completely fill in the type for me.
-- 2. This function looks somewhat similar to the one for comparing ℕ
--    in Data.Nat, and as a result, the "matching" logic for degree
--    and number of variables began too look similar.
--
-- While this approach allowed me too write all the functions I
-- needed, I hit another roadblock when it came time to prove the
-- ring homomorphism. The first thing I realised I needed to prove was
-- basically the following:
--
--   ∀ {i j n}
--   → (i≤n : i ≤ n)
--   → (j≤n : j ≤ n)
--   → ∀ xs Ρ
--   → Σ⟦ xs ⟧ (drop-1 i≤n Ρ) ≈ Σ⟦ xs ⟧ (drop-1 j≤n Ρ)
--
-- In effect, if the inequalities are over the same numbers, then
-- they'll behave the same way when used in evaluation.
--
-- The above is really just a consequence of ≤ being irrelevant:
--
--   ∀ {i n}
--   → (x : i ≤ n)
--   → (y : i ≤ n)
--   → x ≡ y
--
-- Trying to prove this convinced me that it might not even be possible
-- without K. On top of that, I also noticed that I would need to
-- prove things like:
--
--   ∀ {i j n}
--   → (i≤j : i ≤ j)
--   → (j≤n : j ≤ n)
--   → (x : FlatPoly i)
--   → (Ρ : Vec Carrier n)
--   → ⟦ x Π (i≤j ⟨ ≤′-trans ⟩ j≤n) ⟧ Ρ ≈ ⟦ x Π i≤j ⟧ (drop j≤n Ρ)
--
-- Effectively, I needed to prove that transitivity was a
-- homomorphism.
--
-- I realised that I had not run into these difficulties with the
-- comparison function I was using for the exponent gaps: why? Well
-- that function provides a proof about its *arguments* whereas the
-- one I wrote above only provides a proof about the i and j.
--
-- data Ordering : Rel ℕ 0ℓ where
--   less    : ∀ m k → Ordering m (suc (m + k))
--   equal   : ∀ m   → Ordering m m
--   greater : ∀ m k → Ordering (suc (m + k)) m
--
-- If I tried to mimick the above as closely as possible, I would also
-- need an analogue to +: of course this was ≤′-trans, so I was going
-- to get my transitivity proof as well as everything else. The result
-- is as follows.

module Polynomial.NormalForm.InjectionIndex where

open import Data.Nat as ℕ using (ℕ; suc; zero)
open import Data.Nat using (_≤′_; ≤′-refl; ≤′-step; _<′_) public
open import Data.Nat.Properties using (≤′-trans) public
open import Function

data InjectionOrdering {n : ℕ} : ∀ {i j}
                      → (i≤n : i ≤′ n)
                      → (j≤n : j ≤′ n)
                      → Set
                      where
  inj-lt : ∀ {i j-1}
     → (i≤j-1 : i ≤′ j-1)
     → (j≤n : suc j-1 ≤′ n)
     → InjectionOrdering (≤′-step i≤j-1 ⟨ ≤′-trans ⟩ j≤n) j≤n
  inj-gt : ∀ {i-1 j}
     → (i≤n : suc i-1 ≤′ n)
     → (j≤i-1 : j ≤′ i-1)
     → InjectionOrdering i≤n (≤′-step j≤i-1 ⟨ ≤′-trans ⟩ i≤n)
  inj-eq : ∀ {i} → (i≤n : i ≤′ n) → InjectionOrdering i≤n i≤n

inj-compare : ∀ {i j n}
    → (x : i ≤′ n)
    → (y : j ≤′ n)
    → InjectionOrdering x y
inj-compare ≤′-refl ≤′-refl = inj-eq ≤′-refl
inj-compare ≤′-refl (≤′-step y) = inj-gt ≤′-refl y
inj-compare (≤′-step x) ≤′-refl = inj-lt x ≤′-refl
inj-compare (≤′-step x) (≤′-step y) = case inj-compare x y of
    λ { (inj-lt i≤j-1 .y) → inj-lt i≤j-1 (≤′-step y)
      ; (inj-gt .x j≤i-1) → inj-gt (≤′-step x) j≤i-1
      ; (inj-eq .x) → inj-eq (≤′-step x)
      }

open import Data.Fin as Fin using (Fin)

space : ∀ {n} → Fin n → ℕ
space f = suc (go f)
  where
  go : ∀ {n} → Fin n → ℕ
  go {suc n} Fin.zero = n
  go (Fin.suc x) = go x

Fin⇒≤ : ∀ {n} (x : Fin n) → space x ≤′ n
Fin⇒≤ Fin.zero = ≤′-refl
Fin⇒≤ (Fin.suc x) = ≤′-step (Fin⇒≤ x)


{- The following code gives the basic idea of division by repeated
   subtraction.  We have to ask Agda not to check termination of this
   function, because it is not structurally terminating.  The versions
   in nat-division.agda and nat-division-wf.agda correct this problem,
   and can be judged by Agda to be terminating. -}

module nat-division-basic where

open import bool
open import eq
open import nat
open import product
open import sum

{-# NON_TERMINATING #-}
div : (x d : ℕ) → d =ℕ 0 ≡ ff → ℕ × ℕ
div 0 _ _ = 0 , 0
div x d p with (x < d)
div x d p | tt = 0 , x
div x d p | ff with div (x ∸ d) d p
div x d p | ff | q , r = suc q , r

test-div : ℕ × ℕ
test-div = div 17 3 refl


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

open import Data.Product
open import Function hiding (_⇔_)
open import Level
open import Relation.Binary
open import Relation.Binary.Construct.Composition
open import Relation.Binary.PropositionalEquality

open import Categories.Category.Core

-- the category whose objects are sets and whose morphisms are binary relations.
Rels : ∀ o ℓ → Category (suc o) (suc (o ⊔ ℓ)) (o ⊔ ℓ)
Rels o ℓ = record
  { Obj = Set o
  ; _⇒_ = λ A B → REL A B (o ⊔ ℓ)
  ; _≈_ = λ L R → L ⇔ R
  ; id = λ x y → Lift ℓ (x ≡ y)
  ; _∘_ = λ L R → R ; L
  ; assoc = (λ { (b , fxb , c , gbc , hcy) → c , ((b , (fxb , gbc)) , hcy)})
           , λ { (c , (b , fxb , gbc) , hcy) → b , fxb , c , gbc , hcy}
  ; sym-assoc = (λ { (c , (b , fxb , gbc) , hcy) → b , fxb , c , gbc , hcy})
              , (λ { (b , fxb , c , gbc , hcy) → c , ((b , (fxb , gbc)) , hcy)})
  ; identityˡ = (λ { (b , fxb , lift refl) → fxb}) , λ {_} {y} fxy → y , fxy , lift refl
  ; identityʳ = (λ { (a , lift refl , fxy) → fxy}) , λ {x} {_} fxy → x , lift refl , fxy
  ; identity² = (λ { (_ , lift p , lift q) → lift (trans p q)}) , λ { (lift refl) → _ , lift refl , lift refl }
  ; equiv = record
    { refl = id , id
    ; sym = swap
    ; trans = λ { (p₁ , p₂) (q₁ , q₂) → (q₁ ∘′ p₁) , p₂ ∘′ q₂}
    }
  ; ∘-resp-≈ = λ f⇔h g⇔i →
    (λ { (b , gxb , fky) → b , proj₁ g⇔i gxb , proj₁ f⇔h fky }) ,
     λ { (b , ixb , hby) → b , proj₂ g⇔i ixb , proj₂ f⇔h hby }
  }


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

module Math.NumberTheory.Summation.Generic where

-- agda-stdlib
open import Algebra
open import Data.Nat

module MonoidSummation {c e} (M : Monoid c e) where
  open Monoid M renaming (Carrier to A)

  -- Σ< n f = Σₖ₌₀ⁿ⁻¹[f k]
  Σ< : ℕ → (ℕ → A) → A
  Σ< 0       f = ε
  Σ< (suc n) f = Σ< n f ∙ f n

  -- Σ≤ n f = Σₖ₌₀ⁿ[f k]
  Σ≤ : ℕ → (ℕ → A) → A
  Σ≤ n f = Σ< (suc n) f

  -- Σ<range m n f = Σₖ₌ₘⁿ⁻¹[f k]
  Σ<range : ℕ → ℕ → (ℕ → A) → A
  Σ<range m n f = Σ< (n ∸ m) (λ o → f (m + o))

  -- Σ≤range m n f = Σₖ₌ₘⁿ[f k]
  Σ≤range : ℕ → ℕ → (ℕ → A) → A
  Σ≤range m n f = Σ<range m (suc n) f

  -- syntax
  syntax Σ< n (λ k → e) = Σ[ k < n ] e
  syntax Σ≤ n (λ k → e) = Σ[ k ≤ n ] e
  syntax Σ<range m n (λ k → e) = Σ[ m ≤ k < n ] e
  syntax Σ≤range m n (λ k → e) = Σ[ m ≤ k ≤ n ] e


------------------------------------------------------------------------------
-- Well-founded induction on the relation _◁_
------------------------------------------------------------------------------

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

-- N.B This module does not contain combined proofs, but it imports
-- modules which contain combined proofs.

module FOTC.Program.McCarthy91.WF-Relation.Induction.Acc.WF-ATP where

open import FOTC.Base
open import FOTC.Data.Nat

import FOTC.Data.Nat.Induction.Acc.WF-ATP
open FOTC.Data.Nat.Induction.Acc.WF-ATP.<-WF using ( <-wf )

open import FOTC.Data.Nat.Inequalities
open import FOTC.Data.Nat.UnaryNumbers
open import FOTC.Induction.WF
open import FOTC.Program.McCarthy91.WF-Relation
open import FOTC.Program.McCarthy91.WF-Relation.PropertiesATP

-- Parametrized modules
open module InvImg =
  FOTC.Induction.WF.InverseImage {N} {N} {_<_} ◁-fn-N

------------------------------------------------------------------------------
-- The relation _◁_ is well-founded (using the inverse image combinator).
◁-wf : WellFounded _◁_
◁-wf Nn = wellFounded <-wf Nn

-- Well-founded induction on the relation _◁_.
◁-wfind : (A : D → Set) →
          (∀ {n} → N n → (∀ {m} → N m → m ◁ n → A m) → A n) →
          ∀ {n} → N n → A n
◁-wfind A = WellFoundedInduction ◁-wf


module PiNF-algebra where

open import Data.Product hiding (map)
open import Level
open import Relation.Binary.Core
open import Algebra
import Algebra.FunctionProperties as FunctionProperties
open import Algebra.FunctionProperties.Core
open import Algebra.Structures

open import PiNF-syntax

------------------------------------------------------------------------------
-- Establish that Pi syntactically is a commutative semiring

⟷IsEquivalence : IsEquivalence _⟷_
⟷IsEquivalence = record {
    refl = id⟷ ;
    sym = sym  ;
    trans = _◎_
  }

+IsSemigroup : IsSemigroup _⟷_ PLUS
+IsSemigroup = record {
    isEquivalence = ⟷IsEquivalence ;
    assoc = λ x y z → assocr₊ {x} {y} {z} ;
    ∙-cong = _⊕_
  }

+0IsMonoid : IsMonoid _⟷_ PLUS ZERO
+0IsMonoid = record {
    isSemigroup = +IsSemigroup ;
    identity = ((λ x → unite₊ {x}) ,
                (λ x → swap₊ ◎ unite₊ {x}))
  }

+0IsCommutativeMonoid : IsCommutativeMonoid _⟷_ PLUS ZERO
+0IsCommutativeMonoid = record {
    isSemigroup = +IsSemigroup ;
    identityˡ = λ x → unite₊ {x} ;
    comm = λ x y → swap₊ {x} {y}
  }

+0CommutativeMonoid : CommutativeMonoid _ _
+0CommutativeMonoid = record {
  Carrier = B ;
  _≈_ = _⟷_ ;
  _∙_ = PLUS ;
  ε = ZERO ;
  isCommutativeMonoid = +0IsCommutativeMonoid
  }

--

⋆IsSemigroup : IsSemigroup _⟷_ TIMES
⋆IsSemigroup = record {
    isEquivalence = ⟷IsEquivalence ;
    assoc = λ x y z → assocr⋆ {x} {y} {z} ;
    ∙-cong = _⊗_
  }

⋆1IsMonoid : IsMonoid _⟷_ TIMES ONE
⋆1IsMonoid = record {
    isSemigroup = ⋆IsSemigroup ;
    identity = ((λ x → unite⋆ {x}) ,
                (λ x → swap⋆ ◎ unite⋆ {x}))
  }

⋆1IsCommutativeMonoid : IsCommutativeMonoid _⟷_ TIMES ONE
⋆1IsCommutativeMonoid = record {
    isSemigroup = ⋆IsSemigroup ;
    identityˡ = λ x → unite⋆ {x} ;
    comm = λ x y → swap⋆ {x} {y}
  }

⋆1CommutativeMonoid : CommutativeMonoid _ _
⋆1CommutativeMonoid = record {
  Carrier = B ;
  _≈_ = _⟷_ ;
  _∙_ = TIMES ;
  ε = ONE ;
  isCommutativeMonoid = ⋆1IsCommutativeMonoid
  }

record IsCommutativeSemiringWithoutAnnihilatingZero
         {a ℓ} {A : Set a} (≈ : Rel A ℓ)
         (+ * : Op₂ A) (0# 1# : A)
       : Set (a ⊔ ℓ) where
  open FunctionProperties ≈
  field
    +-isCommutativeMonoid : IsCommutativeMonoid ≈ + 0#
    *-isCommutativeMonoid : IsCommutativeMonoid ≈ * 1#
    distrib               : * DistributesOver +

record CommutativeSemiringWithoutAnnihilatingZero c ℓ : Set (suc (c ⊔ ℓ)) where
  field
    Carrier : Set c
    _≈_ : Rel Carrier ℓ
    _+_ : Op₂ Carrier
    _*_ : Op₂ Carrier
    0# : Carrier
    1# : Carrier
    isCommutativeSemiringWithoutAnnihilatingZero :
      IsCommutativeSemiringWithoutAnnihilatingZero _≈_ _+_ _*_ 0# 1#

B-isCommutativeSemiringWithoutAnnihilatingZero
    : IsCommutativeSemiringWithoutAnnihilatingZero _⟷_ PLUS TIMES ZERO ONE
B-isCommutativeSemiringWithoutAnnihilatingZero = record {
    +-isCommutativeMonoid = +0IsCommutativeMonoid ;
    *-isCommutativeMonoid = ⋆1IsCommutativeMonoid ;
    distrib = ( (λ x y z → dist' {x} {y} {z}) ,
                (λ x y z → dist {y} {z} {x} ))
    }

------------------------------------------------------------------------------
-- Establish that Pi+negatives+fractionals syntactically is a meadow

+0-IsGroup : IsGroup _⟷_ PLUS ZERO NEG
+0-IsGroup = record {
  isMonoid = +0IsMonoid ;
  inverse = ( (λ x → swap₊ ◎ ε₊ {x}) ,
              (λ x → ε₊ {x}) );
  ⁻¹-cong = neg
  }

+0-IsAbelianGroup : IsAbelianGroup _⟷_ PLUS ZERO NEG
+0-IsAbelianGroup = record {
    isGroup = +0-IsGroup ;
    comm = λ x y → swap₊ {x} {y}
  }

B-IsRing : IsRing _⟷_ PLUS TIMES NEG ZERO ONE
B-IsRing = record {
    +-isAbelianGroup = +0-IsAbelianGroup ;
    *-isMonoid = ⋆1IsMonoid ;
    distrib = ( (λ x y z → dist' {x} {y} {z}) ,
                (λ x y z → dist {y} {z} {x} ))
  }

B-IsCommutativeRing : IsCommutativeRing _⟷_ PLUS TIMES NEG ZERO ONE
B-IsCommutativeRing = record {
    isRing = B-IsRing ;
    *-comm = λ x y → swap⋆ {x} {y}
  }

--

B-CommutativeRing : CommutativeRing _ _
B-CommutativeRing = record {
    Carrier = B ;
    _≈_ = _⟷_ ;
    _+_ = PLUS ;
    _*_ = TIMES ;
    -_ = NEG ;
    0# = ZERO ;
    1# = ONE ;
    isCommutativeRing = B-IsCommutativeRing
  }

--

record IsMeadow
         {a ℓ} {A : Set a} (≈ : Rel A ℓ)
         (+ * : Op₂ A) (- r : Op₁ A) (0# 1# : A) : Set (a ⊔ ℓ) where
  open FunctionProperties ≈
  field
    +*-isCommutativeRing : IsCommutativeRing ≈ + * - 0# 1#
    *-refl-l : ∀ x → ≈ (r (r x)) x
    *-refl-r : ∀ x → ≈ x (r (r x))
    *-ril-l : ∀ x → ≈ (* x (* x (r x))) x
    *-ril-r : ∀ x → ≈ x (* x (* x (r x)))
    r-cong : ∀ x y → ≈ x y → ≈ (r x) (r y)

record Meadow c ℓ : Set (suc (c ⊔ ℓ)) where
  field
    Carrier : Set c
    _≈_ : Rel Carrier ℓ
    _+_ : Op₂ Carrier
    _*_ : Op₂ Carrier
    -_ : Op₁ Carrier
    r  : Op₁ Carrier
    0# : Carrier
    1# : Carrier
    isMeadow : IsMeadow _≈_ _+_ _*_ -_ r 0# 1#

B-/IsMeadow : IsMeadow _⟷_ PLUS TIMES NEG RECIP ZERO ONE
B-/IsMeadow = record {
    +*-isCommutativeRing = B-IsCommutativeRing ;
    *-refl-l = λ x → refe⋆ {x} ;
    *-refl-r = λ x → sym (refe⋆ {x}) ;
    *-ril-l = λ x → sym (rili⋆ {x}) ;
    *-ril-r = λ x → rili⋆ {x} ;
    r-cong = λ x y → recip {x} {y}
  }

B-/Meadow : Meadow _ _
B-/Meadow = record {
    Carrier = B ;
    _≈_ = _⟷_ ;
    _+_ = PLUS ;
    _*_ = TIMES ;
    -_ = NEG ;
    r  = RECIP ;
    0# = ZERO ;
    1# = ONE ;
    isMeadow = B-/IsMeadow
  }

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


{-# OPTIONS --without-K #-}
open import Library

--------------------------------------------------------------------------------
-- Universes for a Category
--------------------------------------------------------------------------------

record CatLevel : Set where
  field
    Obj  : Level
    Hom  : Level

  Obj-Hom : Level
  Obj-Hom = ℓ-max Obj Hom

  Cat : Level
  Cat = ℓ-suc (ℓ-max Obj Hom)

--------------------------------------------------------------------------------
-- Definition of a Category
--------------------------------------------------------------------------------

module _ (ℓ : CatLevel) (let module ℓ = CatLevel ℓ) where
  record Category : Set ℓ.Cat where
    field
      Obj   : Set ℓ.Obj
      _⇒_   : Obj → Obj → Set ℓ.Hom
      id    : (X : Obj) → X ⇒ X
      _∘_   : ∀{X Y Z} → Y ⇒ Z → X ⇒ Y → X ⇒ Z

    infix 4 _⇒_
    infix 6 _∘_

    field
      idl   : ∀{X Y}{f : X ⇒ Y} → (id Y) ∘ f ≡ f
      idr   : ∀{X Y}{f : X ⇒ Y} → f ∘ (id X) ≡ f
      assoc : ∀{W X Y Z}{f : W ⇒ X}{g : X ⇒ Y}{h : Y ⇒ Z}
                → (h ∘ g) ∘ f ≡ h ∘ (g ∘ f)

--------------------------------------------------------------------------------
-- Dual Category
--------------------------------------------------------------------------------

    op : Category
    op = record { Obj    = Obj
                ; _⇒_    = λ-flip _⇒_
                ; id     = id
                ; _∘_    = λ-flip _∘_
                ; idl    = idr
                ; idr    = idl
                ; assoc  = ≡-sym assoc }

--------------------------------------------------------------------------------
-- Properties of Spacial Morphisms
--------------------------------------------------------------------------------

    record _≅_ (X Y : Obj) : Set ℓ.Cat where
      field
        f   : X ⇒ Y
        g   : Y ⇒ X
        g∘f : g ∘ f ≡ id X
        f∘g : f ∘ g ≡ id Y

    record _≾_ (X Y : Obj) : Set ℓ.Cat where
      field
        s   : X ⇒ Y
        r   : Y ⇒ X
        r∘s : r ∘ s ≡ id X

    module _ {X Y : Obj} (f : X ⇒ Y) where
      is-isomorphism  : Set ℓ.Hom
      is-isomorphism  = Σ[ g ∈ Y ⇒ X ] (g ∘ f ≡ id X) × (f ∘ g ≡ id Y)

      is-section      : Set ℓ.Hom
      is-section      = Σ[ g ∈ Y ⇒ X ] g ∘ f ≡ id X

      is-retraction   : Set ℓ.Hom
      is-retraction   = Σ[ g ∈ Y ⇒ X ] f ∘ g ≡ id Y

      is-monomorphism : Set ℓ.Obj-Hom
      is-monomorphism = ∀{Z}{g h : Z ⇒ X} → f ∘ g ≡ f ∘ h → g ≡ h

      is-epimorphism  : Set ℓ.Obj-Hom
      is-epimorphism  = ∀{Z}{g h : Y ⇒ Z} → g ∘ f ≡ h ∘ f → g ≡ h

      is-bimorphism   : Set ℓ.Obj-Hom
      is-bimorphism   = is-monomorphism × is-epimorphism

    module _ (X Y : Obj) where
      _iso⇒_  : Set ℓ.Hom
      _iso⇒_  = Σ (X ⇒ Y) is-isomorphism

      _mono⇒_ : Set ℓ.Obj-Hom
      _mono⇒_ = Σ (X ⇒ Y) is-monomorphism

      _epi⇒_  : Set ℓ.Obj-Hom
      _epi⇒_  = Σ (X ⇒ Y) is-epimorphism

--------------------------------------------------------------------------------
-- Category of Sets i.e. Types that has no non-trival equality
--------------------------------------------------------------------------------

SetCat : (ℓ : Level) → Category (record { Obj = ℓ-suc ℓ ; Hom = ℓ })
SetCat ℓ = record
  { Obj   = Object
  ; _⇒_   = λ (X Y : Object) → (X → Y)
  ; id    = λ (X : Object) → (λ x → x)
  ; _∘_   = λ {X Y Z : Object} (g : Y → Z) (f : X → Y) → (λ x → g (f x))
  ; idl   = ≡-refl
  ; idr   = ≡-refl
  ; assoc = ≡-refl
  } where Object = Set ℓ

SetCat₀ = SetCat ℓ-zero


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

syntax Naturals | Nat

type
  N : 0-ary

term
  ze   : N
  su   : N  ->  N
  nrec : N  α  (α,N).α  ->  α

theory
  (zeβ) z : α   s : (α,N).α        |> nrec (ze,       z, r m. s[r,m]) = z
  (suβ) z : α   s : (α,N).α  n : N |> nrec (su (n), z, r m. s[r,m]) = s[nrec (n, z, r m. s[r,m]), n]
-}

module Naturals.Signature where

open import SOAS.Context

-- Type declaration
data NatT : Set where
  N : NatT

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

-- Operator symbols
data Natₒ : Set where
  zeₒ suₒ : Natₒ
  nrecₒ : {α : NatT} → Natₒ

-- Term signature
Nat:Sig : Signature Natₒ
Nat:Sig = sig λ
  {  zeₒ        → ⟼₀ N
  ;  suₒ        → (⊢₀ N) ⟼₁ N
  ; (nrecₒ {α}) → (⊢₀ N) , (⊢₀ α) , (α , N ⊢₂ α) ⟼₃ α
  }

open Signature Nat:Sig public


open import Relation.Binary.Core

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

open import BBHeap _≤_
open import BBHeap.Insert _≤_ tot≤ trans≤
open import Bound.Lower A
open import Bound.Lower.Order _≤_
open import Data.List

heapify : List A → BBHeap bot
heapify [] = leaf
heapify (x ∷ xs) = insert {x = x} lebx (heapify xs)


module Prelude where

  id : {a : Set} -> a -> a
  id x = x

  infixr 0 _$_

  _$_ : {a b : Set} -> (a -> b) -> a -> b
  f $ x = f x

  data Bool : Set where
    True  : Bool
    False : Bool

  _&&_ : Bool -> Bool -> Bool
  True  && b = b
  False && _ = False

  data Pair (a b : Set) : Set where
    pair : a -> b -> Pair a b

  fst : {a b : Set} -> Pair a b -> a
  fst (pair x y) = x

  snd : {a b : Set} -> Pair a b -> b
  snd (pair x y) = y

  data Either (a b : Set) : Set where
    left  : a -> Either a b
    right : b -> Either a b

  data Maybe (a : Set) : Set where
    Nothing : Maybe a
    Just    : a -> Maybe a

  data Unit : Set where
    unit : Unit

  data Absurd : Set where

  absurdElim : {whatever : Set} -> Absurd -> whatever
  absurdElim ()

--   data Pi {a : Set} (f : a -> Set) : Set where
--     pi : ((x : a) -> f x) -> Pi f
--
--   apply : {a : Set} -> {f : a -> Set} -> Pi f -> (x : a) -> f x
--   apply (pi f) x = f x

  T : Bool -> Set
  T True  = Unit
  T False = Absurd

  andT : {x y : Bool} -> T x -> T y -> T (x && y)
  andT {True}  {True}  _  _ = unit
  andT {True}  {False} _  ()
  andT {False} {_}     () _

  T' : {a : Set} -> (a -> a -> Bool) -> (a -> a -> Set)
  T' f x y = T (f x y)

  data Not (a : Set) : Set where
    not : (a -> Absurd) -> Not a

  -- Not : Set -> Set
  -- Not a = a -> Absurd

  contrapositive : {a b : Set} -> (a -> b) -> Not b -> Not a
  contrapositive p (not nb) = not (\a -> nb (p a))

  private
    notDistribOut' : {a b : Set} -> Not a -> Not b -> Either a b -> Absurd
    notDistribOut' (not na) _        (left a)  = na a
    notDistribOut' _        (not nb) (right b) = nb b

  notDistribOut : {a b : Set} -> Not a -> Not b -> Not (Either a b)
  notDistribOut na nb = not (notDistribOut' na nb)

  notDistribIn : {a b : Set} -> Not (Either a b) -> Pair (Not a) (Not b)
  notDistribIn (not nab) = pair (not (\a -> nab (left a)))
                                (not (\b -> nab (right b)))

  data _<->_ (a b : Set) : Set where
    iff : (a -> b) -> (b -> a) -> a <-> b

  iffLeft : {a b : Set} -> (a <-> b) -> (a -> b)
  iffLeft (iff l _) = l

  iffRight : {a b : Set} -> (a <-> b) -> (b -> a)
  iffRight (iff _ r) = r

  Dec : (A : Set) -> Set
  Dec A = Either A (Not A)


module Utilities.VecSplit where

-- Standard libraries imports ----------------------------------------
open import Data.Nat using (ℕ ; _+_)
open import Data.Vec using (Vec ; _++_)

open import Relation.Binary.PropositionalEquality
  using (_≡_)
open import Relation.Binary.HeterogeneousEquality
  using (_≅_)
----------------------------------------------------------------------

record Split {A : Set} {n : ℕ} (xs : Vec A n) : Set where
  field
    {m₁} {m₂} : ℕ
    n≡m₁+m₂ : n ≡ m₁ + m₂
    ys : Vec A m₁
    zs : Vec A m₂
    xs≅ys++zs : xs ≅ ys ++ zs


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

module Cubical.HITs.InfNat.Properties where

open import Cubical.Core.Everything
open import Cubical.Data.Maybe
open import Cubical.Data.Nat

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism

open import Cubical.HITs.InfNat.Base
import Cubical.Data.InfNat as Coprod

ℕ+∞→Cℕ+∞ : ℕ+∞ → Coprod.ℕ+∞
ℕ+∞→Cℕ+∞ zero = Coprod.zero
ℕ+∞→Cℕ+∞ (suc n) = Coprod.suc (ℕ+∞→Cℕ+∞ n)
ℕ+∞→Cℕ+∞ ∞ = Coprod.∞
ℕ+∞→Cℕ+∞ (suc-inf i) = Coprod.∞

ℕ→ℕ+∞ : ℕ → ℕ+∞
ℕ→ℕ+∞ zero = zero
ℕ→ℕ+∞ (suc n) = suc (ℕ→ℕ+∞ n)

Cℕ+∞→ℕ+∞ : Coprod.ℕ+∞ → ℕ+∞
Cℕ+∞→ℕ+∞ Coprod.∞ = ∞
Cℕ+∞→ℕ+∞ (Coprod.fin n) = ℕ→ℕ+∞ n

ℕ→ℕ+∞→Cℕ+∞ : ∀ n → ℕ+∞→Cℕ+∞ (ℕ→ℕ+∞ n) ≡ Coprod.fin n
ℕ→ℕ+∞→Cℕ+∞ zero = refl
ℕ→ℕ+∞→Cℕ+∞ (suc n) = cong Coprod.suc (ℕ→ℕ+∞→Cℕ+∞ n)

Cℕ+∞→ℕ+∞→Cℕ+∞ : ∀ n → ℕ+∞→Cℕ+∞ (Cℕ+∞→ℕ+∞ n) ≡ n
Cℕ+∞→ℕ+∞→Cℕ+∞ Coprod.∞ = refl
Cℕ+∞→ℕ+∞→Cℕ+∞ (Coprod.fin n) = ℕ→ℕ+∞→Cℕ+∞ n

suc-hom : ∀ n → Cℕ+∞→ℕ+∞ (Coprod.suc n) ≡ suc (Cℕ+∞→ℕ+∞ n)
suc-hom Coprod.∞ = suc-inf
suc-hom (Coprod.fin x) = refl

ℕ+∞→Cℕ+∞→ℕ+∞ : ∀ n → Cℕ+∞→ℕ+∞ (ℕ+∞→Cℕ+∞ n) ≡ n
ℕ+∞→Cℕ+∞→ℕ+∞ zero = refl
ℕ+∞→Cℕ+∞→ℕ+∞ ∞ = refl
ℕ+∞→Cℕ+∞→ℕ+∞ (suc n) = suc-hom (ℕ+∞→Cℕ+∞ n) ∙ cong suc (ℕ+∞→Cℕ+∞→ℕ+∞ n)
ℕ+∞→Cℕ+∞→ℕ+∞ (suc-inf i) = lemma i
  where
  lemma : (λ i → ∞ ≡ suc-inf i) [ refl ≡ suc-inf ∙ refl ]
  lemma i j = hcomp (λ k → λ
    { (i = i0) → ∞
    ; (i = i1) → compPath-filler suc-inf refl k j
    ; (j = i0) → ∞
    ; (j = i1) → suc-inf i
    }) (suc-inf (i ∧ j))

open Iso

ℕ+∞⇔Cℕ+∞ : Iso ℕ+∞ Coprod.ℕ+∞
ℕ+∞⇔Cℕ+∞ .fun = ℕ+∞→Cℕ+∞
ℕ+∞⇔Cℕ+∞ .inv = Cℕ+∞→ℕ+∞
ℕ+∞⇔Cℕ+∞ .leftInv = ℕ+∞→Cℕ+∞→ℕ+∞
ℕ+∞⇔Cℕ+∞ .rightInv = Cℕ+∞→ℕ+∞→Cℕ+∞


------------------------------------------------------------------------
-- Types with decidable equality have unique identity proofs, and
-- related results
------------------------------------------------------------------------

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

-- The part up to "decidable⇒set" follows a proof by Michael Hedberg
-- ("A coherence theorem for Martin-Löf's type theory", JFP 1998).

open import Equality

module Equality.Decidable-UIP
  {reflexive} (eq : ∀ {a p} → Equality-with-J a p reflexive) where

open Derived-definitions-and-properties eq
open import Logical-equivalence using (module _⇔_)
open import H-level eq
open import Prelude

-- Weakly constant functions.

Constant : ∀ {a b} {A : Type a} {B : Type b} → (A → B) → Type (a ⊔ b)
Constant f = ∀ x y → f x ≡ f y

-- Left inverses.

_Left-inverse-of_ : ∀ {a b} {A : Type a} {B : Type b} →
                    (B → A) → (A → B) → Type a
g Left-inverse-of f = ∀ x → g (f x) ≡ x

abstract

  -- A set with a constant endofunction with a left inverse is a
  -- proposition.

  proposition : ∀ {a} {A : Type a} →
                (f : ∃ λ (f : A → A) → Constant f) →
                (∃ λ g → g Left-inverse-of (proj₁ f)) →
                Is-proposition A
  proposition (f , constant) (g , left-inverse) x y =
    x        ≡⟨ sym (left-inverse x) ⟩
    g (f x)  ≡⟨ cong g (constant x y) ⟩
    g (f y)  ≡⟨ left-inverse y ⟩∎
    y        ∎

  -- Endofunction families on _≡_ always have left inverses.

  left-inverse :
    ∀ {a} {A : Type a} (f : (x y : A) → x ≡ y → x ≡ y) →
    ∀ {x y} → ∃ λ g → g Left-inverse-of f x y
  left-inverse {A = A} f {x} {y} =
    (λ x≡y →
       x  ≡⟨ x≡y ⟩
       y  ≡⟨ sym (f y y (refl y)) ⟩∎
       y  ∎) ,
    elim (λ {x y} x≡y → trans (f x y x≡y) (sym (f y y (refl y))) ≡ x≡y)
         (λ _ → trans-symʳ _)

  -- A type A is a set if there is a family of constant endofunctions
  -- on _≡_ {A = A}.

  constant⇒set :
    ∀ {a} {A : Type a} →
    ((x y : A) → ∃ λ (f : x ≡ y → x ≡ y) → Constant f) →
    Is-set A
  constant⇒set constant {x} {y} =
    proposition (constant x y)
                (left-inverse (λ x y → proj₁ $ constant x y))

  -- If it is known whether or not a type is inhabited, then one can
  -- define a constant endofunction for that type.

  decidable⇒constant : ∀ {a} {A : Type a} → Dec A →
                       ∃ λ (f : A → A) → Constant f
  decidable⇒constant (yes x) = (const x , λ _ _ → refl x)
  decidable⇒constant (no ¬x) = (id      , λ _ → ⊥-elim ∘ ¬x)

  -- Types with decidable equality are sets.

  decidable⇒set : ∀ {a} {A : Type a} → Decidable-equality A → Is-set A
  decidable⇒set dec =
    constant⇒set (λ x y → decidable⇒constant (dec x y))

  -- Non-dependent functions with propositional domains are constant.

  propositional-domain⇒constant :
    ∀ {a b} {A : Type a} {B : Type b} →
    Is-proposition A → (f : A → B) → Constant f
  propositional-domain⇒constant A-prop f = λ x y →
    cong f (A-prop x y)

  -- If there is a propositional, reflexive relation on A, and related
  -- elements are equal, then A is a set.
  --
  -- (The statement of this lemma is one part of the statement of
  -- Theorem 7.2.2 in "Homotopy Type Theory: Univalent Foundations of
  -- Mathematics" (first edition).)

  propositional-identity⇒set :
    ∀ {a b} {A : Type a}
    (B : A → A → Type b) →
    (∀ x y → Is-proposition (B x y)) →
    (∀ x → B x x) →
    (∀ x y → B x y → x ≡ y) →
    Is-set A
  propositional-identity⇒set B B-prop B-refl f =
    constant⇒set λ x y →
      (λ eq → f x y (subst (B x) eq (B-refl x))) ,
      (λ _ _ → propositional-domain⇒constant (B-prop x y) (f x y) _ _)

  -- The function cong {x = x} {y = y} takes (weakly) constant
  -- functions to constant functions.
  --
  -- This is Lemma 3.1 from van Doorn's "Constructing the
  -- Propositional Truncation using Non-recursive HITs".

  cong-preserves-Constant :
    ∀ {a b} {A : Type a} {B : Type b} {f : A → B} {x y : A} →
    Constant f → Constant (cong {x = x} {y = y} f)
  cong-preserves-Constant {f = f} {x = x} {y = y} c p q =
    cong f p                     ≡⟨ lemma p ⟩
    trans (sym (c x x)) (c x y)  ≡⟨ sym (lemma q) ⟩∎
    cong f q                     ∎
    where
    lemma : ∀ p → cong {x = x} {y = y} f p ≡ trans (sym (c x x)) (c x y)
    lemma = elim
      (λ {x y} p → cong {x = x} {y = y} f p ≡ trans (sym (c x x)) (c x y))
      (λ x →
         cong f (refl x)              ≡⟨ cong-refl _ ⟩
         refl (f x)                   ≡⟨ sym $ trans-symˡ _ ⟩∎
         trans (sym (c x x)) (c x x)  ∎)

  -- The following two results come from "Generalizations of Hedberg's
  -- Theorem" by Kraus, Escardó, Coquand and Altenkirch.

  -- Proposition 3.
  --
  -- (I proved this result using cong-preserves-Constant.)

  cong-constant :
    ∀ {a b} {A : Type a} {B : Type b} {f : A → B} {x} {x≡x : x ≡ x} →
    Constant f →
    cong f x≡x ≡ refl (f x)
  cong-constant {f = f} {x} {x≡x} c =
    cong f x≡x       ≡⟨ cong-preserves-Constant c _ _ ⟩
    cong f (refl x)  ≡⟨ cong-refl _ ⟩∎
    refl (f x)       ∎

  -- The "Fixed Point Lemma".

  fixpoint-lemma :
    ∀ {a} {A : Type a} →
    (f : A → A) →
    Constant f →
    Is-proposition (∃ λ x → f x ≡ x)
  fixpoint-lemma f constant (x , fx≡x) (y , fy≡y) =
      let x≡y = x    ≡⟨ sym fx≡x ⟩
                f x  ≡⟨ constant x y ⟩
                f y  ≡⟨ fy≡y ⟩∎
                y    ∎

          x≡x = x    ≡⟨ sym fx≡x ⟩
                f x  ≡⟨ subst (λ z → f z ≡ z) (sym x≡y) fy≡y ⟩∎
                x    ∎

          lemma =
            subst (λ z → f z ≡ z) x≡x fx≡x                       ≡⟨ subst-in-terms-of-trans-and-cong ⟩

            trans (sym (cong f x≡x)) (trans fx≡x (cong id x≡x))  ≡⟨ cong₂ (λ p q → trans (sym p) (trans _ q))
                                                                          (cong-constant constant) (sym $ cong-id _) ⟩
            trans (sym (refl (f x))) (trans fx≡x x≡x)            ≡⟨ cong (λ p → trans p (trans fx≡x x≡x)) sym-refl ⟩

            trans (refl (f x)) (trans fx≡x x≡x)                  ≡⟨ trans-reflˡ _ ⟩

            trans fx≡x x≡x                                       ≡⟨ sym $ trans-assoc _ _ _ ⟩

            trans (trans fx≡x (sym fx≡x))
                  (subst (λ z → f z ≡ z) (sym x≡y) fy≡y)         ≡⟨ cong (λ p → trans p (subst (λ z → f z ≡ z) (sym x≡y) fy≡y)) $
                                                                      trans-symʳ _ ⟩
            trans (refl (f x))
                  (subst (λ z → f z ≡ z) (sym x≡y) fy≡y)         ≡⟨ trans-reflˡ _ ⟩∎

            subst (λ z → f z ≡ z) (sym x≡y) fy≡y                 ∎
      in
      x , fx≡x                                  ≡⟨ Σ-≡,≡→≡ x≡x lemma ⟩
      x , subst (λ z → f z ≡ z) (sym x≡y) fy≡y  ≡⟨ sym $ Σ-≡,≡→≡ (sym x≡y) (refl _) ⟩∎
      y , fy≡y                                  ∎


module PatternSynonyms where

data ℕ : Set where
  zero : ℕ
  suc  : (n : ℕ) → ℕ

{-# BUILTIN NATURAL ℕ #-}
{-# BUILTIN ZERO zero #-}
{-# BUILTIN SUC suc #-}

pattern z    = zero
pattern sz   = suc z
pattern ss x = suc (suc x)

data _≡_ {A : Set}(x : A) : A → Set where
  refl : x ≡ x

test : z ≡ zero
test = refl

test′ : sz ≡ suc zero
test′ = refl

test″ : ss z ≡ suc (suc zero)
test″ = refl

test‴ : ss ≡ λ x → suc (suc x)
test‴ = refl

f : ℕ → ℕ
f z            = zero
f sz           = suc z
f (ss 0)       = 2
f (ss (suc n)) = n

test-f : f zero ≡ zero
test-f = refl

test-f′ : f (suc zero) ≡ suc zero
test-f′ = refl

test-f″ : f (suc (suc 0)) ≡ 2
test-f″ = refl

test-f‴ : ∀ {n} → f (suc (suc (suc n))) ≡ n
test-f‴ = refl

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

data L (A : Set) : Set where
  nil  : L A
  cons : A → L A → L A

pattern cc x y xs = cons x (cons y xs)

test-cc : ∀ {A} → cc ≡ λ (x : A) y xs → cons x (cons y xs)
test-cc = refl

crazyLength : ∀ {A} → L A → ℕ
crazyLength nil          = 0
crazyLength (cons x nil) = 1
crazyLength (cc x y xs)  = 9000

swap : ∀ {A} → L A → L A
swap nil          = nil
swap (cons x nil) = cons x nil
swap (cc x y xs)  = cc y x xs

test-swap : ∀ {xs} → swap (cons 1 (cons 2 xs)) ≡ cons 2 (cons 1 xs)
test-swap = refl

------------------------------------------------------------------------
-- refl and _

record ⊤ : Set where
  constructor tt

data _⊎_ (A B : Set) : Set where
  inj₁ : (x : A) → A ⊎ B
  inj₂ : (y : B) → A ⊎ B

infixr 4 _,_
record Σ (A : Set)(B : A → Set) : Set where
  constructor _,_
  field
    proj₁ : A
    proj₂ : B proj₁

open Σ

_×_ : (A B : Set) → Set
A × B = Σ A λ _ → B

infixr 5 _+_
infixr 6 _*_

data Sig (O : Set) : Set₁ where
  ε ψ     : Sig O
  ρ       : (o : O) → Sig O
  ι       : (o : O) → Sig O
  _+_ _*_ : (Σ Σ′ : Sig O) → Sig O
  σ π     : (A : Set)(φ : A → Sig O) → Sig O

⟦_⟧ : ∀ {O} → Sig O → (Set → (O → Set) → (O → Set))
⟦ ε      ⟧ P R o = ⊤
⟦ ψ      ⟧ P R o = P
⟦ ρ o′   ⟧ P R o = R o′
⟦ ι o′   ⟧ P R o = o ≡ o′
⟦ Σ + Σ′ ⟧ P R o = ⟦ Σ ⟧ P R o ⊎ ⟦ Σ′ ⟧ P R o
⟦ Σ * Σ′ ⟧ P R o = ⟦ Σ ⟧ P R o × ⟦ Σ′ ⟧ P R o
⟦ σ A φ  ⟧ P R o = Σ A λ x → ⟦ φ x ⟧ P R o
⟦ π A φ  ⟧ P R o = (x : A) → ⟦ φ x ⟧ P R o

′List : Sig ⊤
′List = ε + ψ * ρ _

data μ {O}(Σ : Sig O)(P : Set)(o : O) : Set where
  ⟨_⟩ : ⟦ Σ ⟧ P (μ Σ P) o → μ Σ P o

List : Set → Set
List A = μ ′List A _

infixr 5 _∷_
pattern []       = ⟨ inj₁ _ ⟩
pattern _∷_ x xs = ⟨ inj₂ (x , xs) ⟩

length : ∀ {A} → List A → ℕ
length []       = zero
length (x ∷ xs) = suc (length xs)

test-list : List ℕ
test-list = 1 ∷ 2 ∷ []

test-length : length test-list ≡ 2
test-length = refl

′Vec : Sig ℕ
′Vec = ι 0
     + σ ℕ λ m → ψ * ρ m * ι (suc m)

Vec : Set → ℕ → Set
Vec A n = μ ′Vec A n

pattern []V     = ⟨ inj₁ refl ⟩
pattern _∷V_ x xs = ⟨ inj₂ (_ , x , xs , refl) ⟩

nilV : ∀ {A} → Vec A zero
nilV = []V

consV : ∀ {A n} → A → Vec A n → Vec A (suc n)
consV x xs = x ∷V xs

lengthV : ∀ {A n} → Vec A n → ℕ
lengthV []V       = 0
lengthV (x ∷V xs) = suc (lengthV xs)

test-lengthV : lengthV (consV 1 (consV 2 (consV 3 nilV))) ≡ 3
test-lengthV = refl

------------------------------------------------------------------------
-- .-patterns

pattern zr          = (.zero , refl)
pattern underscore² = _ , _

dot : (p : Σ ℕ λ n → n ≡ zero) → ⊤ × ⊤
dot zr = underscore²

------------------------------------------------------------------------
-- Implicit arguments

{-
pattern hiddenUnit = {_} -- XXX: We get lhs error msgs, can we refine
                         -- that?

imp : {p : ⊤} → ⊤
imp hiddenUnit = _
-}

data Box (A : Set) : Set where
  box : {x : A} → Box A

pattern [_] y = box {x = y}

b : Box ℕ
b = [ 1 ]

test-box : b ≡ box {x = 1}
test-box = refl

------------------------------------------------------------------------
-- Anonymous λs

g : ℕ → ℕ
g = λ { z → z
      ; sz → sz
      ; (ss n) → n
      }

test-g : g zero ≡ zero
test-g = refl

test-g′ : g sz ≡ suc zero
test-g′ = refl

test-g″ : ∀ {n} → g (suc (suc n)) ≡ n
test-g″ = refl

------------------------------------------------------------------------
-- λs

postulate
  X Y : Set
  h   : X → Y

p : (x : X)(y : Y) → h x ≡ y → ⊤
p x .((λ x → x) (h x)) refl = _

pattern app x = x , .((λ x → x) (h x))

p′ : (p : X × Y) → h (proj₁ p) ≡ proj₂ p → ⊤
p′ (app x) refl = _

------------------------------------------------------------------------
-- records

record Rec : Set where
  constructor rr
  field
    r : ℕ

rrr : (x : Rec) → x ≡ record { r = 0 } → ⊤
rrr .(record { r = 0}) refl = _

rrr′ : (x : Rec) → x ≡ record { r = 0 } → ⊤
rrr′ .(rr 0) refl = _

rrrr : (a : Rec × ℕ) → proj₁ a ≡ record { r = proj₂ a } → ⊤
rrrr (.(rr 0)       , 0)     refl = _
rrrr (.(rr (suc n)) , suc n) refl = _

pattern pair x = (.(record { r = x }) , x)

rrrr′ : (a : Rec × ℕ) → proj₁ a ≡ record { r = proj₂ a } → ⊤
rrrr′ (pair 0)       refl = _
rrrr′ (pair (suc n)) refl = _

------------------------------------------------------------------------
-- lets

pp : (x : X)(y : Y) → h x ≡ y → ⊤
pp x .(let i = (λ x → x) in i (h x)) refl = _

pattern llet x = x , .(let i = (λ x → x) in i (h x))

pp′ : (p : X × Y) → h (proj₁ p) ≡ proj₂ p → ⊤
pp′ (llet x) refl = _

------------------------------------------------------------------------
-- absurd patterns

pattern absurd = ()

data ⊥ : Set where

⊥-elim : ∀ {A : Set} → ⊥ → A
⊥-elim absurd

------------------------------------------------------------------------
-- ambiguous constructors

data ℕ2 : Set where
  zero : ℕ2
  suc  : ℕ2 -> ℕ2

-- This needs a type signature, because it is ambiguous:
amb : ℕ2
amb = suc (suc zero)

-- This isn't ambiguous, because the overloading is resolved when the
-- pattern synonym is scope-checked:
unamb = ss z

------------------------------------------------------------------------
-- underscore

pattern trivial = ._

trivf : (a : ⊤) -> a ≡ tt -> ⊤
trivf trivial refl = trivial

------------------------------------------------------------------------
-- let open

pattern nuts = .(let open Σ in z)

foo : (n : ℕ) -> n ≡ z -> ℕ
foo nuts refl = nuts

------------------------------------------------------------------------
-- pattern synonym inside unparamterised module

module M where
  pattern sss x = suc (suc (suc x))

  a : ℕ
  a = sss 2

mb : ℕ
mb = M.sss 0

mf : ℕ -> ℕ -> ℕ
mf (M.sss _) = M.sss
mf _         = \ _ -> 0

{-
module M (A : Set)(a : A) where
  pattern peep x = x , .a

  pop : (z : A × A) -> proj₂ z ≡ a -> ⊤
  pop (peep x) refl = _

  peep' = peep

pop' : (z : ⊤ × ⊤) -> proj₂ z ≡ tt -> ⊤
pop' (M.peep tt) refl = _

peep' = M.peep
-}


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

module Bundles where

open import Algebra.Core
open import Quasigroup.Structures
open import Relation.Binary
open import Level
open import Algebra.Bundles
open import Algebra.Structures
open import Structures

record InverseSemigroup c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier            : Set c
    _≈_                : Rel Carrier ℓ
    _∙_                : Op₂ Carrier
    isInverseSemigroup : IsInverseSemigroup _≈_ _∙_

  open IsInverseSemigroup isInverseSemigroup public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (_≉_; rawMagma)

record Rng c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 -_
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _+_     : Op₂ Carrier
    _*_     : Op₂ Carrier
    -_      : Op₁ Carrier
    0#      : Carrier
    isRng  : IsRng _≈_ _+_ _*_ -_ 0#

  open IsRng isRng public

  +-abelianGroup : AbelianGroup _ _
  +-abelianGroup = record { isAbelianGroup = +-isAbelianGroup }

  *-semigroup : Semigroup _ _
  *-semigroup = record { isSemigroup = *-isSemigroup }

  open AbelianGroup +-abelianGroup public
    using () renaming (group to +-group; invertibleMagma to +-invertibleMagma; invertibleUnitalMagma to +-invertibleUnitalMagma)

  open Semigroup *-semigroup public
    using () renaming
    ( rawMagma to *-rawMagma
    ; magma    to *-magma
    )

record NonAssociativeRing c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 -_
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier               : Set c
    _≈_                   : Rel Carrier ℓ
    _+_                   : Op₂ Carrier
    _*_                   : Op₂ Carrier
    -_                    : Op₁ Carrier
    0#                    : Carrier
    1#                    : Carrier
    isNonAssociativeRing  : IsNonAssociativeRing _≈_ _+_ _*_ -_ 0# 1#

  open IsNonAssociativeRing isNonAssociativeRing public

  +-abelianGroup : AbelianGroup _ _
  +-abelianGroup = record { isAbelianGroup = +-isAbelianGroup }

  *-unitalmagma : UnitalMagma _ _
  *-unitalmagma = record { isUnitalMagma = *-isUnitalMagma }

  open AbelianGroup +-abelianGroup public
    using () renaming (group to +-group; invertibleMagma to +-invertibleMagma; invertibleUnitalMagma to +-invertibleUnitalMagma)

  open UnitalMagma *-unitalmagma public
    using () renaming
    ( rawMagma to *-rawMagma
    ; magma    to *-magma
    )


module Rationals.Add.Comm where

open import Equality
open import Function

open import Nats using (zero; ℕ)
                 renaming (suc to s; _+_ to _:+:_; _*_ to _:*:_)
open import Rationals
open import Rationals.Properties
open import Nats.Add.Comm
open import Nats.Multiply.Distrib
open import Nats.Multiply.Comm

------------------------------------------------------------------------
-- internal stuffs

private

  a/c+b/c=a*b/c : ∀ a b c → a ÷ c + b ÷ c ≡ (a :+: b) ÷ c
  a/c+b/c=a*b/c a b c
    rewrite (a :+: b) ÷ c ↑ c
          | sym $ nat-multiply-distrib a b c
            = refl

  a+b=b+a : ∀ x y → x + y ≡ y + x
  a+b=b+a (a ÷ c) (b ÷ d)
    rewrite a ÷ c ↑ d
          | b ÷ d ↑ c
          | a/c+b/c=a*b/c (a :*: d) (b :*: c) $ d :*: c
          | nat-add-comm (a :*: d) $ b :*: c
          | nat-multiply-comm c d
            = refl

------------------------------------------------------------------------
-- public aliases

rational-add-comm : ∀ x y → x + y ≡ y + x
rational-add-comm = a+b=b+a


------------------------------------------------------------------------
-- The Agda standard library
--
-- Bisimilarity for Colists
------------------------------------------------------------------------

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

module Codata.Colist.Bisimilarity where

open import Level using (_⊔_)
open import Size
open import Codata.Thunk
open import Codata.Colist
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as Eq using (_≡_)

data Bisim {a b r} {A : Set a} {B : Set b} (R : A → B → Set r) (i : Size) :
           (xs : Colist A ∞) (ys : Colist B ∞) → Set (r ⊔ a ⊔ b) where
  []  : Bisim R i [] []
  _∷_ : ∀ {x y xs ys} → R x y → Thunk^R (Bisim R) i xs ys → Bisim R i (x ∷ xs) (y ∷ ys)

module _ {a r} {A : Set a} {R : A → A → Set r} where

 reflexive : Reflexive R → ∀ {i} → Reflexive (Bisim R i)
 reflexive refl^R {i} {[]}     = []
 reflexive refl^R {i} {r ∷ rs} = refl^R ∷ λ where .force → reflexive refl^R

module _ {a b} {A : Set a} {B : Set b}
         {r} {P : A → B → Set r} {Q : B → A → Set r} where

 symmetric : Sym P Q → ∀ {i} → Sym (Bisim P i) (Bisim Q i)
 symmetric sym^PQ []       = []
 symmetric sym^PQ (p ∷ ps) = sym^PQ p ∷ λ where .force → symmetric sym^PQ (ps .force)

module _ {a b c} {A : Set a} {B : Set b} {C : Set c}
         {r} {P : A → B → Set r} {Q : B → C → Set r} {R : A → C → Set r} where

 transitive : Trans P Q R → ∀ {i} → Trans (Bisim P i) (Bisim Q i) (Bisim R i)
 transitive trans^PQR []       []       = []
 transitive trans^PQR (p ∷ ps) (q ∷ qs) =
   trans^PQR p q ∷ λ where .force → transitive trans^PQR (ps .force) (qs .force)

-- Pointwise Equality as a Bisimilarity
------------------------------------------------------------------------

module _ {ℓ} {A : Set ℓ} where

 infix 1 _⊢_≈_
 _⊢_≈_ : ∀ i → Colist A ∞ → Colist A ∞ → Set ℓ
 _⊢_≈_ = Bisim _≡_

 refl : ∀ {i} → Reflexive (i ⊢_≈_)
 refl = reflexive Eq.refl

 sym : ∀ {i} → Symmetric (i ⊢_≈_)
 sym = symmetric Eq.sym

 trans : ∀ {i} → Transitive (i ⊢_≈_)
 trans = transitive Eq.trans


{-# OPTIONS --without-K --safe #-}
module Categories.Functor.Construction.Diagonal where

-- A variety of Diagonal functors

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

open import Categories.Category
open import Categories.Functor
open import Categories.Category.Product
open import Categories.Category.Construction.Functors
open import Categories.Functor.Construction.Constant
open import Categories.NaturalTransformation using (ntHelper)

import Categories.Functor.Power as Power

private
  variable
    o ℓ e o′ ℓ′ e′ : Level

Δ : (C : Category o ℓ e) → Functor C (Product C C)
Δ C = record
  { F₀           = λ x → x , x
  ; F₁           = λ f → f , f
  ; identity     = refl , refl
  ; homomorphism = refl , refl
  ; F-resp-≈     = λ x → x , x
  }
  where
    open Category C
    open Equiv

Δ′ : (I : Set) → (C : Category o ℓ e) → Functor C (Power.Exp C I)
Δ′ I C = record
  { F₀           = λ x _ → x
  ; F₁           = λ f _ → f
  ; identity     = λ _ → refl
  ; homomorphism = λ _ → refl
  ; F-resp-≈     = λ x _ → x
  }
  where open Category.Equiv C

ΔF : {C : Category o ℓ e} (I : Category o′ ℓ′ e′) → Functor C (Functors I C)
ΔF {C = C} I = record
  { F₀           = const
  ; F₁           = λ f → ntHelper record { η = λ _ → f; commute = λ _ → C.identityʳ ○ ⟺ C.identityˡ }
  ; identity     = refl
  ; homomorphism = refl
  ; F-resp-≈     = λ x → x
  }
 where
   module C = Category C
   open C.Equiv
   open C.HomReasoning using (_○_; ⟺)


module Test2 where
   open import MiniHoTT

   A : Set
   A = ℕ

--  a, b : A

  {-
   [ a, b ] : List A
   [ a, b ] := inr ( a , ?)
    -- inr ((a, inr ( b, inl(unit))
    -}

   T : {A : Set} → (X : Set) → Set
   T {A} X = 𝟙 lzero + A × X -- This is an example of a polynomial functor.

   data
     List (A : Set)
      : Set
     where
     [] : List A
     cons : A → List A → List A

   data Vec (A : Set) : ℕ → Set
    where
    nil : ∀ n → Vec A n
    cons : ∀ n → A → Vec A n → Vec A (succ n)

   data Fin : ℕ →  Set
    where
    cero : ∀ {n} → Fin n
    succ : ∀ {n} → Fin n → Fin (succ n)

   at : ∀ {n : ℕ} {A : Set}
    → Vec A (succ n)
    → Fin (succ n)
    → A
   at v n = {!   !}

   go' : ∀ {n} {A : Set}
    → (Fin 0n → A) → Fin n → Vec A n
   go' pick cero     = nil _
   go' pick (succ n) = cons {!   !} (pick {! n  !})
    (go' {! pick    !} {!   !})

   record
     Algebra
      (A : Set)
      (T : Set → Set)
      : Set (lsuc lzero)
     where
     constructor algebra
     field
      X : Set
      μ : T X → X

   -- Objects: (X, μ)
   -- morphisms f : (X, μ) --> (Y, ν)
   --   this is given by α : X → Y, that makes the diagram commutes.
   -- Initial object: Object  (X, μ) + initiallity condition:
   --   Any other (Y, ν), there exists unique α : X → Y such that...

   list-is-an-algebra : (A : Set) → Algebra A (λ X → 𝟙 lzero + A × X)
   list-is-an-algebra A =
    algebra (List A) λ { (inl x) → []
                       ; (inr (a , xs)) → cons a xs
                       }

   -- where (T X -> X) is the type of list with elements of type A.
   -- elements? is TA a set?
   -- Yes, assuming A is a set. Let's find that.

   list-of-nats-is-set
     : A is-set
     → isSet (T A)
   list-of-nats-is-set A-is-set
    = +-set
        (prop-is-set 𝟙-is-prop)
        (∑-set
          A-is-set
          λ _ → A-is-set)

  -- T(X) = 1+X + (X ×X) a


------------------------------------------------------------------------
-- The Agda standard library
--
-- Basic definitions for morphisms between algebraic structures
------------------------------------------------------------------------

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

open import Relation.Binary.Core

module Algebra.Morphism.Definitions
  {a} (A : Set a)     -- The domain of the morphism
  {b} (B : Set b)     -- The codomain of the morphism
  {ℓ} (_≈_ : Rel B ℓ)  -- The equality relation over the codomain
  where

open import Algebra.Core
open import Function.Core

------------------------------------------------------------------------
-- Basic definitions

Homomorphic₀ : (A → B) → A → B → Set _
Homomorphic₀ ⟦_⟧ ∙ ∘ = ⟦ ∙ ⟧ ≈ ∘

Homomorphic₁ : (A → B) → Op₁ A → Op₁ B → Set _
Homomorphic₁ ⟦_⟧ ∙_ ∘_ = ∀ x → ⟦ ∙ x ⟧ ≈ (∘ ⟦ x ⟧)

Homomorphic₂ : (A → B) → Op₂ A → Op₂ B → Set _
Homomorphic₂ ⟦_⟧ _∙_ _∘_ = ∀ x y → ⟦ x ∙ y ⟧ ≈ (⟦ x ⟧ ∘ ⟦ y ⟧)

------------------------------------------------------------------------
-- DEPRECATED NAMES
------------------------------------------------------------------------
-- Please use the new names as continuing support for the old names is
-- not guaranteed.

-- Version 1.3

Morphism : Set _
Morphism = A → B

{-# WARNING_ON_USAGE Morphism
"Warning: Morphism was deprecated in v1.3.
Please use the standard function notation (e.g. A → B) instead."
#-}


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

module Bi.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

module Cp where
  infixl 1 _$_
  infixr 0 lam=>_
  infixr 0 abort=>_
  data Tm (tc : Cx) : Ty -> Set where
    var      : forall {a}     -> isTrue a tc               -> Tm tc a
    lam=>_   : forall {a b}   -> Tm (tc , a) b             -> Tm tc (a => b)
    _$_      : forall {a b}   -> Tm tc (a => b) -> Tm tc a -> Tm tc b
    pair'    : forall {a b}   -> Tm tc a        -> Tm tc b -> Tm tc (a && b)
    fst      : forall {a b}   -> Tm tc (a && b)            -> Tm tc a
    snd      : forall {a b}   -> Tm tc (a && b)            -> Tm tc b
    left     : forall {a b}   -> Tm tc a                   -> Tm tc (a || b)
    right    : forall {a b}   -> Tm tc b                   -> Tm tc (a || b)
    case'    : forall {a b c} -> Tm tc (a || b) -> Tm (tc , a) c -> Tm (tc , b) c -> Tm tc c
    abort=>_ : forall {a}     -> Tm (tc , NOT a) FALSE     -> Tm tc a

  syntax pair' x y    = [ x , y ]
  syntax case' xy x y = case xy => x => y

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

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

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

  Thm : Ty -> Set
  Thm a = forall {tc} -> Tm tc a
open Cp public


module Type.Identity.Proofs where

import      Lvl
open import Structure.Function
open import Structure.Relator.Properties
open import Structure.Relator
open import Structure.Type.Identity
open import Type.Identity
open import Type

private variable ℓ ℓ₁ ℓ₂ ℓₑ ℓₑ₁ ℓₑ₂ ℓₚ : Lvl.Level
private variable T A B : Type{ℓ}
private variable P : T → Type{ℓ}
private variable _▫_ : A → B → Type{ℓ}

instance
  Id-reflexivity : Reflexivity(Id{T = T})
  Reflexivity.proof Id-reflexivity = intro

instance
  Id-identityEliminator : IdentityEliminator{ℓₚ = ℓₚ}(Id{T = T})
  IdentityEliminator.elim Id-identityEliminator = elim

instance
  Id-identityEliminationOfIntro : IdentityEliminationOfIntro{ℓₘ = ℓ}(Id{T = T})(Id)
  IdentityEliminationOfIntro.proof Id-identityEliminationOfIntro P p = intro

instance
  Id-identityType : IdentityType(Id)
  Id-identityType = intro

{-
open import Logic.Propositional
open import Logic.Propositional.Equiv
open import Relator.Equals.Proofs
open import Structure.Setoid

te : ⦃ equiv-A : Equiv{ℓₑ}(A)⦄ → ∀{f : A → Type{ℓ}} → Function ⦃ equiv-A ⦄ ⦃ [↔]-equiv ⦄ (f)

test : ⦃ equiv-A : Equiv{ℓₑ}(A)⦄ → ∀{P : A → Type{ℓ}} → UnaryRelator ⦃ equiv-A ⦄ (P)
UnaryRelator.substitution test eq p = [↔]-to-[→] (Function.congruence te eq) p
-}


module Oscar.Class.TermSubstitution.Internal {𝔣} (FunctionName : Set 𝔣) where

open import Oscar.Data.Term.Core FunctionName
open import Oscar.Data.Nat.Core
open import Oscar.Data.Fin.Core
open import Oscar.Data.Vec.Core
open import Oscar.Data.Equality.Core
open import Oscar.Data.Product.Core
open import Oscar.Function
open import Oscar.Level

_⊸_ : (m n : ℕ) → Set 𝔣
m ⊸ n = Fin m → Term n

⊸-Property : {ℓ : Level} → ℕ → Set (lsuc ℓ ⊔ 𝔣)
⊸-Property {ℓ} m = ∀ {n} → m ⊸ n → Set ℓ

_≐_ : {m n : ℕ} → m ⊸ n → m ⊸ n → Set 𝔣
f ≐ g = ∀ x → f x ≡ g x

⊸-Extensional : {ℓ : Level} {m : ℕ} → ⊸-Property {ℓ} m → Set (ℓ ⊔ 𝔣)
⊸-Extensional P = ∀ {m f g} → f ≐ g → P {m} f → P g

⊸-ExtentionalProperty : {ℓ : Level} → ℕ → Set (lsuc ℓ ⊔ 𝔣)
⊸-ExtentionalProperty {ℓ} m = Σ (⊸-Property {ℓ} m) ⊸-Extensional

mutual

  _◃Term_ : ∀ {m n} → (f : m ⊸ n) → Term m → Term n
  f ◃Term i x = f x
  f ◃Term leaf = leaf
  f ◃Term (s fork t) = (f ◃Term s) fork (f ◃Term t)
  f ◃Term (function fn ts) = function fn (f ◃VecTerm ts) where

  _◃VecTerm_ : ∀ {N m n} → m ⊸ n → Vec (Term m) N → Vec (Term n) N
  f ◃VecTerm [] = []
  f ◃VecTerm (t ∷ ts) = f ◃Term t ∷ f ◃VecTerm ts

_◇_ : ∀ {l m n} → m ⊸ n → l ⊸ m → l ⊸ n
_◇_ f g = (f ◃Term_) ∘ g

record Substitution {a} (A : ℕ → Set a) : Set (a ⊔ 𝔣) where
  field
    _◃_ : ∀ {m n} → m ⊸ n → A m → A n
    ◃-extentionality : ∀ {m n} {f g : m ⊸ n} → f ≐ g → (t : A m) → f ◃ t ≡ g ◃ t
    ◃-identity : ∀ {n} → (t : A n) → i ◃ t ≡ t

  field
    ◃-associativity : ∀ {l m n} → {f : m ⊸ n} {g : _} (t : A l) → (f ◇ g) ◃ t ≡ f ◃ (g ◃ t)

  ⊸-Unifies : ∀ {m} (s t : A m) → ⊸-Property m
  ⊸-Unifies s t f = f ◃ s ≡ f ◃ t

open Substitution ⦃ … ⦄ public

{-# DISPLAY Substitution._◃_ _ = _◃_ #-}


module Data.Rational where

import Data.Bool as Bool
import Data.Nat as Nat
import Data.Integer as Int

open Int renaming
            ( _*_  to _*'_
            ; _+_  to _+'_
            ; -_   to -'_
            ; _-_  to _-'_
            ; !_!  to !_!'
            ; _==_ to _=='_
            ; _≤_  to _≤'_
            ; _≥_  to _≥'_
            ; _>_  to _>'_
            ; _<_  to _<'_
            )
open Nat using (Nat; zero; suc)
open Bool

infix  40 _==_ _<_ _>_ _≤_ _≥_
infixl 60 _+_ _-_
infixl 70 _%'_ _%_ _/_ _*_
infixr 80 _^_
infix  90 -_

data Rational : Set where
  _%'_  : Int -> Int -> Rational

numerator : Rational -> Int
numerator (n %' d) = n

denominator : Rational -> Int
denominator (n %' d) = d

_%_ : Int -> Int -> Rational
neg n       % neg m = pos (suc n) % pos (suc m)
pos 0       % neg m = pos 0 %' pos 1
pos (suc n) % neg m = neg n % pos (suc m)
x           % y     = div x z %' div y z
  where
    z = gcd x y

fromInt : Int -> Rational
fromInt x = x %' pos 1

fromNat : Nat -> Rational
fromNat x = fromInt (pos x)

_+_ : Rational -> Rational -> Rational
(a %' b) + (c %' d) = (a *' d +' c *' b) % (b *' d)

-_ : Rational -> Rational
- (a %' b) = -' a %' b

_-_ : Rational -> Rational -> Rational
a - b = a + (- b)

_/_ : Rational -> Rational -> Rational
(a %' b) / (c %' d) = (a *' d) % (b *' c)

_*_ : Rational -> Rational -> Rational
(a %' b) * (c %' d) = (a *' c) % (b *' d)

recip : Rational -> Rational
recip (a %' b) = b %' a

_^_ : Rational -> Int -> Rational
q ^ neg n       = recip q ^ pos (suc n)
q ^ pos zero    = fromNat 1
q ^ pos (suc n) = q * q ^ pos n

!_! : Rational -> Rational
! a %' b ! = pos ! a !' %' pos ! b !'

round : Rational -> Int
round (a %' b) = div (a +' div b (pos 2)) b

_==_ : Rational -> Rational -> Bool
(a %' b) == (c %' d) = a *' d ==' b *' c

_<_ : Rational -> Rational -> Bool
(a %' b) < (c %' d) = a *' d <' b *' c

_>_ : Rational -> Rational -> Bool
(a %' b) > (c %' d) = a *' d >' b *' c

_≤_ : Rational -> Rational -> Bool
(a %' b) ≤ (c %' d) = a *' d ≤' b *' c

_≥_ : Rational -> Rational -> Bool
(a %' b) ≥ (c %' d) = a *' d ≥' b *' c

max : Rational -> Rational -> Rational
max a b = if a < b then b else a

min : Rational -> Rational -> Rational
min a b = if a < b then a else b