{- Name: Bowornmet (Ben) Hudson

--Type safety and meaning functions for L{⇒,+,×,unit}--

-}

open import Preliminaries
open import Preorder
open import Preorder-repackage

module L where

  -- => and + and × and unit
  data Typ : Set where
    _⇒_ : Typ → Typ → Typ
    _×'_ : Typ → Typ → Typ
    _+'_ : Typ → Typ → Typ
    unit : Typ

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

  -- represent a context as a list of types
  Ctx = List Typ

  -- de Bruijn indices (for free variables)
  data _∈_ : Typ → Ctx → Set where
    i0 : ∀ {Γ τ}
       → τ ∈ (τ :: Γ)
    iS : ∀ {Γ τ τ1}
       → τ ∈ Γ
       → τ ∈ (τ1 :: Γ)

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

  -- static semantics
  data _|-_ : Ctx → Typ → Set where
    var : ∀ {Γ τ}
        → (x : τ ∈ Γ) → Γ |- τ
    lam : ∀ {Γ τ ρ}
        → (x : (ρ :: Γ) |- τ)
        → Γ |- (ρ ⇒ τ)
    app : ∀ {Γ τ1 τ2}
       → (e1 : Γ |- (τ2 ⇒ τ1)) → (e2 : Γ |- τ2)
       → Γ |- τ1
    unit : ∀ {Γ}
         → Γ |- unit
    prod : ∀ {Γ τ1 τ2}
         → (e1 : Γ |- τ1) → (e2 : Γ |- τ2)
         → Γ |- (τ1 ×' τ2)
    l-proj : ∀ {Γ τ1 τ2}
           → (e : Γ |- (τ1 ×' τ2))
           → Γ |- τ1
    r-proj : ∀ {Γ τ1 τ2}
           → (e : Γ |- (τ1 ×' τ2))
           → Γ |- τ2
    inl : ∀ {Γ τ1 τ2}
        → (e : Γ |- τ1)
        → Γ |- (τ1 +' τ2)
    inr : ∀ {Γ τ1 τ2}
        → (e : Γ |- τ2)
        → Γ |- (τ1 +' τ2)
    case` : ∀ {Γ τ1 τ2 τ}
         → (e : Γ |- (τ1 +' τ2))
         → (e1 : (τ1 :: Γ) |- τ)
         → (e2 : (τ2 :: Γ) |- τ)
         → Γ |- τ

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

  -- renaming
  rctx : Ctx → Ctx → Set
  rctx Γ Γ' = ∀ {τ} → τ ∈ Γ' → τ ∈ Γ

  -- re: transferring variables in contexts
  lem1 : ∀ {Γ Γ' τ} → rctx Γ Γ' → rctx (τ :: Γ) (τ :: Γ')
  lem1 d i0 = i0
  lem1 d (iS x) = iS (d x)

  -- renaming lemma
  ren : ∀ {Γ Γ' τ} → Γ' |- τ → rctx Γ Γ' → Γ |- τ
  ren (var x) d = var (d x)
  ren (lam e) d = lam (ren e (lem1 d))
  ren (app e1 e2) d = app (ren e1 d) (ren e2 d)
  ren unit d = unit
  ren (prod e1 e2) d = prod (ren e1 d) (ren e2 d)
  ren (l-proj e) d = l-proj (ren e d)
  ren (r-proj e) d = r-proj (ren e d)
  ren (inl x) d = inl (ren x d)
  ren (inr x) d = inr (ren x d)
  ren (case` e e1 e2) d = case` (ren e d) (ren e1 (lem1 d)) (ren e2 (lem1 d))

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

  -- substitution
  sctx : Ctx → Ctx → Set
  sctx Γ Γ' = ∀ {τ} → τ ∈ Γ' → Γ |- τ

  -- weakening (didn't need this later on. Oh well)
  wkn : ∀ {Γ τ1 τ2} → Γ |- τ2 → (τ1 :: Γ) |- τ2
  wkn e = ren e iS

  -- lem2 (need a lemma for subst like we did for renaming)
  lem2 : ∀ {Γ Γ' τ} → sctx Γ Γ' → sctx (τ :: Γ) (τ :: Γ')
  lem2 d i0 = var i0
  lem2 d (iS i0) = ren (d i0) iS
  lem2 d (iS (iS i)) = ren (d (iS i)) iS

  -- another substitution lemma
  lem3 : ∀ {Γ τ} → Γ |- τ → sctx Γ (τ :: Γ)
  lem3 d i0 = d
  lem3 d (iS i) = var i

  -- one final lemma needed for the last stepping rule. Thank you Professor Licata!
  lem4 : ∀ {Γ τ1 τ2} → Γ |- τ1 → Γ |- τ2 → sctx Γ (τ1 :: (τ2 :: Γ))
  lem4 x y i0 = x
  lem4 x y (iS i0) = y
  lem4 x y (iS (iS i)) = var i

  -- the 'real' substitution lemma
  subst : ∀ {Γ Γ' τ} → sctx Γ Γ' → Γ' |- τ → Γ |- τ
  subst d (var x) = d x
  subst d (lam e) = lam (subst (lem2 d) e)
  subst d (app e1 e2) = app (subst d e1) (subst d e2)
  subst d unit = unit
  subst d (prod e1 e2) = prod (subst d e1) (subst d e2)
  subst d (l-proj e) = l-proj (subst d e)
  subst d (r-proj e) = r-proj (subst d e)
  subst d (inl x) = inl (subst d x)
  subst d (inr x) = inr (subst d x)
  subst d (case` e e1 e2) = case` (subst d e) (subst (lem2 d) e1) (subst (lem2 d) e2)

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

  -- closed values of L (when something is a value)
  -- recall that we use empty contexts when we work with dynamic semantics
  data val : ∀ {τ} → [] |- τ → Set where
    unit-isval : val unit
    lam-isval : ∀ {ρ τ} (e : (ρ :: []) |- τ)
              → val (lam e)
    prod-isval : ∀ {τ1 τ2}
               → (e1 : [] |- τ1) → (e2 : [] |- τ2)
               → val e1 → val e2
               → val (prod e1 e2)
    inl-isval : ∀ {τ1 τ2}
              → (e : [] |- τ1)
              → val e
              → val (inl {_} {_} {τ2} e)
    inr-isval : ∀ {τ1 τ2}
              → (e : [] |- τ2)
              → val e
              → val (inr {_} {τ1} {_} e)

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

  -- stepping rules (preservation is folded into this)
  -- Preservation: if e:τ and e=>e', then e':τ
  data _>>_ : ∀ {τ} → [] |- τ → [] |- τ → Set where
     app-steps : ∀ {τ1 τ2}
              → (e1 e1' : [] |- (τ2 ⇒ τ1)) → (e2 : [] |- τ2)
              → e1 >> e1'
              → (app e1 e2) >> (app e1' e2)
     app-steps-2 : ∀ {τ1 τ2}
                → (e1 : [] |- (τ2 ⇒ τ1)) → (e2 e2' : [] |- τ2)
                → val e1 → e2 >> e2'
                → (app e1 e2) >> (app e1 e2')
     app-steps-3 : ∀ {τ1 τ2}
                → (e1 : (τ1 :: []) |- τ2)
                → (e2 : [] |- τ1)
                → (app (lam e1) e2) >> subst (lem3 e2) e1
     prod-steps : ∀ {τ1 τ2}
                → (e1 e1' : [] |- τ1) → (e2 : [] |- τ2)
                → e1 >> e1'
                → (prod e1 e2) >> (prod e1' e2)
     prod-steps-2 : ∀ {τ1 τ2}
                  → (e1 : [] |- τ1) → (e2 e2' : [] |- τ2)
                  → val e1 → e2 >> e2'
                  → (prod e1 e2) >> (prod e1 e2')
     l-proj-steps : ∀ {τ1 τ2}
                  → (e e' : [] |- (τ1 ×' τ2))
                  → e >> e'
                  → (l-proj e) >> (l-proj e')
     l-proj-steps-2 : ∀ {τ1 τ2}
                    → (e1 : [] |- τ1) → (e2 : [] |- τ2)
                    → val e1 → val e2
                    → (l-proj (prod e1 e2)) >> e1
     r-proj-steps : ∀ {τ1 τ2}
                  → (e e' : [] |- (τ1 ×' τ2))
                  → e >> e'
                  → (r-proj e) >> (r-proj e')
     r-proj-steps-2 : ∀ {τ1 τ2}
                    → (e1 : [] |- τ1) → (e2 : [] |- τ2)
                    → val e1 → val e2
                    → (r-proj (prod e1 e2)) >> e2
     inl-steps : ∀ {τ1 τ2}
               → (e e' : [] |- τ1)
               → e >> e'
               → inl {_} {_} {τ2} e >> inl e'
     inr-steps : ∀ {τ1 τ2}
               → (e e' : [] |- τ2)
               → e >> e'
               → inr {_} {τ1} {_} e >> inr e'
     case`-steps : ∀ {τ1 τ2 τ}
                 → (e e' : [] |- (τ1 +' τ2))
                 → (e1 : (τ1 :: []) |- τ)
                 → (e2 : (τ2 :: []) |- τ)
                 → e >> e'
                 → (case` e e1 e2) >> (case` e' e1 e2)
     case`-steps-2 : ∀ {τ1 τ2 τ}
                   → (e : [] |- τ1)
                   → (e1 : (τ1 :: []) |- τ)
                   → (e2 : (τ2 :: []) |- τ)
                   → val e
                   → (case` (inl e) e1 e2) >> subst (lem3 e) e1
     case`-steps-3 : ∀ {τ1 τ2 τ}
                   → (e : [] |- τ2)
                   → (e1 : (τ1 :: []) |- τ)
                   → (e2 : (τ2 :: []) |- τ)
                   → val e
                   → (case` (inr e) e1 e2) >> subst (lem3 e) e2

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

  -- Proof of progress!
  -- Progress: if e:τ, then either e val or ∃e' such that e=>e'
  progress : ∀ {τ} (e : [] |- τ) → Either (val e) (Σ (λ e' → (e >> e')))
  progress (var ())
  progress (lam x) = Inl (lam-isval x)
  progress (app e1 e2) with progress e1
  progress (app .(lam e) e2) | Inl (lam-isval e) = Inr (_ , app-steps-3 e e2)
  progress (app e1 e2) | Inr (x , d) = Inr (_ , app-steps e1 x e2 d)
  progress unit = Inl unit-isval
  progress (prod e1 e2) with progress e1
  progress (prod e1 e2) | Inl d with progress e2
  progress (prod e1 e2) | Inl d | Inl x = Inl (prod-isval e1 e2 d x)
  progress (prod e1 e2) | Inl d | Inr (x , k) = Inr (_ , prod-steps-2 e1 e2 x d k)
  progress (prod e1 e2) | Inr (x , d) = Inr (_ , prod-steps e1 x e2 d)
  progress (l-proj e) with progress e
  progress (l-proj .(prod e1 e2)) | Inl (prod-isval e1 e2 d d₁) = Inr (_ , l-proj-steps-2 e1 e2 d d₁)
  progress (l-proj e) | Inr (x , d) = Inr (_ , l-proj-steps e x d)
  progress (r-proj e) with progress e
  progress (r-proj .(prod e1 e2)) | Inl (prod-isval e1 e2 d d₁) = Inr (_ , r-proj-steps-2 e1 e2 d d₁)
  progress (r-proj e) | Inr (x , d) = Inr (_ , r-proj-steps e x d)
  progress (inl e) with progress e
  progress (inl e) | Inl x = Inl (inl-isval e x)
  progress (inl e) | Inr (x , d) = Inr (_ , inl-steps e x d)
  progress (inr e) with progress e
  progress (inr e) | Inl x = Inl (inr-isval e x)
  progress (inr e) | Inr (x , d) = Inr (_ , inr-steps e x d)
  progress (case` e e1 e2) with progress e
  progress (case` .(inl e) e1 e2) | Inl (inl-isval e x) = Inr (_ , case`-steps-2 e e1 e2 x)
  progress (case` .(inr e) e1 e2) | Inl (inr-isval e x) = Inr (_ , case`-steps-3 e e1 e2 x)
  progress (case` e e1 e2) | Inr (x , d) = Inr (_ , case`-steps e x e1 e2 d)

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

  -- how to interpret types in L as preorders

  interp : Typ → PREORDER
  interp (A ⇒ B) = interp A ->p interp B
  interp (A ×' B) = interp A ×p interp B
  interp (A +' B) = interp A +p interp B
  interp unit = unit-p

  interpC : Ctx → PREORDER
  interpC [] = unit-p
  interpC (A :: Γ) = interpC Γ ×p interp A

  -- look up a variable in context
  lookup : ∀{Γ τ} → τ ∈ Γ → el (interpC Γ ->p interp τ)
  lookup (i0 {Γ} {τ}) = snd' {interpC (τ :: Γ)} {interpC Γ} {_} id
  lookup (iS {Γ} {τ} {τ1} x) = comp {interpC (τ1 :: Γ)} {_} {_} (fst' {interpC (τ1 :: Γ)} {_} {interp τ1} id) (lookup x)

  interpE : ∀{Γ τ} → Γ |- τ → el (interpC Γ ->p interp τ)
  interpE (var x) = lookup x
  interpE (lam e) = lam' (interpE e)
  interpE (app e1 e2) = app' (interpE e1) (interpE e2)
  interpE unit = monotone (λ _ → <>) (λ x y _ → <>)
  interpE (prod e1 e2) = pair' (interpE e1) (interpE e2)
  interpE (l-proj {Γ} {τ1} {τ2} e) = fst' {_} {_} {interp τ2} (interpE e)
  interpE (r-proj {Γ} {τ1} {τ2} e) = snd' {_} {interp τ1} {_} (interpE e)
  interpE (inl e) = inl' (interpE e)
  interpE (inr e) = inr' (interpE e)
  interpE (case` e e1 e2) = case' (interpE e1) (interpE e2) (interpE e)


{-# OPTIONS --safe #-}
module Cubical.Algebra.CommRing.QuotientRing where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Structure
open import Cubical.Foundations.Powerset

open import Cubical.Data.Nat
open import Cubical.Data.FinData

open import Cubical.HITs.SetQuotients using ([_]; squash/; elimProp2)
open import Cubical.HITs.PropositionalTruncation as PT

open import Cubical.Algebra.CommRing
open import Cubical.Algebra.CommRing.Ideal
open import Cubical.Algebra.CommRing.FGIdeal
open import Cubical.Algebra.CommRing.Kernel
open import Cubical.Algebra.Ring
import Cubical.Algebra.Ring.QuotientRing as Ring

private
  variable
    ℓ ℓ' : Level

_/_ : (R : CommRing ℓ) → (I : IdealsIn R) → CommRing ℓ
R / I =
  fst asRing , commringstr _ _ _ _ _
                 (iscommring (RingStr.isRing (snd asRing))
                             (elimProp2 (λ _ _ → squash/ _ _)
                                        commEq))
   where
       asRing = (CommRing→Ring R) Ring./ (CommIdeal→Ideal I)
       _·/_ : fst asRing → fst asRing → fst asRing
       _·/_ = RingStr._·_ (snd asRing)
       commEq : (x y : fst R) → ([ x ] ·/ [ y ]) ≡ ([ y ] ·/ [ x ])
       commEq x y i = [ CommRingStr.·Comm (snd R) x y i ]

[_]/ : {R : CommRing ℓ} {I : IdealsIn R} → (a : fst R) → fst (R / I)
[ a ]/ = [ a ]

module Quotient-FGideal-CommRing-Ring
  (A : CommRing ℓ)
  (B : Ring ℓ')
  (g : RingHom (CommRing→Ring A) B)
  {n : ℕ}
  (v : FinVec ⟨ A ⟩ n)
  (gnull : (k : Fin n) → g $ v k ≡ RingStr.0r (snd B))
  where

  open RingStr (snd B) using (0r)

  zeroOnGeneratedIdeal : (x : ⟨ A ⟩) → x ∈ fst (generatedIdeal A v) → g $ x ≡ 0r
  zeroOnGeneratedIdeal x x∈FGIdeal =
    PT.elim
      (λ _ → isSetRing B (g $ x) 0r)
      (λ {(α , isLC) → subst _ (sym isLC) (cancelLinearCombination A B g _ α v gnull)})
      x∈FGIdeal

  inducedHom : RingHom (CommRing→Ring (A / (generatedIdeal _ v))) B
  inducedHom = Ring.UniversalProperty.inducedHom (CommRing→Ring A) (CommIdeal→Ideal ideal) g zeroOnGeneratedIdeal
    where ideal = generatedIdeal A v

module Quotient-FGideal-CommRing-CommRing
  (A : CommRing ℓ)
  (B : CommRing ℓ')
  (g : CommRingHom A B)
  {n : ℕ}
  (v : FinVec ⟨ A ⟩ n)
  (gnull : (k : Fin n) → g $ v k ≡ CommRingStr.0r (snd B))
  where

  inducedHom : CommRingHom (A / (generatedIdeal _ v)) B
  inducedHom = Quotient-FGideal-CommRing-Ring.inducedHom A (CommRing→Ring B) g v gnull

quotientHom : (R : CommRing ℓ) → (I : IdealsIn R) → CommRingHom R (R / I)
quotientHom R I = Ring.quotientHom (CommRing→Ring R) (CommIdeal→Ideal I)

module _ {R : CommRing ℓ} (I : IdealsIn R) where
  private
    π = quotientHom R I

  kernel≡I : kernelIdeal R (R / I) π ≡ I
  kernel≡I = cong Ideal→CommIdeal (Ring.kernel≡I (CommIdeal→Ideal I))


module Issue268 where

module Example₁ where
  open import Common.Coinduction

  module Record where

    record Stream : Set where
      constructor cons
      field
        tail : ∞ Stream

  module Data where

    data Stream : Set where
      cons : ∞ Stream → Stream

  -- open Data
  open Record

  id : Stream → Stream
  id (cons xs) = cons (♯ id (♭ xs))

  postulate
    P  : Stream → Set
    f  : ∀ xs → P (id xs) → Set
    xs : Stream
    p  : P (id xs)

  Foo : Set
  Foo = f _ p

  -- The code type checks when Data is opened, but not when Record is
  -- opened:
  --
  -- Bug.agda:34,11-12
  -- (Stream.tail (id xs)) != (.Bug.♯-0 _40) of type (∞ Stream)
  -- when checking that the expression p has type P (id (cons _40))

module Example₂ where

  data D : Set where
    d : D

  id : D → D
  id d = d

  module Record where

    record E : Set where
      constructor e
      field
        f : D

  module Data where

    data E : Set where
      e : D → E

  -- open Data
  open Record

  id′ : E → E
  id′ (e xs) = e (id xs)

  postulate
    P : E → Set
    f : (x : E) → P (id′ x) → Set
    x : E
    p : P (id′ x)

  Foo : Set
  Foo = f _ p


open import Data.Nat
module OpenTheory where

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

data Vec (A : Set) : ℕ → Set₁ where
  nil : Vec A zero
  cons : (n : ℕ) (x : A) (xs : Vec A n) → Vec A (suc n)

data Vec2 : Set → ℕ → Set₁ where
  nil : (A : Set) → Vec2 A zero
  cons : (A : Set) (n : ℕ) (x : A) (xs : Vec2 A n) → Vec2 A (suc n)

elimVec : {A : Set} (P : (n : ℕ) → Vec A n → Set)
  (pnil : P zero nil)
  (pcnons : (n : ℕ) (x : A) (xs : Vec A n) → P n xs → P (suc n) (cons n x xs))
  (n : ℕ) (xs : Vec A n) → P n xs
elimVec P pnil pcons .zero nil = pnil
elimVec P pnil pcons .(suc n) (cons n x xs) = pcons n x xs (elimVec P pnil pcons n xs)

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

data Tree (A B : Set) : ℕ → ℕ → Set where
  leaf₁ : A → Tree A B (suc zero) zero
  leaf₂ : B → Tree A B zero (suc zero)
  branch : (m n x y : ℕ)
    → Tree A B m n → Tree A B x y
    → Tree A B (m + x) (n + y)

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


{-# OPTIONS --safe #-}
module Cubical.Categories.Instances.CommAlgebras where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.Powerset

open import Cubical.Algebra.CommRing
open import Cubical.Algebra.Algebra
open import Cubical.Algebra.CommAlgebra

open import Cubical.Categories.Category
open import Cubical.Categories.Functor.Base

open import Cubical.HITs.PropositionalTruncation

open Category
open CommAlgebraHoms

private
 variable
  ℓ ℓ' ℓ'' : Level

module _ (R : CommRing ℓ) where
  CommAlgebrasCategory : Category (ℓ-suc (ℓ-max ℓ ℓ')) (ℓ-max ℓ ℓ')
  ob CommAlgebrasCategory       = CommAlgebra R _
  Hom[_,_] CommAlgebrasCategory = CommAlgebraHom
  id CommAlgebrasCategory {A}   = idCommAlgebraHom A
  _⋆_ CommAlgebrasCategory {A} {B} {C}     = compCommAlgebraHom A B C
  ⋆IdL CommAlgebrasCategory {A} {B}           = compIdCommAlgebraHom {A = A} {B}
  ⋆IdR CommAlgebrasCategory {A} {B}           = idCompCommAlgebraHom {A = A} {B}
  ⋆Assoc CommAlgebrasCategory {A} {B} {C} {D} = compAssocCommAlgebraHom {A = A} {B} {C} {D}
  isSetHom CommAlgebrasCategory               = isSetAlgebraHom _ _

module PreSheafFromUniversalProp (C : Category ℓ ℓ') (P : ob C → Type ℓ)
         {R : CommRing ℓ''} (𝓕 : Σ (ob C) P → CommAlgebra R ℓ'')
         (uniqueHom : ∀ x y → C [ fst x , fst y ] → isContr (CommAlgebraHom (𝓕 y) (𝓕 x)))
         where

 private
  ∥P∥ : ℙ (ob C)
  ∥P∥ x  = ∥ P x ∥ , isPropPropTrunc
  ΣC∥P∥Cat = ΣPropCat C ∥P∥

 𝓕UniqueEquiv : (x : ob C) (p q : P x) → isContr (CommAlgebraEquiv (𝓕 (x , p)) (𝓕 (x , q)))
 𝓕UniqueEquiv x = contrCommAlgebraHom→contrCommAlgebraEquiv (curry 𝓕 x) λ p q → uniqueHom _ _ (id C)

 theMap : (x : ob C) → ∥ P x ∥ → CommAlgebra R ℓ''
 theMap x = recPT→CommAlgebra (curry 𝓕 x) (λ p q → 𝓕UniqueEquiv x p q .fst)
                                         λ p q r → 𝓕UniqueEquiv x p r .snd _

 theAction : (x y : ob C) → C [ x , y ]
           → (p : ∥ P x ∥) (q : ∥ P y ∥) → isContr (CommAlgebraHom (theMap y q) (theMap x p))
 theAction _ _ f = elim2 (λ _ _ → isPropIsContr) λ _ _ → uniqueHom _ _ f

 open Functor
 universalPShf : Functor (ΣC∥P∥Cat ^op) (CommAlgebrasCategory {ℓ = ℓ''} R {ℓ' = ℓ''})
 F-ob universalPShf = uncurry theMap
 F-hom universalPShf {x = x} {y = y} f = theAction _ _ f (y .snd) (x. snd) .fst
 F-id universalPShf {x = x} = theAction (x .fst) (x .fst) (id C) (x .snd) (x .snd) .snd _
 F-seq universalPShf {x = x} {z = z} f g = theAction _ _ (g ⋆⟨ C ⟩ f) (z .snd) (x .snd) .snd _


{-
   FP Lunch, Nottingham
   July 27, 2007
   Conor McBride
-}

module Binary where

data Bit : Set where
  O : Bit
  I : Bit

infixl 80 _◃_

data Pos : Set where
  ◃I  : Pos
  _◃_ : Pos -> Bit -> Pos

bsuc : Pos -> Pos
bsuc ◃I      = ◃I ◃ O
bsuc (n ◃ O) = n ◃ I
bsuc (n ◃ I) = bsuc n ◃ O

data Peano : Pos -> Set where
  pI   : Peano ◃I
  psuc : {n : Pos} -> Peano n -> Peano (bsuc n)

pdouble : {n : Pos} -> Peano n -> Peano (n ◃ O)
pdouble pI       = psuc pI
pdouble (psuc p) = psuc (psuc (pdouble p))

peano : (n : Pos) -> Peano n
peano ◃I      = pI
peano (n ◃ O) = pdouble (peano n)
peano (n ◃ I) = psuc (pdouble (peano n))

-- Slow addition (yay!)
_+_ : Pos -> Pos -> Pos
_+_ n m = peano n ⊕ m
  where
    _⊕_ : {n : Pos} -> Peano n -> Pos -> Pos
    pI     ⊕ m = bsuc m
    psuc p ⊕ m = bsuc (p ⊕ m)

infixl 60 _+_
infix  40 _==_

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

test : (◃I ◃ I ◃ O ◃ O ◃ O) == (◃I ◃ I ◃ O ◃ I) + (◃I ◃ O ◃ I ◃ I)
test = refl


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

open import HoTT
open import homotopy.RibbonCover
import homotopy.CoverClassification

module experimental.CoverClassificationCat {i} (A∙ : Ptd i)
  (A-conn : is-connected 0 (fst A∙)) where

  open Cover
  open Gset
  open homotopy.CoverClassification A∙ A-conn

  private
    A : Type i
    A = fst A∙
    a₁ : A
    a₁ = snd A∙
    π1A = fundamental-group A∙

  -- A covering space constructed from a G-set.
  cover-hom-to-gset-hom : ∀ {j}
    → {cov₁ cov₂ : Cover A j}
    → CoverHom cov₁ cov₂
    → GsetHom (cover-to-gset cov₁) (cover-to-gset cov₂)
  cover-hom-to-gset-hom {cov₁ = cov₁}{cov₂} f = record
    { f = f a₁
    ; pres-act = λ l x → lemma₂ x l
    }
    where
      lemma₁ : ∀ x {a₂} (p : a₁ == a₂)
        → f a₂ (transport (Fiber cov₁) p x)
        == transport (Fiber cov₂) p (f a₁ x)
      lemma₁ _ idp = idp

      lemma₂ : ∀ x {a₂} (p : a₁ =₀ a₂)
        → f a₂ (transport₀ (Fiber cov₁) (Fiber-level cov₁ a₂) p x)
        == transport₀ (Fiber cov₂) (Fiber-level cov₂ a₂) p (f a₁ x)
      lemma₂ x {a₂} = Trunc-elim
        (λ p → =-preserves-level 0 (Fiber-level cov₂ a₂))
        (lemma₁ x {a₂})

  gset-hom-to-cover-hom : ∀ {j}
    → {gset₁ gset₂ : Gset π1A j}
    → GsetHom gset₁ gset₂
    → CoverHom (gset-to-cover gset₁) (gset-to-cover gset₂)
  gset-hom-to-cover-hom {gset₁ = gset₁}{gset₂} (gset-hom f pres-act) a₂ =
    Ribbon-rec
      {P = Ribbon A∙ gset₂ a₂}
      Ribbon-level
      (λ el p → trace (f el) p)
      (λ el loop p →
        trace (f (act gset₁ el loop)) p
          =⟨ pres-act loop el |in-ctx (λ x → trace x p) ⟩
        trace (act gset₂ (f el) loop) p
          =⟨ paste (f el) loop p ⟩
        trace (f el) (loop ∙₀ p)
          ∎)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Induction over Subset
------------------------------------------------------------------------

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

module Data.Fin.Subset.Induction where

open import Data.Nat.Base using (ℕ)
open import Data.Nat.Induction using (<-wellFounded)
open import Data.Fin.Subset using (Subset; _⊂_; ∣_∣)
open import Data.Fin.Subset.Properties
open import Induction
open import Induction.WellFounded as WF

------------------------------------------------------------------------
-- Re-export accessability

open WF public using (Acc; acc)

------------------------------------------------------------------------
-- Complete induction based on _⊂_

⊂-Rec : ∀ {n ℓ} → RecStruct (Subset n) ℓ ℓ
⊂-Rec = WfRec _⊂_

⊂-wellFounded : ∀ {n} → WellFounded (_⊂_ {n})
⊂-wellFounded {n} = Subrelation.wellFounded p⊂q⇒∣p∣<∣q∣ (InverseImage.wellFounded ∣_∣ <-wellFounded)


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

-- 'Traditionally', meaning in nLab and in
-- "Lectures on n-Categories and Cohomology" by Baez and Shulman
-- https://arxiv.org/abs/math/0608420
-- (-2)-Categories are defined to be just a single value, with trivial Hom

-- But that's hardly a definition of a class of things, it's a definition of
-- a single structure!  What we want is the definition of a class which turns
-- out to be (essentially) unique. Rather like the reals are (essentially) the
-- only ordered complete archimedean field.

-- So we will take a -2-Category to be a full-fledge Category, but where
-- 1. |Obj| is (Categorically) contractible
-- 2. |Hom| is connected (all arrows are equal)
-- Note that we don't need to say anything at all about ≈

module Categories.Minus2-Category where

open import Level
open import Categories.Category
open import Data.Product using (Σ)
import Categories.Morphism as M

private
  variable
    o ℓ e : Level

record -2-Category : Set (suc (o ⊔ ℓ ⊔ e)) where
   field
     cat : Category o ℓ e
   open Category cat public
   open M cat using (_≅_)

   field
     Obj-Contr : Σ Obj (λ x → (y : Obj) → x ≅ y)
     Hom-Conn  : {x y : Obj} {f g : x ⇒ y} → f ≈ g


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

module Level where

open import Agda.Primitive
  using (Level)
  renaming ( _⊔_ to _ℓ⊔_
           ; lzero to ℓzero
           ; lsuc  to ℓsuc
           ; Set to Type
           )
  public

variable
  a b c : Level
  A  : Type a
  B  : Type b
  C  : Type c


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

open import lib.Basics
open import lib.NType2
open import lib.types.Int
open import lib.types.Group
open import lib.types.List
open import lib.types.Word
open import lib.groups.Homomorphism
open import lib.groups.Isomorphism
open import lib.groups.FreeAbelianGroup
open import lib.types.SetQuotient

module lib.groups.Int where

ℤ-group-structure : GroupStructure ℤ
ℤ-group-structure = record
  { ident = 0
  ; inv = ℤ~
  ; comp = _ℤ+_
  ; unit-l = ℤ+-unit-l
  ; assoc = ℤ+-assoc
  ; inv-l = ℤ~-inv-l
  }

ℤ-group : Group₀
ℤ-group = group _ ℤ-group-structure

ℤ-group-is-abelian : is-abelian ℤ-group
ℤ-group-is-abelian = ℤ+-comm

ℤ-abgroup : AbGroup₀
ℤ-abgroup = ℤ-group , ℤ-group-is-abelian

ℤ-iso-FreeAbGroup-Unit : ℤ-group ≃ᴳ FreeAbGroup.grp Unit
ℤ-iso-FreeAbGroup-Unit = ≃-to-≃ᴳ (equiv to from to-from from-to) to-pres-comp where
  to = FreeAbGroup.exp Unit fs[ inl unit :: nil ]
  from = FormalSum-extend ℤ-abgroup (λ _ → 1)
  abstract
    to-pres-comp = FreeAbGroup.exp-+ Unit fs[ inl unit :: nil ]

    to-from' : ∀ l → to (Word-extendᴳ ℤ-group (λ _ → 1) l) == fs[ l ]
    to-from' nil = idp
    to-from' (inl unit :: l) =
        FreeAbGroup.exp-succ Unit fs[ inl unit :: nil ] (Word-extendᴳ ℤ-group (λ _ → 1) l)
      ∙ ap (FreeAbGroup.comp Unit fs[ inl unit :: nil ]) (to-from' l)
    to-from' (inr unit :: l) =
        FreeAbGroup.exp-pred Unit fs[ inl unit :: nil ] (Word-extendᴳ ℤ-group (λ _ → 1) l)
      ∙ ap (FreeAbGroup.comp Unit fs[ inr unit :: nil ]) (to-from' l)

    to-from : ∀ fs → to (from fs) == fs
    to-from = FormalSum-elim to-from' (λ _ → prop-has-all-paths-↓)

    from-to : ∀ z → from (to z) == z
    from-to (pos 0) = idp
    from-to (pos 1) = idp
    from-to (negsucc 0) = idp
    from-to (pos (S (S n))) =
        GroupHom.pres-comp (FreeAbGroup-extend ℤ-abgroup (λ _ → 1))
          fs[ inl unit :: nil ] (FreeAbGroup.exp Unit fs[ inl unit :: nil ] (pos (S n)))
      ∙ ap succ (from-to (pos (S n)))
    from-to (negsucc (S n)) =
        GroupHom.pres-comp (FreeAbGroup-extend ℤ-abgroup (λ _ → 1))
          fs[ inr unit :: nil ] (FreeAbGroup.exp Unit fs[ inl unit :: nil ] (negsucc n))
      ∙ ap pred (from-to (negsucc n))

exp-shom : ∀ {i} {GEl : Type i} (GS : GroupStructure GEl) (g : GEl) → ℤ-group-structure →ᴳˢ GS
exp-shom GS g = group-structure-hom (GroupStructure.exp GS g) (GroupStructure.exp-+ GS g)

exp-hom : ∀ {i} (G : Group i) (g : Group.El G) → ℤ-group →ᴳ G
exp-hom G g = group-hom (Group.exp G g) (Group.exp-+ G g)


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

open import Groups.Definition
open import Groups.Abelian.Definition
open import Setoids.Setoids
open import Rings.Definition
open import Modules.Definition
open import Fields.Fields

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

module Vectors.VectorSpace {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+R_ : A → A → A} {_*_ : A → A → A} (R : Ring S _+R_ _*_) {m n : _} {M : Set m} {T : Setoid {m} {n} M} {_+_ : M → M → M} {G' : Group T _+_} (G : AbelianGroup G') (_·_ : A → M → M) where

record VectorSpace : Set (lsuc a ⊔ b ⊔ m ⊔ n) where
  field
    isModule : Module R G _·_
    isField : Field R


--------------------------------------------------------------------------------
-- This is part of Agda Inference Systems

open import Data.Nat
open import Data.Fin

module Examples.Lambda.Lambda where

  {- Terms & Values -}
  data Term (n : ℕ) : Set where
    var : Fin n → Term n
    lambda : Term (suc n) → Term n
    app : Term n → Term n → Term n

  data Value : Set where
    lambda : Term 1 → Value

  term : Value → Term 0
  term (lambda x) = lambda x

  {- Substitution -}
  ext : ∀{n m} → (Fin n → Fin m) → (Fin (suc n) → Fin (suc m))
  ext f zero = zero
  ext f (suc n) = suc (f n)

  rename : ∀{n m} → (Fin n → Fin m) → (Term n → Term m)
  rename f (var x) = var (f x)
  rename f (lambda t) = lambda (rename (ext f) t)
  rename f (app t t₁) = app (rename f t) (rename f t₁)

  exts : ∀{n m} → (Fin n → Term m) → (Fin (suc n) → Term (suc m))
  exts _ zero = var zero
  exts f (suc n) = rename suc (f n)

  subst : ∀{n m} → (Fin n → Term m) → (Term n → Term m)
  subst f (var x) = f x
  subst f (lambda t) = lambda (subst (exts f) t)
  subst f (app t t₁) = app (subst f t) (subst f t₁)

  subst-0 : ∀{n} → Term (suc n) → Term n → Term n
  subst-0 {n} t t₁ = subst {suc n}{n} f t where
    f : Fin (suc n) → Term n
    f zero = t₁
    f (suc n) = var n


module Issue566 where

open import Common.Level using (Level; _⊔_)

data D (a : Level) (A : Set a) : Set a where
 d : D a A → D a A

P-level : (a : Level) (A : Set a) → D a A → Level
P-level a A (d x) = P-level a A x

P : (a : Level) (A : Set a) (x : D a A) → Set (P-level a A x)
P a A (d x) = P a A x

postulate
 a : Level
 E : (b : Level) → Set b → Set a → Set (a ⊔ b)
 Q : (A : Set a) → D a A → Set a
 e : (A : Set a) (x : D a A) → E (P-level a A x) (P a A x) (Q A x)
 A : Set a
 x : D a A

foo : E (P-level a A x) (P a A x) (Q A x)
foo = e _ _

-- Bug.agda:23,7-12
-- P-level a A x ⊔ a != P-level a A x ⊔ a of type Level
-- when checking that the expression e _ _ has type
-- E (P-level a A x) (P a A x) (Q A x)


module DayConvolution where

open import Library
open import Functors
open import Categories
open import Categories.Sets
open import MonoidalCat

-- first draft

ODay : ∀{l m}(M : Monoidal {l}{m})
       (F G : Fun (Monoidal.C M) (Sets {l})) ->
       Cat.Obj (Monoidal.C M) -> Set _
ODay M F G X =
  Σ Obj \Y -> Σ Obj \Z -> OMap F Y × OMap G Z × Hom X (OMap ⊗ (Y , Z))
  where open Monoidal M; open Cat C; open Fun

HDay : ∀{l m}(M : Monoidal {l}{m})
       (F G : Fun (Monoidal.C M) (Sets {l})) -> ∀{X X'} ->
       Cat.Hom (Monoidal.C M) X X' -> ODay M F G X' -> ODay M F G X
HDay M F G f (y , z , fy , gz , g) = y , z , fy , gz , comp g f
  where open Monoidal M; open Cat C

DayF : ∀{l m}(M : Monoidal {l}{m})
       (F G : Fun (Monoidal.C M) (Sets {l})) -> Fun ((Monoidal.C M) Op) Sets
DayF M F G = functor
  (ODay M F G)
  (HDay M F G)
  (\ {X} -> ext (\{ (y , z , fy , gz , g) ->
    cong (λ g → y , z , fy , gz , g) idr}))
  (\ {X Y Z h k} -> ext (\{ (y , z , fy , gz , g) ->
    cong (λ l → y , z , fy , gz , l) (sym ass)}))
  where open Monoidal M; open Cat C

-- subject to some additional conditions
-- forall h : y -> y'.
--   (y , F h fy' , gz , g) ~ (y' , z , fy' , gz , [h,id] . g)
--
-- forall k : z -> z'
--   (y , z , fy , G k gz' , g) ~ (y , z' , fy , gz' , [id,k] . g)


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

module overloading.level where

open import sum
open import equality.core
open import overloading.bundle
open import function.isomorphism
open import hott.level.core
open import sets.unit

open Bundle

bundle-structure-iso : ∀ {i j}{Base : Set i}
                       (Struct : Base → Set j)
                     → Σ Base Struct ≅ Bundle Struct
bundle-structure-iso Struct = record
  { to = λ { (X , s) → bundle X s }
  ; from = λ { (bundle X s) → X , s }
  ; iso₁ = λ _ → refl
  ; iso₂ = λ _ → refl }

bundle-equality-iso : ∀ {i j}{Base : Set i}
                      (Struct : Base → Set j)
                    → ((B : Base) → h 1 (Struct B))
                    → {X Y : Bundle Struct}
                    → (parent X ≡ parent Y)
                    ≅ (X ≡ Y)
bundle-equality-iso Struct hS {X}{Y} = begin
    parent X ≡ parent Y
  ≅⟨ sym≅ ×-right-unit ⟩
    ((parent X ≡ parent Y) × ⊤)
  ≅⟨ Σ-ap-iso refl≅ (λ p → sym≅ (contr-⊤-iso (hS _ _ _))) ⟩
    ( Σ (parent X ≡ parent Y) λ p
    → (subst Struct p (struct X) ≡ struct Y) )
  ≅⟨ Σ-split-iso ⟩
    (parent X , struct X) ≡ (parent Y , struct Y)
  ≅⟨ iso≡ (bundle-structure-iso Struct) ⟩
    X ≡ Y
  ∎
  where open ≅-Reasoning


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.Semigroup.Construct.Unit where

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

open import Cubical.Data.Unit

import Cubical.Algebra.Magma.Construct.Unit as ⊤Magma
open ⊤Magma public hiding (⊤-isMagma; ⊤-Magma)

◯-assoc : Associative _◯_
◯-assoc _ _ _ = refl

⊤-isSemigroup : IsSemigroup ⊤ _◯_
⊤-isSemigroup = record
  { isMagma = ⊤Magma.⊤-isMagma
  ; assoc   = ◯-assoc
  }

⊤-Semigroup : Semigroup ℓ-zero
⊤-Semigroup = record { isSemigroup = ⊤-isSemigroup }


{-# OPTIONS --prop --rewriting #-}

open import Examples.Sorting.Sequential.Comparable

module Examples.Sorting.Sequential.MergeSort.Split (M : Comparable) where

open Comparable M
open import Examples.Sorting.Sequential.Core M

open import Calf costMonoid
open import Calf.Types.Nat
open import Calf.Types.List
open import Calf.Types.Bounded costMonoid

open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl)
open import Data.Product using (_×_; _,_; ∃; proj₁; proj₂)
open import Data.Nat as Nat using (ℕ; zero; suc; _+_; _*_; ⌊_/2⌋; ⌈_/2⌉)
open import Data.Nat.Properties as N using (module ≤-Reasoning)

pair = Σ++ (list A) λ _ → (list A)

split/clocked : cmp (Π nat λ _ → Π (list A) λ _ → F pair)
split/clocked zero    l        = ret ([] , l)
split/clocked (suc k) []       = ret ([] , [])
split/clocked (suc k) (x ∷ xs) = bind (F pair) (split/clocked k xs) λ (l₁ , l₂) → ret (x ∷ l₁ , l₂)

split/clocked/correct : ∀ k k' l → k + k' ≡ length l →
  ◯ (∃ λ l₁ → ∃ λ l₂ → split/clocked k l ≡ ret (l₁ , l₂) × length l₁ ≡ k × length l₂ ≡ k' × l ↭ (l₁ ++ l₂))
split/clocked/correct zero    k' l        refl u = [] , l , refl , refl , refl , refl
split/clocked/correct (suc k) k' (x ∷ xs) h    u =
  let (l₁ , l₂ , ≡ , h₁ , h₂ , ↭) = split/clocked/correct k k' xs (N.suc-injective h) u in
  x ∷ l₁ , l₂ , Eq.cong (λ e → bind (F pair) e _) ≡ , Eq.cong suc h₁ , h₂ , prep x ↭

split/clocked/cost : cmp (Π nat λ _ → Π (list A) λ _ → cost)
split/clocked/cost _ _ = zero

split/clocked≤split/clocked/cost : ∀ k l → IsBounded pair (split/clocked k l) (split/clocked/cost k l)
split/clocked≤split/clocked/cost zero    l        = bound/ret
split/clocked≤split/clocked/cost (suc k) []       = bound/ret
split/clocked≤split/clocked/cost (suc k) (x ∷ xs) = bound/bind/const zero zero (split/clocked≤split/clocked/cost k xs) λ _ → bound/ret

split : cmp (Π (list A) λ _ → F pair)
split l = split/clocked ⌊ length l /2⌋ l

split/correct : ∀ l →
  ◯ (∃ λ l₁ → ∃ λ l₂ → split l ≡ ret (l₁ , l₂) × length l₁ ≡ ⌊ length l /2⌋ × length l₂ ≡ ⌈ length l /2⌉ × l ↭ (l₁ ++ l₂))
split/correct l = split/clocked/correct ⌊ length l /2⌋ ⌈ length l /2⌉ l (N.⌊n/2⌋+⌈n/2⌉≡n (length l))

split/cost : cmp (Π (list A) λ _ → cost)
split/cost l = split/clocked/cost ⌊ length l /2⌋ l

split≤split/cost : ∀ l → IsBounded pair (split l) (split/cost l)
split≤split/cost l = split/clocked≤split/clocked/cost ⌊ length l /2⌋ l


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

open import Categories.Category
open import Categories.Category.Monoidal.Core using (Monoidal)

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

open import Level

open import Categories.Functor.Bifunctor
open import Categories.NaturalTransformation.NaturalIsomorphism

open Category C
open Commutation C

private
  variable
    X : Obj

-- left rigid monoidal category
record LeftRigid : Set (levelOfTerm M) where
  open Monoidal M public

  field
    _⁻¹ : Obj → Obj
    η   : ∀ {X} → unit ⇒ X ⊗₀ X ⁻¹
    ε   : ∀ {X} → X ⁻¹ ⊗₀ X  ⇒ unit

    snake₁ : [ X ⇒ X ]⟨
               unitorˡ.to  ⇒⟨ (unit ⊗₀ X) ⟩
               (η ⊗₁ id)  ⇒⟨ (X ⊗₀ X ⁻¹) ⊗₀ X ⟩
               associator.from  ⇒⟨ X ⊗₀ (X ⁻¹ ⊗₀ X) ⟩
               (id ⊗₁ ε) ⇒⟨ X ⊗₀ unit ⟩
               unitorʳ.from
             ≈ id
             ⟩
    snake₂ : [ X ⁻¹ ⇒ X ⁻¹ ]⟨
               unitorʳ.to  ⇒⟨ X ⁻¹ ⊗₀ unit ⟩
               (id ⊗₁ η)  ⇒⟨ X ⁻¹ ⊗₀ (X ⊗₀ X ⁻¹) ⟩
               associator.to  ⇒⟨ (X ⁻¹ ⊗₀ X) ⊗₀ X ⁻¹ ⟩
               (ε ⊗₁ id) ⇒⟨ unit ⊗₀ X ⁻¹ ⟩
               unitorˡ.from
             ≈ id
             ⟩

-- right rigid monoidal category
record RightRigid : Set (levelOfTerm M) where
  open Monoidal M public

  field
    _⁻¹ : Obj → Obj
    η   : ∀ {X} → unit ⇒ X ⁻¹ ⊗₀ X
    ε   : ∀ {X} → X ⊗₀ X ⁻¹  ⇒ unit

    snake₁ : [ X ⇒ X ]⟨
               unitorʳ.to  ⇒⟨ (X ⊗₀ unit) ⟩
               (id ⊗₁ η)  ⇒⟨ X ⊗₀ (X ⁻¹ ⊗₀ X) ⟩
               associator.to ⇒⟨ (X ⊗₀ X ⁻¹) ⊗₀ X ⟩
               (ε ⊗₁ id) ⇒⟨ unit ⊗₀ X ⟩
               unitorˡ.from
             ≈ id
             ⟩
    snake₂ : [ X ⁻¹ ⇒ X ⁻¹ ]⟨
               unitorˡ.to  ⇒⟨ unit ⊗₀ X ⁻¹ ⟩
               (η ⊗₁ id)  ⇒⟨ (X ⁻¹ ⊗₀ X) ⊗₀ X ⁻¹ ⟩
               associator.from  ⇒⟨ X ⁻¹ ⊗₀ (X ⊗₀ X ⁻¹) ⟩
               (id ⊗₁ ε) ⇒⟨ X ⁻¹ ⊗₀ unit ⟩
               unitorʳ.from
             ≈ id
             ⟩


open import Prelude
open import dynamics-core

module lemmas-ground where
  -- not ground types aren't just a type constructor filled with holes
  ground-not-holes : ∀{τ} →
                     (τ ground → ⊥) →
                     (τ ≠ (⦇-⦈ ==> ⦇-⦈)) × (τ ≠ (⦇-⦈ ⊕ ⦇-⦈)) × (τ ≠ (⦇-⦈ ⊠ ⦇-⦈))
  ground-not-holes notg = (λ{refl → notg GArrHole}) ,
                          (λ{refl → notg GSumHole}) ,
                          (λ{refl → notg GProdHole})

  -- not ground types either have to be hole, an arrow, or a sum
  not-ground : ∀{τ} →
              (τ ground → ⊥) →
              ((τ == ⦇-⦈) +
               (Σ[ τ1 ∈ htyp ] Σ[ τ2 ∈ htyp ] (τ == (τ1 ==> τ2))) +
               (Σ[ τ1 ∈ htyp ] Σ[ τ2 ∈ htyp ] (τ == (τ1 ⊕ τ2))) +
               (Σ[ τ1 ∈ htyp ] Σ[ τ2 ∈ htyp ] (τ == (τ1 ⊠ τ2))))
  not-ground {num} gnd = abort (gnd GNum)
  not-ground {⦇-⦈} gnd = Inl refl
  not-ground {τ ==> τ₁} gnd = Inr (Inl (τ , τ₁ , refl))
  not-ground {τ ⊕ τ₁} gnd = Inr (Inr (Inl (τ , τ₁ , refl)))
  not-ground {τ ⊠ τ₁} gnd = Inr (Inr (Inr (τ , τ₁ , refl)))


module 100-natural where

open import 010-false-true
open import 020-equivalence

record Natural
  {N : Set}
  (zero : N)
  (suc : N -> N)
  (_==_ : N -> N -> Set)
  : Set1 where

  -- axioms
  field
    equiv : Equivalence _==_
    sucn!=zero : ∀ {r} -> suc r == zero -> False
    sucinjective : ∀ {r s} -> suc r == suc s -> r == s
    cong : ∀ {r s} -> r == s -> suc r == suc s
    induction : (p : N -> Set) -> p zero -> (∀ n -> p n -> p (suc n)) -> (∀ n -> p n)

  open Equivalence equiv public


module UniDB.Subst.Shifts where

open import UniDB.Subst.Core
open import UniDB.Morph.Shifts

module _ {T : STX} {{vrT : Vr T}} {{apTT : Ap T T}} {{apVrT : ApVr T}} where

  instance
    iLkCompApShifts : LkCompAp T Shifts
    lk-⊙-ap {{iLkCompApShifts}} ξ₁ ξ₂ i = begin
      vr (lk (ξ₁ ⊙ ξ₂) i)     ≡⟨ cong vr (shiftIx-⊙ ξ₁ ξ₂ i) ⟩
      vr (lk ξ₂ (lk ξ₁ i))     ≡⟨ sym (ap-vr {T} ξ₂ (lk ξ₁ i)) ⟩
      ap {T} ξ₂ (vr (lk ξ₁ i)) ∎


-- TODO: Move these to stuff related to metric spaces

module Continuity where
  open Limit

  -- Statement that the point x of function f is a continous point
  ContinuousPoint : (ℝ → ℝ) → ℝ → Stmt
  ContinuousPoint f(x) = (⦃ limit : Lim f(x) ⦄ → (lim f(x)⦃ limit ⦄ ≡ f(x)))

  -- Statement that the function f is continous
  Continuous : (ℝ → ℝ) → Stmt
  Continuous f = ∀{x} → ContinuousPoint f(x)

module Proofs where
  -- instance postulate DifferentiablePoint-to-ContinuousPoint : ∀{f}{x}{diff} → ⦃ _ : DifferentiablePoint f(x)⦃ diff ⦄ ⦄ → ContinuousPoint f(x)
  -- instance postulate Differentiable-to-Continuous : ∀{f}{diff} → ⦃ _ : Differentiable(f)⦃ diff ⦄ ⦄ → Continuous(f)


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

open import LogicalFormulae
open import Rings.Definition
open import Rings.IntegralDomains.Definition
open import Fields.Fields
open import Setoids.Setoids
open import Sets.EquivalenceRelations

module Fields.FieldOfFractions.Field {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ : A → A → A} {_*_ : A → A → A} {R : Ring S _+_ _*_} (I : IntegralDomain R) where

open import Fields.FieldOfFractions.Ring I

fieldOfFractions : Field fieldOfFractionsRing
Field.allInvertible fieldOfFractions (record { num = fst ; denom = b }) prA = (record { num = b ; denom = fst ; denomNonzero = ans }) , need
  where
    abstract
      open Setoid S
      open Equivalence eq
      need : ((b * fst) * Ring.1R R) ∼ ((fst * b) * Ring.1R R)
      need = Ring.*WellDefined R (Ring.*Commutative R) reflexive
      ans : fst ∼ Ring.0R R → False
      ans pr = prA need'
        where
          need' : (fst * Ring.1R R) ∼ (b * Ring.0R R)
          need' = transitive (Ring.*WellDefined R pr reflexive) (transitive (transitive (Ring.*Commutative R) (Ring.timesZero R)) (symmetric (Ring.timesZero R)))
Field.nontrivial fieldOfFractions pr = IntegralDomain.nontrivial I (symmetric (transitive (symmetric (Ring.timesZero R)) (transitive (Ring.*Commutative R) (transitive pr (Ring.identIsIdent R)))))
  where
    open Setoid S
    open Equivalence eq
    pr' : (Ring.0R R) * (Ring.1R R) ∼ (Ring.1R R) * (Ring.1R R)
    pr' = pr


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

syntax Prod | P

type
  _⊗_ : 2-ary | l40

term
  pair : α  β  ->  α ⊗ β | ⟨_,_⟩
  fst  : α ⊗ β  ->  α
  snd  : α ⊗ β  ->  β

theory
  (fβ) a : α  b : β |> fst (pair(a, b))      = a
  (sβ) a : α  b : β |> snd (pair(a, b))      = b
  (pη) p : α ⊗ β    |> pair (fst(p), snd(p)) = p
-}

module Prod.Equality where

open import SOAS.Common
open import SOAS.Context
open import SOAS.Variable
open import SOAS.Families.Core
open import SOAS.Families.Build
open import SOAS.ContextMaps.Inductive

open import Prod.Signature
open import Prod.Syntax

open import SOAS.Metatheory.SecondOrder.Metasubstitution P:Syn
open import SOAS.Metatheory.SecondOrder.Equality P:Syn

private
  variable
    α β γ τ : PT
    Γ Δ Π : Ctx

infix 1 _▹_⊢_≋ₐ_

-- Axioms of equality
data _▹_⊢_≋ₐ_ : ∀ 𝔐 Γ {α} → (𝔐 ▷ P) α Γ → (𝔐 ▷ P) α Γ → Set where
  fβ : ⁅ α ⁆ ⁅ β ⁆̣ ▹ ∅ ⊢     fst ⟨ 𝔞 , 𝔟 ⟩ ≋ₐ 𝔞
  sβ : ⁅ α ⁆ ⁅ β ⁆̣ ▹ ∅ ⊢     snd ⟨ 𝔞 , 𝔟 ⟩ ≋ₐ 𝔟
  pη : ⁅ α ⊗ β ⁆̣   ▹ ∅ ⊢ ⟨ fst 𝔞 , snd 𝔞 ⟩ ≋ₐ 𝔞

open EqLogic _▹_⊢_≋ₐ_
open ≋-Reasoning


module Sets.IterativeSet.Relator where

import      Lvl
open import Logic.Propositional
open import Logic.Predicate
open import Numeral.Natural
open import Sets.IterativeSet
open import Syntax.Function
open import Type

module _ where
  private variable {ℓ ℓ₁ ℓ₂} : Lvl.Level
  private variable {A B} : Iset{ℓ}
  open Iset

  _≡_ : (A : Iset{ℓ₁}) → (B : Iset{ℓ₂}) → Type{ℓ₁ Lvl.⊔ ℓ₂}
  record _⊆_ (A : Iset{ℓ₁}) (B : Iset{ℓ₂}) : Type{ℓ₁ Lvl.⊔ ℓ₂}
  _⊇_ : Iset{ℓ₁} → Iset{ℓ₂} → Type{ℓ₁ Lvl.⊔ ℓ₂}

  -- Set equality is by definition the antisymmetric property of the subset relation.
  _≡_ A B = (A ⊇ B) ∧ (A ⊆ B)

  -- Set membership is the existence of an index in the set that points to a set equal element to the element.
  _∈_ : Iset{ℓ₁} → Iset{ℓ₂} → Type{ℓ₁ Lvl.⊔ ℓ₂}
  a ∈ B = ∃{Obj = Index(B)} (ib ↦ a ≡ elem(B)(ib))

  -- Set subset is a mapping between the indices such that they point to the same element in both sets.
  record _⊆_ A B where
    constructor intro
    inductive
    eta-equality
    field
      map : Index(A) → Index(B)
      proof : ∀{ia} → (elem(A)(ia) ≡ elem(B)(map(ia)))

  A ⊇ B = B ⊆ A
  module _⊇_ where
    open _⊆_ public

  _∉_ : Iset{ℓ₁} → Iset{ℓ₂} → Type{ℓ₁ Lvl.⊔ ℓ₂}
  a ∉ B = ¬(a ∈ B)


------------------------------------------------------------------------------
-- From inductive PA to Mendelson's axioms
------------------------------------------------------------------------------

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

-- From the definition of PA using Agda data types and primitive
-- recursive functions for addition and multiplication, we can prove the
-- Mendelson's axioms [1].

-- N.B. We make the recursion in the first argument for _+_ and _*_.

-- S₁. m = n → m = o → n = o
-- S₂. m = n → succ m = succ n
-- S₃. 0 ≠ succ n
-- S₄. succ m = succ n → m = n
-- S₅. 0 + n = n
-- S₆. succ m + n = succ (m + n)
-- S₇. 0 * n = 0
-- S₈. succ m * n = (m * n) + m
-- S₉. P(0) → (∀n.P(n) → P(succ n)) → ∀n.P(n), for any wf P(n) of PA.

-- [1]. Elliott Mendelson. Introduction to mathematical
--      logic. Chapman& Hall, 4th edition, 1997, p. 155.

module PA.Inductive2Mendelson where

open import PA.Inductive.Base

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

S₁ :  ∀ {m n o} → m ≡ n → m ≡ o → n ≡ o
S₁ refl refl = refl

S₂ : ∀ {m n} → m ≡ n → succ m ≡ succ n
S₂ refl = refl

S₃ : ∀ {n} → zero ≢ succ n
S₃ ()

S₄ : ∀ {m n} → succ m ≡ succ n → m ≡ n
S₄ refl = refl

S₅ : ∀ n → zero + n ≡ n
S₅ n = refl

S₆ : ∀ m n → succ m + n ≡ succ (m + n)
S₆ m n = refl

S₇ : ∀ n → zero * n ≡ zero
S₇ n = refl

S₈ : ∀ m n → succ m * n ≡ n + m * n
S₈ m n = refl

S₉ : (A : ℕ → Set) → A zero → (∀ n → A n → A (succ n)) → ∀ n → A n
S₉ = ℕ-ind


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

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

open import Cubical.Relation.Binary
open import Cubical.Structures.Carrier

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

Const : ∀ {a b ℓ} {A : Type a} {B : Type b} → hProp ℓ → REL A B ℓ
Const I = λ _ _ → I

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

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

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

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

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

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

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

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

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


module LC.Subst.Term where

open import LC.Base
open import LC.Subst.Var

open import Data.Nat
open import Data.Nat.Properties
open import Relation.Nullary

--------------------------------------------------------------------------------
-- lifting terms

lift : (n i : ℕ) → Term → Term
lift n i (var x) = var (lift-var n i x)
lift n i (ƛ M)   = ƛ lift (suc n) i M
lift n i (M ∙ N) = lift n i M ∙ lift n i N

--------------------------------------------------------------------------------
-- properties of lift

open import Relation.Binary.PropositionalEquality hiding ([_])

--             lift l (n + i)
--        ∙ --------------------------> ∙
--        |                             |
--        |                             |
--   lift l (n + m + i)           lift (l + n) m
--        |                             |
--        ∨                             ∨
--        ∙ --------------------------> ∙
--

lift-lemma : ∀ l m n i N → lift l (n + m + i) N ≡ lift (l + n) m (lift l (n + i) N)
lift-lemma l m n i (var x) = cong var_ (LC.Subst.Var.lift-var-lemma l m n i x)
lift-lemma l m n i (ƛ M)   = cong ƛ_ (lift-lemma (suc l) m n i M)
lift-lemma l m n i (M ∙ N) = cong₂ _∙_ (lift-lemma l m n i M) (lift-lemma l m n i N)

--                lift (l + n) i
--        ∙ --------------------------> ∙
--        |                             |
--        |                             |
--   lift l m                      lift l m
--        |                             |
--        ∨                             ∨
--        ∙ --------------------------> ∙
--              lift (l + m + n) i

lift-lift : ∀ l m n i N → lift l m (lift (l + n) i N) ≡ lift (l + m + n) i (lift l m N)
lift-lift l m n i (var x) = cong var_ (lift-var-lift-var l m n i x)
lift-lift l m n i (ƛ N)   = cong ƛ_ (lift-lift (suc l) m n i N)
lift-lift l m n i (M ∙ N) = cong₂ _∙_ (lift-lift l m n i M) (lift-lift l m n i N)

--------------------------------------------------------------------------------
-- substituting variables

data Match : ℕ → ℕ → Set where
  Under : ∀ {i x} → x     < i → Match x       i
  Exact : ∀ {i x} → x     ≡ i → Match x       i
  Above : ∀ {i} v → suc v > i → Match (suc v) i

open import Relation.Binary.Definitions

match : (x i : ℕ) → Match x i
match x       i with <-cmp x i
match x       i | tri< a ¬b ¬c = Under a
match x       i | tri≈ ¬a b ¬c = Exact b
match (suc x) i | tri> ¬a ¬b c = Above x c

subst-var : ∀ {x i} → Match x i → Term → Term
subst-var {x}     (Under _)     N = var x
subst-var {_} {i} (Exact _)     N = lift 0 i N
subst-var         (Above x _) N = var x

--------------------------------------------------------------------------------
-- properties of subst-var

open import Relation.Nullary.Negation using (contradiction)
open ≡-Reasoning

subst-var-match-< : ∀ {m n} N → (m<n : m < n) → subst-var (match m n) N ≡ var m
subst-var-match-< {m} {n} N m<n with match m n
... | Under m<n' = refl
... | Exact m≡n  = contradiction m≡n (<⇒≢ m<n)
... | Above _ m>n = contradiction m>n (<⇒≱ (≤-step m<n))

subst-var-match-≡ : ∀ {m n} N → (m≡n : m ≡ n) → subst-var {_} {n} (match m n) N ≡ lift 0 n N
subst-var-match-≡ {m} {.m} N refl with match m m
... | Under m<m = contradiction refl (<⇒≢ m<m)
... | Exact m≡m = refl
... | Above _ m>m = contradiction refl (<⇒≢ m>m)

subst-var-match-> : ∀ {m n} N → (1+m>n : suc m > n) → subst-var (match (suc m) n) N ≡ var m
subst-var-match-> {m} {n} N 1+m<n with match (suc m) n
... | Under m<n = contradiction m<n (<⇒≱ (≤-step 1+m<n))
... | Exact m≡n = contradiction (sym m≡n) (<⇒≢ 1+m<n)
... | Above _ m>n = refl

--              subst-var (match x                             m)
--        ∙ -------------------------------------------------------> ∙
--        |                                                          |
--        |                                                          |
--     lift n                                                  lift (m + n)
--        |                                                          |
--        ∨                                                          ∨
--        ∙ --------------------------------------------------------> ∙
--              subst-var (match (lift-var (suc (m + n)) i x) m)

open import Relation.Binary.PropositionalEquality hiding (preorder; [_])
open ≡-Reasoning

subst-var-lift : ∀ m n i x N
    → subst-var (match (lift-var (suc (m + n)) i x) m) (lift n i N)
    ≡ lift (m + n) i (subst-var (match x m) N)
subst-var-lift m n i x N with match x m
... | Under x<m =
    begin
        subst-var (match (lift-var (suc (m + n)) i x) m) (lift n i N)
    ≡⟨ cong (λ w → subst-var (match w m) (lift n i N)) (LC.Subst.Var.lift-var-> prop1) ⟩
        subst-var (match x m) (lift n i N)
    ≡⟨ subst-var-match-< (lift n i N) x<m ⟩
        var x
    ≡⟨ cong var_ (sym (LC.Subst.Var.lift-var-> prop2)) ⟩
        lift (m + n) i (var x)
    ∎
    where
      prop1 : suc (m + n) > x
      prop1 = ≤-trans x<m (≤-step (m≤m+n m n))

      prop2 : m + n > x
      prop2 = ≤-trans x<m (m≤m+n m n)

... | Exact refl =
      begin
        subst-var (match (lift-var (suc (m + n)) i m) m) (lift n i N)
      ≡⟨ cong (λ w → subst-var (match w m) (lift n i N)) (LC.Subst.Var.lift-var-> prop) ⟩
        subst-var (match m m) (lift n i N)
      ≡⟨ subst-var-match-≡ (lift n i N) refl ⟩
        lift 0 m (lift n i N)
      ≡⟨ lift-lift 0 m n i N ⟩
        lift (m + n) i (lift 0 m N)
      ∎
      where
        prop : suc (m + n) > m
        prop =  s≤s (m≤m+n m n)

... | Above v m≤v with inspectBinding (suc m + n) (suc v)
... | Free n≤x =
  begin
    subst-var (match (i + suc v) m) (lift n i N)
  ≡⟨ cong (λ w → subst-var (match w m) (lift n i N)) (+-suc i v) ⟩
    subst-var (match (suc i + v) m) (lift n i N)
  ≡⟨ subst-var-match-> (lift n i N) prop ⟩
    var (i + v)
  ≡⟨ cong var_ (sym (LC.Subst.Var.lift-var-≤ prop2)) ⟩
    var (lift-var (m + n) i v)
  ∎
  where
    prop : suc (i + v) > m
    prop = s≤s (≤-trans (≤-pred m≤v) (m≤n+m v i))

    prop2 : m + n ≤ v
    prop2 = ≤-pred n≤x
... | Bound n>x =
  begin
    subst-var (match (suc v) m) (lift n i N)
  ≡⟨ subst-var-match-> {v} {m} (lift n i N) m≤v ⟩
    var v
  ≡⟨ cong var_ (sym (LC.Subst.Var.lift-var-> {m + n} {i} {v} (≤-pred n>x))) ⟩
    var (lift-var (m + n) i v)
  ∎


module Max where

open import Data.Empty using (⊥-elim)
open import Data.Fin
open import Data.Nat hiding (_≤_)
open import Function using (_∘_)

open import Relation.Nullary

variable
  n : ℕ

-- from https://github.com/zmthy/recursive-types/tree/ftfjp16
-- RecursiveTypes.Inductive.Type
-- adapted to use "variable"

-- A proposition that the indexed number is the largest it can be, i.e. one less
-- than its exclusive upper bound.
data Max : Fin n → Set where
  max : Max {suc n} (fromℕ n)

-- A lemma on Max: if a number is max, then one less than that number with a
-- simultaneously lowered upper bound is also max.
max-pre : {x : Fin (suc n)} → Max (suc x) → Max x
max-pre max = max

-- A lemma on Max: if a number is max, then one more than that number with a
-- simultaneously increased upper bound is also max.
max-suc : {x : Fin n} → Max x → Max (suc x)
max-suc max = max

-- Given a proof that a number is not max, reduce its lower bound by one,
-- keeping the value of the number the same.
reduce : {x : Fin (suc n)} → ¬ Max x → Fin n
reduce {zero}  {zero}   ¬p = ⊥-elim (¬p max)
reduce {zero}  {suc ()} ¬p
reduce {suc n} {zero}   ¬p = zero
reduce {suc n} {suc x}  ¬p = suc (reduce {x = x} (¬p ∘ max-suc))

-- Max is a decidable proposition: just compare the number value to the value of
-- the upper bound.
max? : (x : Fin n) → Dec (Max x)
max? {zero}        ()
max? {suc zero}    zero     = yes max
max? {suc zero}    (suc ())
max? {suc (suc n)} zero     = no (λ ())
max? {suc (suc n)} (suc x)  with max? x
max? {suc (suc n)} (suc .(fromℕ n)) | yes max = yes max
max? {suc (suc n)} (suc x)          | no ¬p = no (¬p ∘ max-pre)

-- The reduce function preserves ≤.
reduce₁ : ∀ {m} {x : Fin n} (¬p : ¬ Max (suc x))
          → m ≤ x → suc m ≤ inject₁ (reduce ¬p)
reduce₁ {m = zero} ¬p₁ z≤n = s≤s z≤n
reduce₁ {m = suc m} {zero} ¬p ()
reduce₁ {m = suc m₁} {suc x₁} ¬p₁ (s≤s q₁) =
  s≤s (reduce₁ (λ z → ¬p₁ (max-suc z)) q₁)

-- Injection is compatible with ordering.
inject-≤ : {i j : Fin n} → inject₁ i ≤ inject₁ j → i ≤ j
inject-≤ {i = 0F} {0F} z≤n = z≤n
inject-≤ {i = 0F} {suc j} z≤n = z≤n
inject-≤ {i = suc i} {0F} ()
inject-≤ {i = suc i} {suc j} (s≤s ii≤ij) = s≤s (inject-≤ ii≤ij)

-- Technical lemma about reduce.
lemma-reduce : {i j : Fin (suc n)} →
  (i≤j : inject₁ i ≤ inject₁ j) → (¬p  : ¬ Max j) → i ≤ inject₁ (reduce ¬p)
lemma-reduce {i = 0F} i≤j ¬p = z≤n
lemma-reduce {i = suc i} {suc j} (s≤s i≤j) ¬p = reduce₁ ¬p (inject-≤ i≤j)

-- A lemma on ≤: if x ≤ y, then x ≤ suc y.
suc-≤ : {x y : Fin n} → x ≤ y → inject₁ x ≤ suc y
suc-≤ {x = zero} z≤n = z≤n
suc-≤ {x = suc x} {zero} ()
suc-≤ {x = suc x} {suc y} (s≤s p) = s≤s (suc-≤ p)

-- A lemma on ≤: if suc x ≤ y, then x ≤ y.
pred-≤ : {x y : Fin n} → suc x ≤ inject₁ y → inject₁ x ≤ inject₁ y
pred-≤ {y = zero} ()
pred-≤ {y = suc x} (s≤s p) = suc-≤ p

-- A lemma on ≤: if x ≤ y, then for any z < x, z ≤ y.
trans-< : {x y : Fin n} {z : Fin′ x} → x ≤ y → inject z ≤ y
trans-< {x = zero} {z = ()} p
trans-< {x = suc x} {zero} ()
trans-< {x = suc x} {suc y} {zero} (s≤s p) = z≤n
trans-< {x = suc x} {suc y} {suc z} (s≤s p) = s≤s (trans-< p)


module Data.Maybe where

data Maybe (a : Set) : Set where
  nothing : Maybe a
  just    : a -> Maybe a

fmap : {A B : Set} -> (A -> B) -> Maybe A -> Maybe B
fmap f nothing  = nothing
fmap f (just a) = just (f a )


------------------------------------------------------------------------
-- The Agda standard library
--
-- Bisimilarity for M-types
------------------------------------------------------------------------

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

module Codata.M.Bisimilarity where

open import Level
open import Size
open import Codata.Thunk
open import Codata.M
open import Data.Container.Core
open import Data.Container.Relation.Binary.Pointwise using (Pointwise; _,_)
open import Data.Product using (_,_)
open import Function
open import Relation.Binary
import Relation.Binary.PropositionalEquality as P

data Bisim {s p} (C : Container s p) (i : Size) : Rel (M C ∞) (s ⊔ p) where
  inf : ∀ {t u} → Pointwise C (Thunk^R (Bisim C) i) t u → Bisim C i (inf t) (inf u)

module _ {s p} {C : Container s p} where

  -- unfortunately the proofs are a lot nicer if we do not use the combinators
  -- C.refl, C.sym and C.trans

  refl : ∀ {i} → Reflexive (Bisim C i)
  refl {x = inf t} = inf (P.refl , λ where p .force → refl)

  sym : ∀ {i} → Symmetric (Bisim C i)
  sym  (inf (P.refl , f)) = inf (P.refl , λ where p .force → sym (f p .force))

  trans : ∀ {i} → Transitive (Bisim C i)
  trans (inf (P.refl , f)) (inf (P.refl , g)) =
    inf (P.refl , λ where p .force → trans (f p .force) (g p .force))

  isEquivalence : ∀ {i} → IsEquivalence (Bisim C i)
  isEquivalence = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }

  setoid : {i : Size} → Setoid (s ⊔ p) (s ⊔ p)
  setoid {i} = record
    { isEquivalence = isEquivalence {i}
    }


import Categories.2-Category
import Categories.2-Functor
import Categories.Adjoint
import Categories.Adjoint.Construction.EilenbergMoore
import Categories.Adjoint.Construction.Kleisli
import Categories.Adjoint.Equivalence
import Categories.Adjoint.Instance.0-Truncation
import Categories.Adjoint.Instance.01-Truncation
import Categories.Adjoint.Instance.Core
import Categories.Adjoint.Instance.Discrete
import Categories.Adjoint.Instance.PosetCore
import Categories.Adjoint.Instance.StrictCore
import Categories.Adjoint.Mate
import Categories.Adjoint.Properties
import Categories.Adjoint.RAPL
import Categories.Bicategory
import Categories.Bicategory.Bigroupoid
import Categories.Bicategory.Construction.1-Category
import Categories.Bicategory.Instance.Cats
import Categories.Bicategory.Instance.EnrichedCats
import Categories.Category
import Categories.Category.BicartesianClosed
import Categories.Category.Cartesian
import Categories.Category.Cartesian.Properties
import Categories.Category.CartesianClosed
import Categories.Category.CartesianClosed.Canonical
import Categories.Category.CartesianClosed.Locally
import Categories.Category.CartesianClosed.Locally.Properties
import Categories.Category.Closed
import Categories.Category.Cocartesian
import Categories.Category.Cocomplete
import Categories.Category.Cocomplete.Finitely
import Categories.Category.Complete
import Categories.Category.Complete.Finitely
import Categories.Category.Construction.0-Groupoid
import Categories.Category.Construction.Arrow
import Categories.Category.Construction.Cocones
import Categories.Category.Construction.Comma
import Categories.Category.Construction.Cones
import Categories.Category.Construction.Coproduct
import Categories.Category.Construction.Core
import Categories.Category.Construction.EilenbergMoore
import Categories.Category.Construction.Elements
import Categories.Category.Construction.EnrichedFunctors
import Categories.Category.Construction.F-Algebras
import Categories.Category.Construction.Fin
import Categories.Category.Construction.Functors
import Categories.Category.Construction.Graphs
import Categories.Category.Construction.Grothendieck
import Categories.Category.Construction.Kleisli
import Categories.Category.Construction.Path
import Categories.Category.Construction.Presheaves
import Categories.Category.Construction.Properties.Comma
import Categories.Category.Construction.Pullbacks
import Categories.Category.Construction.Thin
import Categories.Category.Core
import Categories.Category.Discrete
import Categories.Category.Equivalence
import Categories.Category.Finite
import Categories.Category.Groupoid
import Categories.Category.Groupoid.Properties
import Categories.Category.Indiscrete
import Categories.Category.Instance.Cats
import Categories.Category.Instance.EmptySet
import Categories.Category.Instance.FamilyOfSets
import Categories.Category.Instance.Globe
import Categories.Category.Instance.Groupoids
import Categories.Category.Instance.One
import Categories.Category.Instance.PointedSets
import Categories.Category.Instance.Posets
import Categories.Category.Instance.Properties.Cats
import Categories.Category.Instance.Properties.Posets
import Categories.Category.Instance.Properties.Setoids
import Categories.Category.Instance.Setoids
import Categories.Category.Instance.Sets
import Categories.Category.Instance.Simplex
import Categories.Category.Instance.SimplicialSet
import Categories.Category.Instance.SingletonSet
import Categories.Category.Instance.Span
import Categories.Category.Instance.StrictCats
import Categories.Category.Instance.StrictGroupoids
import Categories.Category.Instance.Zero
import Categories.Category.Monoidal
import Categories.Category.Monoidal.Braided
import Categories.Category.Monoidal.Braided.Properties
import Categories.Category.Monoidal.Closed
import Categories.Category.Monoidal.Closed.IsClosed
import Categories.Category.Monoidal.Closed.IsClosed.Diagonal
import Categories.Category.Monoidal.Closed.IsClosed.Dinatural
import Categories.Category.Monoidal.Closed.IsClosed.Identity
import Categories.Category.Monoidal.Closed.IsClosed.L
import Categories.Category.Monoidal.Closed.IsClosed.Pentagon
import Categories.Category.Monoidal.Construction.Minus2
import Categories.Category.Monoidal.Core
import Categories.Category.Monoidal.Instance.Cats
import Categories.Category.Monoidal.Instance.One
import Categories.Category.Monoidal.Instance.Setoids
import Categories.Category.Monoidal.Instance.Sets
import Categories.Category.Monoidal.Instance.StrictCats
import Categories.Category.Monoidal.Properties
import Categories.Category.Monoidal.Reasoning
import Categories.Category.Monoidal.Symmetric
import Categories.Category.Monoidal.Traced
import Categories.Category.Monoidal.Utilities
import Categories.Category.Product
import Categories.Category.Product.Properties
import Categories.Category.RigCategory
import Categories.Category.SetoidDiscrete
import Categories.Category.Site
import Categories.Category.Slice
import Categories.Category.Slice.Properties
import Categories.Category.SubCategory
import Categories.Category.Topos
import Categories.Category.WithFamilies
import Categories.Comonad
import Categories.Diagram.Cocone
import Categories.Diagram.Cocone.Properties
import Categories.Diagram.Coend
import Categories.Diagram.Coequalizer
import Categories.Diagram.Coequalizer.Properties
import Categories.Diagram.Colimit
import Categories.Diagram.Colimit.DualProperties
import Categories.Diagram.Colimit.Lan
import Categories.Diagram.Colimit.Properties
import Categories.Diagram.Cone
import Categories.Diagram.Cone.Properties
import Categories.Diagram.Duality
import Categories.Diagram.End
import Categories.Diagram.End.Properties
import Categories.Diagram.Equalizer
import Categories.Diagram.Finite
import Categories.Diagram.Limit
import Categories.Diagram.Limit.Properties
import Categories.Diagram.Limit.Ran
import Categories.Diagram.Pullback
import Categories.Diagram.Pullback.Limit
import Categories.Diagram.Pullback.Properties
import Categories.Diagram.Pushout
import Categories.Diagram.Pushout.Properties
import Categories.Diagram.SubobjectClassifier
import Categories.Enriched.Category
import Categories.Enriched.Functor
import Categories.Enriched.NaturalTransformation
import Categories.Enriched.NaturalTransformation.NaturalIsomorphism
import Categories.Enriched.Over.One
import Categories.Functor
import Categories.Functor.Algebra
import Categories.Functor.Bifunctor
import Categories.Functor.Bifunctor.Properties
import Categories.Functor.Coalgebra
import Categories.Functor.Cocontinuous
import Categories.Functor.Construction.Constant
import Categories.Functor.Construction.Diagonal
import Categories.Functor.Construction.LiftSetoids
import Categories.Functor.Construction.Limit
import Categories.Functor.Construction.Zero
import Categories.Functor.Continuous
import Categories.Functor.Core
import Categories.Functor.Equivalence
import Categories.Functor.Fibration
import Categories.Functor.Groupoid
import Categories.Functor.Hom
import Categories.Functor.Instance.0-Truncation
import Categories.Functor.Instance.01-Truncation
import Categories.Functor.Instance.Core
import Categories.Functor.Instance.Discrete
import Categories.Functor.Instance.SetoidDiscrete
import Categories.Functor.Instance.StrictCore
import Categories.Functor.Monoidal
import Categories.Functor.Power
import Categories.Functor.Power.Functorial
import Categories.Functor.Power.NaturalTransformation
import Categories.Functor.Presheaf
import Categories.Functor.Profunctor
import Categories.Functor.Properties
import Categories.Functor.Representable
import Categories.Functor.Slice
import Categories.GlobularSet
import Categories.Kan
import Categories.Kan.Duality
import Categories.Minus2-Category
import Categories.Minus2-Category.Construction.Indiscrete
import Categories.Minus2-Category.Instance.One
import Categories.Minus2-Category.Properties
import Categories.Monad
import Categories.Monad.Duality
import Categories.Monad.Idempotent
import Categories.Monad.Strong
import Categories.Morphism
import Categories.Morphism.Cartesian
import Categories.Morphism.Duality
import Categories.Morphism.HeterogeneousIdentity
import Categories.Morphism.HeterogeneousIdentity.Properties
import Categories.Morphism.IsoEquiv
import Categories.Morphism.Isomorphism
import Categories.Morphism.Properties
import Categories.Morphism.Reasoning
import Categories.Morphism.Reasoning.Core
import Categories.Morphism.Reasoning.Iso
import Categories.Morphism.Universal
import Categories.NaturalTransformation
import Categories.NaturalTransformation.Core
import Categories.NaturalTransformation.Dinatural
import Categories.NaturalTransformation.Equivalence
import Categories.NaturalTransformation.Hom
import Categories.NaturalTransformation.NaturalIsomorphism
import Categories.NaturalTransformation.NaturalIsomorphism.Equivalence
import Categories.NaturalTransformation.NaturalIsomorphism.Functors
import Categories.NaturalTransformation.NaturalIsomorphism.Properties
import Categories.NaturalTransformation.Properties
import Categories.Object.Coproduct
import Categories.Object.Duality
import Categories.Object.Exponential
import Categories.Object.Initial
import Categories.Object.Product
import Categories.Object.Product.Construction
import Categories.Object.Product.Core
import Categories.Object.Product.Morphisms
import Categories.Object.Terminal
import Categories.Object.Zero
import Categories.Pseudofunctor
import Categories.Pseudofunctor.Instance.EnrichedUnderlying
import Categories.Utils.EqReasoning
import Categories.Utils.Product
import Categories.Yoneda
import Categories.Yoneda.Properties
import Relation.Binary.Construct.Symmetrize


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

syntax CommMonoid | CM

type
  * : 0-ary

term
  unit : * | ε
  add  : *  *  ->  * | _⊕_ l20

theory
  (εU⊕ᴸ) a |> add (unit, a) = a
  (εU⊕ᴿ) a |> add (a, unit) = a
  (⊕A) a b c |> add (add(a, b), c) = add (a, add(b, c))
  (⊕C) a b |> add(a, b) = add(b, a)
-}

module CommMonoid.Signature where

open import SOAS.Context

open import SOAS.Common

open import SOAS.Syntax.Signature *T public
open import SOAS.Syntax.Build *T public

-- Operator symbols
data CMₒ : Set where
  unitₒ addₒ : CMₒ

-- Term signature
CM:Sig : Signature CMₒ
CM:Sig = sig λ
  {  unitₒ  → ⟼₀ *
  ;  addₒ   → (⊢₀ *) , (⊢₀ *) ⟼₂ *
  }

open Signature CM:Sig public


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

module Data.List.Properties where

open import Data.List
open import Prelude
open import Data.Fin

map-length : (f : A → B) (xs : List A)
           → length xs ≡ length (map f xs)
map-length f [] _ = zero
map-length f (x ∷ xs) i = suc (map-length f xs i)

map-ind : (f : A → B) (xs : List A)
        → PathP (λ i → Fin (map-length f xs i) → B) (f ∘ (xs !_)) (map f xs !_)
map-ind f [] i ()
map-ind f (x ∷ xs) i f0 = f x
map-ind f (x ∷ xs) i (fs n) = map-ind f xs i n

tab-length : ∀ n (f : Fin n → A) → length (tabulate n f) ≡ n
tab-length zero f _ = zero
tab-length (suc n) f i = suc (tab-length n (f ∘ fs) i)

tab-distrib : ∀ n (f : Fin n → A) m → ∃[ i ] (f i ≡ tabulate n f ! m)
tab-distrib (suc n) f f0 = f0 , refl
tab-distrib (suc n) f (fs m) = let i , p = tab-distrib n (f ∘ fs) m in fs i , p

tab-id : ∀ n (f : Fin n → A) → PathP (λ i → Fin (tab-length n f i) → A) (_!_ (tabulate n f)) f
tab-id zero f _ ()
tab-id (suc n) f i f0 = f f0
tab-id (suc n) f i (fs m) = tab-id n (f ∘ fs) i m


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

module Categories.Category.Lift where

open import Level
open import Categories.Category

liftC : ∀ {o ℓ e} o′ ℓ′ e′ → Category o ℓ e → Category (o ⊔ o′) (ℓ ⊔ ℓ′) (e ⊔ e′)
liftC o′ ℓ′ e′ C = record
  { Obj       = Lift o′ Obj
  ; _⇒_       = λ X Y → Lift ℓ′ (lower X ⇒ lower Y)
  ; _≈_       = λ f g → Lift e′ (lower f ≈ lower g)
  ; id        = lift id
  ; _∘_       = λ f g → lift (lower f ∘ lower g)
  ; assoc     = lift assoc
  ; sym-assoc = lift sym-assoc
  ; identityˡ = lift identityˡ
  ; identityʳ = lift identityʳ
  ; identity² = lift identity²
  ; equiv     = record
    { refl  = lift Equiv.refl
    ; sym   = λ eq → lift (Equiv.sym (lower eq))
    ; trans = λ eq eq′ → lift (Equiv.trans (lower eq) (lower eq′))
    }
  ; ∘-resp-≈  = λ eq eq′ → lift (∘-resp-≈ (lower eq) (lower eq′))
  }
  where open Category C


-- examples for termination with tupled arguments

module Tuple where

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

data Pair (A : Set) (B : Set) : Set where
  pair : A -> B -> Pair A B

-- uncurried addition
add : Pair Nat Nat -> Nat
add (pair x (succ y)) = succ (add (pair x y))
add (pair x zero)     = x

data T (A : Set) (B : Set) : Set where
  c1 : A -> B -> T A B
  c2 : A -> B -> T A B

{-
-- constructor names do not matter
add' : T Nat Nat -> Nat
add' (c1 x (succ y)) = succ (add' (c2 x y))
add' (c2 x (succ y)) = succ (add' (c1 x y))
add' (c1 x zero) = x
add' (c2 x zero) = x

-- additionally: permutation of arguments
add'' : T Nat Nat -> Nat
add'' (c1 x (succ y)) = succ (add'' (c2 y x))
add'' (c2 (succ y) x) = succ (add'' (c1 x y))
add'' (c1 x zero) = x
add'' (c2 zero x) = x
-}


{-# OPTIONS --cubical #-}

open import Cubical.Core.Glue
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Univalence
open import Cubical.Foundations.Isomorphism
open import Cubical.Data.Nat
open import Cubical.Data.Empty
open import Cubical.Data.Unit
open import Cubical.Data.Prod
open import Cubical.Data.BinNat
open import Cubical.Data.Bool
open import Cubical.Relation.Nullary
open import Direction

module NNat where
-- much of this is based directly on the
-- BinNat module in the Cubical Agda library

data BNat : Type₀ where
  b0 : BNat
  b1 : BNat
  x0 : BNat → BNat
  x1 : BNat → BNat

sucBNat : BNat → BNat
sucBNat b0 = b1
sucBNat b1 = x0 b1
sucBNat (x0 bs) = x1 bs
sucBNat (x1 bs) = x0 (sucBNat bs)

BNat→ℕ : BNat → ℕ
BNat→ℕ b0 = 0
BNat→ℕ b1 = 1
BNat→ℕ (x0 x) = doubleℕ (BNat→ℕ x)
BNat→ℕ (x1 x) = suc (doubleℕ (BNat→ℕ x))

-- BNat→Binℕ : BNat → Binℕ
-- BNat→Binℕ pos0 = binℕ0
-- BNat→Binℕ pos1 = binℕpos pos1
-- BNat→Binℕ (x0 x) = {!binℕpos (x0 binℕpos (BNat→Binℕ x))!}
-- BNat→Binℕ (x1 x) = {!!}

BNat→ℕsucBNat : (b : BNat) → BNat→ℕ (sucBNat b) ≡ suc (BNat→ℕ b)
BNat→ℕsucBNat b0 = refl
BNat→ℕsucBNat b1 = refl
BNat→ℕsucBNat (x0 b) = refl
BNat→ℕsucBNat (x1 b) = λ i → doubleℕ (BNat→ℕsucBNat b i)

ℕ→BNat : ℕ → BNat
ℕ→BNat zero = b0
ℕ→BNat (suc zero) = b1
ℕ→BNat (suc (suc n)) = sucBNat (ℕ→BNat (suc n))

ℕ→BNatSuc : ∀ n → ℕ→BNat (suc n) ≡ sucBNat (ℕ→BNat n)
ℕ→BNatSuc zero = refl
ℕ→BNatSuc (suc n) = refl

bNatInd : {P : BNat → Type₀} → P b0 → ((b : BNat) → P b → P (sucBNat b)) → (b : BNat) → P b
-- prove later...

BNat→ℕ→BNat : (b : BNat) → ℕ→BNat (BNat→ℕ b) ≡ b
BNat→ℕ→BNat b = bNatInd refl hs b
  where
  hs : (b : BNat) → ℕ→BNat (BNat→ℕ b) ≡ b → ℕ→BNat (BNat→ℕ (sucBNat b)) ≡ sucBNat b
  hs b hb =
      ℕ→BNat (BNat→ℕ (sucBNat b))
    ≡⟨ cong ℕ→BNat (BNat→ℕsucBNat b) ⟩
      ℕ→BNat (suc (BNat→ℕ b))
    ≡⟨ ℕ→BNatSuc (BNat→ℕ b) ⟩
      sucBNat (ℕ→BNat (BNat→ℕ b))
    ≡⟨ cong sucBNat hb ⟩
      sucBNat b
    ∎

ℕ→BNat→ℕ : (n : ℕ) → BNat→ℕ (ℕ→BNat n) ≡ n
ℕ→BNat→ℕ zero = refl
ℕ→BNat→ℕ (suc n) =
    BNat→ℕ (ℕ→BNat (suc n))
  ≡⟨ cong BNat→ℕ (ℕ→BNatSuc n) ⟩
    BNat→ℕ (sucBNat (ℕ→BNat n))
  ≡⟨ BNat→ℕsucBNat (ℕ→BNat n) ⟩
    suc (BNat→ℕ (ℕ→BNat n))
  ≡⟨ cong suc (ℕ→BNat→ℕ n) ⟩
    suc n
  ∎

BNat≃ℕ : BNat ≃ ℕ
BNat≃ℕ = isoToEquiv (iso BNat→ℕ ℕ→BNat ℕ→BNat→ℕ BNat→ℕ→BNat)

BNat≡ℕ : BNat ≡ ℕ
BNat≡ℕ = ua BNat≃ℕ

open NatImpl

NatImplBNat : NatImpl BNat
z NatImplBNat = b0
s NatImplBNat = sucBNat

--

data np (r : ℕ) : Type₀ where
  bp : DirNum r → np r
  zp : ∀ (d d′ : DirNum r) → bp d ≡ bp d′
  xp : DirNum r → np r → np r

sucnp : ∀ {r} → np r → np r
sucnp {zero} (bp tt) = xp tt (bp tt)
sucnp {zero} (zp tt tt i) = xp tt (bp tt)
sucnp {zero} (xp tt n) = xp tt (sucnp n)
sucnp {suc r} (bp d) = xp (one-n (suc r)) (bp d)
sucnp {suc r} (zp d d′ i) = xp (one-n (suc r)) (zp d d′ i)
sucnp {suc r} (xp d n) with max? d
... | no _ = xp (next d) n
... | yes _ = xp (zero-n (suc r)) (sucnp n)

np→ℕ : (r : ℕ) (x : np r) → ℕ
np→ℕ r (bp x) = 0
np→ℕ r (zp d d′ i) = 0
np→ℕ zero (xp x x₁) = suc (np→ℕ zero x₁)
np→ℕ (suc r) (xp x x₁) = sucn (DirNum→ℕ x) (doublesℕ (suc r) (np→ℕ (suc r) x₁))

ℕ→np : (r : ℕ) → (n : ℕ) → np r
ℕ→np r zero = bp (zero-n r)
ℕ→np zero (suc n) = xp tt (ℕ→np zero n)
ℕ→np (suc r) (suc n) = sucnp (ℕ→np (suc r) n)

---- generalize bnat:

data N (r : ℕ) : Type₀ where
  bn : DirNum r → N r
  xr : DirNum r → N r → N r

-- should define induction principle for N r

-- we have 2ⁿ "unary" constructors, analogous to BNat with 2¹ (b0 and b1)
-- rename n to r
-- this likely introduces inefficiencies compared
-- to BinNat, with the max? check etc.
sucN : ∀ {n} → N n → N n
sucN {zero} (bn tt) = xr tt (bn tt)
sucN {zero} (xr tt x) = xr tt (sucN x)
sucN {suc n} (bn (↓ , ds)) = (bn (↑ , ds))
sucN {suc n} (bn (↑ , ds)) with max? ds
... | no _ = (bn (↓ , next ds))
... | yes _ = xr (zero-n (suc n)) (bn (one-n (suc n)))
sucN {suc n} (xr d x) with max? d
... | no _ = xr (next d) x
... | yes _ = xr (zero-n (suc n)) (sucN x)

sucnN : {r : ℕ} → (n : ℕ) → (N r → N r)
sucnN n = iter n sucN

doubleN : (r : ℕ) → N r → N r
doubleN zero (bn tt) = bn tt
doubleN zero (xr d x) = sucN (sucN (doubleN zero x))
doubleN (suc r) (bn x) with zero-n? x
... | yes _    = bn x
            -- bad:
... | no _ = caseBool (bn (doubleDirNum (suc r) x)) (xr (zero-n (suc r)) (bn x)) (doubleable-n? x)
-- ... | no _  | doubleable  = {!bn (doubleDirNum x)!}
-- ... | no _  | notdoubleable = xr (zero-n (suc r)) (bn x)
doubleN (suc r) (xr x x₁) = sucN (sucN (doubleN (suc r) x₁))

doublesN : (r : ℕ) → ℕ → N r → N r
doublesN r zero m = m
doublesN r (suc n) m = doublesN r n (doubleN r m)

N→ℕ : (r : ℕ) (x : N r) → ℕ
N→ℕ zero (bn tt) = zero
N→ℕ zero (xr tt x) = suc (N→ℕ zero x)
N→ℕ (suc r) (bn x) = DirNum→ℕ x
N→ℕ (suc r) (xr d x) = sucn (DirNum→ℕ d) (doublesℕ (suc r) (N→ℕ (suc r) x))

N→ℕsucN : (r : ℕ) (x : N r) → N→ℕ r (sucN x) ≡ suc (N→ℕ r x)
N→ℕsucN zero (bn tt) = refl
N→ℕsucN zero (xr tt x) =
    suc (N→ℕ zero (sucN x))
  ≡⟨ cong suc (N→ℕsucN zero x) ⟩
    suc (suc (N→ℕ zero x))
  ∎
N→ℕsucN (suc r) (bn (↓ , d)) = refl
N→ℕsucN (suc r) (bn (↑ , d)) with max? d
... | no d≠max =
          doubleℕ (DirNum→ℕ (next d))
        ≡⟨ cong doubleℕ (next≡suc r d d≠max)  ⟩
          doubleℕ (suc (DirNum→ℕ d))
        ∎
... | yes d≡max = -- this can probably be shortened by not reducing down to zero
          sucn (doubleℕ (DirNum→ℕ (zero-n r)))
            (doublesℕ r (suc (suc (doubleℕ (doubleℕ (DirNum→ℕ (zero-n r)))))))
        ≡⟨ cong (λ x → sucn (doubleℕ x) (doublesℕ r (suc (suc (doubleℕ (doubleℕ x)))))) (zero-n→0 {r}) ⟩
          sucn (doubleℕ zero) (doublesℕ r (suc (suc (doubleℕ (doubleℕ zero)))))
        ≡⟨ refl ⟩
          doublesℕ (suc r) (suc zero) -- 2^(r+1)
        ≡⟨ sym (doubleDoubles r 1) ⟩
          doubleℕ (doublesℕ r (suc zero)) --2*2^r
        ≡⟨ sym (sucPred (doubleℕ (doublesℕ r (suc zero))) (doubleDoublesOne≠0 r)) ⟩
          suc (predℕ (doubleℕ (doublesℕ r (suc zero))))
        ≡⟨ cong suc (sym (sucPred (predℕ (doubleℕ (doublesℕ r (suc zero)))) (predDoubleDoublesOne≠0 r))) ⟩
          suc (suc (predℕ (predℕ (doubleℕ (doublesℕ r (suc zero))))))
        ≡⟨ cong (λ x → suc (suc x)) (sym (doublePred (doublesℕ r (suc zero)))) ⟩
          suc (suc (doubleℕ (predℕ (doublesℕ r (suc zero)))))
        ≡⟨ cong (λ x → suc (suc (doubleℕ x))) (sym (maxr≡pred2ʳ r d d≡max)) ⟩
          suc (suc (doubleℕ (DirNum→ℕ d))) -- 2*(2^r - 1) + 2 = 2^(r+1) - 2 + 2 = 2^(r+1)
        ∎
N→ℕsucN (suc r) (xr (↓ , d) x) = refl
N→ℕsucN (suc r) (xr (↑ , d) x) with max? d
... | no d≠max =
          sucn (doubleℕ (DirNum→ℕ (next d)))
           (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))
        ≡⟨ cong (λ y → sucn (doubleℕ y) (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))) (next≡suc r d d≠max) ⟩
          sucn (doubleℕ (suc (DirNum→ℕ d)))
           (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))
        ≡⟨ refl ⟩
          suc
           (suc
            (iter (doubleℕ (DirNum→ℕ d)) suc
            (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))
        ∎
... | yes d≡max =
        sucn (doubleℕ (DirNum→ℕ (zero-n r)))
        (doublesℕ r (doubleℕ (N→ℕ (suc r) (sucN x))))
      ≡⟨ cong (λ z → sucn (doubleℕ z) (doublesℕ r (doubleℕ (N→ℕ (suc r) (sucN x))))) (zero-n≡0 {r}) ⟩
        sucn (doubleℕ zero)
        (doublesℕ r (doubleℕ (N→ℕ (suc r) (sucN x))))
      ≡⟨ refl ⟩
        doublesℕ r (doubleℕ (N→ℕ (suc r) (sucN x)))
      ≡⟨ cong (λ x → doublesℕ r (doubleℕ x)) (N→ℕsucN (suc r) x)  ⟩
        doublesℕ r (doubleℕ (suc (N→ℕ (suc r) x)))
      ≡⟨ refl ⟩
        doublesℕ r (suc (suc (doubleℕ (N→ℕ (suc r) x)))) -- 2^r * (2x + 2) = 2^(r+1)x + 2^(r+1)
      ≡⟨ doublesSucSuc r (doubleℕ (N→ℕ (suc r) x)) ⟩
        sucn (doublesℕ (suc r) 1) -- _ + 2^(r+1)
         (doublesℕ (suc r) (N→ℕ (suc r) x)) --  2^(r+1)x + 2^(r+1)
      ≡⟨ H r (doublesℕ (suc r) (N→ℕ (suc r) x)) ⟩
        suc
         (suc
          (sucn (doubleℕ (predℕ (doublesℕ r 1))) -- _ + 2(2^r - 1) + 2
           (doublesℕ (suc r) (N→ℕ (suc r) x))))
      ≡⟨ refl ⟩
        suc
         (suc
          (sucn (doubleℕ (predℕ (doublesℕ r 1)))
           (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))
      ≡⟨ cong (λ z → suc (suc (sucn (doubleℕ z) (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))) (sym (max→ℕ r))  ⟩
         suc
         (suc
          (sucn (doubleℕ (DirNum→ℕ (max-n r)))
           (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))
      ≡⟨ cong (λ z → suc (suc (sucn (doubleℕ (DirNum→ℕ z)) (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))) (sym (d≡max)) ⟩
         suc
         (suc
          (sucn (doubleℕ (DirNum→ℕ d))
           (doublesℕ r (doubleℕ (N→ℕ (suc r) x))))) -- (2^r*2x + (2*(2^r - 1))) + 2 = 2^(r+1)x + 2^(r+1)
      ∎
      where
        H : (n m : ℕ) → sucn (doublesℕ (suc n) 1) m ≡ suc (suc (sucn (doubleℕ (predℕ (doublesℕ n 1))) m))
        H zero m = refl
        H (suc n) m =
            sucn (doublesℕ n 4) m
          ≡⟨ cong (λ z → sucn z m) (doublesSucSuc n 2) ⟩
            sucn (sucn (doublesℕ (suc n) 1) (doublesℕ n 2)) m
          ≡⟨ refl ⟩
            sucn (sucn (doublesℕ n 2) (doublesℕ  n 2)) m
          ≡⟨ {!!} ⟩
            sucn (doubleℕ (doublesℕ n 2)) m
          ≡⟨ {!!} ⟩ {!!}

ℕ→N : (r : ℕ) → (n : ℕ) → N r
ℕ→N r zero = bn (zero-n r)
ℕ→N zero (suc n) = xr tt (ℕ→N zero n)
ℕ→N (suc r) (suc n) = sucN (ℕ→N (suc r) n)

ℕ→Nsuc : (r : ℕ) (n : ℕ) → ℕ→N r (suc n) ≡ sucN (ℕ→N r n)
ℕ→Nsuc r n = {!!}

ℕ→Nsucn : (r : ℕ) (n m : ℕ) → ℕ→N r (sucn n m) ≡ sucnN n (ℕ→N r m)
ℕ→Nsucn r n m = {!!}

-- NℕNlemma is actually a pretty important fact;
-- this is what allows the direct isomorphism of N and ℕ to go
-- without the need for an extra datatype, e.g. Pos for BinNat,
-- since each ℕ < 2^r maps to its "numeral" in N r.
-- should rename and move elsewhere.
numeral-next : (r : ℕ) (d : DirNum r) → N (suc r)
numeral-next r d = bn (embed-next r d)

--
NℕNlemma : (r : ℕ) (d : DirNum r) → ℕ→N r (DirNum→ℕ d) ≡ bn d
NℕNlemma zero tt = refl
NℕNlemma (suc r) (↓ , ds) =
    ℕ→N (suc r) (doubleℕ (DirNum→ℕ ds))
  ≡⟨ {!!} ⟩ {!!}
NℕNlemma (suc r) (↑ , ds) = {!!}

N→ℕ→N : (r : ℕ) → (x : N r) → ℕ→N r (N→ℕ r x) ≡ x
N→ℕ→N zero (bn tt) = refl
N→ℕ→N zero (xr tt x) = cong (xr tt) (N→ℕ→N zero x)
N→ℕ→N (suc r) (bn (↓ , ds)) =
    ℕ→N (suc r) (doubleℕ (DirNum→ℕ ds))
  ≡⟨ cong (λ x → ℕ→N (suc r) x) (double-lemma ds) ⟩
    ℕ→N (suc r) (DirNum→ℕ {suc r} (↓ , ds))
  ≡⟨ NℕNlemma (suc r) (↓ , ds) ⟩
    bn (↓ , ds)
  ∎
N→ℕ→N (suc r) (bn (↑ , ds)) =
    sucN (ℕ→N (suc r) (doubleℕ (DirNum→ℕ ds)))
  ≡⟨ cong (λ x → sucN (ℕ→N (suc r) x)) (double-lemma ds) ⟩
    sucN (ℕ→N (suc r) (DirNum→ℕ {suc r} (↓ , ds)))
  ≡⟨ cong sucN (NℕNlemma (suc r) (↓ , ds)) ⟩
    sucN (bn (↓ , ds))
  ≡⟨ refl ⟩
    bn (↑ , ds)
  ∎
N→ℕ→N (suc r) (xr (↓ , ds) x) =
     ℕ→N (suc r)
      (sucn (doubleℕ (DirNum→ℕ ds))
       (doublesℕ r (doubleℕ (N→ℕ (suc r) x))))
   ≡⟨ cong (λ z → ℕ→N (suc r) (sucn z (doublesℕ r (doubleℕ (N→ℕ (suc r) x))))) (double-lemma ds)  ⟩
      ℕ→N (suc r)
      (sucn (DirNum→ℕ {suc r} (↓ , ds))
       (doublesℕ r (doubleℕ (N→ℕ (suc r) x))))
   ≡⟨ refl ⟩
     ℕ→N (suc r)
      (sucn (DirNum→ℕ {suc r} (↓ , ds))
       (doublesℕ (suc r) (N→ℕ (suc r) x)))
   ≡⟨ ℕ→Nsucn (suc r) (DirNum→ℕ {suc r} (↓ , ds)) (doublesℕ (suc r) (N→ℕ (suc r) x)) ⟩
     sucnN (DirNum→ℕ {suc r} (↓ , ds))
      (ℕ→N (suc r) (doublesℕ (suc r) (N→ℕ (suc r) x)))
   ≡⟨ cong (λ z → sucnN (DirNum→ℕ {suc r} (↓ , ds)) z) (H (suc r) (suc r) (N→ℕ (suc r) x)) ⟩
     sucnN (DirNum→ℕ {suc r} (↓ , ds))
      (doublesN (suc r) (suc r) (ℕ→N (suc r) (N→ℕ (suc r) x)))
   ≡⟨ cong (λ z → sucnN (DirNum→ℕ {suc r} (↓ , ds)) (doublesN (suc r) (suc r) z)) (N→ℕ→N (suc r) x) ⟩
     sucnN (DirNum→ℕ {suc r} (↓ , ds))
      (doublesN (suc r) (suc r) x)
   ≡⟨ G (suc r) (↓ , ds) x snotz ⟩
     xr (↓ , ds) x ∎
   where
     H : (r m n : ℕ) → ℕ→N r (doublesℕ m n) ≡ doublesN r m (ℕ→N r n)
     H r m n = {!!}
     G : (r : ℕ) (d : DirNum r) (x : N r) → ¬ (r ≡ 0) → sucnN (DirNum→ℕ {r} d) (doublesN r r x) ≡ xr d x
     G zero d x 0≠0 = ⊥-elim (0≠0 refl)
     G (suc r) d (bn x) r≠0 = {!!}
     G (suc r) d (xr x x₁) r≠0 = {!!}
N→ℕ→N (suc r) (xr (↑ , ds) x) with max? ds
... | no ds≠max =
          sucN
          (ℕ→N (suc r)
           (sucn (doubleℕ (DirNum→ℕ ds))
            (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))
        ≡⟨ sym (ℕ→Nsuc (suc r)
                (sucn (doubleℕ (DirNum→ℕ ds)) (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))
         ⟩
           ℕ→N (suc r)
           (suc (sucn (doubleℕ (DirNum→ℕ ds)) (doublesℕ r (doubleℕ (N→ℕ (suc r) x)))))
        ≡⟨ refl ⟩
           ℕ→N (suc r)
           (suc (sucn (doubleℕ (DirNum→ℕ ds)) (doublesℕ (suc r) (N→ℕ (suc r) x))))
        ≡⟨ cong (λ z → ℕ→N (suc r) z)
                (sym (sucnsuc (doubleℕ (DirNum→ℕ ds)) (doublesℕ (suc r) (N→ℕ (suc r) x))))
         ⟩
           ℕ→N (suc r)
           (sucn (doubleℕ (DirNum→ℕ ds)) (suc (doublesℕ (suc r) (N→ℕ (suc r) x))))
         ≡⟨ ℕ→Nsucn (suc r) (doubleℕ (DirNum→ℕ ds)) (suc (doublesℕ (suc r) (N→ℕ (suc r) x))) ⟩
           sucnN (doubleℕ (DirNum→ℕ ds)) (ℕ→N (suc r) (suc (doublesℕ (suc r) (N→ℕ (suc r) x))))
         ≡⟨ cong (λ z → sucnN (doubleℕ (DirNum→ℕ ds)) z)
                  (ℕ→Nsuc (suc r) (doublesℕ (suc r) (N→ℕ (suc r) x)))
          ⟩
           --   (2^(r+1)*x + 1) + 2*ds
           -- = 2*(2^r*x + ds) + 1
           -- = 2*(
           sucnN (doubleℕ (DirNum→ℕ ds)) (sucN (ℕ→N (suc r) (doublesℕ (suc r) (N→ℕ (suc r) x))))
         ≡⟨ {!!} ⟩ {!!}

... | yes ds≡max = {!!}

ℕ→N→ℕ : (r : ℕ) → (n : ℕ) → N→ℕ r (ℕ→N r n) ≡ n
ℕ→N→ℕ zero zero = refl
ℕ→N→ℕ (suc r) zero =
    doubleℕ (DirNum→ℕ (zero-n r))
  ≡⟨ cong doubleℕ (zero-n≡0 {r}) ⟩
    doubleℕ zero
  ≡⟨ refl ⟩
    zero
  ∎
ℕ→N→ℕ zero (suc n) = cong suc (ℕ→N→ℕ zero n)
ℕ→N→ℕ (suc r) (suc n) =
    N→ℕ (suc r) (sucN (ℕ→N (suc r) n))
  ≡⟨ N→ℕsucN (suc r) (ℕ→N (suc r) n) ⟩
    suc (N→ℕ (suc r) (ℕ→N (suc r) n))
  ≡⟨ cong suc (ℕ→N→ℕ (suc r) n) ⟩
    suc n
  ∎

N≃ℕ : (r : ℕ) → N r ≃ ℕ
N≃ℕ r = isoToEquiv (iso (N→ℕ r) (ℕ→N r) (ℕ→N→ℕ r) (N→ℕ→N r))

N≡ℕ : (r : ℕ) → N r ≡ ℕ
N≡ℕ r = ua (N≃ℕ r)

---- pos approach:

data NPos (n : ℕ) : Type₀ where
  npos1 : NPos n
  x⇀ : DirNum n → NPos n → NPos n

sucNPos : ∀ {n} → NPos n → NPos n
sucNPos {zero} npos1      = x⇀ tt npos1
sucNPos {zero} (x⇀ tt x) = x⇀ tt (sucNPos x)
sucNPos {suc n} npos1     = x⇀ (next (one-n (suc n))) npos1
sucNPos {suc n} (x⇀ d x) with (max? d)
...            | (no _)  = x⇀ (next d) x
...            | (yes _) = x⇀ (zero-n (suc n)) (sucNPos x)

-- some examples for sanity check

2₂ : NPos 1
2₂ = x⇀ (↓ , tt) npos1

3₂ : NPos 1
3₂ = x⇀ (↑ , tt) npos1

4₂ : NPos 1
4₂ = x⇀ (↓ , tt) (x⇀ (↓ , tt) npos1)

2₄ : NPos 2
2₄ = x⇀ (↓ , (↑ , tt)) npos1 -- how does this make sense?

3₄ : NPos 2
3₄ = x⇀ (↑ , (↑ , tt)) npos1 -- how does this make sense?

-- sucnpos1≡x⇀one-n : ∀ {r} → sucNPos npos1 ≡ x⇀ (one-n r) npos1
-- sucnpos1≡x⇀one-n {zero} = refl
-- sucnpos1≡x⇀one-n {suc r} = {!!}

-- sucnposx⇀zero-n≡x⇀one-n : ∀ {r} {p} → sucNPos (x⇀ (zero-n r) p) ≡ x⇀ (one-n r) p
-- sucnposx⇀zero-n≡x⇀one-n {zero} {npos1} = {!!}
-- sucnposx⇀zero-n≡x⇀one-n {zero} {x⇀ x p} = {!!}
-- sucnposx⇀zero-n≡x⇀one-n {suc r} {p} = refl

nPosInd : ∀ {r} {P : NPos r → Type₀} →
            P npos1 →
            ((p : NPos r) → P p → P (sucNPos p)) →
            (p : NPos r) →
            P p
nPosInd {r} {P} h1 hs ps = f ps
  where
     H :  (p : NPos r) → P (x⇀ (zero-n r) p) → P (x⇀ (zero-n r) (sucNPos p))
     --H p hx0p = hs (x⇀ (one-n r) p) (hs (x⇀ (zero-n r) p) hx0p)

     f : (ps : NPos r) → P ps
     f npos1 = h1
     f (x⇀ d ps) with (max? d)
     ... | (no _) = {!nPosInd (hs npos1 h1) H ps!}
     ... | (yes _) = {!hs (x⇀ (zero-n r) ps) (nPosInd (hs npos1 h1) H ps)!}

-- nPosInd {zero} {P} h1 hs ps = f ps
--   where
--   H : (p : NPos zero) → P (x⇀ (zero-n zero) p) → P (x⇀ (zero-n zero) (sucNPos p))
--   H p hx0p = hs (x⇀ tt (x⇀ (zero-n zero) p)) (hs (x⇀ (zero-n zero) p) hx0p)

--   f : (ps : NPos zero) → P ps
--   f npos1 = h1
--   f (x⇀ tt ps) = nPosInd (hs npos1 h1) H ps
-- nPosInd {suc r} {P} h1 hs ps = f ps
--   where
--   H : (p : NPos (suc r)) → P (x⇀ (zero-n (suc r)) p) → P (x⇀ (zero-n (suc r)) (sucNPos p))
--   --H p hx0p = hs (x⇀ (one-n r) p) (hs (x⇀ (zero-n r) p) hx0p)

--   f : (ps : NPos (suc r)) → P ps
--   f npos1 = h1
--   f (x⇀ d ps) = {!!}

NPos→ℕ : ∀ r → NPos r → ℕ
NPos→ℕ zero npos1 = suc zero
NPos→ℕ zero (x⇀ tt x) = suc (NPos→ℕ zero x)
NPos→ℕ (suc r) npos1 = suc zero
NPos→ℕ (suc r) (x⇀ d x) with max? d
... | no _ = sucn (DirNum→ℕ (next d)) (doublesℕ (suc r) (NPos→ℕ (suc r) x))
... | yes _ = sucn (DirNum→ℕ (next d)) (doublesℕ (suc r) (suc (NPos→ℕ (suc r) x)))
-- NPos→ℕ (suc r) (x⇀ d x) =
--   sucn (DirNum→ℕ d) (doublesℕ (suc r) (NPos→ℕ (suc r) x))

NPos→ℕsucNPos : ∀ r → (p : NPos r) → NPos→ℕ r (sucNPos p) ≡ suc (NPos→ℕ r p)
NPos→ℕsucNPos zero npos1 = refl
NPos→ℕsucNPos zero (x⇀ d p) = cong suc (NPos→ℕsucNPos zero p)
NPos→ℕsucNPos (suc r) npos1 = {!!}
    sucn (doubleℕ (DirNum→ℕ (zero-n r))) (doublesℕ r 2)
  ≡⟨ cong (λ y → sucn y (doublesℕ r 2)) (zero-n→0) ⟩
    sucn (doubleℕ zero) (doublesℕ r 2)
  ≡⟨ refl ⟩
    doublesℕ r 2
  ≡⟨ {!!} ⟩ {!!}
NPos→ℕsucNPos (suc r) (x⇀ d p) with max? d
... | no _ = {!!}
... | yes _ = {!!}

-- zero≠NPos→ℕ : ∀ {r} → (p : NPos r) → ¬ (zero ≡ NPos→ℕ r p)
-- zero≠NPos→ℕ {r} p = {!!}

ℕ→NPos : ∀ r → ℕ → NPos r
ℕ→NPos zero zero = npos1
ℕ→NPos zero (suc zero) = npos1
ℕ→NPos zero (suc (suc n)) = sucNPos (ℕ→NPos zero (suc n))
ℕ→NPos (suc r) zero = npos1
ℕ→NPos (suc r) (suc zero) = npos1
ℕ→NPos (suc r) (suc (suc n)) = sucNPos (ℕ→NPos (suc r) (suc n))

lemma : ∀ {r} → (ℕ→NPos r (NPos→ℕ r npos1)) ≡ npos1
lemma {zero} = refl
lemma {suc r} = refl

NPos→ℕ→NPos : ∀ r → (p : NPos r) → ℕ→NPos r (NPos→ℕ r p) ≡ p
NPos→ℕ→NPos r p = nPosInd lemma hs p
  where
  hs : (p : NPos r) → ℕ→NPos r (NPos→ℕ r p) ≡ p → ℕ→NPos r (NPos→ℕ r (sucNPos p)) ≡ (sucNPos p)
  hs p hp =
      ℕ→NPos r (NPos→ℕ r (sucNPos p))
    ≡⟨ {!!} ⟩
      ℕ→NPos r (suc (NPos→ℕ r p))
    ≡⟨ {!!} ⟩
      sucNPos (ℕ→NPos r (NPos→ℕ r p))
    ≡⟨ cong sucNPos hp ⟩
      sucNPos p
    ∎

-- note: the cases for zero and suc r are almost identical
-- (why) does this need to split?
ℕ→NPos→ℕ : ∀ r → (n : ℕ) → NPos→ℕ r (ℕ→NPos r (suc n)) ≡ (suc n)
ℕ→NPos→ℕ zero zero = refl
ℕ→NPos→ℕ zero (suc n) =
      NPos→ℕ zero (sucNPos (ℕ→NPos zero (suc n)))
    ≡⟨ {!!} ⟩
      suc (NPos→ℕ zero (ℕ→NPos zero (suc n)))
    ≡⟨ cong suc (ℕ→NPos→ℕ zero n) ⟩
      suc (suc n)
    ∎
ℕ→NPos→ℕ (suc r) zero = refl
ℕ→NPos→ℕ (suc r) (suc n) =
    NPos→ℕ (suc r) (sucNPos (ℕ→NPos (suc r) (suc n)))
  ≡⟨ {!!} ⟩
    suc (NPos→ℕ (suc r) (ℕ→NPos (suc r) (suc n)))
  ≡⟨ cong suc (ℕ→NPos→ℕ (suc r) n) ⟩
    suc (suc n)
  ∎


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

open import Categories.Category

module Categories.Diagram.Pullback.Limit {o ℓ e} (C : Category o ℓ e) where

open import Data.Product using (∃₂; _,_)
open import Function using (_$_)

open import Categories.Category.Instance.Span
open import Categories.Functor
open import Categories.Diagram.Pullback C
open import Categories.Morphism.Reasoning C as MR hiding (center)

import Relation.Binary.PropositionalEquality as ≡

import Categories.Category.Construction.Cones as Con
import Categories.Diagram.Limit as Lim

private
  module C = Category C
  module Span = Category Span
  open Category C
  variable
    X Y Z : Obj
    f g h : X ⇒ Y

open HomReasoning

module _ {F : Functor Span.op C} where
  open Functor F
  open Lim F
  open Con F

  private
    W = F₀ center
    A = F₀ left
    B = F₀ right

    A⇒W : A ⇒ W
    A⇒W = F₁ span-arrˡ

    B⇒W : B ⇒ W
    B⇒W = F₁ span-arrʳ

  limit⇒pullback : Limit → Pullback A⇒W B⇒W
  limit⇒pullback lim = record
    { p₁              = proj left
    ; p₂              = proj right
    ; commute         = trans (limit-commute span-arrˡ) (sym (limit-commute span-arrʳ))
    ; universal       = universal
    ; unique          = commute′
    ; p₁∘universal≈h₁ = commute
    ; p₂∘universal≈h₂ = commute
    }
    where open Limit lim
          universal : A⇒W ∘ f ≈ B⇒W ∘ g → dom f ⇒ apex
          universal {f = f} {g = g} eq = rep $ record
            { apex = record
              { ψ       = λ { center → B⇒W ∘ g
                            ; left   → f
                            ; right  → g
                            }
            ; commute = λ { {center} {center} span-id  → elimˡ identity
                          ; {left} {center} span-arrˡ  → eq
                          ; {left} {left} span-id      → elimˡ identity
                          ; {right} {center} span-arrʳ → refl
                          ; {right} {right} span-id    → elimˡ identity
                          }
              }
            }

          proj-center : proj center ≈ B⇒W ∘ proj right
          proj-center = sym (limit-commute span-arrʳ)

          commute′ : ∀ {eq : A⇒W ∘ f ≈ B⇒W ∘ g} → proj left ∘ h ≈ f → proj right ∘ h ≈ g → h ≈ universal eq
          commute′ {f = f} {g = g} {h = h} {eq = eq} eq₁ eq₂ = sym $ terminal.!-unique $ record
            { arr     = h
            ; commute = λ { {center} → begin
                              proj center ∘ h      ≈⟨ pushˡ proj-center ⟩
                              B⇒W ∘ proj right ∘ h ≈⟨ refl⟩∘⟨ eq₂ ⟩
                              B⇒W ∘ g              ∎
                          ; {left}   → eq₁
                          ; {right}  → eq₂
                          }
            }

module _ (p : Pullback f g) where
  open Pullback p

  pullback⇒limit-F : Functor Span.op C
  pullback⇒limit-F = record
    { F₀           = λ { center → cod f
                       ; left   → dom f
                       ; right  → dom g
                       }
    ; F₁           = λ { {center} {.center} span-id   → C.id
                       ; {left} {.left} span-id       → C.id
                       ; {right} {.right} span-id     → C.id
                       ; {.left} {.center} span-arrˡ  → f
                       ; {.right} {.center} span-arrʳ → g
                       }
    ; identity     = λ { {center} → refl
                       ; {left}   → refl
                       ; {right}  → refl
                       }
    ; homomorphism = λ { {center} {.center} {.center} {span-id} {span-id}   → sym identityˡ
                       ; {left} {.left} {.left} {span-id} {span-id}         → sym identityˡ
                       ; {right} {.right} {.right} {span-id} {span-id}      → sym identityˡ
                       ; {.left} {.left} {.center} {span-id} {span-arrˡ}    → sym identityʳ
                       ; {.right} {.right} {.center} {span-id} {span-arrʳ}  → sym identityʳ
                       ; {.left} {.center} {.center} {span-arrˡ} {span-id}  → sym identityˡ
                       ; {.right} {.center} {.center} {span-arrʳ} {span-id} → sym identityˡ
                       }
    ; F-resp-≈     = λ { {center} {.center} {span-id} {.span-id} ≡.refl     → refl
                       ; {left} {.left} {span-id} {.span-id} ≡.refl         → refl
                       ; {right} {.right} {span-id} {.span-id} ≡.refl       → refl
                       ; {.left} {.center} {span-arrˡ} {.span-arrˡ} ≡.refl  → refl
                       ; {.right} {.center} {span-arrʳ} {.span-arrʳ} ≡.refl → refl
                       }
    }

  open Functor pullback⇒limit-F
  open Lim pullback⇒limit-F
  open Con pullback⇒limit-F

  pullback⇒limit : Limit
  pullback⇒limit = record
    { terminal = record
      { ⊤        = ⊤
      ; !        = !
      ; !-unique = !-unique
      }
    }
    where ⊤ : Cone
          ⊤ = record
            { apex = record
              { ψ       = λ { center → g ∘ p₂
                            ; left   → p₁
                            ; right  → p₂
                            }
              ; commute = λ { {center} {.center} span-id   → identityˡ
                            ; {left} {.left} span-id       → identityˡ
                            ; {right} {.right} span-id     → identityˡ
                            ; {.left} {.center} span-arrˡ  → commute
                            ; {.right} {.center} span-arrʳ → refl
                            }
              }
            }

          ! : ∀ {A : Cone} → Cone⇒ A ⊤
          ! {A} = record
            { arr     = universal commute′
            ; commute = λ { {center} → begin
                            (g ∘ p₂) ∘ universal _ ≈⟨ pullʳ p₂∘universal≈h₂ ⟩
                            g ∘ A.ψ right          ≈⟨ A.commute span-arrʳ ⟩
                            A.ψ center             ∎
                          ; {left}   → p₁∘universal≈h₁
                          ; {right}  → p₂∘universal≈h₂
                          }
            }
            where module A = Cone A
                  commute′ = trans (A.commute span-arrˡ) (sym (A.commute span-arrʳ))

          !-unique : ∀ {A : Cone} (h : Cone⇒ A ⊤) → Cones [ ! ≈ h ]
          !-unique {A} h = sym (unique h.commute h.commute)
            where module h = Cone⇒ h


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

open import LogicalFormulae
open import Numbers.Naturals.Definition
open import Numbers.Naturals.Naturals
open import Numbers.Integers.Integers
open import Groups.Groups
open import Groups.Definition
open import Groups.Lemmas
open import Rings.Definition
open import Rings.Orders.Total.Definition
open import Rings.Orders.Partial.Definition
open import Fields.Fields
open import Setoids.Setoids
open import Setoids.Orders.Partial.Definition
open import Setoids.Orders.Total.Definition
open import Functions.Definition
open import Sets.EquivalenceRelations

module Numbers.Rationals.Definition where

open import Fields.FieldOfFractions.Setoid ℤIntDom
open import Fields.FieldOfFractions.Addition ℤIntDom
open import Fields.FieldOfFractions.Multiplication ℤIntDom
open import Fields.FieldOfFractions.Ring ℤIntDom
open import Fields.FieldOfFractions.Field ℤIntDom
open import Fields.FieldOfFractions.Lemmas ℤIntDom
open import Fields.FieldOfFractions.Order ℤIntDom ℤOrderedRing

ℚ : Set
ℚ = fieldOfFractionsSet

ℚSetoid : Setoid ℚ
ℚSetoid = fieldOfFractionsSetoid

_+Q_ : ℚ → ℚ → ℚ
a +Q b = fieldOfFractionsPlus a b

_*Q_ : ℚ → ℚ → ℚ
a *Q b = fieldOfFractionsTimes a b

ℚRing : Ring fieldOfFractionsSetoid _+Q_ _*Q_
ℚRing = fieldOfFractionsRing

0Q : ℚ
0Q = Ring.0R ℚRing

injectionQ : ℤ → ℚ
injectionQ = embedIntoFieldOfFractions

injectionNQ : ℕ → ℚ
injectionNQ n = injectionQ (nonneg n)

injectionQInjective : Injection injectionQ
injectionQInjective {nonneg x} {nonneg .x} refl = refl
injectionQInjective {negSucc x} {negSucc .x} refl = refl

ℚField : Field ℚRing
ℚField = fieldOfFractions

_<Q_ : ℚ → ℚ → Set
_<Q_ = fieldOfFractionsComparison

_=Q_ : ℚ → ℚ → Set
a =Q b = Setoid._∼_ fieldOfFractionsSetoid a b

reflQ : {x : ℚ} → (x =Q x)
reflQ {x} = Equivalence.reflexive (Setoid.eq fieldOfFractionsSetoid) {x}

_≤Q_ : ℚ → ℚ → Set
a ≤Q b = (a <Q b) || (a =Q b)

negateQ : ℚ → ℚ
negateQ a = Group.inverse (Ring.additiveGroup ℚRing) a

_-Q_ : ℚ → ℚ → ℚ
a -Q b = a +Q negateQ b

a-A : (a : ℚ) → (a -Q a) =Q 0Q
a-A a = Group.invRight (Ring.additiveGroup ℚRing) {a}

ℚPartialOrder : SetoidPartialOrder fieldOfFractionsSetoid fieldOfFractionsComparison
ℚPartialOrder = fieldOfFractionsOrder

ℚTotalOrder : SetoidTotalOrder fieldOfFractionsOrder
ℚTotalOrder = fieldOfFractionsTotalOrder

ℚOrderInherited : (a b : ℤ) → a <Z b → injectionQ a <Q injectionQ b
ℚOrderInherited a b a<b = fieldOfFractionsOrderInherited a<b

open SetoidTotalOrder fieldOfFractionsTotalOrder
open SetoidPartialOrder partial
open Setoid fieldOfFractionsSetoid

negateQWellDefined : (a b : ℚ) → (a =Q b) → (negateQ a) =Q (negateQ b)
negateQWellDefined a b a=b = inverseWellDefined (Ring.additiveGroup ℚRing) {a} {b} a=b

ℚPOrdered : PartiallyOrderedRing ℚRing partial
ℚPOrdered = fieldOfFractionsPOrderedRing

ℚOrdered : TotallyOrderedRing ℚPOrdered
ℚOrdered = fieldOfFractionsOrderedRing