module x where

{-
------------------------------------------------------------------------------
Abstract

Relational program derivation technique :
- stepwise refining a relational spec to a program by algebraic rules.
- program obtained is correct by construction

Dependent type theory rich enough to express correctness properties verified by type checker.

Library, Algebra of Programming in Agda (AoPA)
- http://www.iis.sinica.edu.tw/~scm/2008/aopa/
- encodes relational derivations
- A program is coupled with an algebraic derivation whose correctness is guaranteed by type system

------------------------------------------------------------------------------
1 Introduction

relational program derivation
- specs are input-output relations that are stepwise refined by an algebra of programs.

paper show how program derivation can be encoded in a type and its proof term.

- case study using Curry-Howard isomorphism
- modelled a many concepts that occur in relational program derivation
  including relational folds, relational division, and converse-of-a-function.
  - e.g., Minimum, is defined using division and intersection
  - e.g., greedy theorem proved using the universal property of minimum.
  - the theorem can be used to deal with a number of optimisation problems specified as folds.
• to ensure termination with unfolds and hylomorphisms, enable programmer to
  model an unfold as the relational converse of a fold, but demand a proof of accessibility
  before it is refined to a functional unfold.

------------------------------------------------------------------------------
2 Overview of Relational Program Derivation

Merit of functional programming : programs can be manipulated by equational reasoning.

Program derivation in Bird-Meertens style 1989b) typically start with a specification,
as a function, that is obviously correct but not efficient.

Algebraic identities are then applied, in successive steps,
to show that the specification equals another functional program that is more efficient.

Typical example : Maximum Segment Sum (Gries, 1989; Bird, 1989a), specification :
    max · map sum · segs
where
- segs produces all consecutive segments of the input list of numbers
- map sum computes their summation
- maximum is picked by max
Specification can be shown, after transformation, to be equal a version using foldr (linear).

In 90’s there was a trend in the program derivation community to move from functions to relations.
- spec given in terms of an input/output relation
- relation is refined to smaller, more deterministic relations in each step,
- until obtaining a function

Relational derivation advantages:
- spec often more concise than corresponding functional specification
- optimisation problems can be specified using relations generating all possible solutions
- easier to talk about program inversion

The catch: *must reason in terms of inequalities rather than equalities*

denoted by R : B ← A
- relation R from A to B
- subset of set of pairs B × A
- A function f is seen as a special case where (b, a) ∈ f and (b' , a) ∈ f implies b = b'

converse R˘ : A ← B of R : B ← A
- defined by (a, b) ∈ R ˘ if (b, a) ∈ R

composition of two relations R : C ← B and S : B ← A
- defined by: (c, a) ∈ R ◦ S if ∃b : (c, b) ∈ R ∧ (b, a) ∈ S

power transpose ΛR of R : B ← A
- is a function from A to P B (subsets of B)
- ΛR a = { b | (b, a) ∈ R }.

relation ∈ : A ← P A
- maps a set to one of its arbitrary members
- converse: ∋ : P A ← A

product of two relations, R × S
- defined by ((c, d), (a, b)) ∈ R × S if (c, a) ∈ R and (d, b) ∈ S

--      step fun      base  input    output
foldr : (A → B → B) → B   → List A → B

generalisation to a relation, denote foldR

              input    step relation  base cases
foldR R : B ← List A ← (B ← (A×B))    (set s : PB)

-- relation mapping a list to one of its arbitrary subsequences
subseq = foldR (cons ∪ outr) {[ ]}
where
  cons (x, xs) = x :: xs -- cons keeps the current element
  outr (x, xs) = xs      -- outr drops the current element

Relational fold defined in terms of functional fold:

   foldR R s = ∈ ◦ foldr Λ(R ◦ (id " ∈)) s

of type List A → P B that collects all the results in a set.

step function Λ(R ◦ (id " ∈))  : has type (A × P B) → P B
(id " ∈) : (A × B) ← (A × P B) : pairs current element with one of the results from previous step
                                 before passing the pair to R

foldR R s satisfies the universal property:
foldR R s = S ⇔ R ◦ (id " S) = S ◦ cons ∧ s = ΛS [ ]

-- induction rule
-- states that foldR R s is the unique fixed-point of the monotonic function
λ X → (R ◦ (id " X) ◦ cons ˘) ∪ {(b, [ ]) | b ∈ s}

-- computation rule
-- foldR R s is also the least prefix-point, therefore
foldR R s ⊆ S ⇐ R ◦ (id " S) ⊆ S ◦ cons ∧ s ⊆ ΛS [ ],
R ◦ (id " foldR R s) ⊆ foldR R s ◦ cons ∧ s ⊆ Λ(foldR R s) [ ].

If an optimisation problem can be specified by generating all possible solutions using
foldR or converse of foldR before picking the best one, Bird and de Moor (1997) gave a
number of conditions under which the specification can be refined to a greedy algorithm, a
dynamic programming algorithm, or something in-between.

------------------------------------------------------------------------------
3 A Crash Course in Agda
-}

-- Fig. 2. Some examples of datatype definitions.

data List (A : Set) : Set where
  []   : List A
  _∷_  : A → List A → List A

data ℕ : Set where
  zero : ℕ
  suc  : ℕ → ℕ

data _≤_ : ℕ → ℕ → Set where
  ≤-refl : {n   : ℕ} → n ≤ n
  ≤-step : {m n : ℕ} → m ≤ n → m ≤ suc n

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

-- Fig. 3. An encoding of first-order intuitionistic logic in Agda.

-- Truth : has one unique term — a record with no fields
record ⊤ : Set where

-- Falsity : type with no constructors therefore no inhabitants
data ⊥ : Set where

-- Disjunction : proof deduced either from a proof of P or a proof of Q
data _⨄_ (A B : Set) : Set where
  inj1 : A → A ⨄ B
  inj2 : B → A ⨄ B

-- Dependent Pair : type of 2nd may depend on the first component
data Σ (A : Set)(B : A → Set) : Set where
  _,_ : (x : A) → (y : B x) → Σ A B

proj₁ : ∀ {A B} → Σ A B → A
proj₁ (x , y) = x

proj₂ : ∀ {A B} → (p : Σ A B) → B (proj₁ p)
proj₂ (x , y) = y

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

-- Existential Quantification
-- to prove the proposition ∃ P, where P is a predicate on terms of type A
-- provide, in a pair, a witness w : A and a proof of P w.
∃ : {A : Set} (P : A → Set) → Set
∃ = Σ _

-- Universal Quantification
-- of predicate P on type A is encoded as a dependent function type
-- whose elements, given any x : A, must produce a proof of P x.
-- Agda provides a short hand ∀ x → P x in place of (x : A) → P x when A can be inferred.

-- Implication
-- P → Q is represented as a function taking a proof of P to a proof of Q
-- no new notation for it

-- Predicates
-- on type A are represented by A → Set.
-- e.g., (λ n → zero < n) : N → Set
-- is a predicate stating that a natural number is positive.

{-
3.2 Identity Type

term of type x ≡ y is proof x and y are equal
-}

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

-- REFLEXIVE : by definition

-- SYMMETRIC
≡-sym : {A : Set}{x y : A} → x ≡ y → y ≡ x
≡-sym {A}{x}{.x} ≡-refl = ≡-refl

-- TRANSITIVE
≡-trans : {A : Set}{x y z : A} → x ≡ y → y ≡ z → x ≡ z
≡-trans {A}{x}{.x}{z} ≡-refl x≡z = x≡z -- could replace x≡z with ≡-refl

-- SUBSTITUTIVE — if x ≡ y, they are interchangeable in all contexts
≡-subst : {A : Set}(P : A → Set){x y : A} → x ≡ y → P x → P y
≡-subst P ≡-refl Px = Px

≡-cong : {A B : Set}(f : A → B){x y : A} → x ≡ y → f x ≡ f y
≡-cong f ≡-refl = ≡-refl
{-
≡ NOT EXTENSIONAL
Qquality of terms is checked by expanding them to normal forms.
Problem comparing higher-order values: e.g., sum·map sum     and     sum · concat
while defining the same function summing up a list of lists of numbers, are not “equal” under ≡ .

Can define extensional equality for (non-dependent) functions on first-order values:
-}
_≐_ : {A B : Set} → (A → B) → (A → B) → Set
f ≐ g = ∀ x → f x ≡ g x
{-
≐ NOT SUBSTITUTIVE : congruence of ≐ has to be proved for each context.

Refinement in preorder reasoning usually involves replacing terms in provably monotonic contexts.
This is a significant overhead; but given that this overhead
is incurred anyway, not having extensional equality is no extra trouble.

3.3 Preorder Reasoning

To prove e1 ≡ e2 is to construct a term having that type.

For any binary relation ∼ that is reflexive and transitive
- for which one can construct terms ∼-refl and ∼-trans having the types described in above
can derive a set of combinators, shown in Fig. 4,
which enables one to construct a term of type e₁ ∼ en  in algebraic style.

-- Fig. 4. Combinators for preorder reasoning.
infixr 2 _∼⟨_⟩_
infix  2 _∼∎

_∼⟨_⟩_ : {A : Set}(x : A){y z : A} → x ∼ y → y ∼ z → x ∼ z
x ∼⟨ x∼y ⟩ y∼z = ∼-trans x∼y y∼z

_∼∎ : {A : Set}(x : A) → x ∼ x
x ∼∎ = ∼-refl

implication as a relation:
-}
_⇒_ : Set → Set → Set
P ⇒ Q = P → Q

_⇐_ : Set → Set → Set
P ⇐ Q = Q ⇒ P
{-
Reflexivity and transitivity of ⇐ , for example, can be simply given by ⇐-refl = id and
⇐-trans = · , where · is function composition. Therefore, they induce a pair of operators
_⇐⟨_⟩_ and ⇐∎ for logical reasoning.

Hierarchy of universes
- Set, the type of small types, is in sort Set1

When instantiating ∼ in Fig. 4 to ⇐ : Set → Set → Set
- notice that the type A : Set itself cannot be instantiated to Set, which is in Set1

We resolve this by using different module generators for different universes.
More on this in Sect. 4.1.

3.4 Functional Derivation

Since _≐_ is reflexive and transitive (not shown), it induces its preorder reasoning operators.

Fig. 5 shows a proof of the universal property of foldr.

The steps using ≡-refl are equivalences Agda proves by expanding definitions.
The inductive hypothesis is established by a recursive call to foldr-universal.
-}
infix  3 _≡∎
infixr 2 _≡⟨⟩_ _≡⟨_⟩_
infix  1 begin_

begin_ : {A : Set} {x y : A} → x ≡ y → x ≡ y
begin_ x≡y = x≡y

_≡⟨⟩_ : {A : Set} (x {y} : A) → x ≡ y → x ≡ y
_ ≡⟨⟩ x≡y = x≡y

_≡⟨_⟩_ : {A : Set} (x {y z} : A) → x ≡ y → y ≡ z → x ≡ z
_ ≡⟨ x≡y ⟩ y≡z = ≡-trans x≡y y≡z

_≡∎ : {A : Set} (x : A) → x ≡ x
_≡∎ _ = ≡-refl
{-
Fig. 5. Proving the universal property for foldr
-}
foldr              : {A B : Set}
                   → (A → B → B) → B → List A
                   → B
foldr f e      []  = e
foldr f e (x ∷ xs) = f x (foldr f e xs)

{- https://www.cs.nott.ac.uk/~pszgmh/fold.pdf
For finite lists, the universal property of fold can be stated as the following equivalence
between two definitions for a function g that processes lists:
g      []  = v
                         ⇔ g = fold f v
g (x ∷ xs) = f x (g xs)

right-to-left : substituting g = fold f v into the two equations for g gives recursive fold def
left-to-right : two equations for g are the assumptions required to show that g = fold f v
using a simple proof by induction on finite lists (Bird, 1998)

universal property states that for finite lists the function fold f v is not just a
solution to its defining equations, but the unique solution.

Utility of universal property : makes explicit the two assumptions
required for a certain pattern of inductive proof.

For specific cases, by verifying the two assumptions (typically done without need for induction)
can then appeal to the universal property to complete the inductive proof that g = fold f v.

universal PROPERTY of fold : encapsulates a pattern of inductive proof concerning lists
just as the fold OPERATOR  : encapsulates a pattern of recursion for processing lists
-}
foldr-universal : ∀ {A B} (h : List A → B) f e
                → (h [] ≡ e)
                → (∀ x xs → h (x ∷ xs) ≡ f x (h xs))
                → h ≐ foldr f e
foldr-universal h f e base step      []  = base
foldr-universal h f e base step (x ∷ xs) =
  begin
    h (x ∷ xs)
  ≡⟨ step x xs ⟩
    f x (h xs)
  ≡⟨ ≡-cong (f x) (foldr-universal h f e base step xs) ⟩
    f x (foldr f e xs)
  ≡⟨ ≡-refl ⟩
    foldr f e (x ∷ xs)
  ≡∎
{-
-- Can use the universal property to prove the foldr-fusion theorem:

_·_ : {A : Set} {B : A → Set} {C : (x : A) → B x → Set}
    → (f : {x : A} (y : B x) → C x y)
    → (g : (x : A) → B x)
    → (x : A) → C x (g x)
(f · g) x = f (g x)

-- TODO compile problems
foldr-fusion : ∀ {A B C} (h : B → C) {f : A → B → B} {g : A → C → C}
             → {e : B}
             → (∀ x y → h (f x y) ≡ g x (h y))
             → (h · foldr f e) ≐ (foldr g (h e))
foldr-fusion h {f} {g} e fuse =
  foldr-universal (h · foldr f e) g (h e) ≡-refl (λ x xs → fuse x (foldr f e xs))
-}


module Structure.Category.Categories where

open import Data
open import Data.Proofs
open import Functional
open import Logic
import      Lvl
import      Relator.Equals as Eq
open import Structure.Setoid
open import Structure.Category
open import Structure.Categorical.Proofs
open import Structure.Categorical.Properties
open import Structure.Operator
open import Type

private variable ℓ ℓ₁ ℓ₂ ℓₑ : Lvl.Level
private variable Obj A B : Type{ℓ}
private variable _▫_ : Obj → Obj → Type{ℓ}
private variable f : A → B

-- The empty category is a category containing nothing.
-- The objects are empty.
-- The morphisms are empty.
emptyCategory : Category{ℓ₁}{ℓ₂}{ℓₑ}(empty-morphism) ⦃ \{} ⦄
Category._∘_            emptyCategory = empty-comp
Category.id             emptyCategory = empty-id
Category.binaryOperator emptyCategory {}
Category.associativity  emptyCategory = empty-associativity ⦃ \{} ⦄
Category.identity       emptyCategory = empty-identity ⦃ \{} ⦄

-- The single category is a category containing a single object and a single morphism.
-- The objects consists of a single thing.
-- The morphisms consists of a single connection connecting the single thing to itself.
singleCategory : ∀{ℓₒ ℓᵢ ℓₚₐ₁ ℓₚₐ₂ ℓₚᵢ₁ ℓₚᵢ₂ ℓₚᵢ₃ : Lvl.Level} → Category{ℓ₁}{ℓ₂}(single-morphism)
Category._∘_ (singleCategory{ℓ₁}{ℓ₂}{ℓₒ}{ℓᵢ}{ℓₚₐ₁}{ℓₚₐ₂}{ℓₚᵢ₁}{ℓₚᵢ₂}{ℓₚᵢ₃}) = single-comp{ℓ₂}{ℓₒ}
Category.id  (singleCategory{ℓ₁}{ℓ₂}{ℓₒ}{ℓᵢ}{ℓₚₐ₁}{ℓₚₐ₂}{ℓₚᵢ₁}{ℓₚᵢ₂}{ℓₚᵢ₃}) = single-id{ℓ₂}{ℓᵢ}
BinaryOperator.congruence (Category.binaryOperator singleCategory) Eq.[≡]-intro Eq.[≡]-intro = Eq.[≡]-intro
Category.associativity (singleCategory{ℓ₁}{ℓ₂}{ℓₒ}{ℓᵢ}{ℓₚₐ₁}{ℓₚₐ₂}{ℓₚᵢ₁}{ℓₚᵢ₂}{ℓₚᵢ₃}) = single-associativity{ℓ₂}{ℓ₂}{ℓₚₐ₁}{ℓ₁}{ℓₚₐ₂}
Category.identity      (singleCategory{ℓ₁}{ℓ₂}{ℓₒ}{ℓᵢ}{ℓₚₐ₁}{ℓₚₐ₂}{ℓₚᵢ₁}{ℓₚᵢ₂}{ℓₚᵢ₃}) = single-identity{ℓ₂}{ℓ₂}{ℓₚᵢ₁}{ℓ₁}{ℓₚᵢ₂}{ℓₚᵢ₃}

on₂-category : ⦃ morphism-equiv : ∀{x y} → Equiv{ℓₑ}{ℓ}(x ▫ y) ⦄ → Category{Obj = B}(_▫_) ⦃ morphism-equiv ⦄ → (f : A → B) → Category((_▫_) on₂ f)
Category._∘_ (on₂-category C _) = Category._∘_ C
Category.id  (on₂-category C _) = Category.id  C
BinaryOperator.congruence (Category.binaryOperator (on₂-category C _)) = BinaryOperator.congruence(Category.binaryOperator C)
Category.associativity (on₂-category C f) = on₂-associativity f (Category.associativity C)
Category.identity      (on₂-category C f) = on₂-identity f (Category.identity C)

{-
TODO:
• https://en.wikipedia.org/wiki/Isomorphism_of_categories
• https://en.wikipedia.org/wiki/Equivalence_of_categories
?
-}


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

syntax QIO

type
  T : 0-ary
  P : 0-ary

term
  new      : P.T  ->  T
  measure  : P  T  T  ->  T
  applyX   : P  P.T  ->  T
  applyI2  : P  P.T  ->  T
  applyDuv : P  P  (P,P).T  ->  T
  applyDu  : P  P.T  ->  T
  applyDv  : P  P.T  ->  T

theory
  (A) a:P   t u:T         |> applyX (a, b.measure(b, t, u)) = measure(a, u, t)
  (B) a:P   b:P  t u:P.T  |> measure(a, applyDu(b, b.t[b]), applyDv(b, b.u[b])) = applyDuv(a, b, a b.measure(a, t[b], u[b]))
  (D) t u:T               |> new(a.measure(a, t, u)) = t
  (E) b:P  t:(P, P).T     |> new(a.applyDuv(a, b, a b. t[a,b])) = applyDu(b, b.new(a.t[a,b]))
-}

module QIO.Equality where

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

open import QIO.Signature
open import QIO.Syntax

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

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

infix 1 _▹_⊢_≋ₐ_

-- Axioms of equality
data _▹_⊢_≋ₐ_ : ∀ 𝔐 Γ {α} → (𝔐 ▷ QIO) α Γ → (𝔐 ▷ QIO) α Γ → Set where
  A : ⁅ P ⁆ ⁅ T ⁆ ⁅ T ⁆̣               ▹ ∅ ⊢                             applyX 𝔞 (measure x₀ 𝔟 𝔠) ≋ₐ measure 𝔞 𝔠 𝔟
  B : ⁅ P ⁆ ⁅ P ⁆ ⁅ P ⊩ T ⁆ ⁅ P ⊩ T ⁆̣ ▹ ∅ ⊢ measure 𝔞 (applyDu 𝔟 (𝔠⟨ x₀ ⟩)) (applyDv 𝔟 (𝔡⟨ x₀ ⟩)) ≋ₐ applyDuv 𝔞 𝔟 (measure x₀ (𝔠⟨ x₁ ⟩) (𝔡⟨ x₁ ⟩))
  D : ⁅ T ⁆ ⁅ T ⁆̣                     ▹ ∅ ⊢                                  new (measure x₀ 𝔞 𝔟) ≋ₐ 𝔞
  E : ⁅ P ⁆ ⁅ P · P ⊩ T ⁆̣             ▹ ∅ ⊢                    new (applyDuv x₀ 𝔞 (𝔟⟨ x₀ ◂ x₁ ⟩)) ≋ₐ applyDu 𝔞 (new (𝔟⟨ x₀ ◂ x₁ ⟩))

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


{-# OPTIONS --cubical #-}
module Multidimensional.Data.DirNum.Base where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Unit
open import Cubical.Data.Prod
open import Cubical.Data.Nat

open import Multidimensional.Data.Dir

-- Dependent "directional numerals":
-- for natural n, obtain 2ⁿ "numerals".
-- This is basically a little-endian binary notation.
-- NOTE: Would an implementation of DirNum with dependent vectors be preferable
--       over using products?
DirNum : ℕ → Type₀
DirNum zero = Unit
DirNum (suc n) = Dir × (DirNum n)

DirNum→ℕ : ∀ {n} → DirNum n → ℕ
DirNum→ℕ {zero} tt = zero
DirNum→ℕ {suc n} (↓ , d) = doublesℕ (suc zero) (DirNum→ℕ d)
DirNum→ℕ {suc n} (↑ , d) = suc (doublesℕ (suc zero) (DirNum→ℕ d))

-- give the next numeral, cycling back to 0
-- in case of 2ⁿ - 1
next : ∀ {n} → DirNum n → DirNum n
next {zero} tt = tt
next {suc n} (↓ , ds) = (↑ , ds)
next {suc n} (↑ , ds) = (↓ , next ds)

prev : ∀ {n} → DirNum n → DirNum n
prev {zero} tt = tt
prev {suc n} (↓ , ds) = (↓ , prev ds)
prev {suc n} (↑ , ds) = (↓ , ds)

zero-n : (n : ℕ) → DirNum n
zero-n zero = tt
zero-n (suc n) = (↓ , zero-n n)

one-n : (n : ℕ) → DirNum n
one-n zero = tt
one-n (suc n) = (↑ , zero-n n)

-- numeral for 2ⁿ - 1
max-n : (n : ℕ) → DirNum n
max-n zero = tt
max-n (suc n) = (↑ , max-n n)

-- -- TODO: rename
-- embed-next : (r : ℕ) → DirNum r → DirNum (suc r)
-- embed-next zero tt = (↓ , tt)
-- embed-next (suc r) (d , ds) with zero-n? ds
-- ... | no _ = (d , embed-next r ds)
-- ... | yes _ = (d , zero-n (suc r))

sucDoubleDirNum+ : (r : ℕ) → DirNum r → DirNum (suc r)
sucDoubleDirNum+ r x = (↑ , x)

-- bad name, since this is doubling "to" suc r
doubleDirNum+ : (r : ℕ) → DirNum r → DirNum (suc r)
doubleDirNum+ r x = (↓ , x)

dropLeast : {r : ℕ} → DirNum (suc r) → DirNum r
dropLeast {zero} d = tt
dropLeast {suc r} (x , x₁) = x₁

dropMost : {r : ℕ} → DirNum (suc r) → DirNum r
dropMost {zero} d = tt
dropMost {suc zero} (x , (x₁ , x₂)) = (x₁ , x₂)
dropMost {suc (suc r)} (x , x₁) = (x , dropMost x₁)

-- need to prove property about doubleable
--doubleDirNum : (r : ℕ) (d : DirNum r) → doubleable-n? {r} d ≡ true → DirNum r
-- bad? is not correct when not "doubleable"
-- possibly should view as operations in residue classes?
doubleDirNum : (r : ℕ) (d : DirNum r) → DirNum r
doubleDirNum zero d  = tt
doubleDirNum (suc r) d  = doubleDirNum+ r (dropMost {r} d)
-- doubleDirNum zero d doubleable = ⊥-elim (false≢true doubleable)
-- doubleDirNum (suc r) d doubleable = doubleDirNum+ r (dropMost {r} d)


------------------------------------------------------------------------------
-- FOTC terms properties
------------------------------------------------------------------------------

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

module FOTC.Base.PropertiesI where

open import Common.FOL.Relation.Binary.EqReasoning

open import FOTC.Base

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

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

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

·-cong : ∀ {a b c d} → a ≡ b → c ≡ d → a · c ≡ b · d
·-cong refl refl = refl

succCong : ∀ {m n} → m ≡ n → succ₁ m ≡ succ₁ n
succCong refl = refl

predCong : ∀ {m n} → m ≡ n → pred₁ m ≡ pred₁ n
predCong refl = refl

ifCong₁ : ∀ {b b' t t'} → b ≡ b' →
          (if b then t else t') ≡ (if b' then t else t')
ifCong₁ refl = refl

ifCong₂ : ∀ {b t₁ t₂ t} → t₁ ≡ t₂ →
          (if b then t₁ else t) ≡ (if b then t₂ else t)
ifCong₂ refl = refl

ifCong₃ : ∀ {b t t₁ t₂} → t₁ ≡ t₂ →
          (if b then t else t₁) ≡ (if b then t else t₂)
ifCong₃ refl = refl

------------------------------------------------------------------------------
-- Injective properties

succInjective : ∀ {m n} → succ₁ m ≡ succ₁ n → m ≡ n
succInjective {m} {n} h =
  m                ≡⟨ sym (pred-S m) ⟩
  pred₁ (succ₁ m)  ≡⟨ predCong h ⟩
  pred₁ (succ₁ n)  ≡⟨ pred-S n ⟩
  n                ∎

------------------------------------------------------------------------------
-- Discrimination rules

S≢0 : ∀ {n} → succ₁ n ≢ zero
S≢0 S≡0 = 0≢S (sym S≡0)


module Structure.Function.Ordering where

import      Lvl
open import Logic
open import Logic.Propositional
open import Logic.Predicate
open import Type

module _ {ℓₒ₁ ℓₒ₂ ℓₗ₁ ℓₗ₂} {T₁ : Type{ℓₒ₁}} {T₂ : Type{ℓₒ₂}} (_≤₁_ : T₁ → T₁ → Type{ℓₗ₁}) (_≤₂_ : T₂ → T₂ → Type{ℓₗ₂}) where
  record Increasing (f : T₁ → T₂) : Stmt{ℓₒ₁ Lvl.⊔ ℓₗ₁ Lvl.⊔ ℓₗ₂} where
    constructor intro
    field proof : ∀{a b : T₁} → (a ≤₁ b) → (f(a) ≤₂ f(b))

  record Decreasing (f : T₁ → T₂) : Stmt{ℓₒ₁ Lvl.⊔ ℓₗ₁ Lvl.⊔ ℓₗ₂} where
    constructor intro
    field proof : ∀{a b : T₁} → (a ≤₁ b) → (f(b) ≤₂ f(a))

  Monotone : (T₁ → T₂) → Stmt
  Monotone(f) = (Increasing(f) ∨ Decreasing(f))

  record UpperBoundPointOf (f : T₁ → T₂) (p : T₁) : Stmt{ℓₒ₁ Lvl.⊔ ℓₗ₂} where
    constructor intro
    field proof : ∀{x} → (f(x) ≤₂ f(p))

  UpperBounded : (T₁ → T₂) → Stmt
  UpperBounded(f) = ∃(UpperBoundPointOf(f))

  record LowerBoundPointOf (f : T₁ → T₂) (p : T₁) : Stmt{ℓₒ₁ Lvl.⊔ ℓₗ₂} where
    constructor intro
    field proof : ∀{x} → (f(p) ≤₂ f(x))

  LowerBounded : (T₁ → T₂) → Stmt
  LowerBounded(f) = ∃(LowerBoundPointOf(f))


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

open import HoTT hiding (_::_)

module algebra.Word {i} (A : Type i) where

  data Word : Type i where
    nil : Word
    _::_ : A → Word → Word
    _inv::_ : A → Word → Word
  infixr 60 _::_ _inv::_

  -- The following six functions prove things like if [x ∷ v ≡ y ∷ w],
  -- then [x ≡ y].
  -- This is not as easy as it sounds, you cannot directly induct on the equality
  -- (because [x ∷ v] is not a general element of type word), so you have to
  -- extract the head, but it’s not always possible…

  Word= : (v w : Word) → Type i
  Word= nil         nil         = Lift ⊤
  Word= nil         (y    :: w) = Lift ⊥
  Word= nil         (y inv:: w) = Lift ⊥
  Word= (x    :: v) nil         = Lift ⊥
  Word= (x    :: v) (y    :: w) = (x == y) × (v == w)
  Word= (x    :: v) (y inv:: w) = Lift ⊥
  Word= (x inv:: v) nil         = Lift ⊥
  Word= (x inv:: v) (y    :: w) = Lift ⊥
  Word= (x inv:: v) (y inv:: w) = (x == y) × (v == w)

  Word=-out : {v w : Word} (p : v == w) → Word= v w
  Word=-out {v = nil}       idp = lift unit
  Word=-out {v = x    :: v} idp = (idp , idp)
  Word=-out {v = x inv:: v} idp = (idp , idp)

  Word=-in : {v w : Word} → Word= v w → v == w
  Word=-in {nil}       {nil}       _         = idp
  Word=-in {nil}       {y    :: w} (lift ())
  Word=-in {nil}       {y inv:: w} (lift ())
  Word=-in {x    :: v} {nil}       (lift ())
  Word=-in {x    :: v} {y    :: w} (p , q)   = ap2 _::_ p q
  Word=-in {x    :: v} {y inv:: w} (lift ())
  Word=-in {x inv:: v} {nil}       (lift ())
  Word=-in {x inv:: v} {y    :: w} (lift ())
  Word=-in {x inv:: v} {y inv:: w} (p , q)   = ap2 _inv::_ p q

  Word-fst= : {x y : A} {v w : Word} (p : x :: v == y :: w) → x == y
  Word-fst= p = fst (Word=-out p)

  Word-snd= : {x y : A} {v w : Word} (p : x :: v == y :: w) → v == w
  Word-snd= p = snd (Word=-out p)

  Word-fst=' : {x y : A} {v w : Word} (p : x inv:: v == y inv:: w) → x == y
  Word-fst=' p = fst (Word=-out p)

  Word-snd=' : {x y : A} {v w : Word} (p : x inv:: v == y inv:: w) → v == w
  Word-snd=' p = snd (Word=-out p)


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

-- The 'Trivial' instance, with a single arrow between objects

module Categories.Theory.Lawvere.Instance.Triv where

open import Data.Nat using (_*_)
open import Data.Unit.Polymorphic using (⊤; tt)
open import Relation.Binary.PropositionalEquality
  using (_≡_; refl; isEquivalence)

open import Categories.Theory.Lawvere using (LawvereTheory)

Triv : ∀ {ℓ} → LawvereTheory ℓ ℓ
Triv = record
  { L = record
          { _⇒_ = λ _ _ → ⊤
          ; _≈_ = _≡_
          ; assoc = refl
          ; sym-assoc = refl
          ; identityˡ = refl
          ; identityʳ = refl
          ; identity² = refl
          ; equiv = isEquivalence
          ; ∘-resp-≈ = λ _ _ → refl
          }
  ; T = record
    { terminal = record { ⊤ = 0 ; ⊤-is-terminal = record { ! = tt ; !-unique = λ _ → refl } }
    ; products = record
      { product = λ {m} {n} → record
        { A×B = m * n
        ; project₁ = refl
        ; project₂ = refl
        ; unique = λ _ _ → refl
        }
      }
    }
  ; I = record
    { F₁ = λ _ → tt
    ; identity = refl
    ; homomorphism = refl
    ; F-resp-≈ = λ _ → refl
    }
  ; CartF = record
    { F-resp-⊤ = record { ! = tt ; !-unique = λ _ → refl }
    ; F-resp-× = record { ⟨_,_⟩ = λ _ _ → tt ; project₁ = refl ; project₂ = refl ; unique = λ _ _ → refl }
    }
  }


{-# OPTIONS --universe-polymorphism #-}
module Categories.Graphs.Underlying where

open import Categories.Support.PropositionalEquality

open import Categories.Category
  hiding (module Heterogeneous)
open import Categories.Categories
open import Categories.Graphs
open import Categories.Functor
  using (Functor; module Functor; ≡⇒≣)
  renaming (id to idF; _≡_ to _≡F_)
open import Data.Product
open import Graphs.Graph
open import Graphs.GraphMorphism

Underlying₀ : ∀ {o ℓ e} → Category o ℓ e → Graph o ℓ e
Underlying₀ C = record
  { Obj   = Obj
  ; _↝_   = _⇒_
  ; _≈_   = _≡_
  ; equiv = equiv
  } where open Category C

Underlying₁ : ∀ {o₁ ℓ₁ e₁ o₂ ℓ₂ e₂}
  {X : Category o₁ ℓ₁ e₁}
  {Y : Category o₂ ℓ₂ e₂}
  → Functor X Y
  → GraphMorphism (Underlying₀ X) (Underlying₀ Y)
Underlying₁ G = record
  { F₀        = G₀
  ; F₁        = G₁
  ; F-resp-≈  = G-resp-≡
  }
  where
    open Functor G
      renaming (F₀ to G₀; F₁ to G₁; F-resp-≡ to G-resp-≡)

Underlying : ∀ {o ℓ e} → Functor (Categories o ℓ e) (Graphs o ℓ e)
Underlying {o}{ℓ}{e} = record
  { F₀            = Underlying₀
  ; F₁            = Underlying₁
  ; identity      = (λ x → ≣-refl) , (λ f → Heterogeneous.refl _)
  ; homomorphism  = (λ x → ≣-refl) , (λ f → Heterogeneous.refl _)
  ; F-resp-≡      = λ {A B}{F G : Functor A B} → F-resp-≡ {A}{B}{F}{G}
  }
  where
    module Graphs     = Category (Graphs     o ℓ e)
    module Categories = Category (Categories o ℓ e)

    .F-resp-≡ : ∀ {A B : Categories.Obj} {G H : Functor A B}
      → G ≡F H
      → Underlying₁ G ≈ Underlying₁ H
    F-resp-≡ {A}{B}{G}{H} G≡H
      = (≡⇒≣ G H G≡H) , (λ f → convert-~ (G≡H f))
      where
        open Heterogeneous (Underlying₀ B)
          renaming (_~_ to _~₂_)
        open Categories.Category.Heterogeneous B
          renaming (_∼_ to _~₁_)

        convert-~ : ∀ {a b c d}{x : B [ a , b ]}{y : B [ c , d ]} → x ~₁ y → x ~₂ y
        convert-~ (≡⇒∼ foo) = ≈⇒~ foo


------------------------------------------------------------------------
-- An implementation of tree sort, formally proved to return a
-- permutation of the input
------------------------------------------------------------------------

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

open import Equality
open import Prelude hiding (id)

module Tree-sort.Partial
  {c⁺}
  (eq : ∀ {a p} → Equality-with-J a p c⁺)
  {A : Type}
  (_≤_ : A → A → Bool) -- A comparison function.
  where

open Derived-definitions-and-properties eq

open import Bag-equivalence eq
open import Bijection eq using (_↔_)
open import Function-universe eq hiding (_∘_)
open import List eq
open import Tree eq

------------------------------------------------------------------------
-- Insertion into trees

-- Inserts an element into the tree.

insert : A → Tree A → Tree A
insert x leaf         = singleton x
insert x (node l y r) =
  if x ≤ y then node (insert x l) y r
           else node l y (insert x r)

-- The insert function inserts.

Any-insert : ∀ (P : A → Type) x t →
             AnyT P (insert x t) ↔ P x ⊎ AnyT P t
Any-insert P x leaf =
  AnyT P (singleton x)  ↔⟨ Any-singleton P ⟩
  P x                   ↔⟨ inverse ⊎-right-identity ⟩
  P x ⊎ ⊥               ↔⟨⟩
  P x ⊎ AnyT P leaf     □
Any-insert P x (node l y r) with x ≤ y
... | true  =
  AnyT P (insert x l) ⊎ P y ⊎ AnyT P r  ↔⟨ Any-insert P x l ⊎-cong id ⟩
  (P x ⊎ AnyT P l)    ⊎ P y ⊎ AnyT P r  ↔⟨ inverse ⊎-assoc ⟩
  P x ⊎ AnyT P l      ⊎ P y ⊎ AnyT P r  □
... | false =
  AnyT P l ⊎ P y ⊎ AnyT P (insert x r)  ↔⟨ id ⊎-cong id ⊎-cong Any-insert P x r ⟩
  AnyT P l ⊎ P y ⊎ P x ⊎ AnyT P r       ↔⟨ lemma (AnyT P l) (P y) (P x) (AnyT P r) ⟩
  P x ⊎ AnyT P l ⊎ P y ⊎ AnyT P r       □
  where
  -- The following lemma is easy to prove automatically (for instance
  -- by using a ring solver).

  lemma : (A B C D : Type) → A ⊎ B ⊎ C ⊎ D ↔ C ⊎ A ⊎ B ⊎ D
  lemma A B C D =
    A ⊎ B ⊎ C ⊎ D      ↔⟨ id ⊎-cong ⊎-assoc ⟩
    A ⊎ (B ⊎ C) ⊎ D    ↔⟨ id ⊎-cong ⊎-comm ⊎-cong id ⟩
    A ⊎ (C ⊎ B) ⊎ D    ↔⟨ ⊎-assoc ⟩
    (A ⊎ C ⊎ B) ⊎ D    ↔⟨ ⊎-assoc ⊎-cong id ⟩
    ((A ⊎ C) ⊎ B) ⊎ D  ↔⟨ (⊎-comm ⊎-cong id) ⊎-cong id ⟩
    ((C ⊎ A) ⊎ B) ⊎ D  ↔⟨ inverse ⊎-assoc ⊎-cong id ⟩
    (C ⊎ A ⊎ B) ⊎ D    ↔⟨ inverse ⊎-assoc ⟩
    C ⊎ (A ⊎ B) ⊎ D    ↔⟨ id ⊎-cong inverse ⊎-assoc ⟩
    C ⊎ A ⊎ B ⊎ D      □

------------------------------------------------------------------------
-- Turning a list into a search tree

-- Converts the list to a search tree.

to-search-tree : List A → Tree A
to-search-tree = foldr insert leaf

-- No elements are added or removed.

to-search-tree-lemma : ∀ xs z → z ∈T to-search-tree xs ↔ z ∈ xs
to-search-tree-lemma [] = λ z →
  z ∈T leaf  ↔⟨⟩
  z ∈  []    □
to-search-tree-lemma (x ∷ xs) = λ z →
  z ∈T insert x (to-search-tree xs)  ↔⟨ Any-insert (λ x → z ≡ x) _ _ ⟩
  z ≡ x ⊎ z ∈T to-search-tree xs     ↔⟨ id ⊎-cong to-search-tree-lemma xs z ⟩
  z ∈ x ∷ xs                         □

------------------------------------------------------------------------
-- Sorting

-- Sorts a list.

tree-sort : List A → List A
tree-sort = flatten ∘ to-search-tree

-- The result is a permutation of the input.

tree-sort-permutes : ∀ xs → tree-sort xs ≈-bag xs
tree-sort-permutes xs = λ z →
  z ∈  flatten (to-search-tree xs)  ↔⟨ flatten-lemma (to-search-tree xs) z ⟩
  z ∈T to-search-tree xs            ↔⟨ to-search-tree-lemma xs z ⟩
  z ∈  xs                           □


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

open import HoTT

module homotopy.HSpace where

record HSpaceStructure {i} (A : Type i) : Type i where
  constructor hSpaceStructure
  field
    e : A
    μ : A → A → A
    μe- : (a : A) → μ e a == a
    μ-e : (a : A) → μ a e == a

module ConnectedHSpace {i} (A : Type i) (c : is-connected ⟨0⟩ A)
  (hA : HSpaceStructure A) where

  open HSpaceStructure hA

  {-
  Given that [A] is 0-connected, to prove that each [μ a] is an equivalence we
  only need to prove that one of them is. But for [a] = [e], [μ a] is the
  identity so we’re done.
  -}

  μ-is-equiv : (a : A) → is-equiv (μ a)
  μ-is-equiv = prop-over-connected {a = e} c
    (λ a → (is-equiv (μ a) , is-equiv-is-prop (μ a)))
    (transport! is-equiv (λ= μe-) (idf-is-equiv A))

  μ'-is-equiv : (a : A) → is-equiv (λ a' → μ a' a)
  μ'-is-equiv = prop-over-connected {a = e} c
    (λ a → (is-equiv (λ a' → μ a' a) , is-equiv-is-prop (λ a' → μ a' a)))
    (transport! is-equiv (λ= μ-e) (idf-is-equiv A))

  μ-equiv : A → A ≃ A
  μ-equiv a = (μ a , μ-is-equiv a)

  μ'-equiv : A → A ≃ A
  μ'-equiv a = ((λ a' → μ a' a) , μ'-is-equiv a)


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

module inorder where

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

  open import trees
  open import optics
  open import lemmas

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

  inorder : {A : Set} -> Traversal (Tree A) (Tree A) A A
  inorder = record{ extract = inorderTree }

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

    open Traversal

    inorder1 : Vec ℕ 2
    inorder1 = get inorder tree1

    updatedinorder1 : Tree ℕ
    updatedinorder1 = put inorder tree1  (2 ∷ 3 ∷ [])


------------------------------------------------------------------------------
-- The gcd program is correct
------------------------------------------------------------------------------

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

-- This module proves the correctness of the gcd program using
-- the Euclid's algorithm.

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

module FOTC.Program.GCD.Partial.CorrectnessProofATP where

open import FOTC.Base
open import FOTC.Data.Nat.Divisibility.NotBy0.PropertiesATP using ( 0∤x ; x∣S→x≤S )
open import FOTC.Data.Nat.Type
open import FOTC.Program.GCD.Partial.CommonDivisorATP using ( gcdCD )
open import FOTC.Program.GCD.Partial.Definitions using ( x≢0≢y ; gcdSpec )
open import FOTC.Program.GCD.Partial.DivisibleATP using ( gcdDivisible )
open import FOTC.Program.GCD.Partial.GCD using ( gcd )

import FOTC.Program.GCD.Partial.GreatestAnyCommonDivisor
open module GreatestAnyCommonDivisorATP =
  FOTC.Program.GCD.Partial.GreatestAnyCommonDivisor x∣S→x≤S 0∤x
  using ( gcdGACD )

open import FOTC.Program.GCD.Partial.TotalityATP using ( gcd-N )

------------------------------------------------------------------------------
-- The gcd is correct.
postulate gcdCorrect : ∀ {m n} → N m → N n → x≢0≢y m n → gcdSpec m n (gcd m n)
{-# ATP prove gcdCorrect gcdCD gcdGACD gcd-N gcdDivisible #-}


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

open import LogicalFormulae
open import Monoids.Definition

module Semirings.Definition where

record Semiring {a : _} {A : Set a} (Zero One : A) (_+_ : A → A → A) (_*_ : A → A → A) : Set a where
  field
    monoid : Monoid Zero _+_
    commutative : (a b : A) → a + b ≡ b + a
    multMonoid : Monoid One _*_
    productZeroLeft : (a : A) → Zero * a ≡ Zero
    productZeroRight : (a : A) → a * Zero ≡ Zero
    +DistributesOver* : (a b c : A) → a * (b + c) ≡ (a * b) + (a * c)
    +DistributesOver*' : (a b c : A) → (a + b) * c ≡ (a * c) + (b * c)
  +Associative = Monoid.associative monoid
  *Associative = Monoid.associative multMonoid
  productOneLeft = Monoid.idLeft multMonoid
  productOneRight = Monoid.idRight multMonoid
  sumZeroLeft = Monoid.idLeft monoid
  sumZeroRight = Monoid.idRight monoid
  +WellDefined : {a b c d : A} → (a ≡ c) → (b ≡ d) → (a + b) ≡ (c + d)
  +WellDefined refl refl = refl

-- (b+c)(a+a) == b(a+a) + c(a+a) == ba+ba+ca+ca == (ba+ca) + (ba+ca)
-- (b+c)(a+a) ==? (b+c)a+(b+c)a


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

module Fragment.Setoid.Morphism.Setoid where

open import Fragment.Setoid.Morphism.Base

open import Level using (Level; _⊔_)
open import Relation.Binary using (Setoid; IsEquivalence; Rel)

private
  variable
    a b ℓ₁ ℓ₂ : Level

module _ {S : Setoid a ℓ₁} {T : Setoid b ℓ₂} where

  open Setoid T

  infix 4 _≗_

  _≗_ : Rel (S ↝ T) (a ⊔ ℓ₂)
  f ≗ g = ∀ {x} → ∣ f ∣ x ≈ ∣ g ∣ x

  ≗-refl : ∀ {f} → f ≗ f
  ≗-refl = refl

  ≗-sym : ∀ {f g} → f ≗ g → g ≗ f
  ≗-sym f≗g {x} = sym (f≗g {x})

  ≗-trans : ∀ {f g h} → f ≗ g → g ≗ h → f ≗ h
  ≗-trans f≗g g≗h {x} = trans (f≗g {x}) (g≗h {x})

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

_↝_/≗ : Setoid a ℓ₁ → Setoid b ℓ₂ → Setoid _ _
S ↝ T /≗ = record { Carrier       = S ↝ T
                  ; _≈_           = _≗_
                  ; isEquivalence = ≗-isEquivalence
                  }


module 120-natural-induction-necessary where

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

-- We prove that the induction axiom is necessary.

-- Peano axioms without induction.

record NaturalWithoutInduction
  {M : Set}
  (zero : M)
  (suc : M -> M)
  (_==_ : M -> M -> Set)
  : Set1 where

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

  open Equivalence equiv public

-- Construct a model, and prove it satisfies NaturalWithoutInduction
-- but not Natural. To do this, we add an extra zero.

data M : Set where
  zero1 : M
  zero2 : M
  suc : M -> M

thm-M-is-natural-without-induction : NaturalWithoutInduction zero1 suc _≡_
thm-M-is-natural-without-induction = record {
  equiv = thm-≡-is-equivalence;
  sucn!=zero = sucn!=zero;
  sucinjective = sucinjective;
  cong = cong;
  not-induction = not-induction
  }
  where
    sucn!=zero : ∀ {r} -> suc r ≡ zero1 -> False
    sucn!=zero ()
    sucinjective : ∀ {r s} -> suc r ≡ suc s -> r ≡ s
    sucinjective refl = refl
    cong : ∀ {r s} -> r ≡ s -> suc r ≡ suc s
    cong refl = refl
    -- To prove that induction fails, we test the property "is a
    -- successor of zero1 but not of zero2". This holds for zero1 (the
    -- base case), and it also holds for every successor of n if it
    -- holds for n, but it does not hold for zero2 (or for any of its
    -- successors).
    not-induction :
      ((p : M -> Set) -> p zero1 -> (∀ n -> p n -> p (suc n)) -> ∀ n -> p n)
      -> False
    not-induction induction = induction p base hypothesis zero2
      where
        -- Property "is a successor of zero1 but not a successor of zero2".
        p : M -> Set
        p zero1 = True  -- true for zero1
        p zero2 = False -- false (no proof) for zero2
        p (suc n) = p n -- true for successor of n if and only if true for n

        -- Base case is trivial.
        base : p zero1
        base = trivial

        -- Induction hypothesis follows by application of "p n" itself
        -- due to the recursive definition of p.
        hypothesis : ∀ n -> p n -> p (suc n)
        hypothesis n pn = pn

-- To round this off, we explicitly prove that M is not natural.

thm-M-is-not-natural : (Natural zero1 suc _≡_) -> False
thm-M-is-not-natural nat =
  (NaturalWithoutInduction.not-induction thm-M-is-natural-without-induction)
  (Natural.induction nat)


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

module Cubical.Structures.Group.Morphism where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Structures.Group.Base

private
  variable
    ℓ ℓ' : Level

-- The following definition of GroupHom and GroupEquiv are level-wise heterogeneous.
-- This allows for example to deduce that G ≡ F from a chain of isomorphisms
-- G ≃ H ≃ F, even if H does not lie in the same level as G and F.

isGroupHom : (G : Group {ℓ}) (H : Group {ℓ'}) (f : ⟨ G ⟩ → ⟨ H ⟩) → Type _
isGroupHom G H f = (x y : ⟨ G ⟩) → f (x G.+ y) ≡ (f x H.+ f y) where
  module G = Group G
  module H = Group H

record GroupHom (G : Group {ℓ}) (H : Group {ℓ'}) : Type (ℓ-max ℓ ℓ') where
  constructor grouphom

  field
    fun : ⟨ G ⟩ → ⟨ H ⟩
    isHom : isGroupHom G H fun

record GroupEquiv (G : Group {ℓ}) (H : Group {ℓ'}) : Type (ℓ-max ℓ ℓ') where
  constructor groupequiv

  field
    eq : ⟨ G ⟩ ≃ ⟨ H ⟩
    isHom : isGroupHom G H (equivFun eq)

  hom : GroupHom G H
  hom = grouphom (equivFun eq) isHom


module Nats.Add.Invert where

open import Equality
open import Nats
open import Nats.Add.Comm
open import Function

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

private

  lemma′ : ∀ a b → (suc a ≡ suc b) → (a ≡ b)
  lemma′ _ _ refl = refl

  lemma : ∀ a b → (suc (a + suc a) ≡ suc (b + suc b)) → (a + a ≡ b + b)
  lemma a b
    rewrite nat-add-comm a $ suc a
          | nat-add-comm b $ suc b
            = lemma′ (a + a) (b + b) ∘ lemma′ (suc $ a + a) (suc $ b + b)

  +-invert : ∀ a b → (a + a ≡ b + b) → a ≡ b
  +-invert zero zero ev = refl
  +-invert zero (suc b) ()
  +-invert (suc a) zero ()
  +-invert (suc a) (suc b) = cong suc ∘ +-invert a b ∘ lemma a b

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

nat-add-invert : ∀ a b → (a + a ≡ b + b) → a ≡ b
nat-add-invert = +-invert

nat-add-invert-1 : ∀ a b → (suc a ≡ suc b) → (a ≡ b)
nat-add-invert-1 = lemma′


------------------------------------------------------------------------------
-- Proving mirror (mirror t) = t using a list of trees
------------------------------------------------------------------------------

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

module FOT.FOTC.Program.Mirror.MirrorListSL where

open import Algebra
open import Function
open import Data.List hiding ( reverse )
open import Data.List.Properties
open import Data.Product hiding ( map )

open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

module LM {A : Set} = Monoid (++-monoid A)

------------------------------------------------------------------------------
-- Auxiliary functions

reverse : {A : Set} → List A → List A
reverse []       = []
reverse (x ∷ xs) = reverse xs ++ x ∷ []

++-rightIdentity : {A : Set}(xs : List A) → xs ++ [] ≡ xs
++-rightIdentity = proj₂ LM.identity

reverse-++ : {A : Set}(xs ys : List A) →
             reverse (xs ++ ys) ≡ reverse ys ++ reverse xs
reverse-++ [] ys       = sym (++-rightIdentity (reverse ys))
reverse-++ (x ∷ xs) [] = cong (λ x' → reverse x' ++ x ∷ [])
                              (++-rightIdentity xs)
reverse-++ (x ∷ xs) (y ∷ ys) =
  begin
    reverse (xs ++ y ∷ ys) ++ x ∷ []
      ≡⟨ cong (λ x' → x' ++ x ∷ []) (reverse-++ xs (y ∷ ys)) ⟩
    (reverse (y ∷ ys) ++ reverse xs) ++ x ∷ []
      ≡⟨ LM.assoc (reverse (y ∷ ys)) (reverse xs) (x ∷ []) ⟩
    reverse (y ∷ ys) ++ reverse (x ∷ xs)
  ∎

------------------------------------------------------------------------------
-- The rose tree type.
data Tree (A : Set) : Set where
  tree : A → List (Tree A) → Tree A

------------------------------------------------------------------------------
-- The mirror function.

{-# TERMINATING #-}
mirror : {A : Set} → Tree A → Tree A
mirror (tree a ts) = tree a (reverse (map mirror ts))

-- The proof of the property.
mirror-involutive : {A : Set} → (t : Tree A) → mirror (mirror t) ≡ t
helper            : {A : Set} → (ts : List (Tree A)) →
                    reverse (map mirror (reverse (map mirror ts))) ≡ ts

mirror-involutive (tree a []) = refl
mirror-involutive (tree a (t ∷ ts)) =
  begin
    tree a (reverse (map mirror (reverse (map mirror ts) ++ mirror t ∷ [])))
      ≡⟨ cong (tree a) (helper (t ∷ ts)) ⟩
    tree a (t ∷ ts)
  ∎

helper [] = refl
helper (t ∷ ts) =
  begin
    reverse (map mirror (reverse (map mirror ts) ++ mirror t ∷ []))
     ≡⟨ cong reverse
             (map-++-commute mirror (reverse (map mirror ts)) (mirror t ∷ []))
     ⟩
    reverse (map mirror (reverse (map mirror ts)) ++
            (map mirror (mirror t ∷ [])))
      ≡⟨ subst (λ x → (reverse (map mirror (reverse (map mirror ts)) ++
                                    (map mirror (mirror t ∷ [])))) ≡ x)
               (reverse-++ (map mirror (reverse (map mirror ts)))
                           (map mirror (mirror t ∷ [])))
               refl
      ⟩
    reverse (map mirror (mirror t ∷ [])) ++
    reverse (map mirror (reverse (map mirror ts)))
      ≡⟨ refl ⟩
    mirror (mirror t) ∷ reverse (map mirror (reverse (map mirror ts)))
      ≡⟨ cong (flip _∷_ (reverse (map mirror (reverse (map mirror ts)))))
              (mirror-involutive t)
      ⟩
    t ∷ reverse (map mirror (reverse (map mirror ts)))
      ≡⟨ cong (_∷_ t) (helper ts) ⟩
    t ∷ ts
  ∎


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

module LogicalFramework.Existential where

module LF where
  postulate
    D : Set

    -- Disjunction.
    _∨_  : Set → Set → Set
    inj₁ : {A B : Set} → A → A ∨ B
    inj₂ : {A B : Set} → B → A ∨ B
    case : {A B C : Set} → (A → C) → (B → C) → A ∨ B → C

    -- The existential quantifier type on D.
    ∃       : (A : D → Set) → Set
    _,_     : {A : D → Set}(t : D) → A t → ∃ A
    ∃-proj₁ : {A : D → Set} → ∃ A → D
    ∃-proj₂ : {A : D → Set}(h : ∃ A) → A (∃-proj₁ h)
    ∃-elim  : {A : D → Set}{B : Set} → ∃ A → (∀ {x} → A x → B) → B

  syntax ∃ (λ x → e) = ∃[ x ] e

  module FOL-Examples where
    -- Using the projections.
    ∃∀₁ : {A : D → D → Set} → ∃[ x ](∀ y → A x y) → ∀ y → ∃[ x ] A x y
    ∃∀₁ h y = ∃-proj₁ h , (∃-proj₂ h) y

    ∃∨₁ : {A B : D → Set} → ∃[ x ](A x ∨ B x) → (∃[ x ] A x) ∨ (∃[ x ] B x)
    ∃∨₁ h = case (λ Ax → inj₁ (∃-proj₁ h , Ax))
                 (λ Bx → inj₂ (∃-proj₁ h , Bx))
                 (∃-proj₂ h)

    -- Using the elimination.
    ∃∀₂ : {A : D → D → Set} → ∃[ x ](∀ y → A x y) → ∀ y → ∃[ x ] A x y
    ∃∀₂ h y = ∃-elim h (λ {x} ah → x , ah y)

    ∃∨₂ : {A B : D → Set} → ∃[ x ](A x ∨ B x) → (∃[ x ] A x) ∨ (∃[ x ] B x)
    ∃∨₂ h = ∃-elim h (λ {x} ah → case (λ Ax → inj₁ (x , Ax))
                                      (λ Bx → inj₂ (x , Bx))
                                      ah)

  module NonFOL-Examples where

    -- Using the projections.
    non-FOL₁ : {A : D → Set} → ∃ A → D
    non-FOL₁ h = ∃-proj₁ h

    -- Using the elimination.
    non-FOL₂ : {A : D → Set} → ∃ A → D
    non-FOL₂ h = ∃-elim h (λ {x} _ → x)

module Inductive where

  open import Common.FOL.FOL

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

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

  -- The existential elimination.
  ∃-elim : {A : D → Set}{B : Set} → ∃ A → (∀ {x} → A x → B) → B
  ∃-elim (_ , Ax) h = h Ax

  module FOL-Examples where
    -- Using the projections.
    ∃∀₁ : {A : D → D → Set} → ∃[ x ](∀ y → A x y) → ∀ y → ∃[ x ] A x y
    ∃∀₁ h y = ∃-proj₁ h , (∃-proj₂ h) y

    ∃∨₁ : {A B : D → Set} → ∃[ x ](A x ∨ B x) → (∃[ x ] A x) ∨ (∃[ x ] B x)
    ∃∨₁ h = case (λ Ax → inj₁ (∃-proj₁ h , Ax))
                 (λ Bx → inj₂ (∃-proj₁ h , Bx))
                 (∃-proj₂ h)

    -- Using the elimination.
    ∃∀₂ : {A : D → D → Set} → ∃[ x ](∀ y → A x y) → ∀ y → ∃[ x ] A x y
    ∃∀₂ h y = ∃-elim h (λ {x} ah → x , ah y)

    ∃∨₂ : {A B : D → Set} → ∃[ x ](A x ∨ B x) → (∃[ x ] A x) ∨ (∃[ x ] B x)
    ∃∨₂ h = ∃-elim h (λ {x} ah → case (λ Ax → inj₁ (x , Ax))
                                      (λ Bx → inj₂ (x , Bx))
                                      ah)

    -- Using pattern matching.
    ∃∀₃ : {A : D → D → Set} → ∃[ x ](∀ y → A x y) → ∀ y → ∃[ x ] A x y
    ∃∀₃ (x , Ax) y = x , Ax y

    ∃∨₃ : {A B : D → Set} → ∃[ x ](A x ∨ B x) → (∃[ x ] A x) ∨ (∃[ x ] B x)
    ∃∨₃ (x , inj₁ Ax) = inj₁ (x , Ax)
    ∃∨₃ (x , inj₂ Bx) = inj₂ (x , Bx)

  module NonFOL-Examples where

    -- Using the projections.
    non-FOL₁ : {A : D → Set} → ∃ A → D
    non-FOL₁ h = ∃-proj₁ h

    -- Using the elimination.
    non-FOL₂ : {A : D → Set} → ∃ A → D
    non-FOL₂ h = ∃-elim h (λ {x} _ → x)

    -- Using the pattern matching.
    non-FOL₃ : {A : D → Set} → ∃ A → D
    non-FOL₃ (x , _) = x


------------------------------------------------------------------------
-- The Agda standard library
--
-- The identity function
------------------------------------------------------------------------

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

module Function.Construct.Identity where

open import Data.Product using (_,_)
open import Function using (id)
open import Function.Bundles
import Function.Definitions as Definitions
import Function.Structures as Structures
open import Level
open import Relation.Binary
open import Relation.Binary.PropositionalEquality using (_≡_; setoid)

private
  variable
    a ℓ : Level
    A : Set a

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

module _ (_≈_ : Rel A ℓ) where

  open Definitions _≈_ _≈_

  injective : Injective id
  injective = id

  surjective : Reflexive _≈_ → Surjective id
  surjective refl x = x , refl

  bijective : Reflexive _≈_ → Bijective id
  bijective refl = injective , surjective refl

  inverseˡ : Reflexive _≈_ → Inverseˡ id id
  inverseˡ refl x = refl

  inverseʳ : Reflexive _≈_ → Inverseʳ id id
  inverseʳ refl x = refl

  inverseᵇ : Reflexive _≈_ → Inverseᵇ id id
  inverseᵇ refl = inverseˡ refl , inverseʳ refl

------------------------------------------------------------------------
-- Structures

module _ {_≈_ : Rel A ℓ} (isEq : IsEquivalence _≈_) where

  open Structures _≈_ _≈_
  open IsEquivalence isEq

  isCongruent : IsCongruent id
  isCongruent = record
    { cong           = id
    ; isEquivalence₁ = isEq
    ; isEquivalence₂ = isEq
    }

  isInjection : IsInjection id
  isInjection = record
    { isCongruent = isCongruent
    ; injective   = injective _≈_
    }

  isSurjection : IsSurjection id
  isSurjection = record
    { isCongruent = isCongruent
    ; surjective  = surjective _≈_ refl
    }

  isBijection : IsBijection id
  isBijection = record
    { isInjection = isInjection
    ; surjective  = surjective _≈_ refl
    }

  isLeftInverse : IsLeftInverse id id
  isLeftInverse = record
    { isCongruent = isCongruent
    ; cong₂       = id
    ; inverseˡ    = inverseˡ _≈_ refl
    }

  isRightInverse : IsRightInverse id id
  isRightInverse = record
    { isCongruent = isCongruent
    ; cong₂       = id
    ; inverseʳ    = inverseʳ _≈_ refl
    }

  isInverse : IsInverse id id
  isInverse = record
    { isLeftInverse = isLeftInverse
    ; inverseʳ      = inverseʳ _≈_ refl
    }

------------------------------------------------------------------------
-- Setoid bundles

module _ (S : Setoid a ℓ) where

  open Setoid S

  injection : Injection S S
  injection = record
    { f         = id
    ; cong      = id
    ; injective = injective _≈_
    }

  surjection : Surjection S S
  surjection = record
    { f          = id
    ; cong       = id
    ; surjective = surjective _≈_ refl
    }

  bijection : Bijection S S
  bijection = record
    { f         = id
    ; cong      = id
    ; bijective = bijective _≈_ refl
    }

  equivalence : Equivalence S S
  equivalence = record
    { f     = id
    ; g     = id
    ; cong₁ = id
    ; cong₂ = id
    }

  leftInverse : LeftInverse S S
  leftInverse = record
    { f        = id
    ; g        = id
    ; cong₁    = id
    ; cong₂    = id
    ; inverseˡ = inverseˡ _≈_ refl
    }

  rightInverse : RightInverse S S
  rightInverse = record
    { f        = id
    ; g        = id
    ; cong₁    = id
    ; cong₂    = id
    ; inverseʳ = inverseʳ _≈_ refl
    }

  inverse : Inverse S S
  inverse = record
    { f       = id
    ; f⁻¹     = id
    ; cong₁   = id
    ; cong₂   = id
    ; inverse = inverseᵇ _≈_ refl
    }

------------------------------------------------------------------------
-- Propositional bundles

module _ (A : Set a) where

  id-↣ : A ↣ A
  id-↣ = injection (setoid A)

  id-↠ : A ↠ A
  id-↠ = surjection (setoid A)

  id-⤖ : A ⤖ A
  id-⤖ = bijection (setoid A)

  id-⇔ : A ⇔ A
  id-⇔ = equivalence (setoid A)

  id-↩ : A ↩ A
  id-↩ = leftInverse (setoid A)

  id-↪ : A ↪ A
  id-↪ = rightInverse (setoid A)

  id-↔ : A ↔ A
  id-↔ = inverse (setoid A)


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

module 04-inductive-types where

import 03-natural-numbers
open 03-natural-numbers public

-- Section 4.2 The unit type

-- Definition 4.2.1

data unit : UU lzero where
  star : unit

𝟙 = unit

ind-unit : {i : Level} {P : unit → UU i} → P star → ((x : unit) → P x)
ind-unit p star = p

-- Section 4.3 The empty type

-- Definition 4.3.1

data empty : UU lzero where

𝟘 = empty

ind-empty : {i : Level} {P : empty → UU i} → ((x : empty) → P x)
ind-empty ()

ex-falso : {i : Level} {P : empty →  UU i} → ((x : empty) → P x)
ex-falso = ind-empty

ex-falso' : {i : Level} {A : UU i} → empty → A
ex-falso' = ex-falso

-- Definition 4.3.2

¬ : {i : Level} → UU i → UU i
¬ A = A → empty

-- Section 4.4 The booleans

-- Definition 4.4.1

data bool : UU lzero where
  true false : bool

-- Example 4.4.2

neg-𝟚 : bool → bool
neg-𝟚 true = false
neg-𝟚 false = true

conjunction-𝟚 : bool → (bool → bool)
conjunction-𝟚 true true = true
conjunction-𝟚 true false = false
conjunction-𝟚 false true = false
conjunction-𝟚 false false = false

disjunction-𝟚 : bool → (bool → bool)
disjunction-𝟚 true true = true
disjunction-𝟚 true false = true
disjunction-𝟚 false true = true
disjunction-𝟚 false false = false

-- Section 4.5 Coproducts and the type of integers

-- Definition 4.5.1

data coprod {i j : Level} (A : UU i) (B : UU j) : UU (i ⊔ j)  where
  inl : A → coprod A B
  inr : B → coprod A B

ind-coprod : {i j k : Level} {A : UU i} {B : UU j} (C : coprod A B → UU k) →
  ((x : A) → C (inl x)) → ((y : B) → C (inr y)) →
  (t : coprod A B) → C t
ind-coprod C f g (inl x) = f x
ind-coprod C f g (inr x) = g x

-- Definition 4.5.2

-- The type of integers

ℤ : UU lzero
ℤ = coprod ℕ (coprod unit ℕ)

-- Inclusion of the negative integers

in-neg : ℕ → ℤ
in-neg n = inl n

-- Negative one

neg-one-ℤ : ℤ
neg-one-ℤ = in-neg zero-ℕ

-- Zero

zero-ℤ : ℤ
zero-ℤ = inr (inl star)

-- One

one-ℤ : ℤ
one-ℤ = inr (inr zero-ℕ)

-- Inclusion of the positive integers

in-pos : ℕ → ℤ
in-pos n = inr (inr n)

-- Lemma 4.5.3

{- We prove an induction principle for the integers. -}

ind-ℤ : {i : Level} (P : ℤ → UU i) → P neg-one-ℤ → ((n : ℕ) → P (inl n) → P (inl (succ-ℕ n))) → P zero-ℤ → P one-ℤ → ((n : ℕ) → P (inr (inr (n))) → P (inr (inr (succ-ℕ n)))) → (k : ℤ) → P k
ind-ℤ P p-1 p-S p0 p1 pS (inl zero-ℕ) = p-1
ind-ℤ P p-1 p-S p0 p1 pS (inl (succ-ℕ x)) = p-S x (ind-ℤ P p-1 p-S p0 p1 pS (inl x))
ind-ℤ P p-1 p-S p0 p1 pS (inr (inl star)) = p0
ind-ℤ P p-1 p-S p0 p1 pS (inr (inr zero-ℕ)) = p1
ind-ℤ P p-1 p-S p0 p1 pS (inr (inr (succ-ℕ x))) = pS x (ind-ℤ P p-1 p-S p0 p1 pS (inr (inr (x))))

-- Definition 4.5.4

succ-ℤ : ℤ → ℤ
succ-ℤ (inl zero-ℕ) = zero-ℤ
succ-ℤ (inl (succ-ℕ x)) = inl x
succ-ℤ (inr (inl star)) = one-ℤ
succ-ℤ (inr (inr x)) = inr (inr (succ-ℕ x))

-- Section 4.6 Dependent pair types

-- Definition 4.6.1

data Σ {i j : Level} (A : UU i) (B : A → UU j) : UU (i ⊔ j) where
  pair : (x : A) → (B x → Σ A B)

ind-Σ : {i j k : Level} {A : UU i} {B : A → UU j} {C : Σ A B → UU k} →
  ((x : A) (y : B x) → C (pair x y)) → ((t : Σ A B) → C t)
ind-Σ f (pair x y) = f x y

-- Definition 4.6.2

pr1 : {i j : Level} {A : UU i} {B : A → UU j} → Σ A B → A
pr1 (pair a b) = a

pr2 : {i j : Level} {A : UU i} {B : A → UU j} → (t : Σ A B) → B (pr1 t)
pr2 (pair a b) = b

-- Section 4.7 Cartesian products

-- Definition 4.7.1

prod : {i j : Level} (A : UU i) (B : UU j) → UU (i ⊔ j)
prod A B = Σ A (λ a → B)

pair' :
  {i j : Level} {A : UU i} {B : UU j} → A → B → prod A B
pair' = pair

_×_ :  {i j : Level} (A : UU i) (B : UU j) → UU (i ⊔ j)
A × B = prod A B

-- Exercises

-- Exercise 4.2

{- In this exercise we were asked to show that (A + ¬A) implies (¬¬A → A). In
   other words, we get double negation elimination for the types that are
   decidable. -}

is-decidable : {l : Level} (A : UU l) → UU l
is-decidable A = coprod A (¬ A)

double-negation-elim-is-decidable :
  {i : Level} (A : UU i) → is-decidable A → (¬ (¬ A) → A)
double-negation-elim-is-decidable A (inl x) p = x
double-negation-elim-is-decidable A (inr x) p = ind-empty (p x)

neg-triple-neg : {l : Level} (A : UU l) → (¬ (¬ (¬ A))) → (¬ A)
neg-triple-neg A f a = f (λ g → g a)

-- Exercise 4.3

exclusive-disjunction-𝟚 : bool → (bool → bool)
exclusive-disjunction-𝟚 true true = false
exclusive-disjunction-𝟚 true false = true
exclusive-disjunction-𝟚 false true = true
exclusive-disjunction-𝟚 false false = false

implication-𝟚 : bool → (bool → bool)
implication-𝟚 true true = true
implication-𝟚 true false = false
implication-𝟚 false true = true
implication-𝟚 false false = true

bi-implication-𝟚 : bool → (bool → bool)
bi-implication-𝟚 true true = true
bi-implication-𝟚 true false = false
bi-implication-𝟚 false true = false
bi-implication-𝟚 false false = true

peirce-arrow-𝟚 : bool → (bool → bool)
peirce-arrow-𝟚 true true = false
peirce-arrow-𝟚 true false = false
peirce-arrow-𝟚 false true = false
peirce-arrow-𝟚 false false = true

sheffer-stroke-𝟚 : bool → (bool → bool)
sheffer-stroke-𝟚 true true = false
sheffer-stroke-𝟚 true false = true
sheffer-stroke-𝟚 false true = true
sheffer-stroke-𝟚 false false = true

-- Exercise 4.4

pred-ℤ : ℤ → ℤ
pred-ℤ (inl x) = inl (succ-ℕ x)
pred-ℤ (inr (inl star)) = inl zero-ℕ
pred-ℤ (inr (inr zero-ℕ)) = inr (inl star)
pred-ℤ (inr (inr (succ-ℕ x))) = inr (inr x)

-- Exercise 4.5

-- Addition on ℤ

add-ℤ : ℤ → ℤ → ℤ
add-ℤ (inl zero-ℕ) l = pred-ℤ l
add-ℤ (inl (succ-ℕ x)) l = pred-ℤ (add-ℤ (inl x) l)
add-ℤ (inr (inl star)) l = l
add-ℤ (inr (inr zero-ℕ)) l = succ-ℤ l
add-ℤ (inr (inr (succ-ℕ x))) l = succ-ℤ (add-ℤ (inr (inr x)) l)

-- The negative of an integer

neg-ℤ : ℤ → ℤ
neg-ℤ (inl x) = inr (inr x)
neg-ℤ (inr (inl star)) = inr (inl star)
neg-ℤ (inr (inr x)) = inl x

-- Multiplication on ℤ

mul-ℤ : ℤ → ℤ → ℤ
mul-ℤ (inl zero-ℕ) l = neg-ℤ l
mul-ℤ (inl (succ-ℕ x)) l = add-ℤ (neg-ℤ l) (mul-ℤ (inl x) l)
mul-ℤ (inr (inl star)) l = zero-ℤ
mul-ℤ (inr (inr zero-ℕ)) l = l
mul-ℤ (inr (inr (succ-ℕ x))) l = add-ℤ l (mul-ℤ (inr (inr x)) l)

-- Exercise 4.6

Fibonacci-ℤ : ℤ → ℤ
Fibonacci-ℤ (inl zero-ℕ) = one-ℤ
Fibonacci-ℤ (inl (succ-ℕ zero-ℕ)) = neg-one-ℤ
Fibonacci-ℤ (inl (succ-ℕ (succ-ℕ x))) =
  add-ℤ (Fibonacci-ℤ (inl x)) (neg-ℤ (Fibonacci-ℤ (inl (succ-ℕ x))))
Fibonacci-ℤ (inr (inl star)) = zero-ℤ
Fibonacci-ℤ (inr (inr zero-ℕ)) = one-ℤ
Fibonacci-ℤ (inr (inr (succ-ℕ zero-ℕ))) = one-ℤ
Fibonacci-ℤ (inr (inr (succ-ℕ (succ-ℕ x)))) =
  add-ℤ (Fibonacci-ℤ (inr (inr x))) (Fibonacci-ℤ (inr (inr (succ-ℕ x))))

-- Exercise 4.7

{- In this exercise we were asked to show that 1 + 1 satisfies the induction
   principle of the booleans. In other words, type theory cannot distinguish
   the booleans from the type 1 + 1. We will see later that they are indeed
   equivalent types. -}

t0 : coprod unit unit
t0 = inl star

t1 : coprod unit unit
t1 = inr star

ind-coprod-unit-unit : {i : Level} {P : coprod unit unit → UU i} →
  P t0 → P t1 → (x : coprod unit unit) → P x
ind-coprod-unit-unit p0 p1 (inl star) = p0
ind-coprod-unit-unit p0 p1 (inr star) = p1

-- Exercise 4.8

-- Exercise 4.8(a)

data list {l : Level} (A : UU l) : UU l where
  nil : list A
  cons : A → list A → list A

in-list : {l : Level} {A : UU l} → A → list A
in-list a = cons a nil

-- Exercise 4.8(b)

fold-list :
  {l1 l2 : Level} {A : UU l1} {B : UU l2} (b : B) (μ : A → (B → B)) →
  list A → B
fold-list b μ nil = b
fold-list b μ (cons a l) = μ a (fold-list b μ l)

-- Exercise 4.8(c)

length-list :
  {l : Level} {A : UU l} → list A → ℕ
length-list = fold-list zero-ℕ (λ a → succ-ℕ)

-- Exercise 4.8(d)

sum-list-ℕ :
  list ℕ → ℕ
sum-list-ℕ = fold-list zero-ℕ add-ℕ

-- Exercise 4.8(e)

concat-list :
  {l : Level} {A : UU l} → list A → (list A → list A)
concat-list {l} {A} = fold-list id (λ a f → (cons a) ∘ f)

-- Exercise 4.8(f)

flatten-list :
  {l : Level} {A : UU l} → list (list A) → list A
flatten-list = fold-list nil concat-list

-- Exercise 4.8 (g)

reverse-list :
  {l : Level} {A : UU l} → list A → list A
reverse-list nil = nil
reverse-list (cons a l) = concat-list (reverse-list l) (in-list a)


module Plus where

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

infixr 40 _+_
infix  10 _==_

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

data _==_ (x, y : Nat) : Set where
  -- ...

postulate
  refl : {n : Nat} -> n == n
  cong : (f : Nat -> Nat){n, m : Nat} -> n == m -> f n == f m

plusZero : {n : Nat} -> n + zero == n
plusZero {zero}  = refl
plusZero {suc n} = cong suc plusZero


module Numeral.Finite.Relation.Order where

import      Lvl
open import Data
open import Data.Boolean.Stmt
open import Functional
open import Numeral.Finite
open import Numeral.Finite.Oper.Comparisons
open import Numeral.Natural
open import Type

private variable an bn cn n : ℕ
private variable a : 𝕟(an)
private variable b : 𝕟(bn)
private variable c : 𝕟(cn)

_≤_ : 𝕟(an) → 𝕟(bn) → Type
_≤_ = IsTrue ∘₂ (_≤?_)

_≥_ : 𝕟(an) → 𝕟(bn) → Type
_≥_ = IsTrue ∘₂ (_≥?_)

_<_ : 𝕟(an) → 𝕟(bn) → Type
_<_ = IsTrue ∘₂ (_<?_)

_>_ : 𝕟(an) → 𝕟(bn) → Type
_>_ = IsTrue ∘₂ (_>?_)

_≡_ : 𝕟(an) → 𝕟(bn) → Type
_≡_ = IsTrue ∘₂ (_≡?_)

_≢_ : 𝕟(an) → 𝕟(bn) → Type
_≢_ = IsTrue ∘₂ (_≢?_)

-- TODO: open import Structure.Relator.Properties

import Numeral.Natural.Relation.Order as ℕ

[≤]-minimum : (𝟎{n} ≤ a)
[≤]-minimum {a = 𝟎}   = <>
[≤]-minimum {a = 𝐒 _} = <>

-- [≤]-maximum : (bound a ℕ.≤ n) → (a ≤ maximum{n})
-- [≤]-maximum {_}    {𝟎}            ℕ.[≤]-with-[𝐒]                 = <>
-- [≤]-maximum {𝐒 an} {𝐒 a} {.(𝐒 n)} (ℕ.[≤]-with-[𝐒] {y = n} ⦃ p ⦄) = [≤]-maximum {an}{a}{n} p
[≤]-maximum : (bound a ℕ.≤ 𝐒(n)) → (a ≤ maximum{n})
[≤]-maximum {a = 𝟎}         {𝟎}   (ℕ.succ _) = <>
[≤]-maximum {a = 𝟎}         {𝐒 _} (ℕ.succ _) = <>
[≤]-maximum {a = 𝐒 a}       {𝐒 x} (ℕ.succ p) = [≤]-maximum {a = a} p
[≤]-maximum {a = 𝐒 {𝟎} ()}  {𝟎}   (ℕ.succ _)
[≤]-maximum {a = 𝐒 {𝐒 n} a} {𝟎}   (ℕ.succ ())

[≤]-reflexivity-raw : (a ≤ a)
[≤]-reflexivity-raw {a = 𝟎}   = <>
[≤]-reflexivity-raw {a = 𝐒 a} = [≤]-reflexivity-raw {a = a}

[≤]-asymmetry-raw : (a ≤ b) → (b ≤ a) → (a ≡ b)
[≤]-asymmetry-raw {a = 𝟎} {b = 𝟎}     _ _ = <>
[≤]-asymmetry-raw {a = 𝐒 a} {b = 𝐒 b} p q = [≤]-asymmetry-raw {a = a}{b = b} p q

[≤]-transitivity-raw : (a ≤ b) → (b ≤ c) → (a ≤ c)
[≤]-transitivity-raw {a = 𝟎}   {b = 𝟎}   {c = 𝟎}   p q = <>
[≤]-transitivity-raw {a = 𝟎}   {b = 𝟎}   {c = 𝐒 c} p q = <>
[≤]-transitivity-raw {a = 𝟎}   {b = 𝐒 b} {c = 𝐒 c} p q = <>
[≤]-transitivity-raw {a = 𝐒 a} {b = 𝐒 b} {c = 𝐒 c} p q = [≤]-transitivity-raw {a = a} {b = b} {c = c} p q


------------------------------------------------------------------------
-- Code for converting Vec n A → B to and from n-ary functions
------------------------------------------------------------------------

module Data.Vec.N-ary where

open import Data.Nat
open import Data.Vec
open import Data.Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality

------------------------------------------------------------------------
-- N-ary functions

N-ary : ℕ → Set → Set → Set
N-ary zero    A B = B
N-ary (suc n) A B = A → N-ary n A B

------------------------------------------------------------------------
-- Conversion

curryⁿ : ∀ {n A B} → (Vec A n → B) → N-ary n A B
curryⁿ {zero}  f = f []
curryⁿ {suc n} f = λ x → curryⁿ (f ∘ _∷_ x)

_$ⁿ_ : ∀ {n A B} → N-ary n A B → (Vec A n → B)
f $ⁿ []       = f
f $ⁿ (x ∷ xs) = f x $ⁿ xs

------------------------------------------------------------------------
-- N-ary function equality

Eq : ∀ {A B} n → Rel B → (f g : N-ary n A B) → Set
Eq zero    _∼_ f g = f ∼ g
Eq (suc n) _∼_ f g = ∀ x → Eq n _∼_ (f x) (g x)

-- A variant where all the arguments are implicit (hidden).

Eqʰ : ∀ {A B} n → Rel B → (f g : N-ary n A B) → Set
Eqʰ zero    _∼_ f g = f ∼ g
Eqʰ (suc n) _∼_ f g = ∀ {x} → Eqʰ n _∼_ (f x) (g x)

------------------------------------------------------------------------
-- Some lemmas

-- The functions curryⁿ and _$ⁿ_ are inverses.

left-inverse : ∀ {n A B} (f : Vec A n → B) →
               ∀ xs → curryⁿ f $ⁿ xs ≡ f xs
left-inverse f []       = refl
left-inverse f (x ∷ xs) = left-inverse (f ∘ _∷_ x) xs

right-inverse : ∀ {A B} n (f : N-ary n A B) →
                Eq n _≡_ (curryⁿ (_$ⁿ_ {n} f)) f
right-inverse zero    f = refl
right-inverse (suc n) f = λ x → right-inverse n (f x)

-- Conversion preserves equality.

curryⁿ-pres : ∀ {n A B _∼_} (f g : Vec A n → B) →
              (∀ xs → f xs ∼ g xs) →
              Eq n _∼_ (curryⁿ f) (curryⁿ g)
curryⁿ-pres {zero}  f g hyp = hyp []
curryⁿ-pres {suc n} f g hyp = λ x →
  curryⁿ-pres (f ∘ _∷_ x) (g ∘ _∷_ x) (λ xs → hyp (x ∷ xs))

curryⁿ-pres⁻¹ : ∀ {n A B _∼_} (f g : Vec A n → B) →
                Eq n _∼_ (curryⁿ f) (curryⁿ g) →
                ∀ xs → f xs ∼ g xs
curryⁿ-pres⁻¹ f g hyp []       = hyp
curryⁿ-pres⁻¹ f g hyp (x ∷ xs) =
  curryⁿ-pres⁻¹ (f ∘ _∷_ x) (g ∘ _∷_ x) (hyp x) xs

appⁿ-pres : ∀ {n A B _∼_} (f g : N-ary n A B) →
            Eq n _∼_ f g →
            (xs : Vec A n) → (f $ⁿ xs) ∼ (g $ⁿ xs)
appⁿ-pres f g hyp []       = hyp
appⁿ-pres f g hyp (x ∷ xs) = appⁿ-pres (f x) (g x) (hyp x) xs

appⁿ-pres⁻¹ : ∀ {n A B _∼_} (f g : N-ary n A B) →
              ((xs : Vec A n) → (f $ⁿ xs) ∼ (g $ⁿ xs)) →
              Eq n _∼_ f g
appⁿ-pres⁻¹ {zero}  f g hyp = hyp []
appⁿ-pres⁻¹ {suc n} f g hyp = λ x →
  appⁿ-pres⁻¹ (f x) (g x) (λ xs → hyp (x ∷ xs))

-- Eq and Eqʰ are equivalent.

Eq-to-Eqʰ : ∀ {A B} n {_∼_ : Rel B} {f g : N-ary n A B} →
            Eq n _∼_ f g → Eqʰ n _∼_ f g
Eq-to-Eqʰ zero    eq = eq
Eq-to-Eqʰ (suc n) eq = Eq-to-Eqʰ n (eq _)

Eqʰ-to-Eq : ∀ {A B} n {_∼_ : Rel B} {f g : N-ary n A B} →
            Eqʰ n _∼_ f g → Eq n _∼_ f g
Eqʰ-to-Eq zero    eq = eq
Eqʰ-to-Eq (suc n) eq = λ _ → Eqʰ-to-Eq n eq


{-# OPTIONS --safe --experimental-lossy-unification #-}
module Cubical.Data.Vec.OperationsNat where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Nat renaming(_+_ to _+n_; _·_ to _·n_)
open import Cubical.Data.Vec.Base
open import Cubical.Data.Sigma

private variable
  ℓ : Level

_+n-vec_ : {m : ℕ} → Vec ℕ m → Vec ℕ m → Vec ℕ m
_+n-vec_ {.zero} [] [] = []
_+n-vec_ {.(suc _)} (k ∷ v) (l ∷ v') = (k +n l) ∷ (v +n-vec v')

+n-vec-lid : {m : ℕ} → (v : Vec ℕ m) → replicate 0 +n-vec v ≡ v
+n-vec-lid {.zero} [] = refl
+n-vec-lid {.(suc _)} (k ∷ v) = cong (_∷_ k) (+n-vec-lid v)

+n-vec-rid : {m : ℕ} → (v : Vec ℕ m) → v +n-vec replicate 0 ≡ v
+n-vec-rid {.zero} [] = refl
+n-vec-rid {.(suc _)} (k ∷ v) = cong₂ _∷_ (+-zero k) (+n-vec-rid v)

+n-vec-assoc : {m : ℕ} → (v v' v'' : Vec ℕ m) → v +n-vec (v' +n-vec v'') ≡ (v +n-vec v') +n-vec v''
+n-vec-assoc [] [] [] = refl
+n-vec-assoc (k ∷ v) (l ∷ v') (p ∷ v'') = cong₂ _∷_ (+-assoc k l p) (+n-vec-assoc v v' v'')

+n-vec-comm : {m : ℕ} → (v v' : Vec ℕ m) → v +n-vec v' ≡ v' +n-vec v
+n-vec-comm {.zero} [] [] = refl
+n-vec-comm {.(suc _)} (k ∷ v) (l ∷ v') = cong₂ _∷_ (+-comm k l) (+n-vec-comm v v')

sep-vec : (k l : ℕ) → Vec ℕ (k +n l) → (Vec ℕ k) ×  (Vec ℕ l )
sep-vec zero l v = [] , v
sep-vec (suc k) l (x ∷ v) = (x ∷ fst (sep-vec k l v)) , (snd (sep-vec k l v))

sep-vec-fst : (k l : ℕ) → (v : Vec ℕ k) → (v' : Vec ℕ l) → fst (sep-vec k l (v ++ v')) ≡ v
sep-vec-fst zero l [] v' = refl
sep-vec-fst (suc k) l (x ∷ v) v' = cong (λ X → x ∷ X) (sep-vec-fst k l v v')

sep-vec-snd : (k l : ℕ) → (v : Vec ℕ k) → (v' : Vec ℕ l) → snd (sep-vec k l (v ++ v')) ≡ v'
sep-vec-snd zero l [] v' = refl
sep-vec-snd (suc k) l (x ∷ v) v' = sep-vec-snd k l v v'

sep-vec-id : (k l : ℕ) → (v : Vec ℕ (k +n l)) → fst (sep-vec k l v) ++ snd (sep-vec k l v) ≡ v
sep-vec-id zero l v = refl
sep-vec-id (suc k) l (x ∷ v) = cong (λ X → x ∷ X) (sep-vec-id k l v)

rep-concat : (k l : ℕ) → {B : Type ℓ} → (b : B) →
             replicate {_} {k} {B} b ++ replicate {_} {l} {B} b ≡ replicate {_} {k +n l} {B} b
rep-concat zero l b = refl
rep-concat (suc k) l b = cong (λ X → b ∷ X) (rep-concat k l b)

+n-vec-concat : (k l : ℕ) → (v w : Vec ℕ k) → (v' w' : Vec ℕ l)
                → (v +n-vec w) ++ (v' +n-vec w') ≡ (v ++ v') +n-vec (w ++ w')
+n-vec-concat zero l [] [] v' w' = refl
+n-vec-concat (suc k) l (x ∷ v) (y ∷ w) v' w' = cong (λ X → x +n y ∷ X) (+n-vec-concat k l v w v' w')


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

open import Functions.Definition
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import LogicalFormulae
open import Setoids.Subset
open import Setoids.Setoids
open import Setoids.Orders.Partial.Definition
open import Fields.Fields
open import Rings.Orders.Total.Definition
open import Rings.Orders.Total.Lemmas
open import Rings.Orders.Partial.Definition
open import Rings.Definition
open import Fields.Orders.LeastUpperBounds.Definition
open import Fields.Orders.Total.Definition

module Numbers.ClassicalReals.RealField where

record RealField : Agda.Primitive.Setω where
  field
    a b c : _
    A : Set a
    S : Setoid {_} {b} A
    _+_ : A → A → A
    _*_ : A → A → A
    R : Ring S _+_ _*_
    F : Field R
    _<_ : Rel {_} {c} A
    pOrder : SetoidPartialOrder S _<_
    pOrderedRing : PartiallyOrderedRing R pOrder
    orderedRing : TotallyOrderedRing pOrderedRing
    lub : {d : _} → {pred : A → Set d} → (sub : subset S pred) → (nonempty : Sg A pred) → (boundedAbove : Sg A (UpperBound pOrder sub)) → Sg A (LeastUpperBound pOrder sub)
  open Setoid S
  open Field F
  charNot2 : (Ring.1R R + Ring.1R R) ∼ Ring.0R R → False
  charNot2 = orderedImpliesCharNot2 orderedRing nontrivial
  oField : TotallyOrderedField F pOrderedRing
  oField = record { oRing = orderedRing }


module Utils where

open import Data.Fin using (Fin)
import      Data.Fin as F
open import Data.Nat

data Fromℕ (n : ℕ) : ℕ → Set where
  yes : (m : Fin n) → Fromℕ n (F.toℕ m)
  no  : (m : ℕ)     → Fromℕ n (n + m)

fromℕ : ∀ n m → Fromℕ n m
fromℕ zero m = no m
fromℕ (suc n) zero = yes F.zero
fromℕ (suc n) (suc m) with fromℕ n m
fromℕ (suc n) (suc .(F.toℕ m)) | yes m = yes (F.suc m)
fromℕ (suc n) (suc .(n + m))   | no  m = no m


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

module Categories.Functor.Construction.LiftSetoids where

open import Level
open import Relation.Binary
open import Function.Equality
open import Function using (_$_) renaming (id to idf)

open import Categories.Category
open import Categories.Category.Instance.Setoids
open import Categories.Functor

private
  variable
    c ℓ : Level

-- Use pattern-matching (instead of explicit calls to lower) to minimize the
-- number of needed parens, and also make it syntactically apparent that
-- this is indeed just a Lift.
LiftedSetoid : ∀ c′ ℓ′ → Setoid c ℓ → Setoid (c ⊔ c′) (ℓ ⊔ ℓ′)
LiftedSetoid c′ ℓ′ S = record
  { Carrier       = Lift c′ Carrier
  ; _≈_           = λ where (lift x) (lift y) → Lift ℓ′ $ x ≈ y
  ; isEquivalence = record
    { refl  = lift refl
    ; sym   = λ where (lift eq)            → lift $ sym eq
    ; trans = λ where (lift eq) (lift eq′) → lift $ trans eq eq′
    }
  }
  where open Setoid S

LiftSetoids : ∀ c′ ℓ′ → Functor (Setoids c ℓ) (Setoids (c ⊔ c′) (ℓ ⊔ ℓ′))
LiftSetoids c′ ℓ′ = record
  { F₀           = LiftedSetoid c′ ℓ′
  ; F₁           = λ f → record
    { _⟨$⟩_  = λ where (lift x)  → lift $ f ⟨$⟩ x
    ; cong  = λ where (lift eq) → lift $ cong f eq
    }
  ; identity     = idf
  ; homomorphism = λ where {f = f} {g = g} (lift eq) → lift $ cong g $ cong f eq
  ; F-resp-≈     = λ where fx≈gy (lift x≈y)          → lift $ fx≈gy x≈y
  }


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

module PolynomialFunctors where

-- From: Ulf Norell. Dependently typed programming in Agda. In Koopman
-- et al., editors. Advanced Functional Programming (AFP 2008), volume
-- 5832 of LNCS. Springer-Verlag, 2009. pages 230–266.

infixr 50 _|+|_ _⊕_
infixr 60 _|x|_ _×_

record True : Set where

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

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

data Functor : Set₁ where
  |Id|  : Functor
  |K|   : Set → Functor
  _|+|_ : Functor → Functor → Functor
  _|x|_ : Functor → Functor → Functor

[_] : Functor → Set → Set
[ |Id|    ] X = X
[ |K| A   ] X = A
[ F |+| G ] X = [ F ] X ⊕ [ G ] X
[ F |x| G ] X = [ F ] X × [ G ] X

data μ_ (F : Functor) : Set where
  <_> : [ F ] (μ F) → μ F

NatF : Functor
NatF = |K| True |+| |Id|

NAT : Set
NAT = μ NatF

Z : NAT
Z = < inl _ >

S : NAT → NAT
S n = < inr n >

_+_ : NAT → NAT → NAT
m + < inl _ > = m
m + < inr n > = S (m + n)

ListF : (A : Set) → Functor
ListF = λ A → |K| True |+| |K| A |x| |Id|

LIST : (A : Set) → Set
LIST = λ A → μ (ListF A)

nil : {A : Set} → LIST A
nil = < inl _ >

cons : {A : Set} → A → LIST A → LIST A
cons x xs = < inr (x , xs) >


{-# OPTIONS --without-K --safe #-}
module Categories.Comonad where

open import Level

open import Categories.Category using (Category)
open import Categories.Functor using (Functor; Endofunctor; _∘F_) renaming (id to idF)
open import Categories.NaturalTransformation renaming (id to idN)
open import Categories.NaturalTransformation.NaturalIsomorphism hiding (_≃_)
open import Categories.NaturalTransformation.Equivalence
open NaturalIsomorphism

record Comonad {o ℓ e} (C : Category o ℓ e) : Set (o ⊔ ℓ ⊔ e) where
  field
    F : Endofunctor C
    ε : NaturalTransformation F idF
    δ : NaturalTransformation F (F ∘F F)

  module F = Functor F
  module ε = NaturalTransformation ε
  module δ = NaturalTransformation δ

  open Category C
  open Functor F

  field
    assoc     : ∀ {X : Obj} → δ.η (F₀ X) ∘ δ.η X ≈ F₁ (δ.η X) ∘ δ.η X
    sym-assoc : ∀ {X : Obj} → F₁ (δ.η X) ∘ δ.η X ≈ δ.η (F₀ X) ∘ δ.η X
    identityˡ : ∀ {X : Obj} → F₁ (ε.η X) ∘ δ.η X ≈ id
    identityʳ : ∀ {X : Obj} → ε.η (F₀ X) ∘ δ.η X ≈ id


record SemiRing : Set1 where
  field
    R    : Set
    _+_  : R -> R -> R
    zero : R
    _*_  : R -> R -> R
    one  : R

module Vectors (S : SemiRing) where

  open SemiRing S
  open import Data.Nat renaming (ℕ to Nat; zero to z; _*_ to times; _+_ to plus)
  open import Data.Fin renaming (zero to z) hiding (_+_)
  open import RMonads
  open import Functors.Fin
  open import Data.Bool
  open import Function
  open import Relation.Binary.HeterogeneousEquality

  Vec : Nat -> Set
  Vec n = Fin n -> R

  Matrix : Nat -> Nat -> Set
  Matrix m n = Fin m -> Vec n

  -- unit
  delta : forall {n} -> Matrix n n
  delta i j = if feq i j then one else zero

  transpose : forall {m n} -> Matrix m n -> Matrix n m
  transpose A = λ j i -> A i j

  dot : forall {n} -> Vec n -> Vec n -> R
  dot {z}     x y = zero
  dot {suc n} x y = (x z * y z) + dot (x ∘ suc) (y ∘ suc)

  mult : forall {m n} -> Matrix m n -> Vec m -> Vec n
  mult A x = λ j -> dot (transpose A j) x

  VecRMon : RMonad FinF
  VecRMon = rmonad
    Vec
    delta
    mult
    {!!}
    {!!}
    {!!}

    where
{-
    lem : forall {n}(x : Vec n)(j : Fin n) -> dot (λ i → if feq i j then one else zero) x ≅ x j
    lem {z} x ()
    lem {suc n} x z = {!lem {n} (x ∘ suc) !}
    lem {suc n} x (suc j) = {!!}

 -}


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

module Avionics.Probability where

--open import Data.Fin using (Fin; fromℕ<)
open import Data.Nat using (ℕ; zero; suc)
open import Data.Product using (_×_; _,_)
open import Data.Vec using (Vec; lookup)
open import Relation.Binary.PropositionalEquality using (refl)
open import Relation.Unary using (_∈_)

open import Avionics.Real using (
    ℝ; _+_; _-_; _*_; _÷_; _^_; √_; 1/_; _^2;
    -1/2; π; e; 2ℝ; 1ℝ; 0ℝ;
    ⟨0,∞⟩; [0,∞⟩; [0,1])

record Dist (Input : Set) : Set where
  field
    pdf : Input → ℝ
    cdf : Input → ℝ
    pdf→[0,∞⟩ : ∀ x → pdf x ∈ [0,∞⟩
    cdf→[0,1] : ∀ x → cdf x ∈ [0,1]
    --∫pdf≡cdf : ∫ pdf ≡ cdf
    --∫pdf[-∞,∞]≡1ℝ : ∫ pdf [ -∞ , ∞ ] ≡ 1ℝ

record NormalDist : Set where
  constructor ND
  field
    μ : ℝ
    σ : ℝ
    --.0<σ : 0ℝ <? σ

  dist : Dist ℝ
  dist = record
    {
      pdf = pdf
    ; cdf = ?
    ; pdf→[0,∞⟩ = ?
    ; cdf→[0,1] = ?
    }
    where
      √2π = (√ (2ℝ * π))
      1/⟨σ√2π⟩ = (1/ (σ * √2π))

      pdf : ℝ → ℝ
      pdf x = 1/⟨σ√2π⟩ * e ^ (-1/2 * (⟨x-μ⟩÷σ ^2))
        where
          ⟨x-μ⟩÷σ = ((x - μ) ÷ σ)

-- Bivariate Normal Distribution
-- Representation taken from: https://upload.wikimedia.org/wikipedia/commons/a/a2/Cumulative_function_n_dimensional_Gaussians_12.2013.pdf
record BiNormalDist : Set where
  constructor ND
  field
    μ₁ : ℝ
    μ₂ : ℝ
    σ₁ : ℝ
    σ₂ : ℝ
    ρ : ℝ

  μ : ℝ × ℝ
  μ = μ₁ , μ₂

  Σ : ℝ × ℝ × ℝ × ℝ
  Σ = σ₁ , (ρ * σ₁ * σ₂) , (ρ * σ₁ * σ₂) , σ₂

  Σ-¹ : ℝ × ℝ × ℝ × ℝ
  Σ-¹ = ( 1/1-ρ² * (1ℝ ÷ σ₁)
        , 1/1-ρ² * -ρ/σ₁σ₂
        , 1/1-ρ² * -ρ/σ₁σ₂
        , 1/1-ρ² * (1ℝ ÷ σ₂))
    where 1/1-ρ² = 1ℝ ÷ (1ℝ - ρ * ρ)
          -ρ/σ₁σ₂ = (0ℝ - ρ) ÷ (σ₁ * σ₂)

  dist : Dist ℝ
  dist = record
    {
      pdf = ?
    ; cdf = ?
    ; pdf→[0,∞⟩ = ?
    ; cdf→[0,1] = ?
    }

Mat : ℕ → Set
Mat n = Vec (Vec ℝ n) n

-- Multivariate Normal Distribution
record MultiNormal : Set where
  constructor MultiND
  field
    n : ℕ
    μ : Vec ℝ n
    Σ : Mat n

  dist : Dist (Vec ℝ n)
  dist = record
    {
      pdf = ?
    ; cdf = ?
    ; pdf→[0,∞⟩ = ?
    ; cdf→[0,1] = ?
    }

--num : Vec ℕ 2 → ℕ
--num vec = lookup vec (fromℕ< {0} _)

--num2 : MultiNormal → ℝ
--num2 mn = lookup μ (fromℕ< {0} _)
--  where open MultiNormal mn using (n; μ; Σ) --; dist)
--        --open Dist dist using (pdf)


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

-- Co-algebras of a Functor
open import Level
open import Function using (_$_)

open import Categories.Category using (Category)
open import Categories.Functor using (Functor; Endofunctor)

record F-Coalgebra {o ℓ e} {C : Category o ℓ e} (F : Endofunctor C) : Set (o ⊔ ℓ) where
  open Category C
  field
    A : Obj
    α : A ⇒ Functor.F₀ F A

open F-Coalgebra

-- Given a F-Coalgebra F, one can apply F to it to obtain an new 'iterated' F-Coalgebra
iterate : ∀ {o ℓ e} {C : Category o ℓ e} {F : Endofunctor C} → F-Coalgebra F → F-Coalgebra F
iterate {F = F} F-alg = record { A = Functor.F₀ F $ A F-alg ; α = Functor.F₁ F $ α F-alg }


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

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

module Rings.Associates.Lemmas {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ _*_ : A → A → A} {R : Ring S _+_ _*_} (intDom : IntegralDomain R) where

open import Rings.Divisible.Definition R
open import Rings.IntegralDomains.Lemmas intDom
open import Rings.Associates.Definition intDom
open import Rings.Ideals.Definition R
open Setoid S
open Ring R
open Equivalence eq

associatesEquiv : Equivalence Associates
Equivalence.reflexive associatesEquiv {x} = 1R , ((1R , identIsIdent) ,, symmetric (transitive *Commutative identIsIdent))
Equivalence.symmetric associatesEquiv {x} {y} (a , ((invA , prInv) ,, x=ya)) = invA , ((a , transitive *Commutative prInv) ,, transitive (symmetric identIsIdent) (transitive (*WellDefined (symmetric prInv) reflexive) (transitive *Commutative (transitive *Associative (*WellDefined (symmetric x=ya) reflexive)))))
Equivalence.transitive associatesEquiv {x} {y} {z} (a , ((invA , prInvA) ,, x=ya)) (b , ((invB , prInvB) ,, y=zb)) = (a * b) , (((invA * invB) , transitive *Associative (transitive (*WellDefined (transitive *Commutative *Associative) reflexive) (transitive (symmetric *Associative) (transitive (*WellDefined (transitive *Commutative prInvA) prInvB) identIsIdent)))) ,, transitive x=ya (transitive (*WellDefined y=zb reflexive) (transitive (symmetric *Associative) (*WellDefined reflexive *Commutative))))

associateImpliesMutualDivision : {a b : A} → Associates a b → a ∣ b
associateImpliesMutualDivision {a} {b} (x , ((invX , prInvX) ,, a=bx)) = invX , transitive (transitive (*WellDefined a=bx reflexive) (transitive (transitive (symmetric *Associative) (*WellDefined reflexive prInvX)) *Commutative)) identIsIdent

mutualDivisionImpliesAssociate : {a b : A} → (a ∣ b) → (b ∣ a) → ((a ∼ 0R) → False) → Associates a b
mutualDivisionImpliesAssociate {a} {b} (r , ar=b) (s , bs=a) a!=0 = s , ((r , cancelIntDom {a = a} (transitive (transitive (transitive (*WellDefined reflexive *Commutative) (transitive *Associative (*WellDefined ar=b reflexive))) bs=a) (transitive (symmetric identIsIdent) *Commutative)) a!=0) ,, symmetric bs=a)

mutualDivisionImpliesAssociate' : {a b : A} → (a ∣ b) → (b ∣ a) → (a ∼ 0R) → Associates a b
mutualDivisionImpliesAssociate' {a} {b} (r , ar=b) (s , bs=a) a=0 = 1R , ((1R , identIsIdent) ,, transitive a=0 (symmetric (transitive (*WellDefined b=0 reflexive) (transitive *Commutative timesZero))))
  where
    b=0 : b ∼ 0R
    b=0 = transitive (symmetric ar=b) (transitive (transitive *Commutative (*WellDefined reflexive a=0)) (timesZero {r}))

associateImpliesGeneratedIdealsEqual : {a b : A} → Associates a b → {x : A} → generatedIdealPred a x → generatedIdealPred b x
associateImpliesGeneratedIdealsEqual {a} {b} (r , ((s , rs=1) ,, a=br)) {x} (c , ac=x) = (r * c) , transitive *Associative (transitive (*WellDefined (symmetric a=br) reflexive) ac=x)

associateImpliesGeneratedIdealsEqual' : {a b : A} → Associates a b → {x : A} → generatedIdealPred b x → generatedIdealPred a x
associateImpliesGeneratedIdealsEqual' assoc = associateImpliesGeneratedIdealsEqual (Equivalence.symmetric associatesEquiv assoc)


module Misc.NumeralSystem where -- One Numeral System to rule them all!?

open import Data.Maybe using (Maybe; nothing; just)
open import Data.Nat
open import Data.Product

open import Data.Unit using (⊤; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Relation.Nullary using (¬_ ; yes; no)

open import Relation.Binary

open import Level
  renaming (zero to lzero; suc to lsuc)

open import Relation.Binary.PropositionalEquality as PropEq
  using (_≡_; refl; setoid; cong)

open import Data.Nat.Properties using (≤-step)
open DecTotalOrder Data.Nat.decTotalOrder using () renaming (refl to ≤-refl; trans to ≤-trans)

infixr 5 _∷[_,_]_

--------------------------------------------------------------------------------
--  PN - Positional Notation
--  http://en.wikipedia.org/wiki/Positional_notation
--
--  base: b
--  digits: consecutive ℕ from m to n
--                             ●────○

data PN (b m n : ℕ) : Set where
  [_] : m < n → PN b m n
  _∷[_,_]_ : (x : ℕ) → (m ≤ x) → (x < n) → PN b m n → PN b m n

--------------------------------------------------------------------------------
toℕ : ∀ {b m n} → PN b m n → ℕ
toℕ [ _ ] = 0
toℕ {b} (x ∷[ x≥m , x<n ] xs) = x + b * toℕ xs

private
   ≤→< : ∀ {m n} → m ≤ n → ¬ (m ≡ n) → m < n
   ≤→< {n = zero} z≤n 0≠0 = ⊥-elim (0≠0 refl)
   ≤→< {n = suc n} z≤n neq = s≤s z≤n
   ≤→< (s≤s m≤n) 1+m≠1+n = s≤s (≤→< m≤n (λ m≡n → 1+m≠1+n (cong suc m≡n)))

--------------------------------------------------------------------------------
-- increment
-- the image of 'incr' is "continuous" if when
--    b = 1 ⇒ m ≥ 1, n ≥ 2m
--    b > 1 ⇒ m ≥ 0, n ≥ m + b, n ≥ 1 + mb

incr : ∀ {b m n} → m ≤ 1 → 2 ≤ n → PN b m n → PN b m n
incr m≤1 2≤n [ m<n ] = 1 ∷[ m≤1 , 2≤n ] [ m<n ]
incr {b} {m} {n} m≤1 2≤n (x ∷[ m≤x , x<n ] xs) with suc x ≟ n
incr {b} {m} m≤1 2≤n (x ∷[ m≤x , x<n ] xs) | no  1+x≠n = suc x ∷[ ≤-step m≤x , ≤→< x<n 1+x≠n ] xs
incr {b} {m} m≤1 2≤n (x ∷[ m≤x , x<n ] xs) | yes refl  = m ∷[ ≤-refl , s≤s m≤x ] incr m≤1 2≤n xs

base=1-incr : ∀ {m n} → 1 ≤ m → m * 2 ≤ n → PN 1 m n → PN 1 m n
base=1-incr {m} {n} 1≤m 2m≤n [ m<n ] = m ∷[ ≤-refl , m<n ] [ m<n ]
base=1-incr {m} {n} 1≤m 2m≤n (x ∷[ m≤x , x<n ] xs) with suc x ≟ n
base=1-incr {m} {n} 1≤m 2m≤n (x ∷[ m≤x , x<n ] xs) | no 1+x≠n = suc x ∷[ ≤-step m≤x , ≤→< x<n 1+x≠n ] xs
base=1-incr {m} 1≤m 2m≤n (x ∷[ m≤x , x<n ] xs) | yes refl = m ∷[ ≤-refl , s≤s m≤x ] base=1-incr 1≤m 2m≤n xs

base>1-incr : ∀ {b m n} → 1 < b → 0 ≤ m → m + b ≤ n → m * b + 1 ≤ n → PN b m n → PN b m n
base>1-incr {b} {m} {n} 1<b 0≤m m+b≤n mb+1≤n [ m<n ] = m ∷[ ≤-refl , m<n ] [ m<n ]
base>1-incr {b} {m} {n} 1<b 0≤m m+b≤n mb+1≤n (x ∷[ m≤x , x<n ] xs) with suc x ≟ n
base>1-incr {b} {m} {n} 1<b 0≤m m+b≤n mb+1≤n (x ∷[ m≤x , x<n ] xs) | no 1+x≠n = suc x ∷[ ≤-step m≤x , ≤→< x<n 1+x≠n ] xs
base>1-incr {b} {m} 1<b 0≤m m+b≤n mb+1≤n (x ∷[ m≤x , x<n ] xs) | yes refl = m ∷[ ≤-refl , s≤s m≤x ] base>1-incr 1<b 0≤m m+b≤n mb+1≤n xs

--
--   A ── incr ⟶ A'
--   |             |
--  toℕ           toℕ
--   ↓             ↓
--   n ── suc ⟶ suc n
--

-- first attempt :p
-- unary-toℕ-hom : (a : PN 1 1 2) → suc (toℕ a) ≡ toℕ (base=1-incr (s≤s z≤n) (s≤s (s≤s z≤n)) a)
-- unary-toℕ-hom [ m<n ] = refl
-- unary-toℕ-hom (zero ∷[ () , x<n ] xs)
-- unary-toℕ-hom (suc zero ∷[ m≤x , x<n ] xs) = cong suc {!   !}
-- unary-toℕ-hom (suc (suc x) ∷[ m≤x , s≤s (s≤s ()) ] xs)

--------------------------------------------------------------------------------
--  Instances

private
  -- Unary
  Unary : Set
  Unary = PN 1 1 2

  u₀ : Unary
  u₀ = 1 ∷[ s≤s z≤n , s≤s (s≤s z≤n) ] 1 ∷[ s≤s z≤n , s≤s (s≤s z≤n) ] [ s≤s (s≤s z≤n) ]

  -- Binary
  Bin : Set
  Bin = PN 2 0 2

  b₀ : Bin
  b₀ = 1 ∷[ z≤n , s≤s (s≤s z≤n) ] 0 ∷[ z≤n , s≤s z≤n ] [ s≤s z≤n ]

  -- Zeroless Binary
  Bin+ : Set
  Bin+ = PN 2 1 3


module Golden.Factorial where

open import Agda.Builtin.Nat

fac : Nat -> Nat
fac 0 = 1
fac (suc n) = suc n * fac n

a = fac 0
b = fac 10


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

open import Groups.Definition
open import Setoids.Setoids
open import Setoids.Orders.Partial.Definition
open import Functions.Definition
open import Rings.Definition

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

module Rings.Orders.Partial.Definition {n m : _} {A : Set n} {S : Setoid {n} {m} A} {_+_ : A → A → A} {_*_ : A → A → A} (R : Ring S _+_ _*_) where

open Ring R
open Group additiveGroup
open Setoid S
open import Groups.Orders.Partial.Definition

record PartiallyOrderedRing {p : _} {_<_ : Rel {_} {p} A} (pOrder : SetoidPartialOrder S _<_) : Set (lsuc n ⊔ m ⊔ p) where
  field
    orderRespectsAddition : {a b : A} → (a < b) → (c : A) → (a + c) < (b + c)
    orderRespectsMultiplication : {a b : A} → (0R < a) → (0R < b) → (0R < (a * b))
  open SetoidPartialOrder pOrder

toGroup : {p : _} {_<_ : Rel {_} {p} A} {pOrder : SetoidPartialOrder S _<_} → PartiallyOrderedRing pOrder → PartiallyOrderedGroup additiveGroup pOrder
PartiallyOrderedGroup.orderRespectsAddition (toGroup p) = PartiallyOrderedRing.orderRespectsAddition p


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

open import Categories.Category

-- the usual notion requires C to have finite limits.
-- this definition is a generalization by omitting that requirement as the definition
-- itself does not involve any limit.
module Categories.Diagram.SubobjectClassifier {o ℓ e} (C : Category o ℓ e) where

open Category C

open import Level

open import Categories.Object.Terminal C
open import Categories.Morphism C
open import Categories.Diagram.Pullback C

record SubobjectClassifier : Set (o ⊔ ℓ ⊔ e) where
  field
    Ω        : Obj
    terminal : Terminal

  module terminal = Terminal terminal
  open terminal

  field
    true      : ⊤ ⇒ Ω
    universal : ∀ {X Y} {f : X ⇒ Y} → Mono f → Y ⇒ Ω
    pullback  : ∀ {X Y} {f : X ⇒ Y} {mono : Mono f} → Pullback (universal mono) true
    unique    : ∀ {X Y} {f : X ⇒ Y} {g} {mono : Mono f} → Pullback g true → universal mono ≈ g


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

open import LogicalFormulae
open import Groups.Definition
open import Groups.Abelian.Definition
open import Groups.FiniteGroups.Definition
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Numbers.Naturals.Order.Lemmas
open import Setoids.Setoids
open import Sets.FinSet.Definition
open import Sets.FinSet.Lemmas
open import Functions.Definition
open import Functions.Lemmas
open import Semirings.Definition
open import Numbers.Modulo.Definition
open import Numbers.Modulo.Addition
open import Orders.Total.Definition
open import Numbers.Modulo.ModuloFunction

module Numbers.Modulo.Group where

open TotalOrder ℕTotalOrder
open Semiring ℕSemiring

private
  0<s : {n : ℕ} → 0 <N succ n
  0<s {n} = le n (applyEquality succ (Semiring.sumZeroRight ℕSemiring n))

  inverseN : {n : ℕ} → .(0<n : 0 <N n) → (x : ℤn n 0<n) → ℤn n 0<n
  inverseN 0<n record { x = 0 ; xLess = _ } = record { x = 0 ; xLess = 0<n }
  inverseN 0<n record { x = succ x ; xLess = xLess } with <NProp xLess
  ... | le subtr pr = record { x = succ subtr ; xLess = le x (transitivity (commutative (succ x) (succ subtr)) pr) }

  invLeft : {n : ℕ} → .(0<n : 0 <N n) → (x : ℤn n 0<n) → _+n_ 0<n (inverseN 0<n x) x ≡ record { x = 0 ; xLess = 0<n }
  invLeft {n} 0<n record { x = 0 ; xLess = xLess } = plusZnIdentityLeft 0<n (record { x = 0 ; xLess = 0<n })
  invLeft {n} 0<n record { x = (succ x) ; xLess = xLess } with <NProp xLess
  ... | le subtr pr rewrite pr = equalityZn (modN 0<n)

ℤnGroup : (n : ℕ) → .(pr : 0 <N n) → Group (reflSetoid (ℤn n pr)) (_+n_ pr)
Group.+WellDefined (ℤnGroup n 0<n) refl refl = refl
Group.0G (ℤnGroup n 0<n) = record { x = 0 ; xLess = 0<n }
Group.inverse (ℤnGroup n 0<n) = inverseN 0<n
Group.+Associative (ℤnGroup n 0<n) {a} {b} {c} = equalityCommutative (plusZnAssociative 0<n a b c)
Group.identRight (ℤnGroup n 0<n) {a} = plusZnIdentityRight 0<n a
Group.identLeft (ℤnGroup n 0<n) {a} = plusZnIdentityLeft 0<n a
Group.invLeft (ℤnGroup n 0<n) {a} = invLeft 0<n a
Group.invRight (ℤnGroup n 0<n) {a} = transitivity (plusZnCommutative 0<n a (inverseN 0<n a)) (invLeft 0<n a)

ℤnAbGroup : (n : ℕ) → (pr : 0 <N n) → AbelianGroup (ℤnGroup n pr)
AbelianGroup.commutative (ℤnAbGroup n pr) {a} {b} = plusZnCommutative pr a b

ℤnFinite : (n : ℕ) → (pr : 0 <N n) → FiniteGroup (ℤnGroup n pr) (FinSet n)
SetoidToSet.project (FiniteGroup.toSet (ℤnFinite (succ n) 0<n)) record { x = x ; xLess = xLess } = ofNat x xLess
SetoidToSet.wellDefined (FiniteGroup.toSet (ℤnFinite (succ n) 0<n)) x y x=y rewrite x=y = refl
SetoidToSet.surj (FiniteGroup.toSet (ℤnFinite (succ n) 0<n)) b = record { x = toNat b ; xLess = toNatSmaller b } , ofNatToNat b
SetoidToSet.inj (FiniteGroup.toSet (ℤnFinite (succ n) 0<n)) record { x = x ; xLess = xLess } record { x = y ; xLess = yLess } eq = equalityZn (ofNatInjective x y xLess yLess eq)
FiniteGroup.finite (ℤnFinite n pr) = record { size = n ; mapping = id ; bij = idIsBijective }


------------------------------------------------------------------------
-- A derivative operator for parsers
------------------------------------------------------------------------

-- Similar to the derivative operator in Brzozowski's "Derivatives of
-- Regular Expressions".

module TotalParserCombinators.Derivative where

-- Definition of the derivative.

open import TotalParserCombinators.Derivative.Definition public

-- The derivative operator is sound and complete with respect to the
-- semantics.

open import TotalParserCombinators.Derivative.SoundComplete public
  hiding (complete′)

-- A proof showing that the derivative operator does not introduce any
-- unneeded ambiguity.

open import TotalParserCombinators.Derivative.LeftInverse public

-- A proof showing that the derivative operator does not remove any
-- ambiguity.

open import TotalParserCombinators.Derivative.RightInverse public
  hiding (sound∘complete′)

-- Some corollaries.

open import TotalParserCombinators.Derivative.Corollaries public


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

open import Categories.Category.Core

module Categories.Morphism.Regular.Properties {o ℓ e} (𝒞 : Category o ℓ e) where

open import Categories.Morphism 𝒞
open import Categories.Morphism.Regular 𝒞
open import Categories.Diagram.Equalizer 𝒞
open import Categories.Diagram.Equalizer.Properties 𝒞
open import Categories.Diagram.Coequalizer.Properties 𝒞

open Category 𝒞

private
  variable
    A B : Obj
    f g : A ⇒ B

Section⇒RegularMono : f SectionOf g → RegularMono f
Section⇒RegularMono {f = f} {g = g} g∘f≈id = record
  { g = id
  ; h = f ∘ g
  ; equalizer = section-equalizer g∘f≈id
  }

Retract⇒RegularEpi : f RetractOf g → RegularEpi f
Retract⇒RegularEpi {f = f} {g = g} f∘g≈id = record
  { h = g ∘ f
  ; g = id
  ; coequalizer = retract-coequalizer f∘g≈id
  }


module lambda.untyped where

open import Data.Nat
open import Data.Fin hiding (lift)

data term (n : ℕ) : Set where
  lam : term (suc n) → term n
  var : Fin n → term n
  app : term n → term n → term n

data norm {n : ℕ} : term n → Set
data neut {n : ℕ} : term n → Set

data norm {n} where
  lam : {x : term (suc n)} → norm x → norm (lam x)
  gnd : {x : term n} → neut x → norm x

data neut {n} where
  var : {i : Fin n} → neut (var i)
  app : {x y : term n} → neut x → norm y → neut (app x y)

lift : ∀ {n} → term n → term (suc n)
lift (lam x) = lam (lift x)
lift (var i) = var (suc i)
lift (app x y) = app (lift x) (lift y)

lift₁ : ∀ {n} → term (suc n) → term (suc (suc n))
lift₁ (lam x) = lam (lift₁ x)
lift₁ (var zero) = var zero
lift₁ (var (suc i)) = var (suc (suc i))
lift₁ (app x y) = app (lift₁ x) (lift₁ y)

↑ : ∀ {n m} → (Fin n → term m) → Fin (suc n) → term (suc m)
↑ ρ zero = var zero
↑ ρ (suc i) = lift (ρ i)

subst : ∀ {n m} → term n → (Fin n → term m) → term m
subst (lam x) ρ = lam (subst x (↑ ρ))
subst (var i) ρ = ρ i
subst (app x y) ρ = app (subst x ρ) (subst y ρ)

subst₁ : ∀ {n} → term (suc n) → term n → term n
subst₁ x y = subst x (λ {zero → y; (suc i) → var i})

data _→β_ {n : ℕ} : term n → term n → Set where
  β-beta : ∀ {x y} → app (lam x) y →β subst₁ x y
  β-app₁ : ∀ {x y z} → x →β y → app x z →β app y z
  β-app₂ : ∀ {x y z} → y →β z → app x y →β app x z
  β-lam : ∀ {x y} → x →β y → lam x →β lam y

data _β*_ {n : ℕ} : term n → term n → Set where
  ε : ∀ {x} → x β* x
  _←_ : ∀ {x y z} → x →β y → y β* z → x β* z


open import Oscar.Prelude
open import Oscar.Class.Reflexivity
open import Oscar.Class.Symmetry
open import Oscar.Class.Transitivity

module Oscar.Class.IsEquivalence where

record IsEquivalence
  {𝔬} {𝔒 : Ø 𝔬}
  {ℓ} (_≈_ : 𝔒 → 𝔒 → Ø ℓ)
  : Ø 𝔬 ∙̂ ℓ where
  constructor ∁
  field
    ⦃ `𝓡eflexivity ⦄ : Reflexivity.class _≈_
    ⦃ `𝓢ymmetry ⦄ : Symmetry.class _≈_
    ⦃ `𝓣ransitivity  ⦄ : Transitivity.class _≈_


{-# OPTIONS --rewriting --confluence-check #-}

open import Agda.Builtin.Nat using (Nat; zero; suc)
open import Agda.Builtin.Equality
open import Agda.Builtin.Equality.Rewrite

variable
  k l m n : Nat

postulate
  max : Nat → Nat → Nat
  max-0l : max 0 n ≡ n
  max-0r : max m 0 ≡ m
  max-diag : max m m ≡ m
  max-ss : max (suc m) (suc n) ≡ suc (max m n)
  max-diag-s : max (suc m) (suc m) ≡ suc m -- for global confluence
  max-assoc : max (max k l) m ≡ max k (max l m)

{-# REWRITE max-0l max-0r #-}
{-# REWRITE max-ss max-diag max-diag-s #-}
--{-# REWRITE max-assoc #-} -- not confluent!

postulate
  _+_ : Nat → Nat → Nat
  plus-0l : 0 + n ≡ n
  plus-0r : m + 0 ≡ m
  plus-00 : 0 + 0 ≡ 0  -- for global confluence
  plus-suc-l : (suc m) + n ≡ suc (m + n)
  plus-suc-0 : (suc m) + 0 ≡ suc m -- for global confluence
  plus-suc-r : m + (suc n) ≡ suc (m + n)
  plus-0-suc : 0 + (suc n) ≡ suc n
  plus-suc-suc : (suc m) + (suc n) ≡ suc (suc (m + n))
  plus-assoc : (k + l) + m ≡ k + (l + m) -- not accepted by global confluence check

{-# REWRITE plus-00 plus-0l plus-0r
            plus-suc-l plus-suc-0
            plus-suc-r plus-0-suc
            plus-suc-suc #-}

postulate
  _*_ : Nat → Nat → Nat
  mult-0l : 0 * n ≡ 0
  mult-0r : m * 0 ≡ 0
  mult-00 : 0 * 0 ≡ 0
  mult-suc-l : (suc m) * n ≡ n + (m * n)
  mult-suc-l-0 : (suc m) * 0 ≡ 0
  mult-suc-r : m * (suc n) ≡ (m * n) + m
  plus-mult-distr-l : k * (l + m) ≡ (k * l) + (k * m)
  plus-mult-distr-r : (k + l) * m ≡ (k * m) + (l * m)
  mult-assoc : (k * l) * m ≡ k * (l * m)

{-# REWRITE mult-0l mult-0r mult-00
            mult-suc-l mult-suc-l-0 #-}
--{-# REWRITE mult-suc-r #-} -- requires rule plus-assoc!
--{-# REWRITE plus-mult-distr-l #-}
--{-# REWRITE plus-mult-distr-r #-}
--{-# REWRITE mult-assoc #-}


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

open import Categories.Category
open import Categories.Functor.Bifunctor

module Categories.Diagram.End {o ℓ e o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′}
  (F : Bifunctor (Category.op C) C D) where

private
  module D = Category D
  open D
  open HomReasoning
  open Equiv
  variable
    A B : Obj
    f g : A ⇒ B

open import Level

open import Categories.Diagram.Wedge F
open import Categories.NaturalTransformation.Dinatural

record End : Set (levelOfTerm F) where
  field
    wedge : Wedge

  module wedge = Wedge wedge
  open wedge public
  open Wedge

  field
    factor    : (W : Wedge) → E W ⇒ wedge.E
    universal : ∀ {W : Wedge} {A} → wedge.dinatural.α A ∘ factor W ≈ dinatural.α W A
    unique    : ∀ {W : Wedge} {g : E W ⇒ wedge.E} → (∀ {A} → wedge.dinatural.α A ∘ g ≈ dinatural.α W A) → factor W ≈ g

  η-id : factor wedge ≈ D.id
  η-id = unique identityʳ

  unique′ :(∀ {A} → wedge.dinatural.α A ∘ f ≈ wedge.dinatural.α A ∘ g) → f ≈ g
  unique′ {f = f} {g = g} eq = ⟺ (unique {W = Wedge-∘ wedge f} refl) ○ unique (⟺ eq)


module Cats.Trans where

open import Level using (_⊔_)

open import Cats.Category.Base
open import Cats.Functor using (Functor)

open Functor

module _ {lo la l≈ lo′ la′ l≈′}
  {C : Category lo la l≈} {D : Category lo′ la′ l≈′}
  where

  infixr 9 _∘_

  private
    module C = Category C
    module D = Category D
    open D.≈-Reasoning

  record Trans (F G : Functor C D) : Set (lo ⊔ la ⊔ la′ ⊔ l≈′) where
    field
      component : (c : C.Obj) → fobj F c D.⇒ fobj G c
      natural : ∀ {c d} {f : c C.⇒ d}
        → component d D.∘ fmap F f D.≈ fmap G f D.∘ component c

  open Trans public

  id : ∀ {F} → Trans F F
  id {F} = record
      { component = λ _ → D.id
      ; natural = D.≈.trans D.id-l (D.≈.sym D.id-r)
      }

  _∘_ : ∀ {F G H} → Trans G H → Trans F G → Trans F H
  _∘_ {F} {G} {H} θ ι = record
      { component = λ c → component θ c D.∘ component ι c
      ; natural = λ {c} {d} {f} →
          begin
            (component θ d D.∘ component ι d) D.∘ fmap F f
          ≈⟨ D.assoc ⟩
            component θ d D.∘ component ι d D.∘ fmap F f
          ≈⟨ D.∘-resp-r (natural ι) ⟩
            component θ d D.∘ fmap G f D.∘ component ι c
          ≈⟨ D.unassoc ⟩
            (component θ d D.∘ fmap G f) D.∘ component ι c
          ≈⟨ D.∘-resp-l (natural θ)  ⟩
            (fmap H f D.∘ component θ c) D.∘ component ι c
          ≈⟨ D.assoc ⟩
            fmap H f D.∘ component θ c D.∘ component ι c
          ∎
      }


module Functional.Combinations where

open import Type

-- TODO: Generalize these. Probably by lists and foldᵣ of combination and rotation construction functions. Also categorically or dependently
rotate₃Fn₃Op₂ : ∀{ℓ₁ ℓ₂}{A : Type{ℓ₁}}{B : Type{ℓ₂}} → (A → A → A → B) → (B → B → B) → (A → A → A → B)
rotate₃Fn₃Op₂(F)(_▫_) a b c = (F a b c) ▫ ((F b c a) ▫ (F c a b))

combine₃Fn₂Op₂ : ∀{ℓ₁ ℓ₂}{A : Type{ℓ₁}}{B : Type{ℓ₂}} → (A → A → B) → (B → B → B) → (A → A → A → B)
combine₃Fn₂Op₂(F)(_▫_) a b c = (F a b) ▫ ((F a c) ▫ (F b c))

all₃Fn₁Op₂ : ∀{ℓ₁ ℓ₂}{A : Type{ℓ₁}}{B : Type{ℓ₂}} → (A → B) → (B → B → B) → (A → A → A → B)
all₃Fn₁Op₂(F)(_▫_) a b c = (F a) ▫ ((F b) ▫ (F c))

combine₄Fn₃Op₂ : ∀{ℓ₁ ℓ₂}{A : Type{ℓ₁}}{B : Type{ℓ₂}} → (A → A → A → B) → (B → B → B) → (A → A → A → A → B)
combine₄Fn₃Op₂(F)(_▫_) a b c d = (F a b c) ▫ ((F a b d) ▫ ((F a c d) ▫ (F b c d)))