{- Name: Bowornmet (Ben) Hudson

--Preorders in Agda!--

-}

open import Preliminaries

module Preorder where

  {- definition: a Preorder on a set A is a binary relation
     that is reflexive and transitive.
  -}
  record Preorder-str (A : Set) : Set1 where
    constructor preorder
    field
      ≤ : A → A → Set
      refl : ∀ x → ≤ x x
      trans : ∀ x y z → ≤ x y → ≤ y z → ≤ x z

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

  -- Task 1: Show that the Natural numbers with ≤ form a preorder

  -- the ≤ relation on Natural numbers
  ≤nat : Nat → Nat → Set
  ≤nat Z Z = Unit
  ≤nat Z (S y) = Unit
  ≤nat (S x) Z = Void
  ≤nat (S x) (S y) = ≤nat x y

  -- proof that Nat is reflexive under ≤
  nat-refl : ∀ (x : Nat) → ≤nat x x
  nat-refl Z = <>
  nat-refl (S x) = nat-refl x

  -- proof that Nat is transitive under ≤
  nat-trans : ∀ (x y z : Nat) → ≤nat x y → ≤nat y z → ≤nat x z
  nat-trans Z Z Z p q = <>
  nat-trans Z Z (S z) p q = <>
  nat-trans Z (S y) Z p q = abort q
  nat-trans Z (S y) (S z) p q = <>
  nat-trans (S x) Z Z () q
  nat-trans (S x) Z (S z) () q
  nat-trans (S x) (S y) Z p ()
  nat-trans (S x) (S y) (S z) p q = nat-trans x y z p q

  -- proof that Nat and ≤ (the ≤ relation defined on the natural numbers) form a preorder
  nat-ispreorder : Preorder-str Nat
  nat-ispreorder = record { ≤ = ≤nat; refl = nat-refl; trans = nat-trans }

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

  -- Task 2: Show that the product of two preorders is a preorder

  {- defining the relation: when is one cartesian product 'less than' another?
     if A and B are preorders and we have cartesian products (a1,b1) and (a2,b2)
     such that a1,a2 ∈ A and b1,b2 ∈ B,
     then (a1,b1)≤(a2,b2) iff a1≤a2 and b1≤b2
  -}
  ≤axb : ∀ {A B : Set} → Preorder-str A → Preorder-str B → (A × B) → (A × B) → Set
  ≤axb PA PB (a1 , b1) (a2 , b2) = Preorder-str.≤ PA a1 a2 × Preorder-str.≤ PB b1 b2

  {-  a cartesian product (a,b) is 'less than' itself
     if each component of the product is reflexive, i.e.
     just show that a is reflexive and b is reflexive
  -}
  axb-refl : ∀ {A B : Set} → (PA : Preorder-str A) → (PB : Preorder-str B) → (x : (A × B)) →  ≤axb PA PB x x
  axb-refl PA PB (a , b) = Preorder-str.refl PA a , Preorder-str.refl PB b

  -- same idea for transitivity...
  axb-trans : ∀ {A B : Set} → (PA : Preorder-str A) → (PB : Preorder-str B) → (x y z : (A × B)) → ≤axb PA PB x y → ≤axb PA PB y z → ≤axb PA PB x z
  axb-trans PA PB (a1 , b1) (a2 , b2) (a3 , b3) (a1<a2 , b1<b2) (a2<a3 , b2<b3) =
                          Preorder-str.trans PA a1 a2 a3 a1<a2 a2<a3 , Preorder-str.trans PB b1 b2 b3 b1<b2 b2<b3

  -- proof that AxB is a preorder
  AxB-ispreorder : ∀ (A B : Set) → Preorder-str A → Preorder-str B → Preorder-str (A × B)
  AxB-ispreorder A B pre-a pre-b = record { ≤ = ≤axb pre-a pre-b; refl = axb-refl pre-a pre-b; trans = axb-trans pre-a pre-b }

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

  -- Task 3: Show that the sum of two preorders is a preorder

  ≤a+b : ∀ {A B : Set} → Preorder-str A → Preorder-str B → (Either A B) → (Either A B) → Set
  ≤a+b (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inl a1) (Inl a2) = (a1 ≤a a2)
  ≤a+b (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inl a1) (Inr b2) = Void
  ≤a+b (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inr b1) (Inl a2) = Void
  ≤a+b (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inr b1) (Inr b2) = (b1 ≤b b2)

  a+b-refl : ∀ {A B : Set} → (a : Preorder-str A) → (b : Preorder-str B) → (x : (Either A B)) → ≤a+b a b x x
  a+b-refl (preorder _≤a_ refla transa) pre-b (Inl a) = refla a
  a+b-refl pre-a (preorder _≤b_ reflb transb) (Inr b) = reflb b

  a+b-trans : ∀ {A B : Set} → (a : Preorder-str A) → (b : Preorder-str B) → (x y z : (Either A B)) → ≤a+b a b x y → ≤a+b a b y z → ≤a+b a b x z
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inl a1) (Inl a2) (Inl a3) a1<a2 a2<a3 = transa a1 a2 a3 a1<a2 a2<a3
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inl a1) (Inl a2) (Inr b3) p ()
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inl a1) (Inr b2) (Inl a3) () q
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inl a1) (Inr b2) (Inr b3) () q
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inr b1) (Inl a2) (Inl a3) () q
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inr b1) (Inl a2) (Inr b3) () q
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inr b1) (Inr b2) (Inl a3) p ()
  a+b-trans (preorder _≤a_ refla transa) (preorder _≤b_ reflb transb) (Inr b1) (Inr b2) (Inr b3) b1<b2 b2<b3 = transb b1 b2 b3 b1<b2 b2<b3

  -- proof that A+B is a preorder
  A+B-ispreorder : ∀ (A B : Set) → Preorder-str A → Preorder-str B → Preorder-str (Either A B)
  A+B-ispreorder A B pre-a pre-b = record { ≤ = ≤a+b pre-a pre-b; refl = a+b-refl pre-a pre-b; trans = a+b-trans pre-a pre-b }

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

  -- Task 4: Show that given a Preorder A and Preorder B, Preorder (Monotone A B)

  -- the type of monotone functions from A to B
  -- i.e. functions which give you bigger outputs when you give them bigger inputs
  record Monotone (A : Set) (B : Set) (PA : Preorder-str A) (PB : Preorder-str B) : Set where
    constructor monotone
    field
      f : A → B
      is-monotone : ∀ (x y : A) → Preorder-str.≤ PA x y → Preorder-str.≤ PB (f x) (f y)

  -- the order on monotone functions is just the
  -- pointwise order on the underlying functions
  ≤mono : ∀ {A B : Set} → (PA : Preorder-str A) → (PB : Preorder-str B) → (Monotone A B PA PB) → (Monotone A B PA PB) → Set
  ≤mono {A} PA PB f g = (x : A) → Preorder-str.≤ PB (Monotone.f f x) (Monotone.f g x)

  mono-refl : ∀ {A B : Set} → (PA : Preorder-str A) → (PB : Preorder-str B) → (x : (Monotone A B PA PB)) → ≤mono PA PB x x
  mono-refl PA PB f = λ x → Preorder-str.refl PB (Monotone.f f x)

  mono-trans : ∀ {A B : Set} → (PA : Preorder-str A) → (PB : Preorder-str B) → (x y z : (Monotone A B PA PB)) → ≤mono PA PB x y → ≤mono PA PB y z → ≤mono PA PB x z
  mono-trans PA PB f g h p q = λ x → Preorder-str.trans PB (Monotone.f f x) (Monotone.f g x) (Monotone.f h x) (p x) (q x)

  monotone-ispreorder : ∀ (A B : Set) → (PA : Preorder-str A) → (PB : Preorder-str B) → Preorder-str (Monotone A B PA PB)
  monotone-ispreorder A B PA PB = preorder (≤mono PA PB) (mono-refl PA PB) (mono-trans PA PB)

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

-- New stuff: Interpreting types as preorders

  -- repackaging preorder as a type together with a Preorder structure on that type
  PREORDER = Σ (λ (A : Set) → Preorder-str A)

  MONOTONE : (PΓ PA : PREORDER) → Set
  MONOTONE (Γ , PΓ) (A , PA) = Monotone Γ A PΓ PA

  -- some operations
  _×p_ : PREORDER → PREORDER → PREORDER
  (A , PA) ×p (B , PB) = A × B , AxB-ispreorder A B PA PB

  _+p_ : PREORDER → PREORDER → PREORDER
  (A , PA) +p (B , PB) = Either A B , A+B-ispreorder A B PA PB

  _->p_ : PREORDER → PREORDER → PREORDER
  (A , PA) ->p (B , PB) = Monotone A B PA PB , monotone-ispreorder A B PA PB

  -- Unit is a preorder
  unit-p : PREORDER
  unit-p = Unit , preorder (λ x y → Unit) (λ x → <>) (λ x y z _ _ → <>)

  -- identity preserves monotonicity
  id : ∀ {Γ} → MONOTONE Γ Γ
  id = λ {Γ} → monotone (λ x → x) (λ x y x₁ → x₁)

  -- composition preserves monotonicity
  comp : ∀ {PA PB PC} → MONOTONE PA PB → MONOTONE PB PC → MONOTONE PA PC
  comp (monotone f f-ismono) (monotone g g-ismono) =
          monotone (λ x → g (f x)) (λ x y x₁ → g-ismono (f x) (f y) (f-ismono x y x₁))

  -- proofs that types like pairs etc. with preorders are monotone
  pair' : ∀ {PΓ PA PB} → MONOTONE PΓ PA → MONOTONE PΓ PB → MONOTONE PΓ (PA ×p PB)
  pair' (monotone f f-ismono) (monotone g g-ismono) =
          monotone (λ x → f x , g x) (λ x y z → f-ismono x y z , g-ismono x y z)

  fst' : ∀ {PΓ PA PB} → MONOTONE PΓ (PA ×p PB) → MONOTONE PΓ PA
  fst' (monotone f f-ismono) =
          monotone (λ x → fst (f x)) (λ x y z → fst (f-ismono x y z))

  snd' : ∀ {PΓ PA PB} → MONOTONE PΓ (PA ×p PB) → MONOTONE PΓ PB
  snd' (monotone f f-ismono) =
          monotone (λ x → snd (f x)) (λ x y z → snd (f-ismono x y z))

  lam' : ∀ {PΓ PA PB} → MONOTONE (PΓ ×p PA) PB → MONOTONE PΓ (PA ->p PB)
  lam' {Γ , preorder ≤Γ reflΓ transΓ} {a , preorder ≤a refla transa} {b , preorder ≤b reflb transb} (monotone f f-ismono) =
          monotone (λ x → monotone (λ p → f (x , p)) (λ a b c → f-ismono (x , a) (x , b) (reflΓ x , c))) (λ x y z w → f-ismono (x , w) (y , w) (z , refla w))

  app' : ∀ {PΓ PA PB} → MONOTONE PΓ (PA ->p PB) → MONOTONE PΓ PA → MONOTONE PΓ PB
  app' {Γ , preorder ≤Γ reflΓ transΓ} {a , preorder ≤a refla transa} {b , preorder ≤b reflb transb} (monotone f f-ismono) (monotone g g-ismono) =
          monotone (λ x → Monotone.f (f x) (g x)) (λ x y z → transb (Monotone.f (f x) (g x)) (Monotone.f (f y) (g x)) (Monotone.f (f y) (g y))
          (f-ismono x y z (g x)) (Monotone.is-monotone (f y) (g x) (g y) (g-ismono x y z)))

  inl' : ∀ {PΓ PA PB} → MONOTONE PΓ PA → MONOTONE PΓ (PA +p PB)
  inl' (monotone f f-ismono) =
          monotone (λ x → Inl (f x)) (λ x y z → f-ismono x y z)

  inr' : ∀ {PΓ PA PB} → MONOTONE PΓ PB → MONOTONE PΓ (PA +p PB)
  inr' (monotone f f-ismono) =
          monotone (λ x → Inr (f x)) (λ x y z → f-ismono x y z)

  case : ∀ {A B C : Set} → (A → C) → (B → C) → (Either A B → C)
  case a b (Inl x) = a x
  case a b (Inr x) = b x

  el : PREORDER → Set
  el = fst

  PREORDER≤ : (PA : PREORDER) → el PA → el PA → Set
  PREORDER≤ PA = Preorder-str.≤ (snd PA)

  -- oh my god
  lemma : ∀ {PA PB PC} {c1 c2 : el (PA +p PB)} {f1 f2 : el (PA ->p PC)} {g1 g2 : el (PB ->p PC)}
        → (PREORDER≤ (PA +p PB) c1 c2)
        → (PREORDER≤ (PA ->p PC) f1 f2)
        → (PREORDER≤ (PB ->p PC) g1 g2)
        → (PREORDER≤ PC (case (Monotone.f f1) (Monotone.f g1) c1) (case (Monotone.f f2) (Monotone.f g2) c2))
  lemma {A , preorder ≤a refla transa} {B , preorder ≤b reflb transb} {C , preorder ≤c reflc transc}
        {Inl a1} {Inl a2}
        {monotone f1 f1-ismono} {monotone f2 f2-ismono}
        a b c = transc (f1 a1) (f1 a2) (f2 a2) (f1-ismono a1 a2 a) (b a2)
  lemma {PA} {PB} {PC} {Inl a1} {Inr b1} () b c
  lemma {PA} {PB} {PC} {Inr b1} {Inl a1} () b c
  lemma {A , preorder ≤a refla transa} {B , preorder ≤b reflb transb} {C , preorder ≤c reflc transc}
        {Inr b1} {Inr b2}
        {monotone f1 f1-ismono} {monotone f2 f2-ismono} {monotone g1 g1-ismono} {monotone g2 g2-ismono}
        a b c = transc (g1 b1) (g1 b2) (g2 b2) (g1-ismono b1 b2 a) (c b2)

  lemma2 : ∀ {PΓ PA PC} → MONOTONE (PΓ ×p PA) PC → el PΓ → MONOTONE PA PC
  lemma2 {Γ , preorder ≤Γ reflΓ transΓ} (monotone f f-ismono) q = monotone (λ a → f (q , a)) (λ x y z → f-ismono (q , x) (q , y) (reflΓ q , z))

  case' : ∀ {PΓ PA PB PC} → MONOTONE (PΓ ×p PA) PC -> MONOTONE (PΓ ×p PB) PC -> MONOTONE PΓ (PA +p PB) -> MONOTONE PΓ PC
  case' {Γ , preorder ≤Γ reflΓ transΓ} {a , preorder ≤a refla transa} {b , preorder ≤b reflb transb} {c , preorder ≤c reflc transc}
        (monotone f f-ismono) (monotone g g-ismono) (monotone h h-ismono) =
          monotone (λ x → case (λ a → f (x , a)) (λ b → g (x , b)) (h x))
            (λ x y z → lemma {a , preorder ≤a refla transa} {b , preorder ≤b reflb transb} {c , preorder ≤c reflc transc} {h x} {h y}
            {lemma2 {Γ , preorder ≤Γ reflΓ transΓ}
               {a , preorder ≤a refla transa} {c , preorder ≤c reflc transc}
               (monotone f f-ismono) x}
            {lemma2 {Γ , preorder ≤Γ reflΓ transΓ}
               {a , preorder ≤a refla transa} {c , preorder ≤c reflc transc}
               (monotone f f-ismono) y}
            {lemma2 {Γ , preorder ≤Γ reflΓ transΓ}
               {b , preorder ≤b reflb transb} {c , preorder ≤c reflc transc}
               (monotone g g-ismono) x}
            {lemma2 {Γ , preorder ≤Γ reflΓ transΓ}
               {b , preorder ≤b reflb transb} {c , preorder ≤c reflc transc}
               (monotone g g-ismono) y}
                         (h-ismono x y z) (λ a₁ → f-ismono (x , a₁) (y , a₁) (z , refla a₁)) (λ b₁ → g-ismono (x , b₁) (y , b₁) (z , reflb b₁)))


------------------------------------------------------------------------
-- Unary relations
------------------------------------------------------------------------

module Relation.Unary where

open import Data.Empty
open import Data.Function
open import Data.Unit
open import Data.Product
open import Data.Sum
open import Relation.Nullary

------------------------------------------------------------------------
-- Unary relations

Pred : Set → Set₁
Pred a = a → Set

------------------------------------------------------------------------
-- Unary relations can be seen as sets

-- I.e., they can be seen as subsets of the universe of discourse.

private
 module Dummy {a : Set} -- The universe of discourse.
          where

  -- Set membership.

  infix 4 _∈_ _∉_

  _∈_ : a → Pred a → Set
  x ∈ P = P x

  _∉_ : a → Pred a → Set
  x ∉ P = ¬ x ∈ P

  -- The empty set.

  ∅ : Pred a
  ∅ = λ _ → ⊥

  -- The property of being empty.

  Empty : Pred a → Set
  Empty P = ∀ x → x ∉ P

  ∅-Empty : Empty ∅
  ∅-Empty x ()

  -- The universe, i.e. the subset containing all elements in a.

  U : Pred a
  U = λ _ → ⊤

  -- The property of being universal.

  Universal : Pred a → Set
  Universal P = ∀ x → x ∈ P

  U-Universal : Universal U
  U-Universal = λ _ → _

  -- Set complement.

  ∁ : Pred a → Pred a
  ∁ P = λ x → x ∉ P

  ∁∅-Universal : Universal (∁ ∅)
  ∁∅-Universal = λ x x∈∅ → x∈∅

  ∁U-Empty : Empty (∁ U)
  ∁U-Empty = λ x x∈∁U → x∈∁U _

  -- P ⊆ Q means that P is a subset of Q. _⊆′_ is a variant of _⊆_.

  infix 4 _⊆_ _⊇_ _⊆′_ _⊇′_

  _⊆_ : Pred a → Pred a → Set
  P ⊆ Q = ∀ {x} → x ∈ P → x ∈ Q

  _⊆′_ : Pred a → Pred a → Set
  P ⊆′ Q = ∀ x → x ∈ P → x ∈ Q

  _⊇_ : Pred a → Pred a → Set
  Q ⊇ P = P ⊆ Q

  _⊇′_ : Pred a → Pred a → Set
  Q ⊇′ P = P ⊆′ Q

  ∅-⊆ : (P : Pred a) → ∅ ⊆ P
  ∅-⊆ P ()

  ⊆-U : (P : Pred a) → P ⊆ U
  ⊆-U P _ = _

  -- Set union.

  infixl 6 _∪_

  _∪_ : Pred a → Pred a → Pred a
  P ∪ Q = λ x → x ∈ P ⊎ x ∈ Q

  -- Set intersection.

  infixl 7 _∩_

  _∩_ : Pred a → Pred a → Pred a
  P ∩ Q = λ x → x ∈ P × x ∈ Q

open Dummy public

------------------------------------------------------------------------
-- Unary relation combinators

infixr 2 _⟨×⟩_
infixr 1 _⟨⊎⟩_
infixr 0 _⟨→⟩_

_⟨×⟩_ : ∀ {A B} → Pred A → Pred B → Pred (A × B)
(P ⟨×⟩ Q) p = P (proj₁ p) × Q (proj₂ p)

_⟨⊎⟩_ : ∀ {A B} → Pred A → Pred B → Pred (A ⊎ B)
(P ⟨⊎⟩ Q) (inj₁ p) = P p
(P ⟨⊎⟩ Q) (inj₂ q) = Q q

_⟨→⟩_ : ∀ {A B} → Pred A → Pred B → Pred (A → B)
(P ⟨→⟩ Q) f = P ⊆ Q ∘₀ f


{-# OPTIONS --safe #-}
open import Relation.Ternary.Separation

module Relation.Ternary.Separation.Allstar
  {i} {I : Set i}
  {c} {C : Set c} {{rc : RawSep C}} {u} {{sc : IsUnitalSep rc u}}
  where

open import Level
open import Data.Product
open import Data.List hiding (concat)
open import Relation.Unary

{- Inductive separating forall over a list -}
module _ {ℓ} where
  data Allstar (P : I → Pred C ℓ) : List I → SPred (ℓ ⊔ c ⊔ i) where
    nil  :            ε[ Allstar P [] ]
    cons : ∀ {x xs} → ∀[ P x ✴ Allstar P xs ⇒ Allstar P (x ∷ xs) ]

  -- not typed well in non-pattern positions
  infixr 5 _:⟨_⟩:_
  pattern _:⟨_⟩:_ x p xs = cons (x ×⟨ p ⟩ xs)

  singleton : ∀ {P x} → ∀[ P x ⇒ Allstar P [ x ] ]
  singleton v = cons (v ×⟨ ⊎-idʳ ⟩ nil)

  open import Relation.Ternary.Separation.Construct.List I
  open import Data.List.Relation.Ternary.Interleaving.Propositional as I

  repartition : ∀ {P} {Σ₁ Σ₂ Σ} →
                Σ₁ ⊎ Σ₂ ≣ Σ → ∀[ Allstar P Σ ⇒ Allstar P Σ₁ ✴ Allstar P Σ₂ ]
  repartition [] nil   = nil ×⟨ ⊎-idˡ ⟩ nil
  repartition (consˡ σ) (cons (a ×⟨ σ′ ⟩ qx)) =
    let
      xs ×⟨ σ′′ ⟩ ys = repartition σ qx
      _ , τ₁ , τ₂    = ⊎-unassoc σ′ σ′′
    in (cons (a ×⟨ τ₁ ⟩ xs)) ×⟨ τ₂ ⟩ ys
  repartition (consʳ σ) (cons (a ×⟨ σ′ ⟩ qx)) =
    let
      xs ×⟨ σ′′ ⟩ ys = repartition σ qx
      _ , τ₁ , τ₂    = ⊎-unassoc σ′ (⊎-comm σ′′)
    in xs ×⟨ ⊎-comm τ₂ ⟩ (cons (a ×⟨ τ₁ ⟩ ys))

  concat : ∀ {P} {Γ₁ Γ₂} → ∀[ Allstar P Γ₁ ✴ Allstar P Γ₂ ⇒ Allstar P (Γ₁ ++ Γ₂) ]
  concat (nil ×⟨ s ⟩ env₂) rewrite ⊎-id⁻ˡ s = env₂
  concat (cons (v ×⟨ s ⟩ env₁) ×⟨ s' ⟩ env₂) =
    let _ , eq₁ , eq₂ = ⊎-assoc s s' in
    cons (v ×⟨ eq₁ ⟩ (concat (env₁ ×⟨ eq₂ ⟩ env₂)))


{-# OPTIONS --universe-polymorphism #-}
module Categories.Cocones where

open import Level

open import Categories.Category
open import Categories.Functor hiding (_∘_; _≡_; equiv; id; assoc; identityˡ; identityʳ; ∘-resp-≡)
open import Categories.Cocone

record CoconeMorphism {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {J : Category o′ ℓ′ e′} {F : Functor J C} (c₁ c₂ : Cocone F) : Set (ℓ ⊔ e ⊔ o′ ⊔ ℓ′) where
  module c₁ = Cocone c₁
  module c₂ = Cocone c₂
  module C = Category C
  module J = Category J
  open C
  field
    f : C [ c₁.N , c₂.N ]
    .commute : ∀ {X} → f ∘ c₁.ψ X ≡ c₂.ψ X

Cocones : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {J : Category o′ ℓ′ e′} (F : Functor J C) → Category (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′) (ℓ ⊔ e ⊔ o′ ⊔ ℓ′) e
Cocones {C = C} F = record
  { Obj = Obj′
  ; _⇒_ = Hom′
  ; _≡_ = _≡′_
  ; _∘_ = _∘′_
  ; id = record { f = id; commute = identityˡ }
  ; assoc = assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; equiv = record
    { refl = Equiv.refl
    ; sym = Equiv.sym
    ; trans = Equiv.trans
    }
  ; ∘-resp-≡ = ∘-resp-≡
  }
  where
  open Category C
  open Cocone
  open CoconeMorphism
  open Functor F

  infixr 9 _∘′_
  infix  4 _≡′_

  Obj′ = Cocone F

  Hom′ : Obj′ → Obj′ → Set _
  Hom′ = CoconeMorphism

  _≡′_ : ∀ {A B} → Hom′ A B → Hom′ A B → Set _
  F ≡′ G = f F ≡ f G

  _∘′_ : ∀ {A B C} → Hom′ B C → Hom′ A B → Hom′ A C
  _∘′_ {A} {B} {C} F G = record
    { f = f F ∘ f G
    ; commute = commute′
    }
    where
    .commute′ : ∀ {X} → (f F ∘ f G) ∘ ψ A X ≡ ψ C X
    commute′ {X} =
        begin
          (f F ∘ f G) ∘ ψ A X
        ↓⟨ assoc ⟩
          f F ∘ (f G ∘ ψ A X)
        ↓⟨ ∘-resp-≡ʳ (CoconeMorphism.commute G) ⟩
          f F ∘ ψ B X
        ↓⟨ CoconeMorphism.commute F ⟩
          ψ C X
        ∎
      where
      open HomReasoning


------------------------------------------------------------------------------
-- In the Agda standard library zero divides zero
------------------------------------------------------------------------------

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

module FOT.FOTC.Data.Nat.Divisibility.ZeroDividesZero where

open import Data.Nat.Divisibility
open import Relation.Binary.PropositionalEquality

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

0∣0 : 0 ∣ 0
0∣0 = divides 0 refl


module Structure.Relator.Names where

import      Lvl
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Functional
open import Lang.Instance
open import Logic
open import Logic.Propositional
open import Logic.Propositional.Xor
open import Numeral.Natural
open import Type

private variable ℓ ℓ₁ ℓ₂ ℓ₃ ℓ₄ : Lvl.Level
private variable T A B C D E : Type{ℓ}

ConversePattern : (Stmt{ℓ₁} → Stmt{ℓ₂} → Stmt{ℓ}) → (A → B → Stmt) → (B → A → Stmt) → Stmt
ConversePattern(_▫_)(_▫₁_)(_▫₂_) = ∀{x}{y} → (x ▫₁ y) ▫ (y ▫₂ x)

Subrelation : (A → B → Stmt{ℓ₁}) → (A → B → Stmt{ℓ₂}) → Stmt
Subrelation(_▫₁_)(_▫₂_) = ∀{x}{y} → (x ▫₁ y) → (x ▫₂ y)

TransitivityPattern : (A → B → Stmt{ℓ₁}) → (B → C → Stmt{ℓ₂}) → (A → C → Stmt{ℓ₃}) → Stmt
TransitivityPattern(_▫₁_)(_▫₂_)(_▫₃_) = ∀{x}{y}{z} → (x ▫₁ y) → (y ▫₂ z) → (x ▫₃ z)

FlippedTransitivityₗPattern : (A → C → Stmt{ℓ₁}) → (B → C → Stmt{ℓ₂}) → (A → B → Stmt{ℓ₃}) → Stmt
FlippedTransitivityₗPattern(_▫₁_)(_▫₂_)(_▫₃_) = ∀{x}{y}{z} → (x ▫₁ z) → (y ▫₂ z) → (x ▫₃ y)

FlippedTransitivityᵣPattern : (A → B → Stmt{ℓ₁}) → (A → C → Stmt{ℓ₂}) → (B → C → Stmt{ℓ₃}) → Stmt
FlippedTransitivityᵣPattern(_▫₁_)(_▫₂_)(_▫₃_) = ∀{x}{y}{z} → (x ▫₁ y) → (x ▫₂ z) → (y ▫₃ z)

module _ (_▫_ : T → T → Stmt{ℓ}) where
  Symmetry : Stmt
  Symmetry = ConversePattern(_→ᶠ_)(_▫_)(_▫_)

  Asymmetry : Stmt
  Asymmetry = ConversePattern(_→ᶠ_)(_▫_)((¬_) ∘₂ (_▫_))

  Reflexivity : Stmt
  Reflexivity = ∀{x : T} → (x ▫ x)

  Transitivity : Stmt
  Transitivity = TransitivityPattern(_▫_)(_▫_)(_▫_)

  SwappedTransitivity : Stmt
  SwappedTransitivity = ∀{x y z : T} → (y ▫ z) → (x ▫ y) → (x ▫ z)

  -- Also called: Left Euclidean.
  FlippedTransitivityₗ : Stmt
  FlippedTransitivityₗ = FlippedTransitivityₗPattern(_▫_)(_▫_)(_▫_)

  -- Also called: Right Euclidean.
  FlippedTransitivityᵣ : Stmt
  FlippedTransitivityᵣ = FlippedTransitivityᵣPattern(_▫_)(_▫_)(_▫_)

  Irreflexivity : Stmt
  Irreflexivity = ∀{x : T} → ¬(x ▫ x)

  -- Also called: Total, complete, connex.
  ConverseTotal : Stmt
  ConverseTotal = ConversePattern(_∨_)(_▫_)(_▫_)

  ConverseDichotomy : Stmt
  ConverseDichotomy = ConversePattern(_⊕_)(_▫_)(_▫_)

  -- Also called: Comparison.
  CoTransitivity : Stmt
  CoTransitivity = ∀{x y z : T} → (x ▫ z) → ((x ▫ y) ∨ (y ▫ z))

module _ (_▫₁_ : T → T → Stmt{ℓ₁}) (_▫₂_ : T → T → Stmt{ℓ₂}) where
  Antisymmetry : Stmt
  Antisymmetry = ∀{a b} → (a ▫₁ b) → (b ▫₁ a) → (a ▫₂ b)

  ConverseTrichotomy : Stmt
  ConverseTrichotomy = ∀{x y} → (x ▫₁ y) ∨ (x ▫₂ y) ∨ (y ▫₁ x)

module _ (_▫₁_ : A → B → Stmt{ℓ₁}) (_▫₂_ : A → A → Stmt{ℓ₂}) where
  Subtransitivityₗ : Stmt
  Subtransitivityₗ = TransitivityPattern(_▫₂_)(_▫₁_)(_▫₁_)

module _ (_▫₁_ : A → B → Stmt{ℓ₁}) (_▫₂_ : B → B → Stmt{ℓ₂}) where
  Subtransitivityᵣ : Stmt
  Subtransitivityᵣ = TransitivityPattern(_▫₁_)(_▫₂_)(_▫₁_)


module Star where

open import Prelude

infixr 40 _•_ _++_
infixl 30 _on_
infixr 20 _==>_ _=[_]=>_

data Star {X : Set} (R : Rel X) : Rel X where
  ε   : {x : X} -> Star R x x
  _•_ : {x y z : X} -> R x y -> Star R y z -> Star R x z

_++_ : {X : Set}{R : Rel X}{x y z : X} ->
       Star R x y -> Star R y z -> Star R x z
ε        ++ ys  =  ys
(x • xs) ++ ys  =  x • (xs ++ ys)

_==>_ : {X : Set} -> Rel X -> Rel X -> Set
R ==> S = forall {a b} -> R a b -> S a b

_on_ : {X Y : Set} -> (R : Rel X) -> (f : Y -> X) -> Rel Y
R on f = \a b -> R (f a) (f b)

_=[_]=>_ : {X Y : Set} (R : Rel X) (f : X -> Y) (S : Rel Y) -> Set
R =[ f ]=> S = R ==> S on f

return : {X : Set}{R : Rel X} -> R ==> Star R
return x = x • ε

module JoinMap where

  join : {X : Set}{R : Rel X} -> Star (Star R) ==> Star R
  join ε           =  ε
  join (xs • xss)  =  xs ++ join xss

  map : forall {X Y R S} -> (f : X -> Y) ->
        R =[ f ]=> S  ->  Star R =[ f ]=> Star S
  map f pm ε         =  ε
  map f pm (x • xs)  =  pm x • map f pm xs

  bind : forall {X Y R S} -> (f : X -> Y) ->
         R =[ f ]=> Star S  ->  Star R =[ f ]=> Star S
  bind f k m = join (map f k m)

bind : forall {X Y R S} -> (f : X -> Y) ->
        R =[ f ]=> Star S  ->  Star R =[ f ]=> Star S
bind f k ε         =  ε
bind f k (x • xs)  =  k x ++ bind f k xs

join : {X : Set}{R : Rel X} -> Star (Star R) ==> Star R
join = bind id id

map : forall {X Y R S} -> (f : X -> Y) ->
       R =[ f ]=> S  ->  Star R =[ f ]=> Star S
map f k = bind f (return · k)

-- Generic length

length : {X : Set}{R : Rel X} -> Star R =[ ! ]=> Star One
length = map ! !

-- Reverse

_op : {X : Set} -> Rel X -> Rel X
(R op) a b = R b a

reverse : {X : Set}{R : Rel X}{a b : X} -> Star R a b -> Star (R op) b a
reverse {X}{R} xs = rev xs ε
  where
    rev : forall {a b c} ->
          Star R a b -> Star (R op) a c -> Star (R op) b c
    rev ε ys = ys
    rev (x • xs) ys = rev xs (x • ys)


module StreamPredicates where

open import PropsAsTypes
open import Stream

module Modalities (A : Set) where

  private
    Aω : Set
    Aω = Stream A

  record Always (P : Pred Aω) (s : Stream A) : Prop where
    coinductive
    field
      valid : P s
      step : Always P (tl s)
  open Always public

  data Eventually (P : Pred Aω) (s : Stream A) : Prop where
    now : P s → Eventually P s
    later : Eventually P (tl s) → Eventually P s

  GE : Pred Aω → Pred Aω
  GE P = Always (Eventually P)

  EG : Pred Aω → Pred Aω
  EG P = Eventually (Always P)

  Always⇒GE : ∀{P : Pred Aω} → Always P ⊆ GE P
  Always⇒GE s p .valid = now (p .valid)
  Always⇒GE s p .step  = Always⇒GE (s .tl) (p .step)

  EG⇒Eventually : ∀{P : Pred Aω} → EG P ⊆ Eventually P
  EG⇒Eventually s (now p)      = now (p .valid)
  EG⇒Eventually s (later Evs') = later (EG⇒Eventually (s .tl) Evs')

  EG⇒GE : ∀{P : Pred Aω} → EG P ⊆ GE P
  EG⇒GE s p         .valid = EG⇒Eventually s p
  EG⇒GE s (now p)   .step  = Always⇒GE (tl s) (p .step)
  EG⇒GE s (later p) .step  = EG⇒GE (tl s) p

module ModalitiesExamples where
  open import Data.Nat
  open import Relation.Binary.PropositionalEquality as PE

  exP : Pred (Stream ℕ)
  exP s = s .hd ≡ 0

  alt : Stream ℕ
  alt .hd     = 0
  alt .tl .hd = 1
  alt .tl .tl = alt

  open Modalities ℕ

  exP-holds-on-alt-GE : GE exP alt
  exP-holds-on-alt-GE .valid       = now refl
  exP-holds-on-alt-GE .step .valid = later (now refl)
  exP-holds-on-alt-GE .step .step  = exP-holds-on-alt-GE

  exP-holds-not-on-alt-EG : ¬ (EG exP alt)
  exP-holds-not-on-alt-EG (now p)         = zero-not-suc 0 (p .step .valid)
  exP-holds-not-on-alt-EG (later (now p)) = zero-not-suc 0 (p .valid)
  exP-holds-not-on-alt-EG (later (later EGalt'')) =
    exP-holds-not-on-alt-EG EGalt''


-- test termination using structured orders

module TerminationTupledAckermann where

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

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

-- addition in tupled form

add : Nat × Nat -> Nat
add (zero   , m) = m
add (succ n , m) = succ (add (n , m))

-- ackermann in tupled form

ack : Nat × Nat -> Nat
ack (zero   , y)      = succ y
ack (succ x , zero)   = ack (x , succ zero)
ack (succ x , succ y) = ack (x , ack (succ x , y))


module BTA3 where

open import Data.Nat
open import Data.Bool
open import Data.List

-- Binding times
data BT : Set where
  S : BT
  D : BT

-- defining a data type [BT],where two members are
-- [S] standing for "static" and [D] standing for dynamic.

-- ``subsumption'' binding times; static can be treated as dynamic,
-- but not vice versa
_≼_ : BT → BT → Bool
_≼_ D S  = false
_≼_ _ _  = true

-- note that the above function can also be specified as follows,
-- _≼_ : BT → BT → Bool
-- D ≼ S = false
-- _ ≼ _ = true

-- note that the function [≼] specifies that a "static",S, can be treated
-- as a "dynamic",D, and not the other way round
-- since in Agda, pattern matching is conducted in a sequencial fashion,
-- the above specification makes sure that it returns [false] when the
-- first argument is [D] and the second [S] and returns [true] in all
-- the other three cases.

-- BEGIN: stuff that is also in the standard library

-- Standard propositional equality, see also Relation.Binary.PropositionalEquality
data _==_ {A : Set} (x : A) : A → Set where
  refl : x == x
-- [_==_] defines an equality proposition
-- it takes two identical elements of one type as arguments and gives one
-- evidence,[refl],for the proposition

-- subst lemma
subst : {A B : Set}{x x' : A} {C : A → B} → x == x' → C x == C x'
subst{A}{B}{x}{.x} refl = refl

-- or being defined in the following manner...
-- my_subst : {A B : Set}{x x' : A}{C : A → B} →  x == x' → C x == C x'
-- my_subst refl = refl

-- the above function further helps to construct evidence for equality
-- proposition
-- it says that if two elements are identical then two new elements obtained
-- by applying the former to a function  should also be identical

record True : Set where
data False : Set where

-- note that the above is regarding two simple proposition [True] and [False]
-- regarding [True],
-- it is defined as empty record with a single element of type [True],[record{}]
-- the trick here is that the type checker knows this and fills in any implicit
-- arguments of [True] with this element
-- another way of defining [True] as follows,
-- record True : Set where
-- trivial : True
-- trivial = _

-- regarding [False],
-- it is defined as a proposition without any evidence corresponding well to
-- what a [False] proposition really means

isTrue : Bool → Set
isTrue true  = True
isTrue false = False
-- note the isTrue b,given b as boolean, is the type of proof that b is equal to
-- true since if it is the case, [isTrue b] returns type [True] where its
-- evidence is automatically filled in by the type checker while if it is not
-- the case there is no way to supply for the evidence due to the way how
-- [false] is constructed

-- END standard library

----------------------
-- Sublists
----------------------
data _cx-≤_ {A : Set} : List A → List A → Set where
  cxle-eq : (l : List A) → l cx-≤ l
  cxle-lt : ∀ {l₁ l₂} x → l₁ cx-≤ l₂ → l₁ cx-≤ (x ∷ l₂)

lem-cx-≤-trans : {A : Set} → {l₁ : List A} {l₂ : List A} {l₃ : List A} →
                 l₁ cx-≤ l₂ → l₂ cx-≤ l₃ → l₁ cx-≤ l₃
lem-cx-≤-trans le1  (cxle-eq l) = le1
lem-cx-≤-trans (cxle-eq l) (cxle-lt x e) = cxle-lt x e
lem-cx-≤-trans (cxle-lt x e) (cxle-lt x' e') = cxle-lt x' (lem-cx-≤-trans (cxle-lt x e) e')

_cxle-∷_ : {A : Set} (x : A) (l : List A) → l cx-≤ (x ∷ l)
x cxle-∷ l = cxle-lt x (cxle-eq l)

data _⊆_ {A : Set} : List A → List A → Set where
  refl-⊆ : ∀ {l} → l ⊆ l
  step-⊆ : ∀ {l} x l₁ l₂ → l ⊆ (l₁ ++ l₂) → l ⊆ (l₁ ++ (x ∷ l₂))

lem-⊆-trans : {A : Set} → {l₁ : List A} {l₂ : List A} {l₃ : List A} →
                 l₁ ⊆ l₂ → l₂ ⊆ l₃ → l₁ ⊆ l₃
lem-⊆-trans e (refl-⊆ {l}) = e
lem-⊆-trans (refl-⊆ {l}) (step-⊆ x l₁ l₂ e) = step-⊆ x l₁ l₂ e
lem-⊆-trans (step-⊆ x l₁ l₂ e) (step-⊆ x' l₁' l₂' e') = step-⊆ x' l₁' l₂' (lem-⊆-trans (step-⊆ x l₁ l₂ e) e')

-- data _≤1_ {A : Set} : List A → List A → Set where
--   cxle1-eq : (l : List A) → l ≤1 l
--   cxle1-lt : ∀ x (l : List A) → l ≤1 (x ∷ l)

-- data _?∷_ {A : Set} (x : A): List A → Set where
--   yes∷ : (l : List A) → x ?∷ (x ∷ l)
--   no∷ : (l : List A) → x ?∷ l

-- getList : ∀ {A} {x : A} {l : List A} → x ?∷ l → List A
-- getList {x = x} (yes∷ l) = x ∷ l
-- getList {_} {_} {l} (no∷ .l) = l

-- end sublists

-- some lemmas about BT subsumption
lem-bt≼S : {bt : BT} → isTrue (bt ≼ S) → bt == S
lem-bt≼S {S} bt≼S = refl
lem-bt≼S {D} ()

-- which can also be defined as follows,
-- my_lem-bt≼S : {bt : BT} → isTrue (bt ≼ S) → bt == S
-- my_lem-bt≼S {S} _ = refl
-- my_lem-bt≼S {D} ()

lem-D≼bt : {bt : BT} → isTrue (D ≼ bt) → bt == D
lem-D≼bt {S} ()
lem-D≼bt {D} D≼bt = refl

-- Types of the calculus
mutual
  -- s ^ BT
  data AType : Set where
    Ann : BT → SType → AType

  -- int | t -> t
  data SType : Set where
    SInt  : SType
    SFun  : AType → AType → SType

-- aux definitions
ATInt : BT → AType
ATInt bt = Ann bt SInt
ATFun  : BT → AType → AType → AType
ATFun  bt at1 at2 = Ann bt (SFun at1 at2)

-- note that the above function labels a ground type with annotations [S] or
-- [D],sort of a labelling function

-- projection: get the BT from a type
btof : AType → BT
btof (Ann bt _) = bt

-- a related function which takes an annotated type as argument and returns
-- the annotation of that type

-- "constraint on types: functions have to be at least as dynamic as their component" should be corrected as follows,
-- arguments of function should be as dynamic as the function

data wft : AType → Set where
  wf-int  : ∀ {bt} → wft (Ann bt SInt)
  wf-fun  : ∀ {bt at1 at2} → wft at1 → wft at2
          → isTrue (bt ≼ btof at1) → isTrue (bt ≼ btof at2) → wft (Ann bt (SFun at1 at2))

-- the above proposition specifies a set of well-formed [AType]s,
-- any annotated [SInt]s are well-formed, wft (Ann bt SInt) forall bt ∈ BT
-- in case of functional type with annotation, the following two criteria have
-- to be satisfied to be a well form,
-- a. each of its arguments is well-formed
-- b. the annotation of the function and the annotations of its arguments must
--    satisfy [_≼_] relation
--    for instance, the functional type defined above is well-formed while
--    the following is not,
--    Ann D (
--            SFun (Ann S SInt) (Ann D SInt)
--          )
--    in conclusion,for functional type with annotation to be well-formed,
--    each of its arguments annotations has to be [D] when that of the function
--    is [D] while there is no constraint upon the annotations of its arguments
--    when that of the function is [S]

lem-force-bt : ∀ {bt at} → isTrue (bt ≼ btof at) → D == bt → D == btof at
lem-force-bt {S} bt≼at ()
lem-force-bt {D} {Ann S y'} () D=bt
lem-force-bt {D} {Ann D y'} bt≼at D=bt = refl

-- note the above function takes an element[bt] of type [BT] and a type with
-- annotation,
-- if both
-- a. the type is at least as dynamic as [bt]
-- b. [bt == D]
-- then we know that the annotation of the type must be [D] as well
-- and the function in that case returns evidence for that

-- Low-level types; types wihtout binding information
data Type : Set where
  TInt : Type
  TFun : Type → Type → Type

-- translation from ATypes to low-level types
mutual
  strip : AType → Type
  strip (Ann _ σ) = strip' σ

  strip' : SType → Type
  strip' SInt = TInt
  strip' (SFun y y') = TFun (strip y) (strip y')

-- note that the above function [strip] converts a type with annotation [AType]
-- to a low-level type [Type],
-- for instance,
-- strip (Ann D SInt)
-- = strip' SInt
-- = TInt
-- strip (Ann S
--         SFun (Ann S SInt) (Ann D SInt)
--       )
-- = strip' (SFun (Ann S SInt) (Ann D SInt))
-- = TFun (strip (Ann S SInt)) (strip (Ann D SInt))
-- = TFun (strip' SInt) (strip' SInt)
-- = TFun TInt TInt^

-- More general purpose definitions (should also be in standard library)
-- list membership
infix 4 _∈_
data _∈_ {A : Set} : A → List A → Set where
  hd : ∀ {x xs} → x ∈ (x ∷ xs)
  tl : ∀ {x y xs} → x ∈ xs → x ∈ (y ∷ xs)

-- note the above proposition gives us two constructors for getting
-- evidences for an element being a member of one list

-- end general purpose definitions

-- Typing context
Ctx = List Type

--data Exp' (Γ Γ' : Ctx) : Type → Set where
--  EVar' :

-- Typed expression
data Exp (Γ : Ctx) : Type → Set where
  -- [EVar] corresponds to the bounded variables in [AExp]
  EVar : ∀ {τ} → τ ∈ Γ → Exp Γ τ
  EInt : ℕ → Exp Γ TInt
  EFun : ∀ {τ₁ τ₂} → Exp (τ₂ ∷ Γ) τ₁ → Exp Γ (TFun τ₂ τ₁)
  EApp : ∀ {τ₁ τ₂} → Exp Γ (TFun τ₂ τ₁) → Exp Γ τ₂ → Exp Γ τ₁
-- one additional term,
count_tl : ∀ {A  Γ Γ'} {τ : A } → τ ∈ Γ → Γ cx-≤ Γ' → τ ∈ Γ'
count_tl  x (cxle-eq Γ) = x
count_tl x  (cxle-lt T e) = tl (count_tl x e)

data _cx=≤_ {A : Set} : List A → List A → Set where
  cxle-peq : ∀ {l₁ l₂} { x } → l₁ cx-≤ l₂ → (x ∷ l₁) cx=≤ (x ∷ l₂)
  cxle-plt : ∀ {l₁ l₂} { x } → l₁ cx=≤ l₂ → (x ∷ l₁) cx=≤ (x ∷ l₂)

count_tl' : ∀ {A  Γ Γ'} {τ : A } → τ ∈ Γ → Γ cx=≤ Γ' → τ ∈ Γ'
count_tl' hd (cxle-plt e) = hd
count_tl' hd (cxle-peq e) = hd
count_tl' (tl xid) (cxle-plt e) = tl (count_tl' xid  e)
count_tl' (tl xid) (cxle-peq e) = tl (count_tl xid e)

lem-Exp-weakening' : ∀ {τ₂ τ₁ Γ Γ'} → Exp (τ₂ ∷ Γ) τ₁ → (τ₂ ∷ Γ) cx=≤ (τ₂ ∷ Γ') → Exp (τ₂ ∷ Γ') τ₁
lem-Exp-weakening' (EVar x) e = EVar (count_tl' x  e)
lem-Exp-weakening'  (EInt n) e = EInt n
lem-Exp-weakening'  (EFun t) e = EFun (lem-Exp-weakening' t (cxle-plt e))
lem-Exp-weakening'  (EApp t1 t2) e = EApp (lem-Exp-weakening' t1 e) (lem-Exp-weakening' t2 e)

lem-Exp-weakening : ∀ {τ Γ Γ'} → Exp Γ τ → Γ cx-≤ Γ' → Exp Γ' τ
lem-Exp-weakening t (cxle-eq Γ) = t
lem-Exp-weakening (EInt n) e = EInt n
lem-Exp-weakening (EVar x) e  = EVar (count_tl x e)
lem-Exp-weakening (EFun t) (cxle-lt T e) = EFun (lem-Exp-weakening' t (cxle-peq (cxle-lt T e)))
lem-Exp-weakening (EApp t1 t2) e = EApp (lem-Exp-weakening t1 e) (lem-Exp-weakening t2 e)

-- typed annotated expressions
ACtx = List AType

data AExp (Δ : ACtx) : AType → Set where
  AVar : ∀ {α} → α ∈ Δ → AExp Δ α
  AInt : (bt : BT) → ℕ → AExp Δ (ATInt bt)
  AFun : ∀ {α₁ α₂} (bt : BT) → wft (ATFun bt α₂ α₁) → AExp (α₂ ∷ Δ) α₁ → AExp Δ (ATFun bt α₂ α₁)
  AApp : ∀ {α₁ α₂} (bt : BT) → wft (ATFun bt α₂ α₁) → AExp Δ (ATFun bt α₂ α₁) → AExp Δ α₂ → AExp Δ α₁

-- stripping of contexts
residual : ACtx → Ctx
residual [] = []
residual (Ann S _ ∷ xs) = residual xs
residual (Ann D σ ∷ xs) = strip' σ ∷ residual xs

-- ``semantic domain'' for partially evaluated AExp-terms:
--   - AExp-terms of dynamic type evaluate to Exp-terms
--   - AExp-terms of static type evaluate to agda terms, where SFun
--     are functions and SInt are natural numbers
mutual
  impTA : Ctx → AType → Set
  impTA Γ (Ann S σ) = impTA' Γ σ
  impTA Γ (Ann D σ) = Exp Γ (strip' σ)

  impTA' : Ctx → SType → Set
  impTA' Γ SInt = ℕ
  -- impTA' Γ (SFun y y') = impTA Γ y → impTA Γ y'
  impTA' Γ (SFun y y') = ∀ {Γ'} → Γ cx-≤ Γ' → impTA Γ' y → impTA Γ' y'

lem-impTA-weakening : ∀ {α Γ Γ'} →
                      impTA Γ α →
                      Γ cx-≤ Γ' →
                      impTA Γ' α
lem-impTA-weakening {Ann S SInt} v _ = v
lem-impTA-weakening {Ann S (SFun x x₁)} f prf = λ prf' → f (lem-cx-≤-trans prf prf')
lem-impTA-weakening {Ann D x₁} v prf = lem-Exp-weakening v prf

-- mutual
--   impTA-try : Ctx → AType → Set
--   impTA-try Γ (Ann S σ) = impTA-try' Γ σ
--   impTA-try Γ (Ann D σ) = Exp Γ (strip' σ)

--   impTA-try' : Ctx → SType → Set
--   impTA-try' Γ SInt = ℕ
--   impTA-try' Γ (SFun y y') = impTA-try Γ y → impTA-try Γ y'

-- lem-impTA-try-weakening : ∀ {α Γ Γ'} →
--                       impTA-try Γ α →
--                       Γ cx-≤ Γ' →
--                       impTA-try Γ' α
-- lem-impTA-try-weakening {Ann S SInt} v _ = v
-- lem-impTA-try-weakening {Ann S (SFun α x₁)} {Γ} {Γ'} f prf = {! λ (v : impTA-try Γ' α) → f v!}
-- lem-impTA-try-weakening {Ann D x₁} v prf = lem-Exp-weakening v prf

data AEnv : Ctx → ACtx → Set where
  env[] :  ∀ {Γ} → AEnv Γ []
  envS:: : ∀ {Γ Δ} {α} →
           impTA Γ α →
           AEnv Γ Δ →
           AEnv Γ (α ∷ Δ)
  envD:: : ∀ {Γ Δ} →
           (σ : SType) →
           impTA (strip' σ ∷ Γ) (Ann D σ) →
           AEnv Γ Δ →
           AEnv (strip' σ ∷ Γ) (Ann D σ ∷ Δ)

lem-AEnv-weakening : ∀ {Γ Γ' Δ} → AEnv Γ Δ → Γ cx-≤ Γ' → AEnv Γ' Δ
lem-AEnv-weakening env[] prf = env[]
lem-AEnv-weakening (envS:: {α = α} x env) prf = envS:: (lem-impTA-weakening {α} x prf) (lem-AEnv-weakening env prf)
lem-AEnv-weakening (envD:: {Γ} σ x env) prf = envS:: (lem-impTA-weakening {Ann D σ} x prf) (lem-AEnv-weakening env (lem-cx-≤-trans (cxle-lt (strip' σ) (cxle-eq Γ)) prf))  -- non-primitive recursion... this should be fixable by extending Γ in the middle, rather than in the end

lookup : ∀ {Γ Δ α} → AEnv Γ Δ → (o : α ∈ Δ ) → impTA Γ α
lookup env[] ()
lookup (envS:: x env) hd = x
lookup (envS:: x env) (tl idx) = lookup env idx
lookup (envD:: σ x env) hd = x
lookup {α = α} (envD:: {Γ} σ x env) (tl idx) = lem-impTA-weakening {α} (lookup env idx) (strip' σ cxle-∷ Γ)

data IsDynamic : AType → Set where
  is-dyn : ∀ σ → IsDynamic (Ann D σ)

lem-IsDynamic-by-wf : ∀ α → isTrue (D ≼ btof α) → IsDynamic α
lem-IsDynamic-by-wf (Ann S σ) ()
lem-IsDynamic-by-wf (Ann D σ) _ = is-dyn σ

-- TODO: Do we need additional assurance in the type signature (or as
-- an aux. lemma) that Γ is the residue of Δ?
pe : ∀ {Δ Γ α} → AEnv Γ Δ → AExp Δ α → impTA Γ α
pe env (AVar idx) = lookup env idx
pe env (AInt S i) = i
pe env (AInt D i) = EInt i
pe {Γ = Γ} env (AFun {α₁} {α₂} S prf exp) = λ {Γ'} (prf₁ : Γ cx-≤ Γ') (v : impTA Γ' α₂) →
                                                     pe (envS:: v (lem-AEnv-weakening env prf₁)) exp
pe env (AFun {α₁} {α₂} D (wf-fun _ _ prf-2 prf-1) e)
  with lem-IsDynamic-by-wf α₁ prf-1 | lem-IsDynamic-by-wf α₂ prf-2
pe {Γ = Γ} env (AFun {.(Ann D σ₁)} {.(Ann D σ₂)} D (wf-fun _ _ prf-1 prf-2) e)
  | is-dyn σ₁ | is-dyn σ₂ =
  EFun (pe (envD:: σ₂ (EVar hd) env) e)
pe {Γ = Γ} env (AApp S _ f e) = (pe env f (cxle-eq Γ)) (pe env e)
pe env (AApp {α₁} {α₂} D (wf-fun _ _ prf-2 prf-1) f e)
  with lem-IsDynamic-by-wf α₁ prf-1 | lem-IsDynamic-by-wf α₂ prf-2
pe env (AApp {.(Ann D σ₁)}{.(Ann D σ₂)} D (wf-fun _ _ prf-2 prf-1) f e)
 | is-dyn σ₁ | is-dyn σ₂ =
 EApp (pe env f) (pe env e) -- construct an Exp-application using the proof that argument and results are dynamic and thus pe yields Exp-terms for them


open import lib
open import eq-reas-nouni

equiv = _≡_

Val = nat

data Expn : Set where
  val : Val -> Expn
  plus : Expn -> Expn -> Expn

eval : Expn -> Val
eval (val v) = v
eval (plus e1 e2) = (eval e1) + (eval e2)

data evalsTo : Expn -> Val -> Set where

  e-val : forall {v : Val}
          ------------------------
          -> (evalsTo (val v) v)

  e-add : forall {e1 e2 : Expn}{v1 v2 : Val}
          -> (evalsTo e1 v1)
          -> (evalsTo e2 v2)
          -------------------------------------
          -> (evalsTo (plus e1 e2) (v1 + v2))

e-thm-fwd : forall {e : Expn}{v : Val}
  -> evalsTo e v -> equiv (eval e) v

e-thm-fwd (e-val{v}) =
  begin
    eval (val v)
  equiv[ refl ]
    v
  qed
e-thm-fwd (e-add{e1}{e2}{v1}{v2} e1-evalsTo-v1 e2-evalsTo-v2) =
  let
    eval-e1-is-v1 = e-thm-fwd e1-evalsTo-v1
    eval-e2-is-v2 = e-thm-fwd e2-evalsTo-v2
  in begin
    eval (plus e1 e2)
  equiv[ refl ]
    (eval e1) + (eval e2)
  equiv[ cong2 _+_ eval-e1-is-v1 eval-e2-is-v2 ]
    v1 + v2
  qed

e-thm-alt : forall (e : Expn) -> evalsTo e (eval e)
e-thm-alt (val v) = e-val
e-thm-alt (plus e1 e2) = (e-add (e-thm-alt e1) (e-thm-alt e2))


------------------------------------------------------------------------------
-- Existential quantifier on the inductive PA universe
------------------------------------------------------------------------------

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

module PA.Inductive.Existential where

infix 2 ∃

------------------------------------------------------------------------------
-- PA universe
open import PA.Inductive.Base.Core

-- The existential quantifier type on M.
data ∃ (A : ℕ → Set) : Set where
  _,_ : (x : ℕ) → A x → ∃ A

-- Sugar syntax for the existential quantifier.
syntax ∃ (λ x → e) = ∃[ x ] e

-- 2012-03-05: We avoid to use the existential elimination or the
-- existential projections because we use pattern matching (and the
-- Agda's with constructor).

-- The existential elimination.
--
-- NB. We do not use the usual type theory elimination with two
-- projections because we are working in first-order logic where we do
-- not need extract a witness from an existence proof.
-- ∃-elim : {A : ℕ → Set}{B : Set} → ∃ A → (∀ {x} → A x → B) → B
-- ∃-elim (_ , Ax) h = h Ax

-- The existential proyections.
-- ∃-proj₁ : ∀ {A} → ∃ A → M
-- ∃-proj₁ (x , _) = x

-- ∃-proj₂ : ∀ {A} → (h : ∃ A) → A (∃-proj₁ h)
-- ∃-proj₂ (_ , Ax) = Ax


-- Andreas, 2014-10-05

{-# OPTIONS --cubical-compatible --sized-types #-}

-- {-# OPTIONS -v tc.size:20  #-}

open import Agda.Builtin.Size

data Nat : {size : Size} -> Set where
  zero : {size : Size} -> Nat {↑ size}
  suc  : {size : Size} -> Nat {size} -> Nat {↑ size}

-- subtraction is non size increasing
sub : {size : Size} -> Nat {size} -> Nat {∞} -> Nat {size}
sub zero    n       = zero
sub (suc m) zero    = suc m
sub (suc m) (suc n) = sub m n

-- div' m n  computes  ceiling(m/(n+1))
div' : {size : Size} -> Nat {size} -> Nat -> Nat {size}
div' zero    n = zero
div' (suc m) n = suc (div' (sub m n) n)

-- should termination check even --cubical-compatible

-- -}


module Auto-EqualityReasoning where

-- equality reasoning, computation and induction

open import Auto.Prelude

module AdditionCommutative where

 lemma : ∀ n m → (n + succ m) ≡ succ (n + m)
 lemma n m = {!-c!}  -- h0
{-
 lemma zero m = refl
 lemma (succ x) m = cong succ (lemma x m)
-}

 lemma' : ∀ n m → (n + succ m) ≡ succ (n + m)
 lemma' zero m = refl
 lemma' (succ n) m = cong succ (lemma' n m)

 addcommut : ∀ n m → (n + m) ≡ (m + n)
 addcommut n m = {!-c lemma'!}  -- h1
{-
 addcommut zero zero = refl
 addcommut zero (succ x) = sym (cong succ (addcommut x zero))  -- solution does not pass termination check
 addcommut (succ x) m = begin (succ (x + m) ≡⟨ cong succ (addcommut x m) ⟩ (succ (m + x) ≡⟨ sym (lemma' m x) ⟩ ((m + succ x) ∎)))
-}


open import Agda.Builtin.Nat

data Vec (a : Set) : {n : Nat} → Set where
  Nil : Vec a {0}
  Cons : {n : Nat} → a → Vec a {n} → Vec a {suc n}
{-# COMPILE AGDA2HS Vec #-}

mapV : {a b : Set} {n : Nat} (f : a → b) → Vec a {n} → Vec b {n}
mapV f Nil = Nil
mapV f (Cons x xs) = Cons (f x) (mapV f xs)
{-# COMPILE AGDA2HS mapV #-}

tailV : {a : Set} {n : Nat} → Vec a {suc n} → Vec a {n}
tailV (Cons x xs) = xs
{-# COMPILE AGDA2HS tailV #-}

-- Using erasure instead of implicit arguments
data Vec' (a : Set) : (@0 n : Nat) → Set where
  Nil' : Vec' a 0
  Cons' : {@0 n : Nat} → a → Vec' a n → Vec' a (suc n)
{-# COMPILE AGDA2HS Vec' #-}

mapV' : {a b : Set} {@0 n : Nat} (f : a → b) → Vec' a n → Vec' b n
mapV' f Nil' = Nil'
mapV' f (Cons' x xs) = Cons' (f x) (mapV' f xs)
{-# COMPILE AGDA2HS mapV' #-}

tailV' : {a : Set} {@0 n : Nat} → Vec' a (suc n) → Vec' a n
tailV' (Cons' x xs) = xs
{-# COMPILE AGDA2HS tailV' #-}


module Structure.Relator.Apartness where

import      Lvl
open import Logic
open import Logic.Propositional
open import Structure.Relator.Properties
  hiding (irreflexivity ; symmetry ; cotransitivity)
open import Type

private variable ℓ₁ ℓ₂ : Lvl.Level

-- An apartness relation is a irreflexive, symmetric and cotransitive relation.
record Apartness {T : Type{ℓ₁}} (_#_ : T → T → Stmt{ℓ₂}) : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
  instance constructor intro
  field
    instance ⦃ irreflexivity ⦄  : Irreflexivity  (_#_)
    instance ⦃ symmetry ⦄       : Symmetry       (_#_)
    instance ⦃ cotransitivity ⦄ : CoTransitivity (_#_)


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

open import LogicalFormulae
open import Lists.Definition
open import Lists.Length
open import Numbers.Naturals.Semiring

module Lists.Concat where

appendEmptyList : {a : _} → {A : Set a} → (l : List A) → (l ++ [] ≡ l)
appendEmptyList [] = refl
appendEmptyList (x :: l) = applyEquality (_::_ x) (appendEmptyList l)

concatAssoc : {a : _} → {A : Set a} → (x : List A) → (y : List A) → (z : List A) → ((x ++ y) ++ z) ≡ x ++ (y ++ z)
concatAssoc [] m n = refl
concatAssoc (x :: l) m n = applyEquality (_::_ x) (concatAssoc l m n)

canMovePrepend : {a : _} → {A : Set a} → (l : A) → (x : List A) (y : List A) → ((l :: x) ++ y ≡ l :: (x ++ y))
canMovePrepend l [] n = refl
canMovePrepend l (x :: m) n = refl

lengthConcat : {a : _} {A : Set a} (l1 l2 : List A) → length (l1 ++ l2) ≡ length l1 +N length l2
lengthConcat [] l2 = refl
lengthConcat (x :: l1) l2 = applyEquality succ (lengthConcat l1 l2)


{-# OPTIONS --without-K --safe #-}
open import Categories.Category

module Categories.Object.Coproduct {o ℓ e} (𝒞 : Category o ℓ e) where

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

open Category 𝒞

open import Categories.Morphism.Reasoning 𝒞
open import Categories.Morphism 𝒞

open HomReasoning

private
  variable
    A B C D : Obj
    f g h : A ⇒ B

record Coproduct (A B : Obj) : Set (o ⊔ ℓ ⊔ e) where
  infix 10 [_,_]

  field
    A+B   : Obj
    i₁    : A ⇒ A+B
    i₂    : B ⇒ A+B
    [_,_] : A ⇒ C → B ⇒ C → A+B ⇒ C

    inject₁ : [ f , g ] ∘ i₁ ≈ f
    inject₂ : [ f , g ] ∘ i₂ ≈ g
    unique   : h ∘ i₁ ≈ f → h ∘ i₂ ≈ g → [ f , g ] ≈ h

  g-η : [ f ∘ i₁ , f ∘ i₂ ] ≈ f
  g-η = unique Equiv.refl Equiv.refl

  η : [ i₁ , i₂ ] ≈ id
  η = unique identityˡ identityˡ

  []-cong₂ : ∀ {C} → {f f′ : A ⇒ C} {g g′ : B ⇒ C} → f ≈ f′ → g ≈ g′ → [ f , g ] ≈ [ f′ , g′ ]
  []-cong₂ f≈f′ g≈g′ = unique (inject₁ ○ ⟺ f≈f′) (inject₂ ○ ⟺ g≈g′)

  ∘-distribˡ-[] : ∀ {f : A ⇒ C} {g : B ⇒ C} {q : C ⇒ D} → q ∘ [ f , g ] ≈ [ q ∘ f , q ∘ g ]
  ∘-distribˡ-[] = ⟺ $ unique (pullʳ inject₁) (pullʳ inject₂)


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

module Cubical.HITs.Modulo.Properties where

open import Cubical.Data.Nat
open import Cubical.Data.Nat.Order
open import Cubical.Data.Fin
open import Cubical.Data.Sigma

open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Univalence

open import Cubical.HITs.Modulo.Base
open import Cubical.HITs.Modulo.FinEquiv public

private
  variable
    ℓ : Level
    k : ℕ

-- `Modulo 0` is easily shown equivalent to `ℕ`, because we don't need
-- to account for the path constructor at all.
Modulo0≡ℕ : Modulo 0 ≡ ℕ
Modulo0≡ℕ = isoToPath lemma
 where
 open Iso
 lemma : Iso (Modulo 0) ℕ
 fun lemma (embed n) = n
 inv lemma = embed
 rightInv lemma n = refl
 leftInv lemma (embed n) = refl

isSetModulo0 : isSet (Modulo 0)
isSetModulo0 = subst isSet (sym Modulo0≡ℕ) isSetℕ

-- `Modulo 1` is contractible just like `Fin 1`
isContrModulo1 : isContr (Modulo 1)
isContrModulo1
  = value , λ
  { (embed n) → universal n
  ; (step n i) → universal-path n i
  }
  where
  value : Modulo 1
  value = embed 0

  universal : ∀ n → value ≡ embed n
  universal zero = refl
  universal (suc n) = universal n ∙ step n

  universal-path
   : ∀ n → PathP (λ i → value ≡ step n i) (universal n) (universal (suc n))
  universal-path n i j
    = compPath-filler (universal n) (step n) i j

-- `expand o k m` is congruent to `m` modulo `k`, so there is a path
-- between their image in `Modulo k`.
steps : ∀ m o → embed {k = k} m ≡ embed (expand o k m)
steps m zero = refl
steps {k} m (suc o) = steps m o ∙ ztep (expand o k m)

steps≡
  : ∀ m n
  → PathP (λ i → embed {k} m ≡ ztep (expand n k m) i)
      (steps m n)
      (steps m (suc n))
steps≡ m n = λ i j → compPath-filler (steps m n) (ztep (expand n _ m)) i j

stepOver : ∀ m n o → expand o k m ≡ n → embed {k = k} m ≡ embed n
stepOver m n o p = steps m o ∙ cong embed p

-- `Modulo k` is a set for all `k`, because we can transport the
-- evidence from either `ℕ` or `Fin k`.
isSetModulo : isSet (Modulo k)
isSetModulo {0} = isSetModulo0
isSetModulo {suc k} = subst isSet (sym Modulo≡Fin) isSetFin


module sum-thms where

open import eq
open import sum
open import list
open import product
open import empty
open import negation

inj₁-inj : ∀{ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'}{x : A}{x'} → inj₁{ℓ}{ℓ'}{A}{B} x ≡ inj₁ x' → x ≡ x'
inj₁-inj refl = refl

⊎-assoc-iso₁ : ∀{ℓ}{U V W : Set ℓ}{x : U ⊎ V ⊎ W} → ⊎-assoc-inv (⊎-assoc x) ≡ x
⊎-assoc-iso₁ {x = inj₁ x} = refl
⊎-assoc-iso₁ {x = inj₂ (inj₁ x)} = refl
⊎-assoc-iso₁ {x = inj₂ (inj₂ y)} = refl

⊎-assoc-iso₂ : ∀{ℓ}{U V W : Set ℓ}{x : (U ⊎ V) ⊎ W} → ⊎-assoc (⊎-assoc-inv x) ≡ x
⊎-assoc-iso₂ {x = inj₁ (inj₁ x)} = refl
⊎-assoc-iso₂ {x = inj₁ (inj₂ y)} = refl
⊎-assoc-iso₂ {x = inj₂ y} = refl

⊎-left-ident-iso₁ : ∀{ℓ}{X : Set ℓ}{x} → ⊎-left-ident-inv {_}{X} (⊎-left-ident x) ≡ x
⊎-left-ident-iso₁ {x = inj₁ x} = ⊥-elim x
⊎-left-ident-iso₁ {x = inj₂ y} = refl

⊎-left-ident-iso₂ : ∀{ℓ}{X : Set ℓ}{x} → ⊎-left-ident {_}{X} (⊎-left-ident-inv x) ≡ x
⊎-left-ident-iso₂ = refl

⊎-right-ident-iso₁ : ∀{ℓ}{X : Set ℓ}{x} → ⊎-right-ident-inv {_}{X} (⊎-right-ident x) ≡ x
⊎-right-ident-iso₁ {x = inj₁ x} = refl
⊎-right-ident-iso₁ {x = inj₂ y} = ⊥-elim y

⊎-right-ident-iso₂ : ∀{ℓ}{X : Set ℓ}{x} → ⊎-right-ident {_}{X} (⊎-right-ident-inv x) ≡ x
⊎-right-ident-iso₂ = refl

¬⊎→× : ∀{ℓ}{A B : Set ℓ} → ¬ (_⊎_ {ℓ} A B) → ¬ A × ¬ B
¬⊎→× {ℓ}{A}{B} p = (λ x → p (inj₁ x)) , λ x → p (inj₂ x)


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

-- The category of partially ordered sets and order-preserving maps.

open import Level
open import Relation.Binary using (Poset; IsEquivalence; _Preserves_⟶_)
open import Relation.Binary.Morphism using (IsOrderHomomorphism)
open import Relation.Binary.Morphism.Bundles using (PosetHomomorphism)
import Relation.Binary.Morphism.Construct.Identity as Id
import Relation.Binary.Morphism.Construct.Composition as Comp

open import Categories.Category

open Poset renaming (_≈_ to ₍_₎_≈_; _≤_ to ₍_₎_≤_)
open PosetHomomorphism using (⟦_⟧; cong)

private
  variable
    a₁ a₂ a₃ b₁ b₂ b₃ : Level
    A B C : Poset a₁ a₂ a₃

module _ {A : Poset a₁ a₂ a₃} {B : Poset b₁ b₂ b₃} where

  infix 4 _≗_

  -- Pointwise equality (on order preserving maps).

  _≗_ : (f g : PosetHomomorphism A B) → Set (a₁ ⊔ b₂)
  f ≗ g = ∀ {x} → ₍ B ₎ ⟦ f ⟧ x ≈ ⟦ g ⟧ x

  ≗-isEquivalence : IsEquivalence _≗_
  ≗-isEquivalence = record
    { refl    = Eq.refl B
    ; sym     = λ f≈g → Eq.sym B f≈g
    ; trans   = λ f≈g g≈h → Eq.trans B f≈g g≈h
    }

  module ≗ = IsEquivalence ≗-isEquivalence

-- The category of posets and order-preserving maps.

Posets : ∀ c ℓ₁ ℓ₂ → Category (suc (c ⊔ ℓ₁ ⊔ ℓ₂)) (c ⊔ ℓ₁ ⊔ ℓ₂) (c ⊔ ℓ₁)
Posets c ℓ₁ ℓ₂ = record
  { Obj       = Poset c ℓ₁ ℓ₂
  ; _⇒_       = PosetHomomorphism
  ; _≈_       = _≗_
  ; id        = λ {A} → Id.posetHomomorphism A
  ; _∘_       = λ f g → Comp.posetHomomorphism g f
  ; assoc     = λ {_ _ _ D} → Eq.refl D
  ; sym-assoc = λ {_ _ _ D} → Eq.refl D
  ; identityˡ = λ {_ B} → Eq.refl B
  ; identityʳ = λ {_ B} → Eq.refl B
  ; identity² = λ {A} → Eq.refl A
  ; equiv     = ≗-isEquivalence
  ; ∘-resp-≈  = λ {_ _ C _ h} f≈h g≈i → Eq.trans C f≈h (cong h g≈i)
  }


{-# OPTIONS --cubical --safe --postfix-projections #-}

module Data.Nat.Order where

open import Prelude
open import Data.Nat.Properties
open import Relation.Binary

<-trans : Transitive _<_
<-trans {zero} {suc y} {suc z} x<y y<z = tt
<-trans {suc x} {suc y} {suc z} x<y y<z = <-trans {x} {y} {z} x<y y<z

<-asym : Asymmetric _<_
<-asym {suc x} {suc y} x<y y<x = <-asym {x} {y} x<y y<x

<-irrefl : Irreflexive _<_
<-irrefl {suc x} = <-irrefl {x = x}

<-conn : Connected _<_
<-conn {zero} {zero} x≮y y≮x = refl
<-conn {zero} {suc y} x≮y y≮x = ⊥-elim (x≮y tt)
<-conn {suc x} {zero} x≮y y≮x = ⊥-elim (y≮x tt)
<-conn {suc x} {suc y} x≮y y≮x = cong suc (<-conn x≮y y≮x)

≤-antisym : Antisymmetric _≤_
≤-antisym {zero} {zero} x≤y y≤x = refl
≤-antisym {suc x} {suc y} x≤y y≤x = cong suc (≤-antisym x≤y y≤x)

ℕ-≰⇒> : ∀ x y → ¬ (x ≤ y) → y < x
ℕ-≰⇒> x y x≰y with y <ᴮ x
... | false = x≰y tt
... | true = tt

ℕ-≮⇒≥ : ∀ x y → ¬ (x < y) → y ≤ x
ℕ-≮⇒≥ x y x≮y with x <ᴮ y
... | false = tt
... | true = x≮y tt

totalOrder : TotalOrder ℕ ℓzero ℓzero
totalOrder .TotalOrder.strictPartialOrder .StrictPartialOrder.strictPreorder .StrictPreorder._<_ = _<_
totalOrder .TotalOrder.strictPartialOrder .StrictPartialOrder.strictPreorder .StrictPreorder.trans {x} {y} {z} = <-trans {x} {y} {z}
totalOrder .TotalOrder.strictPartialOrder .StrictPartialOrder.strictPreorder .StrictPreorder.irrefl {x} = <-irrefl {x = x}
totalOrder .TotalOrder.strictPartialOrder .StrictPartialOrder.conn = <-conn
totalOrder .TotalOrder.partialOrder .PartialOrder.preorder .Preorder._≤_ = _≤_
totalOrder .TotalOrder.partialOrder .PartialOrder.preorder .Preorder.refl {x} = ≤-refl x
totalOrder .TotalOrder.partialOrder .PartialOrder.preorder .Preorder.trans {x} {y} {z} = ≤-trans x y z
totalOrder .TotalOrder.partialOrder .PartialOrder.antisym = ≤-antisym
totalOrder .TotalOrder._<?_ x y = T? (x <ᴮ y)
totalOrder .TotalOrder.≰⇒> {x} {y} = ℕ-≰⇒> x y
totalOrder .TotalOrder.≮⇒≥ {x} {y} = ℕ-≮⇒≥ x y


------------------------------------------------------------------------------
-- Some proofs related to the power function
------------------------------------------------------------------------------

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

module FOT.FOTC.Data.Nat.Pow.PropertiesATP where

open import FOT.FOTC.Data.Nat.Pow

open import FOTC.Base
open import FOTC.Data.Nat
open import FOTC.Data.Nat.Inequalities
open import FOTC.Data.Nat.UnaryNumbers
open import FOTC.Data.Nat.UnaryNumbers.TotalityATP

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

postulate 0^0≡1 : 0' ^ 0' ≡ 1'
{-# ATP prove 0^0≡1 #-}

0^Sx≡0 : ∀ {n} → N n → 0' ^ succ₁ n ≡ 0'
0^Sx≡0 {.zero} nzero  = prf
  where postulate prf : 0' ^ succ₁ zero ≡ 0'
        {-# ATP prove prf #-}

0^Sx≡0 (nsucc {n} Nn) = prf
  where postulate prf : 0' ^ succ₁ (succ₁ n) ≡ 0'
        {-# ATP prove prf #-}

thm₁ : ∀ {n} → N n → 5' ≤ n → n ^ 5' ≤ 5' ^ n
thm₁ nzero h = prf
  where postulate prf : zero ^ 5' ≤ 5' ^ zero
        {-# ATP prove prf #-}
thm₁ (nsucc {n} Nn) h = prf (thm₁ Nn) h
  where
  postulate prf : (5' ≤ n → n ^ 5' ≤ 5' ^ n) →
                  5' ≤ succ₁ n →
                  succ₁ n ^ 5' ≤ 5' ^ succ₁ n
  -- 2018-06-28: The ATPs could not prove the theorem (300 sec).
  -- {-# ATP prove prf 5-N #-}

thm₂ : ∀ {n} → N n →
       ((2' ^ n) ∸ 1') + 1' + ((2' ^ n) ∸ 1') ≡ 2' ^ (n + 1') ∸ 1'
thm₂ nzero = prf
  where
  postulate prf : ((2' ^ zero) ∸ 1') + 1' + ((2' ^ zero) ∸ 1') ≡
                  2' ^ (zero + 1') ∸ 1'
  {-# ATP prove prf #-}
thm₂ (nsucc {n} Nn) = prf (thm₂ Nn)
  where
  postulate prf : ((2' ^ n) ∸ 1') + 1' + ((2' ^ n) ∸ 1') ≡
                  2' ^ (n + 1') ∸ 1' →
                  ((2' ^ succ₁ n) ∸ 1') + 1' + ((2' ^ succ₁ n) ∸ 1') ≡
                  2' ^ (succ₁ n + 1') ∸ 1'
  -- 2018-06-28: The ATPs could not prove the theorem (300 sec).
  -- {-# ATP prove prf #-}


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

-- Pi combinators inspired by duals and traced monoidal categories

module Trace where

open import Data.Product using (Σ; _,_; proj₁; proj₂)
open import Relation.Binary.PropositionalEquality
  using (_≡_; subst)

open import PiFrac

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

dual : {A B : 𝕌} → (f : A ⟷ B) → (v : ⟦ A ⟧ ) →
                   (𝟙/● B [ eval f v ] ⟷ 𝟙/● A [ v ])
dual f v = uniti⋆l ⊚ (η v ⊗ id⟷) ⊚ ((lift f ⊗ id⟷) ⊗ id⟷) ⊚
  assocr⋆ ⊚ (id⟷ ⊗ swap⋆) ⊚ assocl⋆ ⊚ (ε (eval f v) ⊗ id⟷) ⊚ unite⋆l

-- name, coname
name : {A B : 𝕌} → (f : A ⟷ B) → (v : ⟦ A ⟧ ) → 𝟙 ⟷ ● B [ eval f v ] ×ᵤ 𝟙/● A [ v ]
name f v = η v ⊚ (lift f ⊗ id⟷)

coname : {A B : 𝕌} → (f : A ⟷ B) → (v : ⟦ A ⟧ ) → ● A [ v ] ×ᵤ 𝟙/● B [ eval f v ] ⟷ 𝟙
coname f v = (lift f ⊗ id⟷) ⊚ ε (eval f v)

-- and 'trace' reveals something neat: we can't choose just any random 'a' and 'c'
-- to start with, but we need that make a coherence choice of a and c !!
trace : {A B C : 𝕌} (a : ⟦ A ⟧ ) → (f : A ×ᵤ C ⟷ B ×ᵤ C) →
  (coh : Σ ⟦ C ⟧ (λ c → proj₂ (eval f (a , c)) ≡ c)) →
  ● A [ a ] ⟷ ● B [ proj₁ (eval f (a , proj₁ coh)) ]
trace {A} {B} {C} a f (c , choice) =
  uniti⋆r ⊚        -- A ×ᵤ 1
  (id⟷ ⊗ η c) ⊚   -- A ×ᵤ (C ×ᵤ 1/C)
  assocl⋆ ⊚       -- (A ×ᵤ C) ×ᵤ 1/C
  (tensorr ⊗ id⟷) ⊚ -- bring in the ●
  (lift f ⊗ id⟷) ⊚ -- (B ×ᵤ C) ×ᵤ 1/C
  (tensorl ⊗ id⟷) ⊚ -- bring out the ●
  assocr⋆ ⊚          -- B ×ᵤ (C ×ᵤ 1/C)
  (id⟷ ⊗ (subst fixer choice id⟷ ⊚ ε c)) ⊚ -- B ×ᵤ 1
  unite⋆r
  where
    fixer : ⟦ C ⟧ → Set
    fixer d = (● C [ proj₂ (eval f (a , c)) ] ×ᵤ 𝟙/● C [ d ]) ⟷ (● C [ d ] ×ᵤ 𝟙/● C [ d ])


open import Logic
open import Type

module Structure.Sets.Quantifiers {ℓₑ ℓₛ ℓₗ}{E : Type{ℓₑ}}{S : Type{ℓₛ}} (_∈_ : E → S → Stmt{ℓₗ}) where

import      Lvl
open import Logic.Propositional
open import Logic.Predicate
open import Syntax.Function

private variable ℓ : Lvl.Level

-- Set restricted existential quantifier.
∃ₛ : S → (E → Stmt{ℓ}) → Stmt
∃ₛ(A) P = ∃(x ↦ (x ∈ A) ∧ P(x))

-- Set restricted universal quantifier.
∀ₛ : S → (E → Stmt{ℓ}) → Stmt
∀ₛ(A) P = ∀ₗ(x ↦ ((x ∈ A) → P(x)))


open import Relation.Nullary using (¬_)

module AKS.Fin where

open import AKS.Nat using (ℕ; _+_; _<_)

record Fin (n : ℕ) : Set where
  constructor Fin✓
  field
    i : ℕ
    i<n : i < n

¬Fin0 : ¬ (Fin 0)
¬Fin0 ()

from< : ∀ {i n} → i < n → Fin n
from< {i} i<n = Fin✓ i i<n


module Functor where

record IsEquivalence {A : Set} (_≈_ : A → A → Set) : Set where
  field
    refl  : ∀ {x} → x ≈ x
    sym   : ∀ {i j} → i ≈ j → j ≈ i
    trans : ∀ {i j k} → i ≈ j → j ≈ k → i ≈ k

record Setoid : Set₁ where
  infix 4 _≈_
  field
    Carrier       : Set
    _≈_           : Carrier → Carrier → Set
    isEquivalence : IsEquivalence _≈_

  open IsEquivalence isEquivalence public

infixr 0 _⟶_

record _⟶_ (From To : Setoid) : Set where
  infixl 5 _⟨$⟩_
  field
    _⟨$⟩_ : Setoid.Carrier From → Setoid.Carrier To
    cong  : ∀ {x y} →
            Setoid._≈_ From x y → Setoid._≈_ To (_⟨$⟩_ x) (_⟨$⟩_ y)

open _⟶_ public

id : ∀ {A} → A ⟶ A
id = record { _⟨$⟩_ = λ x → x; cong = λ x≈y → x≈y }

infixr 9 _∘_

_∘_ : ∀ {A B C} → B ⟶ C → A ⟶ B → A ⟶ C
f ∘ g = record
  { _⟨$⟩_ = λ x → f ⟨$⟩ (g ⟨$⟩ x)
  ; cong  = λ x≈y → cong f (cong g x≈y)
  }

_⇨_ : (To From : Setoid) → Setoid
From ⇨ To = record
  { Carrier       = From ⟶ To
  ; _≈_           = λ f g → ∀ {x y} → x ≈₁ y → f ⟨$⟩ x ≈₂ g ⟨$⟩ y
  ; isEquivalence = record
    { refl  = λ {f} → cong f
    ; sym   = λ f∼g x∼y → To.sym (f∼g (From.sym x∼y))
    ; trans = λ f∼g g∼h x∼y → To.trans (f∼g From.refl) (g∼h x∼y)
    }
  }
  where
  open module From = Setoid From using () renaming (_≈_ to _≈₁_)
  open module To   = Setoid To   using () renaming (_≈_ to _≈₂_)

record Functor (F : Setoid → Setoid) : Set₁ where
  field
    map : ∀ {A B} → (A ⇨ B) ⟶ (F A ⇨ F B)

    identity : ∀ {A} →
      let open Setoid (F A ⇨ F A) in
      map ⟨$⟩ id ≈ id

    composition : ∀ {A B C} (f : B ⟶ C) (g : A ⟶ B) →
      let open Setoid (F A ⇨ F C) in
      map ⟨$⟩ (f ∘ g) ≈ (map ⟨$⟩ f) ∘ (map ⟨$⟩ g)


module MinMax where

open import Prelude
open import Logic.Base
open import Logic.Relations
open import Logic.Identity using (_≡_)
import Logic.ChainReasoning
open import DecidableOrder as DecOrder

module Min {A : Set}(Ord : DecidableOrder A) where

  open DecidableOrder Ord

  min : A → A → A
  min a b with decide a b
  ... | \/-IL _ = a
  ... | \/-IR _ = b

  data CaseMin x y : A → Set where
    leq : x ≤ y → CaseMin x y x
    geq : x ≥ y → CaseMin x y y

  case-min′ : ∀ x y → CaseMin x y (min x y)
  case-min′ x y with decide x y
  ... | \/-IL xy  = leq xy
  ... | \/-IR ¬xy with total x y
  ...   | \/-IL xy = elim-False (¬xy xy)
  ...   | \/-IR yx = geq yx

  case-min : (P : A → Set)(x y : A) →
            (x ≤ y → P x) →
            (y ≤ x → P y) → P (min x y)
  case-min P x y ifx ify with min x y | case-min′ x y
  ... | .x | leq xy = ifx xy
  ... | .y | geq yx = ify yx

  min-glb : ∀ x y z → z ≤ x → z ≤ y → z ≤ min x y
  min-glb x y z zx zy with min x y | case-min′ x y
  ... | .x | leq _ = zx
  ... | .y | geq _ = zy

  min-left : ∀ x y → min x y ≤ x
  min-left x y with min x y | case-min′ x y
  ... | .x | leq _  = refl _
  ... | .y | geq yx = yx

  min-right : ∀ x y → min x y ≤ y
  min-right x y with min x y | case-min′ x y
  ... | .x | leq xy = xy
  ... | .y | geq _  = refl _

  min-sym : ∀ x y → min x y ≡ min y x
  min-sym x y = antisym _ _ (lem x y) (lem y x)
    where
      lem : ∀ a b → min a b ≤ min b a
      lem a b with min b a | case-min′ b a
      ... | .b | leq _ = min-right _ _
      ... | .a | geq _ = min-left _ _

Dual : {A : Set} → DecidableOrder A → DecidableOrder A
Dual Ord = record
    { _≤_     = _≥_
    ; refl    = refl
    ; antisym = \x y xy yx   → antisym _ _ yx xy
    ; trans   = \x y z xy yz → trans _ _ _ yz xy
    ; total   = \x y         → total _ _
    ; decide  = \x y         → decide _ _
    }
  where
    open DecidableOrder Ord

module Max {A : Set}(Ord : DecidableOrder A)
      = Min (Dual Ord) renaming
              ( min       to max
              ; case-min  to case-max
              ; case-min′ to case-max′
              ; CaseMin   to CaseMax
              ; module CaseMin to CaseMax
              ; leq       to geq
              ; geq       to leq
              ; min-glb   to max-lub
              ; min-sym   to max-sym
              ; min-right to max-right
              ; min-left  to max-left
              )

module MinMax {A : Set}(Ord : DecidableOrder A) where
  open DecidableOrder Ord public
  open Min Ord public
  open Max Ord public

module DistributivityA {A : Set}(Ord : DecidableOrder A) where

  open MinMax Ord

  min-max-distr : ∀ x y z → min x (max y z) ≡ max (min x y) (min x z)
  min-max-distr x y z = antisym _ _ left right
    where
      open Logic.ChainReasoning.Mono.Homogenous _≤_ refl trans

      left : min x (max y z) ≤ max (min x y) (min x z)
      left with max y z | case-max′ y z
      ... | .z | Min.geq _ = max-right _ _
      ... | .y | Min.leq _ = max-left _ _

      right : max (min x y) (min x z) ≤ min x (max y z)
--      right with max (min x y) (min x z) | case-max′ (min x y) (min x z)
      right = case-max (\w → w ≤ min x (max y z)) (min x y) (min x z)
                       (\_ → case-max (\w → min x y ≤ min x w) y z
                                (\_  → refl _)
                                (\yz → min-glb x z _ (min-left x y)
                                          ( chain>
                                            min x y === y  by  min-right x y
                                                    === z  by  yz
                                          )
                                )
                       )
                       (\_ → case-max (\w → min x z ≤ min x w) y z
                                (\zy → min-glb x y _ (min-left x z)
                                          ( chain>
                                            min x z === z  by  min-right x z
                                                    === y  by  zy
                                          )
                                )
                                (\_  → refl _)
                       )

module DistributivityB {A : Set}(Ord : DecidableOrder A) where

  open DistributivityA (Dual Ord) public renaming (min-max-distr to max-min-distr)

module Distributivity {A : Set}(Ord : DecidableOrder A) where

  open DistributivityA Ord public
  open DistributivityB Ord public

-- Testing
postulate
  X    : Set
  OrdX : DecidableOrder X

-- open DecidableOrder OrdX
open MinMax OrdX -- hiding (_≤_)
open Distributivity OrdX

open Logic.ChainReasoning.Mono.Homogenous

-- Displayforms doesn't work for MinMax._≤_ (reduces to DecidableOrder._≤_)
test : ∀ x y → min x y ≤ x
test x y = min-left x y


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

open import Categories.Category

-- this module characterizes a category of all products indexed by I.
-- this notion formalizes a category with all products up to certain cardinal.
module Categories.Object.Product.Indexed {o ℓ e} (C : Category o ℓ e) where

open import Level

open import Categories.Morphism.Reasoning C

open Category C
open Equiv
open HomReasoning

record IndexedProductOf {i} {I : Set i} (P : I → Obj) : Set (i ⊔ o ⊔ e ⊔ ℓ) where
  field
    -- the product
    X : Obj

    π   : ∀ i → X ⇒ P i
    ⟨_⟩ : ∀ {Y} → (∀ i → Y ⇒ P i) → Y ⇒ X

    commute : ∀ {Y} (f : ∀ i → Y ⇒ P i) → ∀ i → π i ∘ ⟨ f ⟩ ≈ f i
    unique  : ∀ {Y} (h : Y ⇒ X) (f : ∀ i → Y ⇒ P i) → (∀ i → π i ∘ h ≈ f i) → ⟨ f ⟩ ≈ h

  η : ∀ {Y} (h : Y ⇒ X) → ⟨ (λ i → π i ∘ h) ⟩ ≈ h
  η h = unique _ _ λ _ → refl

  ⟨⟩∘ : ∀ {Y Z} (f : ∀ i → Y ⇒ P i) (g : Z ⇒ Y) → ⟨ f ⟩ ∘ g ≈ ⟨ (λ i → f i ∘ g) ⟩
  ⟨⟩∘ f g = ⟺ (unique _ _ λ i → pullˡ (commute _ _))

  ⟨⟩-cong : ∀ {Y} (f g : ∀ i → Y ⇒ P i) → (eq : ∀ i → f i ≈ g i) → ⟨ f ⟩ ≈ ⟨ g ⟩
  ⟨⟩-cong f g eq = unique _ _ λ i → trans (commute _ _) (⟺ (eq i))

  unique′ : ∀ {Y} (h h′ : Y ⇒ X) → (∀ i → π i ∘ h′ ≈ π i ∘ h) → h′ ≈ h
  unique′ h h′ f = trans (⟺ (unique _ _ f)) (η _)

record IndexedProduct {i} (I : Set i) : Set (i ⊔ o ⊔ e ⊔ ℓ) where
  field
    P         : I → Obj
    productOf : IndexedProductOf P

  open IndexedProductOf productOf public

AllProducts : ∀ i → Set (o ⊔ ℓ ⊔ e ⊔ suc i)
AllProducts i = (I : Set i) → IndexedProduct I

AllProductsOf : ∀ i → Set (o ⊔ ℓ ⊔ e ⊔ suc i)
AllProductsOf i = ∀ {I : Set i} (P : I → Obj) → IndexedProductOf P


{-# OPTIONS --cubical --safe #-}
module Cubical.Data.Nat.Coprime where

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

open import Cubical.Data.Sigma
open import Cubical.Data.NatPlusOne

open import Cubical.HITs.PropositionalTruncation as PropTrunc

open import Cubical.Data.Nat.Base
open import Cubical.Data.Nat.Properties
open import Cubical.Data.Nat.Divisibility
open import Cubical.Data.Nat.GCD

areCoprime : ℕ × ℕ → Type₀
areCoprime (m , n) = isGCD m n 1

-- Any pair (m , n) can be converted to a coprime pair (m' , n') s.t.
--  m' ∣ m, n' ∣ n if and only if one of m or n is nonzero

module _ ((m , n) : ℕ × ℕ₊₁) where
  private
    d    = gcd m (ℕ₊₁→ℕ n)
    d∣m  = gcdIsGCD m (ℕ₊₁→ℕ n) .fst .fst
    d∣sn = gcdIsGCD m (ℕ₊₁→ℕ n) .fst .snd
    gr   = gcdIsGCD m (ℕ₊₁→ℕ n) .snd

    c₁ : ℕ
    p₁ : c₁ * d ≡ m
    c₁ = ∣-untrunc d∣m .fst; p₁ = ∣-untrunc d∣m .snd

    c₂ : ℕ₊₁
    p₂ : (ℕ₊₁→ℕ c₂) * d ≡ (ℕ₊₁→ℕ n)
    c₂ = 1+ (∣s-untrunc d∣sn .fst); p₂ = ∣s-untrunc d∣sn .snd

  toCoprime : ℕ × ℕ₊₁ → ℕ × ℕ₊₁
  toCoprime (m , n) = (c₁ , c₂)

  private
    lem : ∀ a {b c d e} → a * b ≡ c → c * d ≡ e → a * (b * d) ≡ e
    lem a p q = *-assoc a _ _ ∙ cong (_* _) p ∙ q

    gr' : ∀ d' → prediv d' c₁ → prediv d' (ℕ₊₁→ℕ c₂) → (d' * d) ∣ d
    gr' d' (b₁ , q₁) (b₂ , q₂) = gr (d' * d) ((∣ b₁ , lem b₁ q₁ p₁ ∣) ,
                                              (∣ b₂ , lem b₂ q₂ p₂ ∣))

    -- this only works because d > 0 (<=> m > 0 or n > 0)
    d-cancelʳ : ∀ d' → (d' * d) ∣ d → d' ∣ 1
    d-cancelʳ d' div = ∣-cancelʳ d-1 (∣-trans (subst (λ x → (d' * x) ∣ x) p div)
                                              (∣-refl (sym (*-identityˡ _))))
      where d-1 = m∣sn→z<m d∣sn .fst
            p : d ≡ suc d-1
            p = sym (+-comm 1 d-1 ∙ m∣sn→z<m d∣sn .snd)

  toCoprimeAreCoprime : areCoprime (c₁ , ℕ₊₁→ℕ c₂)
  fst toCoprimeAreCoprime = ∣-oneˡ c₁ , ∣-oneˡ (ℕ₊₁→ℕ c₂)
  snd toCoprimeAreCoprime d' (d'∣c₁ , d'∣sc₂) = PropTrunc.rec isProp∣ (λ a →
                                                PropTrunc.rec isProp∣ (λ b →
                                                 d-cancelʳ d' (gr' d' a b)) d'∣sc₂) d'∣c₁

  toCoprime∣ : (c₁ ∣ m) × (ℕ₊₁→ℕ c₂ ∣ ℕ₊₁→ℕ n)
  toCoprime∣ = ∣ d , *-comm d c₁ ∙ p₁ ∣ , ∣ d , *-comm d (ℕ₊₁→ℕ c₂) ∙ p₂ ∣


open import Numeral.Natural
open import Relator.Equals
open import Type.Properties.Decidable
open import Type

module Formalization.ClassicalPredicateLogic.Syntax.Substitution
  {ℓₚ ℓᵥ ℓₒ}
  (Prop : ℕ → Type{ℓₚ})
  (Var : Type{ℓᵥ}) ⦃ var-eq-dec : Decidable(2)(_≡_ {T = Var}) ⦄
  (Obj : ℕ → Type{ℓₒ})
  where

open import Data.Boolean
open import Data.ListSized
import      Data.ListSized.Functions as List
open import Formalization.ClassicalPredicateLogic.Syntax(Prop)(Var)(Obj)

private variable n : ℕ

substituteTerm : Var → Term → Term → Term
substituteTerm₊ : Var → Term → List(Term)(n) → List(Term)(n)
substituteTerm v t (var x)    = if(decide(2)(_≡_) v x) then t else (var x)
substituteTerm v t (func f x) = func f (substituteTerm₊ v t x)
substituteTerm₊ {0}    v t ∅        = ∅
substituteTerm₊ {𝐒(n)} v t (x ⊰ xs) = (substituteTerm v t x ⊰ substituteTerm₊ {n} v t xs)

substitute : Var → Term → Formula → Formula
substitute v t (f $ x)  = f $ List.map (substituteTerm v t) x
substitute v t ⊤        = ⊤
substitute v t ⊥        = ⊥
substitute v t (φ ∧ ψ)  = (substitute v t φ) ∧ (substitute v t ψ)
substitute v t (φ ∨ ψ)  = (substitute v t φ) ∨ (substitute v t ψ)
substitute v t (φ ⟶ ψ)  = (substitute v t φ) ⟶ (substitute v t ψ)
substitute v t (Ɐ(x) φ) = Ɐ(x) (if(decide(2)(_≡_) v x) then φ else (substitute v t φ))
substitute v t (∃(x) φ) = ∃(x) (if(decide(2)(_≡_) v x) then φ else (substitute v t φ))


module Oscar.Data.Substitist {𝔣} (FunctionName : Set 𝔣) where

open import Oscar.Data.Fin
open import Oscar.Data.Nat
open import Oscar.Data.Product
open import Oscar.Data.Term FunctionName
open import Oscar.Data.AList
open import Oscar.Data.Equality

Substitist : Nat → Nat → Set 𝔣
Substitist m n = AList (λ m → Term m × Fin (suc m)) n m

pattern anil = []
pattern _asnoc_/_ σ t x = (t , x) ∷ σ

_⊸_ = Substitist

infixr 9 _∙_
_∙_ : ∀ {m n} → m ⊸ n → ∀ {l} → l ⊸ m → l ⊸ n
ρ ∙ anil = ρ
ρ ∙ (σ asnoc t / x) = (ρ ∙ σ) asnoc t / x

∙-associativity : ∀ {k l} (f : k ⊸ l) {m} (g : l ⊸ m) {n} (h : m ⊸ n) → (h ∙ g) ∙ f ≡ h ∙ g ∙ f
∙-associativity anil σ _ = refl
∙-associativity (τ asnoc t / x) ρ σ = cong (λ s → s asnoc t / x) (∙-associativity τ ρ σ)

ε : ∀ {n} → n ⊸ n
ε = anil

∙-left-identity : ∀ {m n} (σ : m ⊸ n) → ε ∙ σ ≡ σ
∙-left-identity anil = refl
∙-left-identity (σ asnoc t' / x) = cong (λ σ → σ asnoc t' / x) (∙-left-identity σ)

∙-right-identity : ∀ {m n} (σ : m ⊸ n) → σ ∙ ε ≡ σ
∙-right-identity _ = refl

open import Oscar.Category

semigroupoidSubstitist : Semigroupoid Substitist (λ {x y} → ≡-setoid (Substitist x y))
Semigroupoid._∙_ semigroupoidSubstitist = _∙_
Semigroupoid.∙-extensionality semigroupoidSubstitist refl refl = refl
Semigroupoid.∙-associativity semigroupoidSubstitist = ∙-associativity

Substitist' : Nat → Nat → Set 𝔣
Substitist' m n = AList (λ m → Term m × Fin (suc m)) m n

semigroupoidSubstitist' : Semigroupoid Substitist' (λ {x y} → ≡-setoid (Substitist' x y))
semigroupoidSubstitist' = Category'.semigroupoidAList

categorySubstitist : Category semigroupoidSubstitist
Category.ε categorySubstitist = ε
Category.ε-left-identity categorySubstitist = ∙-left-identity _
Category.ε-right-identity categorySubstitist = ∙-right-identity _


module Structure.Setoid.Uniqueness.Proofs where

import      Lvl
open import Functional
open import Logic.Propositional
open import Logic.Predicate
open import Structure.Setoid.Uniqueness
open import Structure.Setoid
open import Structure.Function.Domain
open import Structure.Relator.Properties
open import Syntax.Transitivity
open import Type

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

module _ ⦃ equiv-A : Equiv{ℓₑ₁}(A) ⦄ ⦃ equiv-B : Equiv{ℓₑ₂}(B) ⦄ {f : A → B} where
  Uniqueness-Injectivity : (∀{y : B} → Unique(x ↦ y ≡ f(x))) ↔ Injective(f)
  Uniqueness-Injectivity = [↔]-intro l r where
    l : (∀{y : B} → Unique(x ↦ y ≡ f(x))) ← Injective(f)
    l inj {y} {x₁}{x₂} (y≡fx₁) (y≡fx₂) = injective _ ⦃ inj ⦄ {x₁}{x₂} (symmetry(_≡_) (y≡fx₁) 🝖 (y≡fx₂))

    r : (∀{y : B} → Unique(x ↦ y ≡ f(x))) → Injective(f)
    Injective.proof(r unique) {x₁}{x₂} (fx₁≡fx₂) = unique {f(x₁)}{x₁}{x₂} (reflexivity(_≡_)) (fx₁≡fx₂)


-- Some basic structures and operations for dealing
-- with non-deterministic values.
--
-- @author Sergio Antoy, Michael Hanus, Steven Libby

module nondet where

open import bool
open import nat
open import list

infixr 8 _??_

----------------------------------------------------------------------
-- A tree datatype to represent a non-deterministic value of some type.
-- It is either a value or a choice between non-deterministic values.
----------------------------------------------------------------------

data ND (A : Set) : Set where
  Val  : A → ND A
  _??_ : ND A → ND A → ND A

----------------------------------------------------------------------
-- Some operations to define functions working this the ND datatype:

-- Apply a (deterministic) function to a non-deterministic argument.
-- This corresponds to a functor on the ND structure.
_$*_ : {A B : Set} → (A → B) → ND A → ND B
f $* (Val xs) = Val (f xs)
f $* (t1 ?? t2) = f $* t1 ?? f $* t2

-- Apply a non-deterministic function to a non-deterministic argument.
-- If ND would be an instance of the monad class, this is a monadic bind
-- with swapped arguments.
_*$*_ : {A B : Set} → (A → ND B) → ND A → ND B
f *$* (Val x)    = f x
f *$* (t1 ?? t2) = f *$* t1 ?? f *$* t2

-- Apply a binary non-deterministic function to non-deterministic arguments.
apply-nd2 : {A B C : Set} → (A → B → ND C) → ND A → ND B → ND C
apply-nd2 f a b = (λ x -> (λ y -> f x y) *$* b) *$* a

-- Apply a ternary non-deterministic function to non-deterministic arguments.
apply-nd3 : {A B C D : Set} → (A → B → C → ND D) → ND A → ND B → ND C → ND D
apply-nd3 f a b c = (λ x -> (λ y -> (λ z → f x y z) *$* c) *$* b) *$* a

-- Extend a deterministic function to one with non-deterministic result:
toND : {A B : Set} → (A → B) → A → ND B
toND f x = Val (f x)

----------------------------------------------------------------------
-- Some operations to define properties of non-deterministic values:

-- Count the number of values:
#vals : {A : Set} → ND A → ℕ
#vals (Val _) = 1
#vals (t1 ?? t2) = #vals t1 + #vals t2

-- Extract the list of all values:
vals-of : {A : Set} → ND A → 𝕃 A
vals-of (Val v)    = v :: []
vals-of (t1 ?? t2) = vals-of t1 ++ vals-of t2

-- All values in a Boolean tree are true:
always : ND 𝔹 → 𝔹
always (Val b)    = b
always (t1 ?? t2) = always t1 && always t2

-- There exists some true value in a Boolean tree:
eventually : ND 𝔹 → 𝔹
eventually (Val b)    = b
eventually (t1 ?? t2) = eventually t1 || eventually t2

-- All non-deterministic values satisfy a given predicate:
_satisfy_ : {A : Set} → ND A → (A → 𝔹) → 𝔹
(Val n)    satisfy p = p n
(t1 ?? t2) satisfy p = t1 satisfy p && t2 satisfy p

-- Every value in a tree is equal to the second argument w.r.t. a
-- comparison function provided as the first argument:
every : {A : Set} → (eq : A → A → 𝔹) → A → ND A → 𝔹
every eq x xs = xs satisfy (eq x)

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


module Numeric.Nat.LCM.Properties where

open import Prelude
open import Numeric.Nat.Divide
open import Numeric.Nat.Divide.Properties
open import Numeric.Nat.LCM

is-lcm-unique : ∀ {m m₁ a b} → IsLCM m a b → IsLCM m₁ a b → m ≡ m₁
is-lcm-unique {m} {m₁} (is-lcm a|m b|m lm) (is-lcm a|m₁ b|m₁ lm₁) =
  divides-antisym (lm m₁ a|m₁ b|m₁) (lm₁ m a|m b|m)

lcm-unique : ∀ {m a b} → IsLCM m a b → lcm! a b ≡ m
lcm-unique {a = a} {b} lm with lcm a b
... | lcm-res m₁ lm₁ = is-lcm-unique lm₁ lm

is-lcm-commute : ∀ {m a b} → IsLCM m a b → IsLCM m b a
is-lcm-commute (is-lcm a|m b|m g) = is-lcm b|m a|m (flip ∘ g)

lcm-commute : ∀ {a b} → lcm! a b ≡ lcm! b a
lcm-commute {a} {b} with lcm b a
... | lcm-res m lm = lcm-unique (is-lcm-commute lm)

private
  _|>_ = divides-trans

lcm-assoc : ∀ a b c → lcm! a (lcm! b c) ≡ lcm! (lcm! a b) c
lcm-assoc a b c with lcm a b | lcm b c
... | lcm-res ab (is-lcm a|ab b|ab lab)
    | lcm-res bc (is-lcm b|bc c|bc lbc) with lcm ab c
...    | lcm-res ab-c (is-lcm ab|abc c|abc labc) =
  lcm-unique {ab-c} {a} {bc}
    (is-lcm (a|ab |> ab|abc)
            (lbc ab-c (b|ab |> ab|abc) c|abc)
            λ k a|k bc|k → labc k (lab k a|k (b|bc |> bc|k)) (c|bc |> bc|k))


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

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

open import Setoids.Setoids
open import Setoids.Subset
open import Setoids.Functions.Definition
open import LogicalFormulae
open import Functions
open import Lists.Lists
open import Setoids.Orders
open import Rings.Orders.Partial.Definition
open import Rings.Definition

module LectureNotes.MetAndTop.Chapter2 {a b c : _} {R : Set a} {S : Setoid {a} {b} R} {_<_ : Rel {a} {c} R} {_+_ _*_ : R → R → R} {ring : Ring S _+_ _*_} {ps : SetoidPartialOrder S _<_} (pRing : PartiallyOrderedRing ring ps) where

open Setoid S renaming (_∼_ to _∼R_)
open Ring ring

record Metric {d1 e : _} {A : Set d1} {T : Setoid {d1} {e} A} (d : A → A → R) : Set (a ⊔ b ⊔ c ⊔ d1 ⊔ e) where
  open Setoid T
  field
    dWellDefined : (x y v w : A) → x ∼ y → v ∼ w → (d x v) ∼R (d w y)
    dZero : (x y : A) → (d x y) ∼R 0R → x ∼ y
    dZero' : (x y : A) → x ∼ y → (d x y) ∼R 0R
    dSymmetric : (x y : A) → (d x y) ∼R (d y x)
    dTriangle : (x y z : A) → ((d x z) < ((d x y) + (d y z))) || ((d x z) ∼R ((d x y) + (d y z)))
  dNonnegative : (x y : A) → (0R < d x y) || (0R ∼R (d x y))
  dNonnegative x y = {!!}


module Structure.Operator.Monoid where

import      Lvl
open import Logic
open import Logic.Predicate
open import Structure.Setoid
open import Structure.Operator.Properties hiding (associativity ; identityₗ ; identityᵣ)
open import Structure.Operator
open import Type

-- A type and a binary operator using this type is a monoid when:
-- • The operator is associative.
-- • The operator have an identity in both directions.
record Monoid {ℓ ℓₑ} {T : Type{ℓ}} ⦃ _ : Equiv{ℓₑ}(T) ⦄ (_▫_ : T → T → T) : Stmt{ℓ Lvl.⊔ ℓₑ} where
  constructor intro
  field
    ⦃ binary-operator ⦄    : BinaryOperator(_▫_)
    ⦃ associativity ⦄      : Associativity(_▫_)
    ⦃ identity-existence ⦄ : ∃(Identity(_▫_))

  id = [∃]-witness identity-existence

  identity : Identity (_▫_) id
  identity = [∃]-proof identity-existence

  identityₗ : Identityₗ (_▫_) id
  identityₗ = Identity.left(identity)

  identityᵣ : Identityᵣ (_▫_) id
  identityᵣ = Identity.right(identity)

  identity-existenceₗ : ∃(Identityₗ(_▫_))
  identity-existenceₗ = [∃]-intro id ⦃ identityₗ ⦄

  identity-existenceᵣ : ∃(Identityᵣ(_▫_))
  identity-existenceᵣ = [∃]-intro id ⦃ identityᵣ ⦄

record MonoidObject {ℓ ℓₑ} : Stmt{Lvl.𝐒(ℓ Lvl.⊔ ℓₑ)} where
  constructor intro
  field
    {T} : Type{ℓ}
    ⦃ equiv ⦄ : Equiv{ℓₑ}(T)
    _▫_ : T → T → T
    ⦃ monoid ⦄ : Monoid(_▫_)
  open Monoid(monoid) public


module x1-Base where

data List (X : Set) : Set where
  []  :              List X
  _∷_ : X → List X → List X
infixr 5 _∷_

foldr : ∀ {A} {B : Set} → (A → B → B) → B → List A → B
foldr f b      []  = b
foldr f b (a ∷ as) = f a (foldr f b as)

data Either (A : Set) (B : Set) : Set where
  left  : A → Either A B
  right : B → Either A B

[_,_] : ∀ {A B} {C : Set} → (A → C) → (B → C) → Either A B → C
[ f , g ] (left  x) = f x
[ f , g ] (right x) = g x

-- Unhabited type
data Empty : Set where

absurd : {X : Set} → Empty → X
absurd ()

-- use Empty to define something close to negation in logic:
-- e.g., terms of type ¬ (3 > 4)
infix 3 ¬_
¬_ : Set → Set
¬ X = X → Empty

-- binary relation on a type X
Rel : Set → Set₁
Rel X = X → X → Set

-- decidable relations
Decidable : ∀ {X} → Rel X → Set
Decidable R = ∀ x y → Either (R x y) (¬ (R x y))

-- To sort a list, need two relations on elements of list:

-- equality
record Equivalence {X} (_≈_ : Rel X) : Set₁ where
  field
    refl  : ∀ {x}     → x ≈ x
    sym   : ∀ {x y}   → x ≈ y → y ≈ x
    trans : ∀ {x y z} → x ≈ y → y ≈ z → x ≈ z

-- and ordering
record TotalOrder {X} (_≈_ : Rel X) (_≤_ : Rel X) : Set₁ where
  field
    antisym     : ∀ {x y}   → x ≤ y → y ≤ x → x ≈ y
    trans       : ∀ {x y z} → x ≤ y → y ≤ z → x ≤ z
    total       : ∀  x y    → Either (x ≤ y) (y ≤ x)
    reflexive   : ∀ {x y}   → x ≈ y → x ≤ y
    equivalence : Equivalence _≈_


open import Agda.Builtin.Nat

data Tree : Set where
  `    : Nat → Tree
  _`+_ : Tree → Tree → Tree

⟦_⟧ : Tree → Nat
⟦ ` n    ⟧ = n
⟦ t `+ u ⟧ = ⟦ t ⟧ + ⟦ u ⟧

data Target : Tree → Set where
  0+_ : ∀ e → Target (` 0 `+ e)
  _+0 : ∀ e → Target (e `+ ` 0)
  [_] : ∀ e → Target e

target : ∀ e → Target e
target (` 0 `+ e) = 0+ e
target (e `+ ` 0) = e +0
target e          = [ e ]

optimise   : Tree → Tree
structural : Tree → Tree

optimise t with {structural t} | target (structural t)
... | 0+ e  = e
... | e +0  = e
... | [ e ] = e

structural (` n)    = ` n
structural (e `+ f) = optimise e `+ optimise f

open import Agda.Builtin.Equality

suc-cong : ∀ {m n} → m ≡ n → suc m ≡ suc n
suc-cong refl = refl

+-cong : ∀ {m n p q} → m ≡ n → p ≡ q → m + p ≡ n + q
+-cong refl refl = refl

trans : {m n p : Nat} → m ≡ n → n ≡ p → m ≡ p
trans refl eq = eq

m≡m+0 : ∀ m → m ≡ m + 0
m≡m+0 0       = refl
m≡m+0 (suc m) = suc-cong (m≡m+0 m)

optimise-sound   : ∀ t → ⟦ optimise t ⟧ ≡ ⟦ t ⟧
structural-sound : ∀ t → ⟦ structural t ⟧ ≡ ⟦ t ⟧

optimise-sound t with {structural t} | target (structural t) | structural-sound t
... | 0+ e  | eq = eq
... | e +0  | eq = trans (m≡m+0 ⟦ e ⟧) eq
... | [ e ] | eq = eq

structural-sound (` n)    = refl
structural-sound (e `+ f) = +-cong (optimise-sound e) (optimise-sound f)


module Formalization.PrimitiveRecursion where

import      Lvl
open import Data
open import Data.ListSized
open import Numeral.Finite
open import Numeral.Natural
open import Syntax.Number
open import Type{Lvl.𝟎}

-- Function(n) is a syntactic representation of primitive recursive functions of type (ℕⁿ → ℕ).
-- The syntax
data Function : ℕ → Type where
  -- Base cases
  Base        : Function(0)
  Successor   : Function(1)
  Projection  : ∀{n : ℕ} → (i : 𝕟(n)) → Function(n)

  -- Inductive cases
  Composition : ∀{m n : ℕ} → Function(n) → List(Function(m))(n) → Function(m)
  Recursion   : ∀{n : ℕ} → Function(n) → Function(𝐒(𝐒(n))) → Function(𝐒(n))

Primitive : Type
Primitive = ℕ

module _ where
  open import Data.ListSized.Functions
  open import Functional

  private variable m n   : ℕ
  private variable i     : 𝕟(n)
  private variable x v   : Primitive
  private variable xs vs : List(Primitive)(n)
  private variable f g   : Function(m)
  private variable fs gs : List(Function(m))(n)

  -- The operational semantics.
  data _$_⟹_ : ∀{m n} → List(Function(m))(n) → List(Primitive)(m) → List(Primitive)(n) → Type
  data _$_⟶_ : ∀{n} → Function(n) → List(Primitive)(n) → ℕ → Type where
    zero : (Base $ ∅ ⟶ 𝟎)
    succ : (Successor $ singleton(n) ⟶ 𝐒(n))
    proj : (Projection{n}(i) $ xs ⟶ index(i)(xs))
    comp : (f $ vs ⟶ v) → (gs $ xs ⟹ vs) → (Composition{m}{n} f gs $ xs ⟶ v)
    rec𝟎 : (f $ xs ⟶ v) → (Recursion f g $ (𝟎 ⊰ xs) ⟶ v)
    rec𝐒 : (Recursion f g $ (n ⊰ xs) ⟶ x) → (g $ (n ⊰ x ⊰ xs) ⟶ v) → (Recursion f g $ (𝐒(n) ⊰ xs) ⟶ v)
  data _$_⟹_ where
    base : (∅ $ xs ⟹ ∅)
    step : (f $ xs ⟶ v) → (fs $ xs ⟹ vs) → ((f ⊰ fs) $ xs ⟹ (v ⊰ vs))

  -- Functionally equivalent to `evaluate f (map(g ↦ evaluate g xs)(gs))`, but the termination checker does not accept that form.
  mapEvaluate : ∀{m n} → List(Function(m))(n) → List(Primitive)(m) → List(Primitive)(n)

  -- The denotational semantics.
  -- This is possible to encode into an Agda function because: Primitive recursive functions ⊆ Agda functions.
  -- `Base` is interpreted as the constant 0.
  -- `Successor` is interpreted as the successor function of ℕ.
  -- `Projection{n}(i)` is interpreted as the projection of the i:th element of ℕⁿ.
  -- `Composition(f)(gs)` is interpreted as generalized composition by using map on the arguments of a function.
  --    Specifically (f ∘ (map gs)).
  -- `Recursion(f)(g)` is interpreted as a "recursion constructor".
  --    This is used to construct a function `r` in which the following holds:
  --    • r(0   ,..xs) = f(..xs)
  --    • r(𝐒(n),..xs) = g(n,r(n,..xs),..xs)
  {-# TERMINATING #-} -- TODO: Terminated before but the termination checker in Agda version 2.6.2-9bed10c denies this (or in some random cases it gives an internal error at src/full/Agda/TypeChecking/Reduce/Fast.hs:1358)
  evaluate : ∀{n} → Function(n) → (List(Primitive)(n) → Primitive)
  evaluate {.𝟎}   (Base)                     ∅             = 𝟎
  evaluate {.𝐒(𝟎)}(Successor)                (singleton x) = 𝐒(x)
  evaluate {_}    (Projection(i))            xs            = index(i)(xs)
  evaluate {m}    (Composition{m}{n}(f)(gs)) xs            = evaluate{n} f (mapEvaluate{m}{n} gs xs)
  evaluate {𝐒(_)} (Recursion(f)(g))          (𝟎    ⊰ xs)   = evaluate f xs
  evaluate {𝐒(m)} (Recursion(f)(g))          (𝐒(n) ⊰ xs)   = evaluate{𝐒(𝐒(m))} g (n ⊰ (evaluate{𝐒 m} (Recursion(f)(g)) (n ⊰ xs) ⊰ xs))

  mapEvaluate          ∅        xs = ∅
  mapEvaluate{m}{𝐒(n)} (g ⊰ gs) xs = (evaluate{m} g xs) ⊰ (mapEvaluate{m}{n} gs xs)

  ------------------------------------------------------
  -- This section proves the equivalence between the operational and the denotational semantics. Or it can be interpreted as the correctness of one of the definitions by the other one.
  -- This equivalence should be obvious from the definitions.
  --

  open import Relator.Equals
  open import Relator.Equals.Proofs
  open import Syntax.Transitivity

  [⟹]-to-eval : (fs $ xs ⟹ vs) → (mapEvaluate fs xs ≡ vs)

  [⟶]-to-eval : (f $ xs ⟶ v) → (evaluate f xs ≡ v)
  [⟶]-to-eval zero = [≡]-intro
  [⟶]-to-eval succ = [≡]-intro
  [⟶]-to-eval {xs = _⊰_ {𝟎}   x xs} (proj {i = 𝟎})   = [≡]-intro
  [⟶]-to-eval {xs = _⊰_ {𝐒 n} x xs} (proj {i = 𝟎})   = [≡]-intro
  [⟶]-to-eval {xs = _⊰_ {𝐒 n} x xs} (proj {i = 𝐒 i}) = [≡]-intro
  [⟶]-to-eval (comp p q) with [⟶]-to-eval p | [⟹]-to-eval q
  ... | [≡]-intro | [≡]-intro = [≡]-intro
  [⟶]-to-eval (rec𝟎 p) with [⟶]-to-eval p
  ... | [≡]-intro = [≡]-intro
  [⟶]-to-eval (rec𝐒 p q) with [⟶]-to-eval p | [⟶]-to-eval q
  ... | [≡]-intro | [≡]-intro = [≡]-intro
  [⟹]-to-eval {fs = ∅}      {vs = ∅}      _           = [≡]-intro
  [⟹]-to-eval {fs = f ⊰ fs} {vs = v ⊰ vs} (step p ps) with [⟶]-to-eval p | [⟹]-to-eval {fs = fs} {vs = vs} ps
  ... | [≡]-intro | [≡]-intro = [≡]-intro

  eval-to-[⟹] : (mapEvaluate fs xs ≡ vs) → (fs $ xs ⟹ vs)

  {-# TERMINATING #-} -- TODO: See TODO above in eval
  eval-to-[⟶] : (evaluate f xs ≡ v) → (f $ xs ⟶ v)
  eval-to-[⟶] {f = Base}             {∅}           [≡]-intro = zero
  eval-to-[⟶] {f = Successor}        {singleton x} [≡]-intro = succ
  eval-to-[⟶] {f = Projection _}                   [≡]-intro = proj
  eval-to-[⟶] {f = Composition f gs} {xs}          p         = comp (eval-to-[⟶] p) (eval-to-[⟹] [≡]-intro)
  eval-to-[⟶] {f = Recursion f g}    {𝟎    ⊰ xs}   p         = rec𝟎(eval-to-[⟶] {f = f}{xs = xs} p)
  eval-to-[⟶] {f = Recursion f g}    {𝐒(n) ⊰ xs}   p         = rec𝐒 (eval-to-[⟶] [≡]-intro) (eval-to-[⟶] p)

  eval-to-[⟹] {fs = ∅}      [≡]-intro = base
  eval-to-[⟹] {fs = f ⊰ fs} [≡]-intro = step (eval-to-[⟶] [≡]-intro) (eval-to-[⟹] [≡]-intro)

  -- TODO: Is it possible to prove that _⟶_ terminates and normalizes by using [⟶]-to-eval (total and deterministic)?

  open import Function.Equals
  open import Logic
  open import Logic.Predicate

  -- When a function on lists of primitives are primitive recursive.
  PrimitiveRecursive : (List(Primitive)(n) → Primitive) → Stmt
  PrimitiveRecursive(f) = ∃(e ↦ evaluate e ⊜ f)

Const : Function(0) → ∀{n} → Function(n)
Const(c) = Composition(c) ∅

-- TODO: Would encoding pairs make this easier to implement (e.g. the Cantor Pairing Function?
--  This is used to construct a function `r` in which the following holds for its evaluation:
--  • r(0      ,..xs) = f(..xs)
--  • r(1      ,..xs) = g(..xs)
--  • r(𝐒(𝐒(n)),..xs) = h(n,r(𝐒(n),..xs),r(n,..xs),..xs)
-- Recursion₂ : ∀{n : ℕ} → Function(n) → Function(n) → Function(𝐒(𝐒(𝐒(n)))) → Function(𝐒(n))
-- Recursion₂{n} (f)(g)(h) = Composition(Projection(0)) (Helper ⊰ ∅) where
--   Recursion
--
--   Helper : Function(2)
--   Helper =
--

module Arithmetic where -- TODO: Prove that these are correct by `evaluate`
  Zero = Base

  Number : ℕ → Function(0)
  Number(𝟎)    = Zero
  Number(𝐒(n)) = Composition(Successor) (Number(n) ⊰ ∅)

  Swap₂ : Function(2) → Function(2)
  Swap₂(f) = Composition(f) (Projection(1) ⊰ Projection(0) ⊰ ∅)

  -- Addition (+) in ℕ.
  -- It describes the following function:
  --   evaluate(Addition)[𝟎   ,b] = 𝟎
  --   evaluate(Addition)[𝐒(a),b] = 𝐒(b)
  Addition : Function(2)
  Addition = Recursion(Projection(0)) (Composition Successor (Projection(1) ⊰ ∅))

  -- Multiplication (⋅) in ℕ.
  -- It describes the following function:
  --   evaluate(Multiplication)[𝟎   ,b] = 𝟎
  --   evaluate(Multiplication)[𝐒(a),b] = evaluate(Multiplication)[a,b] + b
  Multiplication : Function(2)
  Multiplication = Recursion (Const(Zero)) (Composition Addition (Projection(1) ⊰ Projection(2) ⊰ ∅))

  -- Exponentiation (^) in ℕ.
  -- It describes the following function:
  --   evaluate(Exponentiation)[a   ,0   ] = 1
  --   evaluate(Exponentiation)[a   ,𝐒(b)] = evaluate(Exponentiation)[a,b] ⋅ a
  Exponentiation : Function(2)
  Exponentiation = Swap₂(Recursion (Composition Successor (Const Zero ⊰ ∅)) (Composition Multiplication (Projection(1) ⊰ Projection(2) ⊰ ∅)))

  -- Factorial (!) in ℕ.
  -- It describes the following function:
  --   evaluate(Factorial)[𝟎   ] = 1
  --   evaluate(Factorial)[𝐒(a)] = 𝐒(a) ⋅ evaluate(Factorial)[a,b]
  Factorial : Function(1)
  Factorial = Recursion(Number(1)) (Composition Multiplication ((Composition Successor (Projection(0) ⊰ ∅)) ⊰ Projection(1) ⊰ ∅))

  -- Predecessor (𝐏) in ℕ.
  -- It describes the following function:
  --   evaluate(Predecessor)[𝟎   ] = 𝟎
  --   evaluate(Predecessor)[𝐒(a)] = a
  Predecessor : Function(1)
  Predecessor = Recursion(Zero) (Projection(0))

  -- Monus/Cut-off minus (−₀) in ℕ.
  -- It describes the following function:
  --   evaluate(Monus)[b,𝟎   ] = b
  --   evaluate(Monus)[b,𝐒(a)] = 𝐏(evaluate(Monus)[b,a])
  Monus : Function(2)
  Monus = Swap₂(Recursion(Projection(0)) (Composition Predecessor (Projection(1) ⊰ ∅)))

  -- Maximum (max) of ℕ² in ℕ.
  -- It describes the following function:
  --   evaluate(Max)[a,b] = a + (b −₀ a)
  Max : Function(2)
  Max = Composition(Addition) (Projection(0) ⊰ Swap₂(Monus) ⊰ ∅)

  -- Minimum (min) of ℕ² in ℕ.
  -- It describes the following function:
  --   evaluate(Min)[a,b] = (a + b) −₀ max(a,b)
  Min : Function(2)
  Min = Composition(Monus) (Addition ⊰ Max ⊰ ∅)

  -- It describes the following function:
  --   evaluate(Distance)[a,b] = max(x −₀ y , y −₀ x)
  Distance : Function(2)
  Distance = Composition(Addition) (Monus ⊰ Swap₂(Monus) ⊰ ∅)

  -- It describes the following function:
  --   evaluate(IsZero)[𝟎]    = 1
  --   evaluate(IsZero)[𝐒(_)] = 0
  IsZero : Function(1)
  IsZero = Recursion(Number(1)) (Const(Zero))

  -- It describes the following function:
  --   evaluate(IsZero)[𝟎]    = 0
  --   evaluate(IsZero)[𝐒(_)] = 1
  IsNonZero : Function(1)
  IsNonZero = Composition(IsZero) (IsZero ⊰ ∅)

  Eq : Function(2)
  Eq = Composition(IsZero) (Distance ⊰ ∅)

  -- It describes the following function:
  --   evaluate(Fibonacci)[𝟎]    = 0
  --   evaluate(Fibonacci)[𝐒(_)] = 1
  -- Fibonacci : Function(1)
  -- Fibonacci = Composition(Projection(0)) (Fib ⊰ ∅) where
  --   Fib : Function(2)
  --   Fib =

-- TODO: http://www.reluctantm.com/gcruttw/teaching/cpsc513.W2010/A3Solutions.pdf
-- TODO: http://ii.fmph.uniba.sk/cl/courses/1-AIN-625-lpp/0910zs/ln/doc/ch_p_gd.pdf

module Proofs where
  open import Functional
  open import Logic.Propositional
  open import Numeral.Natural.Oper
  open import Numeral.Natural.Oper.Comparisons
  open import Numeral.Natural.Oper.Proofs
  open import Relator.Equals
  open import Relator.Equals.Proofs
  open import Structure.Operator.Properties
  open import Structure.Relator.Properties
  open import Syntax.Transitivity

  addition-correctness : ∀{a b} → (evaluate Arithmetic.Addition (a ⊰ b ⊰ ∅) ≡ a + b)
  addition-correctness {𝟎}   {b} = [≡]-intro
  addition-correctness {𝐒 a} {b} = [≡]-with(𝐒) (addition-correctness {a}{b})

  multiplication-correctness : ∀{a b} → (evaluate Arithmetic.Multiplication (a ⊰ b ⊰ ∅) ≡ a ⋅ b)
  multiplication-correctness {𝟎}   {b} = [≡]-intro
  multiplication-correctness {𝐒 a} {b} =
    addition-correctness {evaluate Arithmetic.Multiplication (a ⊰ b ⊰ ∅)}{b}
    🝖 [≡]-with(_+ b) (multiplication-correctness {a}{b})
    🝖 symmetry(_≡_) ([⋅]-with-[𝐒]ₗ {a}{b})

  exponentiation-correctness : ∀{a b} → (evaluate Arithmetic.Exponentiation (a ⊰ b ⊰ ∅) ≡ a ^ b)
  exponentiation-correctness {a} {𝟎}   = [≡]-intro
  exponentiation-correctness {a} {𝐒 b} =
    multiplication-correctness {evaluate Arithmetic.Exponentiation (a ⊰ b ⊰ ∅)}{a}
    🝖 [≡]-with(_⋅ a) (exponentiation-correctness {a}{b})
    🝖 commutativity(_⋅_) {a ^ b}{a}

  factorial-correctness : ∀{a} → (evaluate Arithmetic.Factorial (a ⊰ ∅) ≡ a !)
  factorial-correctness {𝟎}   = [≡]-intro
  factorial-correctness {𝐒 a} =
    multiplication-correctness {𝐒 a}
    🝖 [≡]-with(𝐒(a) ⋅_) (factorial-correctness {a})

  predecessor-correctness : ∀{a} → (evaluate Arithmetic.Predecessor (a ⊰ ∅) ≡ 𝐏(a))
  predecessor-correctness {𝟎}   = [≡]-intro
  predecessor-correctness {𝐒 a} = [≡]-intro

  monus-correctness : ∀{a b} → (evaluate Arithmetic.Monus (a ⊰ b ⊰ ∅) ≡ a −₀ b)
  monus-correctness {a}   {𝟎}   = [≡]-intro
  monus-correctness {𝟎}   {𝐒 b} = predecessor-correctness{evaluate Arithmetic.Monus (𝟎 ⊰ b ⊰ ∅)} 🝖 [≡]-with(𝐏) (monus-correctness {𝟎}{b})
  monus-correctness {𝐒 a} {𝐒 b} =
    predecessor-correctness{evaluate Arithmetic.Monus (𝐒(a) ⊰ b ⊰ ∅)}
    🝖 [≡]-with(𝐏) (monus-correctness {𝐒 a}{b})
    🝖 symmetry(_≡_) ([−₀]-with-[𝐒]ᵣ {𝐒(a)}{b})

  isnonzero-correctness : ∀{a} → (evaluate Arithmetic.IsNonZero (a ⊰ ∅) ≡ ℕbool(a ≢? 𝟎))
  isnonzero-correctness {𝟎}   = [≡]-intro
  isnonzero-correctness {𝐒 a} = [≡]-intro

  iszero-correctness : ∀{a} → (evaluate Arithmetic.IsZero (a ⊰ ∅) ≡ ℕbool(a ≡? 𝟎))
  iszero-correctness {𝟎}   = [≡]-intro
  iszero-correctness {𝐒 a} = [≡]-intro

  -- TODO: Formalize "Function(1) is countably infinite". Maybe take some inspiration from https://proofwiki.org/wiki/Not_All_URM_Computable_Functions_are_Primitive_Recursive . Then prove that (ℕ → ℕ) is not countably infinite, and therefore not all computable functions are expressible primitive recursively (is this argument constructive?)

  open import Data.Tuple
  open import Function.Inverse
  open import Logic.Predicate
  open import Logic.Propositional
  open import Type.Size.Countable
  open import Structure.Function.Domain.Proofs
  open import Structure.Function using (congruence₁)
  open import Syntax.Function
  open import Syntax.Transitivity

  postulate Function-countablyInfinite : CountablyInfinite(Function(1))
  encodeFunction : Function(1) → ℕ
  encodeFunction = inv _ ⦃ bijective-to-invertible ⦃ bij = [∃]-proof Function-countablyInfinite ⦄ ⦄

  -- TODO: Use a lifted Numeral.Natural.Sequence.pairIndexing as a witness directly (instead of encodePair). Another alternative is (a ↦ b ↦ 2ᵃ⋅3ᵇ) if it is easier to construct f that way.
  postulate Function-value-pair-countablyInfinite : CountablyInfinite(Function(1) ⨯ ℕ)
  encodePair : (Function(1) ⨯ ℕ) → ℕ
  encodePair = inv _ ⦃ bijective-to-invertible ⦃ bij = [∃]-proof Function-value-pair-countablyInfinite ⦄ ⦄

  -- TODO: Is it possible to use Logic.DiagonalMethod for this proof?
  no-self-interpreter : ¬ ∃(interpret ↦ ∀{f}{n} → evaluate interpret (singleton (encodePair(f , n))) ≡ evaluate f (singleton n))
  no-self-interpreter ([∃]-intro interpret ⦃ p ⦄) = 𝐒-not-self(symmetry(_≡_) x) where
    postulate f : Function(1)
    postulate f-correctness : ∀{g} → (evaluate f (singleton(encodeFunction g)) ≡ encodePair(g , encodeFunction g))

    g : Function(1)
    g = Composition Successor (singleton (Composition interpret (singleton f)))

    x : evaluate g (singleton (encodeFunction g)) ≡ 𝐒(evaluate g (singleton (encodeFunction g)))
    x =
      evaluate g (singleton (encodeFunction g))                                   🝖[ _≡_ ]-[]
      𝐒(evaluate interpret (singleton(evaluate f (singleton(encodeFunction g))))) 🝖[ _≡_ ]-[ congruence₁(𝐒) (congruence₁(evaluate interpret) (congruence₁(singleton) f-correctness)) ]
      𝐒(evaluate interpret (singleton(encodePair(g , encodeFunction g))))         🝖[ _≡_ ]-[ congruence₁(𝐒) p ]
      𝐒(evaluate g (singleton(encodeFunction g)))                                 🝖-end


module Numeral.Natural.Coprime where

open import Logic
import      Lvl
open import Numeral.Natural
open import Numeral.Natural.Relation.Divisibility
open import Relator.Equals

private variable n x y : ℕ

-- Two numbers are coprime when their only divisor is 1.
record Coprime (x : ℕ) (y : ℕ) : Stmt{Lvl.𝟎} where
  constructor intro
  field proof : (n ∣ x) → (n ∣ y) → (n ≡ 1)