------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties related to negation
------------------------------------------------------------------------

module Relation.Nullary.Negation where

open import Relation.Nullary
open import Relation.Unary
open import Data.Bool
open import Data.Empty
open import Function
open import Data.Product as Prod
open import Data.Fin using (Fin)
open import Data.Fin.Dec
open import Data.Sum as Sum
open import Category.Monad
open import Level

contradiction : ∀ {p w} {P : Set p} {Whatever : Set w} →
                P → ¬ P → Whatever
contradiction p ¬p = ⊥-elim (¬p p)

contraposition : ∀ {p q} {P : Set p} {Q : Set q} →
                 (P → Q) → ¬ Q → ¬ P
contraposition f ¬q p = contradiction (f p) ¬q

-- Note also the following use of flip:

private
  note : ∀ {p q} {P : Set p} {Q : Set q} →
         (P → ¬ Q) → Q → ¬ P
  note = flip

-- If we can decide P, then we can decide its negation.

¬? : ∀ {p} {P : Set p} → Dec P → Dec (¬ P)
¬? (yes p) = no (λ ¬p → ¬p p)
¬? (no ¬p) = yes ¬p

------------------------------------------------------------------------
-- Quantifier juggling

∃⟶¬∀¬ : ∀ {a p} {A : Set a} {P : A → Set p} →
        ∃ P → ¬ (∀ x → ¬ P x)
∃⟶¬∀¬ = flip uncurry

∀⟶¬∃¬ : ∀ {a p} {A : Set a} {P : A → Set p} →
        (∀ x → P x) → ¬ ∃ λ x → ¬ P x
∀⟶¬∃¬ ∀xPx (x , ¬Px) = ¬Px (∀xPx x)

¬∃⟶∀¬ : ∀ {a p} {A : Set a} {P : A → Set p} →
        ¬ ∃ (λ x → P x) → ∀ x → ¬ P x
¬∃⟶∀¬ = curry

∀¬⟶¬∃ : ∀ {a p} {A : Set a} {P : A → Set p} →
        (∀ x → ¬ P x) → ¬ ∃ (λ x → P x)
∀¬⟶¬∃ = uncurry

∃¬⟶¬∀ : ∀ {a p} {A : Set a} {P : A → Set p} →
        ∃ (λ x → ¬ P x) → ¬ (∀ x → P x)
∃¬⟶¬∀ = flip ∀⟶¬∃¬

-- When P is a decidable predicate over a finite set the following
-- lemma can be proved.

¬∀⟶∃¬ : ∀ n {p} (P : Fin n → Set p) → Decidable P →
        ¬ (∀ i → P i) → ∃ λ i → ¬ P i
¬∀⟶∃¬ n P dec ¬P = Prod.map id proj₁ $ ¬∀⟶∃¬-smallest n P dec ¬P

------------------------------------------------------------------------
-- Double-negation

¬¬-map : ∀ {p q} {P : Set p} {Q : Set q} →
         (P → Q) → ¬ ¬ P → ¬ ¬ Q
¬¬-map f = contraposition (contraposition f)

-- Stability under double-negation.

Stable : ∀ {ℓ} → Set ℓ → Set ℓ
Stable P = ¬ ¬ P → P

-- Everything is stable in the double-negation monad.

stable : ∀ {p} {P : Set p} → ¬ ¬ Stable P
stable ¬[¬¬p→p] = ¬[¬¬p→p] (λ ¬¬p → ⊥-elim (¬¬p (¬[¬¬p→p] ∘ const)))

-- Negated predicates are stable.

negated-stable : ∀ {p} {P : Set p} → Stable (¬ P)
negated-stable ¬¬¬P P = ¬¬¬P (λ ¬P → ¬P P)

-- Decidable predicates are stable.

decidable-stable : ∀ {p} {P : Set p} → Dec P → Stable P
decidable-stable (yes p) ¬¬p = p
decidable-stable (no ¬p) ¬¬p = ⊥-elim (¬¬p ¬p)

¬-drop-Dec : ∀ {p} {P : Set p} → Dec (¬ ¬ P) → Dec (¬ P)
¬-drop-Dec (yes ¬¬p) = no ¬¬p
¬-drop-Dec (no ¬¬¬p) = yes (negated-stable ¬¬¬p)

-- Double-negation is a monad (if we assume that all elements of ¬ ¬ P
-- are equal).

¬¬-Monad : ∀ {p} → RawMonad (λ (P : Set p) → ¬ ¬ P)
¬¬-Monad = record
  { return = contradiction
  ; _>>=_  = λ x f → negated-stable (¬¬-map f x)
  }

¬¬-push : ∀ {p q} {P : Set p} {Q : P → Set q} →
          ¬ ¬ ((x : P) → Q x) → (x : P) → ¬ ¬ Q x
¬¬-push ¬¬P⟶Q P ¬Q = ¬¬P⟶Q (λ P⟶Q → ¬Q (P⟶Q P))

-- A double-negation-translated variant of excluded middle (or: every
-- nullary relation is decidable in the double-negation monad).

excluded-middle : ∀ {p} {P : Set p} → ¬ ¬ Dec P
excluded-middle ¬h = ¬h (no (λ p → ¬h (yes p)))

-- If Whatever is instantiated with ¬ ¬ something, then this function
-- is call with current continuation in the double-negation monad, or,
-- if you will, a double-negation translation of Peirce's law.
--
-- In order to prove ¬ ¬ P one can assume ¬ P and prove ⊥. However,
-- sometimes it is nice to avoid leaving the double-negation monad; in
-- that case this function can be used (with Whatever instantiated to
-- ⊥).

call/cc : ∀ {w p} {Whatever : Set w} {P : Set p} →
          ((P → Whatever) → ¬ ¬ P) → ¬ ¬ P
call/cc hyp ¬p = hyp (λ p → ⊥-elim (¬p p)) ¬p

-- The "independence of premise" rule, in the double-negation monad.
-- It is assumed that the index set (Q) is inhabited.

independence-of-premise
  : ∀ {p q r} {P : Set p} {Q : Set q} {R : Q → Set r} →
    Q → (P → Σ Q R) → ¬ ¬ (Σ[ x ∈ Q ] (P → R x))
independence-of-premise {P = P} q f = ¬¬-map helper excluded-middle
  where
  helper : Dec P → _
  helper (yes p) = Prod.map id const (f p)
  helper (no ¬p) = (q , ⊥-elim ∘′ ¬p)

-- The independence of premise rule for binary sums.

independence-of-premise-⊎
  : ∀ {p q r} {P : Set p} {Q : Set q} {R : Set r} →
    (P → Q ⊎ R) → ¬ ¬ ((P → Q) ⊎ (P → R))
independence-of-premise-⊎ {P = P} f = ¬¬-map helper excluded-middle
  where
  helper : Dec P → _
  helper (yes p) = Sum.map const const (f p)
  helper (no ¬p) = inj₁ (⊥-elim ∘′ ¬p)

private

  -- Note that independence-of-premise-⊎ is a consequence of
  -- independence-of-premise (for simplicity it is assumed that Q and
  -- R have the same type here):

  corollary : ∀ {p ℓ} {P : Set p} {Q R : Set ℓ} →
              (P → Q ⊎ R) → ¬ ¬ ((P → Q) ⊎ (P → R))
  corollary {P = P} {Q} {R} f =
    ¬¬-map helper (independence-of-premise
                     true ([ _,_ true , _,_ false ] ∘′ f))
    where
    helper : ∃ (λ b → P → if b then Q else R) → (P → Q) ⊎ (P → R)
    helper (true  , f) = inj₁ f
    helper (false , f) = inj₂ f

-- The classical statements of excluded middle and double-negation
-- elimination.

Excluded-Middle : (ℓ : Level) → Set (suc ℓ)
Excluded-Middle p = {P : Set p} → Dec P

Double-Negation-Elimination : (ℓ : Level) → Set (suc ℓ)
Double-Negation-Elimination p = {P : Set p} → Stable P

private

  -- The two statements above are equivalent. The proofs are so
  -- simple, given the definitions above, that they are not exported.

  em⇒dne : ∀ {ℓ} → Excluded-Middle ℓ → Double-Negation-Elimination ℓ
  em⇒dne em = decidable-stable em

  dne⇒em : ∀ {ℓ} → Double-Negation-Elimination ℓ → Excluded-Middle ℓ
  dne⇒em dne = dne excluded-middle


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

open import Cubical.Core.Everything

open import Cubical.Foundations.Prelude

data Interval : Type₀ where
  zero : Interval
  one  : Interval
  seg  : zero ≡ one

isContrInterval : isContr Interval
isContrInterval = (zero , (λ x → rem x))
  where
  rem : (x : Interval) → zero ≡ x
  rem zero      = refl
  rem one       = seg
  rem (seg i) j = seg (i ∧ j)

funExtInterval : ∀ {ℓ} (A B : Type ℓ) (f g : A → B) → ((x : A) → f x ≡ g x) → f ≡ g
funExtInterval A B f g p = λ i x → hmtpy x (seg i)
  where
  hmtpy : A → Interval → B
  hmtpy x zero    = f x
  hmtpy x one     = g x
  hmtpy x (seg i) = p x i

intervalElim : (A : Interval → Type₀) (x : A zero) (y : A one)
               (p : PathP (λ i → A (seg i)) x y) → (x : Interval) → A x
intervalElim A x y p zero    = x
intervalElim A x y p one     = y
intervalElim A x y p (seg i) = p i

-- Note that this is not definitional (it is not proved by refl)
intervalEta : ∀ {A : Type₀} (f : Interval → A) → intervalElim _ (f zero) (f one) (λ i → f (seg i)) ≡ f
intervalEta f i zero    = f zero
intervalEta f i one     = f one
intervalEta f i (seg j) = f (seg j)


{-# OPTIONS --no-exact-split --safe #-}
module Cubical.Data.Nat.Base where

open import Cubical.Core.Primitives

open import Agda.Builtin.Nat public
  using (zero; suc; _+_)
  renaming (Nat to ℕ; _-_ to _∸_; _*_ to _·_)

open import Cubical.Data.Nat.Literals public
open import Cubical.Data.Bool.Base
open import Cubical.Data.Sum.Base hiding (elim)
open import Cubical.Data.Empty.Base hiding (elim)
open import Cubical.Data.Unit.Base

predℕ : ℕ → ℕ
predℕ zero = zero
predℕ (suc n) = n

caseNat : ∀ {ℓ} → {A : Type ℓ} → (a0 aS : A) → ℕ → A
caseNat a0 aS zero    = a0
caseNat a0 aS (suc n) = aS

doubleℕ : ℕ → ℕ
doubleℕ zero = zero
doubleℕ (suc x) = suc (suc (doubleℕ x))

-- doublesℕ n m = 2^n · m
doublesℕ : ℕ → ℕ → ℕ
doublesℕ zero m = m
doublesℕ (suc n) m = doublesℕ n (doubleℕ m)

-- iterate
iter : ∀ {ℓ} {A : Type ℓ} → ℕ → (A → A) → A → A
iter zero f z    = z
iter (suc n) f z = f (iter n f z)

elim : ∀ {ℓ} {A : ℕ → Type ℓ}
  → A zero
  → ((n : ℕ) → A n → A (suc n))
  → (n : ℕ) → A n
elim a₀ _ zero = a₀
elim a₀ f (suc n) = f n (elim a₀ f n)

isEven isOdd : ℕ → Bool
isEven zero = true
isEven (suc n) = isOdd n
isOdd zero = false
isOdd (suc n) = isEven n

--Typed version
private
  toType : Bool → Type
  toType false = ⊥
  toType true = Unit

isEvenT : ℕ → Type
isEvenT n = toType (isEven n)

isOddT : ℕ → Type
isOddT n = isEvenT (suc n)

isZero : ℕ → Bool
isZero zero = true
isZero (suc n) = false

-- exponential

_^_ : ℕ → ℕ → ℕ
m ^ 0 = 1
m ^ (suc n) = m · m ^ n


module ReasoningEx where

open import Prelude
open import T
open import Contexts
open import Eq
open import Eq.Theory
open import Eq.ObsTheory

---- some example programs
-- boy, de bruijn indexes are unreadable
w = weaken-closed

plus-rec : ∀{Γ} → TExp Γ nat → TExp Γ nat → TExp Γ nat
plus-rec n m = rec n m (suc (var Z))

t-plus1 : TCExp (nat ⇒ nat ⇒ nat)
t-plus1 = Λ (Λ (plus-rec (var Z) (var (S Z))))
t-plus2 : TCExp (nat ⇒ nat ⇒ nat)
t-plus2 = Λ (Λ (plus-rec (var (S Z)) (var Z)))

plus-adds : ∀{Γ} → (n : Nat) (m : Nat) →
            Γ ⊢ plus-rec (t-numeral n) (t-numeral m) ≅ t-numeral (n +n m) :: nat
plus-adds Z m = obs-contains-def def-rec-z
plus-adds {Γ} (S n) m with
  (def-rec-s {Γ} {e = (t-numeral n)} {e0 = t-numeral m} {es = suc (var Z)})
-- If I don't name the def eq thing above and use it directly, agda uses all my core.
... | bullshit-workaround with obs-contains-def bullshit-workaround
... | step-eq with obs-congruence (plus-adds {Γ} n m) (suc ∘)
... | reccase = obs-trans step-eq reccase

help : (n : Nat) → ObservEq (nat :: []) nat
                   (rec (t-numeral n) (var Z) (suc (var Z)))
                   (rec (var Z) (t-numeral n) (suc (var Z)))
help n = {!!}

plus-commutes : [] ⊢ t-plus1 ≅ t-plus2 :: nat ⇒ nat ⇒ nat
plus-commutes with
  def-cong (def-beta {e = Λ (plus-rec (var Z) (var (S Z)))} {e' = var (S Z)}) (∘ $e var Z) |
  def-cong (def-beta {e = Λ (plus-rec (var (S Z)) (var Z))} {e' = var (S Z)}) (∘ $e var Z)
... | beq1 | beq2 with def-beta {e = plus-rec (var Z) (var (S (S Z)))} {e' = var Z} |
                       def-beta {e = plus-rec (var (S (S Z))) (var Z)} {e' = var Z}
... | beq1' | beq2' with obs-contains-def (def-trans beq1 beq1') | obs-contains-def (def-trans beq2 beq2')
... | oeq1 | oeq2 with function-induction-obs help
... | main-eq with obs-trans oeq1 (obs-trans main-eq (obs-sym oeq2))
... | lol = function-ext-obs (function-ext-obs lol)


module Prelude where
  open import Agda.Primitive using (Level; lzero; lsuc) renaming (_⊔_ to lmax)

  -- empty type
  data ⊥ : Set where

  -- from false, derive whatever
  abort : ∀ {C : Set} → ⊥ → C
  abort ()

  -- unit
  data ⊤ : Set where
    <> : ⊤

  -- sums
  data _+_ (A B : Set) : Set where
    Inl : A → A + B
    Inr : B → A + B

  -- pairs
  infixr 1 _,_
  record Σ {l1 l2 : Level} (A : Set l1) (B : A → Set l2) : Set (lmax l1 l2) where
    constructor _,_
    field
      π1 : A
      π2 : B π1
  open Σ public

  -- Sigma types, or dependent pairs, with nice notation.
  syntax Σ A (\ x -> B) = Σ[ x ∈ A ] B

  _×_ : {l1 : Level} {l2 : Level} → (Set l1) → (Set l2) → Set (lmax l1 l2)
  A × B = Σ A λ _ → B

  infixr 1 _×_
  infixr 1 _+_

  -- equality
  data _==_ {l : Level} {A : Set l} (M : A) : A → Set l where
    refl : M == M

  infixr 9 _==_

  -- disequality
  _≠_ : {l : Level} {A : Set l} → (a b : A) → Set l
  a ≠ b = (a == b) → ⊥

  {-# BUILTIN EQUALITY _==_ #-}

  -- transitivity of equality
  _·_ : {l : Level} {α : Set l} {x y z : α} → x == y → y == z → x == z
  refl · refl = refl

  -- symmetry of equality
  ! : {l : Level} {α : Set l} {x y : α} → x == y → y == x
  ! refl = refl

  -- ap, in the sense of HoTT, that all functions respect equality in their
  -- arguments. named in a slightly non-standard way to avoid naming
  -- clashes with hazelnut constructors.
  ap1 : {l1 l2 : Level} {α : Set l1} {β : Set l2} {x y : α} (F : α → β)
          → x == y → F x == F y
  ap1 F refl = refl

  -- transport, in the sense of HoTT, that fibrations respect equality
  tr : {l1 l2 : Level} {α : Set l1} {x y : α}
                    (B : α → Set l2)
                    → x == y
                    → B x
                    → B y
  tr B refl x₁ = x₁

  -- options
  data Maybe (A : Set) : Set where
    Some : A → Maybe A
    None : Maybe A

  -- the some constructor is injective. perhaps unsurprisingly.
  someinj : {A : Set} {x y : A} → Some x == Some y → x == y
  someinj refl = refl

  --  some isn't none.
  somenotnone : {A : Set} {x : A} → Some x == None → ⊥
  somenotnone ()

  -- function extensionality, used to reason about contexts as finite
  -- functions.
  postulate
     funext : {A : Set} {B : A → Set} {f g : (x : A) → (B x)} →
              ((x : A) → f x == g x) → f == g

  -- non-equality is commutative
  flip : {A : Set} {x y : A} → (x == y → ⊥) → (y == x → ⊥)
  flip neq eq = neq (! eq)

  -- two types are said to be equivalent, or isomorphic, if there is a pair
  -- of functions between them where both round-trips are stable up to ==
  _≃_ : Set → Set → Set
  _≃_ A B = Σ[ f ∈ (A → B) ] Σ[ g ∈ (B → A) ]
             (((a : A) → g (f a) == a) × (((b : B) → f (g b) == b)))


{-

This is a HoTT-UF core library based on cubical type theory, where the
cubical machinery is hidden, using the HoTT Book terminology and
notation.

The point is that function extensionality, propositional truncation
and univalence compute (an example is given below).

For the moment, this requires the development version of Agda.

-}

{-# OPTIONS --cubical --exact-split --safe #-}

module Cubical.Foundations.HoTT-UF where

open import Cubical.Core.Primitives hiding ( _≡_ )
open import Cubical.Core.Id public

open import Cubical.Foundations.Id public
     using ( _≡_            -- The identity type.
           ; refl           -- Unfortunately, pattern matching on refl is not available.
           ; J              -- Until it is, you have to use the induction principle J.

           ; transport      -- As in the HoTT Book.
           ; ap
           ; _∙_
           ; _⁻¹

           ; _≡⟨_⟩_         -- Standard equational reasoning.
           ; _∎

           ; funExt         -- Function extensionality
                            -- (can also be derived from univalence).

           ; Σ              -- Sum type. Needed to define contractible types, equivalences
           ; _,_            -- and univalence.
           ; pr₁            -- The eta rule is available.
           ; pr₂

           ; isProp         -- The usual notions of proposition, contractible type, set.
           ; isContr
           ; isSet

           ; isEquiv        -- A map with contractible fibers
                            -- (Voevodsky's version of the notion).
           ; _≃_            -- The type of equivalences between two given types.
           ; EquivContr     -- A formulation of univalence.

           ; ∥_∥             -- Propositional truncation.
           ; ∣_∣             -- Map into the propositional truncation.
           ; ∥∥-isProp       -- A truncated type is a proposition.
           ; ∥∥-recursion    -- Non-dependent elimination.
           ; ∥∥-induction    -- Dependent elimination.
           )

{-

Here is an illustration of how function extensionality computes.

-}

private

  data ℕ : Type₀ where
   zero : ℕ
   succ : ℕ → ℕ

  f g : ℕ → ℕ

  f n = n

  g zero = zero
  g (succ n) = succ (g n)

  h : (n : ℕ) → f n ≡ g n
  h zero = refl
  h (succ n) = ap succ (h n)

  p : f ≡ g
  p = funExt h

  five : ℕ
  five = succ (succ (succ (succ (succ zero))))

  a : Σ ℕ (λ n → f n ≡ five)
  a = five , refl

  b : Σ ℕ (λ n → g n ≡ five)
  b = transport (λ - → Σ ℕ (λ n → - n ≡ five)) p a

  c : pr₁ b ≡ five
  c = refl

{-

If we had funExt as a postulate, then the definition of c would not
type check. Moreover, the term pr₁ b would not evaluate to five, as it
does with the cubical type theory implementation of funext.

TODO. A similar computational example with univalence.

-}


-- Issue #2814 reported by tomjack on 2017-10-18

{-# OPTIONS --cubical --rewriting #-}

-- prelude stolen from Saizan/cubical-demo

open import Agda.Primitive.Cubical public

postulate
  Path' : ∀ {ℓ} {A :     Set ℓ} → A    → A    → Set ℓ
  PathP : ∀ {ℓ} (A : I → Set ℓ) → A i0 → A i1 → Set ℓ

{-# BUILTIN PATHP        PathP     #-}

infix 4 _≡_
_≡_ : ∀ {ℓ} {A : Set ℓ} → A → A → Set ℓ
_≡_ {A = A} = PathP (λ _ → A)

Path = _≡_

refl : ∀ {ℓ} {A : Set ℓ} {x : A} → x ≡ x
refl {x = x} = λ _ → x

postulate
  Rewrite : ∀ {ℓ} {A : Set ℓ} → A → A → Set

{-# BUILTIN REWRITE Rewrite #-}

module Good where
  postulate
    Unit : Set
    unit : Unit

  module UnitElim (P : Unit → Set) (unit* : P unit) where
    postulate
      Unit-elim : (x : Unit) → P x
      unit-β : Rewrite (Unit-elim unit) unit*
  open UnitElim public
  {-# REWRITE unit-β #-}

  test₁ : {C : Set} {c₀ : C} → Path {A = C} (Unit-elim (λ _ → C) c₀ unit) c₀
  test₁ = refl

  test₂ : {C : Set} {c₀ : C} → Path {A = Path c₀ c₀} (λ j → Unit-elim (λ _ → C) c₀ unit) refl
  test₂ = refl

-- same code, but with a dummy module parameter
module Bad (Dummy : Set) where
  postulate
    Unit : Set
    unit : Unit

  module UnitElim (P : Unit → Set) (unit* : P unit) where
    postulate
      Unit-elim : (x : Unit) → P x
      unit-β : Rewrite (Unit-elim unit) unit*
  open UnitElim public
  {-# REWRITE unit-β #-}

  test₁ : {C : Set} {c₀ : C} → Path {A = C} (Unit-elim (λ _ → C) c₀ unit) c₀
  test₁ = refl
  test₂ : {C : Set} {c₀ : C} → Path {A = Path c₀ c₀} (λ j → Unit-elim (λ _ → C) c₀ unit) refl
  test₂ = refl

-- WAS:
-- Unit-elim (λ _ → .C) .c₀ unit != .c₀ of type .C
-- when checking that the expression refl has type
-- Path (λ j → Unit-elim (λ _ → .C) .c₀ unit) refl

-- SHOULD: succeed


{-# OPTIONS --without-K --safe #-}
module Categories.Category.Construction.Properties.EilenbergMoore where

open import Level
import Relation.Binary.PropositionalEquality as ≡

open import Categories.Adjoint
open import Categories.Adjoint.Properties
open import Categories.Category
open import Categories.Functor using (Functor; _∘F_)
open import Categories.Functor.Equivalence
open import Categories.Monad

open import Categories.NaturalTransformation renaming (id to idN)
open import Categories.Morphism.HeterogeneousIdentity

open import Categories.Adjoint.Construction.EilenbergMoore
open import Categories.Category.Construction.EilenbergMoore

private
  variable
    o ℓ e : Level
    𝒞 𝒟 : Category o ℓ e

module _ {F : Functor 𝒞 𝒟} {G : Functor 𝒟 𝒞} (F⊣G : Adjoint F G) where
  private
    T : Monad 𝒞
    T = adjoint⇒monad F⊣G

    𝒞ᵀ : Category _ _ _
    𝒞ᵀ = EilenbergMoore T

    module 𝒞 = Category 𝒞
    module 𝒟 = Category 𝒟
    module 𝒞ᵀ = Category 𝒞ᵀ

    open 𝒞.HomReasoning

    module T = Monad T
    module F = Functor F
    module G = Functor G

    open Adjoint F⊣G
    open NaturalTransformation

  -- Maclane's Comparison Functor
  ComparisonF : Functor 𝒟 𝒞ᵀ
  ComparisonF = record
    { F₀ = λ X → record
      { A = G.F₀ X
      ; action = G.F₁ (counit.η X)
      ; commute = commute (G ∘ˡ counit) (counit.η X)
      ; identity = zag
      }
    ; F₁ = λ {A} {B} f → record
      { arr = G.F₁ f
      ; commute =  begin
        𝒞 [ G.F₁ f ∘ G.F₁ (counit.η A) ]               ≈˘⟨ G.homomorphism ⟩
        G.F₁ (𝒟 [ f ∘ (counit.η A) ])                  ≈˘⟨ G.F-resp-≈ (counit.commute f) ⟩
        G.F₁ (𝒟 [ counit.η B ∘ F.F₁ (G.F₁ f) ])        ≈⟨ G.homomorphism  ⟩
        𝒞 [ G.F₁ (counit.η B) ∘ G.F₁ (F.F₁ (G.F₁ f)) ] ∎
      }
    ; identity = G.identity
    ; homomorphism = G.homomorphism
    ; F-resp-≈ = G.F-resp-≈
    }

  private
    K = ComparisonF
    module K = Functor K
    module Gᵀ = Functor (Forgetful T)
    module Fᵀ = Functor (Free T)

  Comparison∘F≡Free : (ComparisonF ∘F F) ≡F Free T
  Comparison∘F≡Free = record
    { eq₀ = λ X → ≡.refl
    ; eq₁ = λ {A} {B} f → begin
      Module⇒.arr (𝒞ᵀ [ (hid 𝒞ᵀ ≡.refl) ∘ K.F₁ (F.F₁ f) ]) ≈⟨ hid-refl 𝒞ᵀ {A = K.F₀ (F.F₀ B)} ⟩∘⟨refl ⟩
      Module⇒.arr (𝒞ᵀ [ 𝒞ᵀ.id ∘ K.F₁ (F.F₁ f) ])           ≈⟨ 𝒞.identityˡ {f = Module⇒.arr (K.F₁ (F.F₁ f))} ⟩
      Module⇒.arr (K.F₁ (F.F₁ f))                           ≈⟨ refl ⟩
      Module⇒.arr (Fᵀ.F₁ f)                                 ≈˘⟨ 𝒞ᵀ.identityʳ {f = Fᵀ.F₁ f} ⟩
      Module⇒.arr (𝒞ᵀ [ Fᵀ.F₁ f ∘ 𝒞ᵀ.id ])                 ≈˘⟨ refl⟩∘⟨ hid-refl 𝒞ᵀ {A = Fᵀ.F₀ A} ⟩
      Module⇒.arr (𝒞ᵀ [ Fᵀ.F₁ f ∘ (hid 𝒞ᵀ ≡.refl) ])       ∎
    }

  Forgetful∘ComparisonF≡G : (Forgetful T ∘F ComparisonF) ≡F G
  Forgetful∘ComparisonF≡G = record
    { eq₀ = λ X → ≡.refl
    ; eq₁ = λ f → begin
      𝒞 [ (hid 𝒞 ≡.refl) ∘ (Gᵀ.F₁ (K.F₁ f)) ] ≈⟨ hid-refl 𝒞 ⟩∘⟨refl ⟩
      𝒞 [ 𝒞.id ∘ (Gᵀ.F₁ (K.F₁ f)) ]           ≈⟨ 𝒞.identityˡ ⟩
      (Gᵀ.F₁ (K.F₁ f))                         ≈⟨ refl ⟩
      G.F₁ f                                   ≈˘⟨ 𝒞.identityʳ ⟩
      𝒞 [ G.F₁ f ∘ 𝒞.id ]                     ≈˘⟨ refl⟩∘⟨ hid-refl 𝒞 ⟩
      𝒞 [ G.F₁ f ∘ (hid 𝒞 ≡.refl) ]           ∎
    }


{-# OPTIONS --exact-split #-}

module ExactSplitParity where

data Bool : Set where
  true false : Bool

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

parity : ℕ → ℕ → Bool
parity zero          zero          = true
parity zero          (suc zero)    = false
parity zero          (suc (suc n)) = parity zero n
parity (suc zero)    zero          = false
parity (suc (suc m)) zero          = parity m zero
parity (suc m)       (suc n)       = parity m n


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

-- Definitions for the types of a polynomial stored in sparse horner
-- normal form.
--
-- These definitions ensure that the polynomial is actually in fully
-- canonical form, with no trailing zeroes, etc.

open import Polynomial.Parameters

module Polynomial.NormalForm.Definition
  {a ℓ}
  (coeffs : RawCoeff a ℓ)
  where

open import Polynomial.NormalForm.InjectionIndex

open import Relation.Nullary using (¬_)
open import Level            using (_⊔_)
open import Data.Empty       using (⊥)
open import Data.Unit        using (⊤)
open import Data.Nat         using (ℕ; suc; zero)
open import Data.Bool        using (T)
open import Data.List.Kleene public

infixl 6 _Δ_
record PowInd {c} (C : Set c) : Set c where
  inductive
  constructor _Δ_
  field
    coeff : C
    pow   : ℕ
open PowInd public

open RawCoeff coeffs

mutual
  -- A Polynomial is indexed by the number of variables it contains.
  infixl 6 _Π_
  record Poly (n : ℕ) : Set a where
    inductive
    constructor _Π_
    field
      {i}  : ℕ
      flat : FlatPoly i
      i≤n  : i ≤′ n

  data FlatPoly : ℕ → Set a where
    Κ : Carrier → FlatPoly zero
    Σ : ∀ {n} → (xs : Coeff n +) → .{xn : Norm xs} → FlatPoly (suc n)

  -- A list of coefficients, paired with the exponent *gap* from the
  -- preceding coefficient. In other words, to represent the
  -- polynomial:
  --
  --   3 + 2x² + 4x⁵ + 2x⁷
  --
  -- We write:
  --
  --   [(3,0),(2,1),(4,2),(2,1)]
  --
  -- Which can be thought of as a representation of the expression:
  --
  --   x⁰ * (3 + x * x¹ * (2 + x * x² * (4 + x * x¹ * (2 + x * 0))))
  --
  -- This is sparse Horner normal form.

  Coeff : ℕ → Set a
  Coeff n = PowInd (NonZero n)

  -- We disallow zeroes in the coefficient list. This condition alone
  -- is enough to ensure a unique representation for any polynomial.
  infixl 6 _≠0
  record NonZero (i : ℕ) : Set a where
    inductive
    constructor _≠0
    field
      poly : Poly i
      .{poly≠0} : ¬ Zero poly

  -- This predicate is used (in its negation) to ensure that no
  -- coefficient is zero, preventing any trailing zeroes.
  Zero : ∀ {n} → Poly n → Set
  Zero (Κ x Π _) = T (Zero-C x)
  Zero (Σ _ Π _) = ⊥

  -- This predicate is used to ensure that all polynomials are in
  -- normal form: if a particular level is constant, than it can
  -- be collapsed into the level below it.
  Norm : ∀ {i} → Coeff i + → Set
  Norm (_ Δ zero  & [])  = ⊥
  Norm (_ Δ zero  & ∹ _) = ⊤
  Norm (_ Δ suc _ & _)   = ⊤
open NonZero public
open Poly public


------------------------------------------------------------------------
-- The Agda standard library
--
-- Convenient syntax for reasoning with a setoid
------------------------------------------------------------------------

-- Example use:

-- n*0≡0 : ∀ n → n * 0 ≡ 0
-- n*0≡0 zero    = refl
-- n*0≡0 (suc n) = begin
--   suc n * 0 ≈⟨ refl ⟩
--   n * 0 + 0 ≈⟨ ... ⟩
--   n * 0     ≈⟨ n*0≡0 n ⟩
--   0         ∎

-- Module `≡-Reasoning` in `Relation.Binary.PropositionalEquality`
-- is recommended for equational reasoning when the underlying equality is
-- `_≡_`.

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

open import Relation.Binary

module Relation.Binary.Reasoning.Setoid {s₁ s₂} (S : Setoid s₁ s₂) where

open Setoid S

------------------------------------------------------------------------
-- Reasoning combinators

open import Relation.Binary.Reasoning.PartialSetoid partialSetoid public
open import Relation.Binary.Reasoning.Base.Single _≈_ refl trans public
  using (_∎)


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

open import Categories.Category
open import Categories.Category.Monoidal

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

open import Level

open import Data.Product using (Σ; _,_)

open import Categories.Functor.Bifunctor
open import Categories.Functor.Properties
open import Categories.NaturalTransformation.NaturalIsomorphism using (NaturalIsomorphism)

open import Categories.Morphism C
open import Categories.Morphism.Properties C
open import Categories.Category.Monoidal.Braided M
open Category C
open Commutation

private
  variable
    X Y Z : Obj

-- symmetric monoidal category
-- commutative braided monoidal category
--
-- the reason why we define symmetric categories via braided monoidal categories could
-- be not obvious, but it is the right definition: it requires again a redundant
-- hexagon proof which allows achieves definitional equality of the opposite.
record Symmetric : Set (levelOfTerm M) where
  field
    braided : Braided

  module braided = Braided braided
  open braided public

  private
    B : ∀ {X Y} → X ⊗₀ Y ⇒ Y ⊗₀ X
    B {X} {Y} = braiding.⇒.η (X , Y)

  field
    commutative : B {X} {Y} ∘ B {Y} {X} ≈ id

  braided-iso : X ⊗₀ Y ≅ Y ⊗₀ X
  braided-iso = record
    { from = B
    ; to   = B
    ; iso  = record
      { isoˡ = commutative
      ; isoʳ = commutative
      }
    }

  module braided-iso {X Y} = _≅_ (braided-iso {X} {Y})

private
  record Symmetric′ : Set (levelOfTerm M) where
    open Monoidal M

    field
      braiding : NaturalIsomorphism ⊗ (flip-bifunctor ⊗)

    module braiding = NaturalIsomorphism braiding

    private
      B : ∀ {X Y} → X ⊗₀ Y ⇒ Y ⊗₀ X
      B {X} {Y} = braiding.⇒.η (X , Y)

    field
      commutative : B {X} {Y} ∘ B {Y} {X} ≈ id
      hexagon     : [ (X ⊗₀ Y) ⊗₀ Z ⇒ Y ⊗₀ Z ⊗₀ X ]⟨
                      B  ⊗₁ id                    ⇒⟨ (Y ⊗₀ X) ⊗₀ Z ⟩
                      associator.from             ⇒⟨ Y ⊗₀ X ⊗₀ Z ⟩
                      id ⊗₁ B
                    ≈ associator.from             ⇒⟨ X ⊗₀ Y ⊗₀ Z ⟩
                      B                           ⇒⟨ (Y ⊗₀ Z) ⊗₀ X ⟩
                      associator.from
                    ⟩

    braided-iso : X ⊗₀ Y ≅ Y ⊗₀ X
    braided-iso = record
      { from = B
      ; to   = B
      ; iso  = record
        { isoˡ = commutative
        ; isoʳ = commutative
        }
      }

    module braided-iso {X Y} = _≅_ (braided-iso {X} {Y})

    -- we don't define [Symmetric] from [Braided] because we want to avoid asking
    -- [hexagon₂], which can readily be proven using the [hexagon] and [commutative].
    braided : Braided
    braided = record
      { braiding = braiding
      ; hexagon₁ = hexagon
      ; hexagon₂ = λ {X Y Z} →
                     Iso-≈ hexagon
                           (Iso-∘ (Iso-∘ ([ -⊗ Y ]-resp-Iso braided-iso.iso) associator.iso)
                                  ([ X ⊗- ]-resp-Iso braided-iso.iso))
                           (Iso-∘ (Iso-∘ associator.iso braided-iso.iso)
                                  associator.iso)
      }

symmetricHelper : Symmetric′ → Symmetric
symmetricHelper S = record
  { braided     = braided
  ; commutative = commutative
  }
  where open Symmetric′ S


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

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

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

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

record fieldOfFractionsSet : Set (a ⊔ b) where
  field
    num : A
    denom : A
    .denomNonzero : (Setoid._∼_ S denom (Ring.0R R) → False)

fieldOfFractionsSetoid : Setoid fieldOfFractionsSet
Setoid._∼_ fieldOfFractionsSetoid (record { num = a ; denom = b ; denomNonzero = b!=0 }) (record { num = c ; denom = d ; denomNonzero = d!=0 }) = Setoid._∼_ S (a * d) (b * c)
Equivalence.reflexive (Setoid.eq fieldOfFractionsSetoid) {record { num = a ; denom = b ; denomNonzero = b!=0 }} = Ring.*Commutative R
Equivalence.symmetric (Setoid.eq fieldOfFractionsSetoid) {record { num = a ; denom = b ; denomNonzero = b!=0 }} {record { num = c ; denom = d ; denomNonzero = d!=0 }} ad=bc = transitive (Ring.*Commutative R) (transitive (symmetric ad=bc) (Ring.*Commutative R))
  where
    open Equivalence (Setoid.eq S)
Equivalence.transitive (Setoid.eq fieldOfFractionsSetoid) {record { num = a ; denom = b ; denomNonzero = b!=0 }} {record { num = c ; denom = d ; denomNonzero = d!=0 }} {record { num = e ; denom = f ; denomNonzero = f!=0 }} ad=bc cf=de = p5
  where
    open Setoid S
    open Ring R
    open Equivalence eq
    p : (a * d) * f ∼ (b * c) * f
    p = Ring.*WellDefined R ad=bc reflexive
    p2 : (a * f) * d ∼ b * (d * e)
    p2 = transitive (transitive (symmetric *Associative) (transitive (*WellDefined reflexive *Commutative) *Associative)) (transitive p (transitive (symmetric *Associative) (*WellDefined reflexive cf=de)))
    p3 : (a * f) * d ∼ (b * e) * d
    p3 = transitive p2 (transitive (*WellDefined reflexive *Commutative) *Associative)
    p4 : ((d ∼ 0R) → False) → ((a * f) ∼ (b * e))
    p4 = cancelIntDom I (transitive *Commutative (transitive p3 *Commutative))
    p5 : (a * f) ∼ (b * e)
    p5 = p4 λ t → exFalso (d!=0 t)


module Natural where

open import Agda.Builtin.Equality

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

-- seven = suc (suc (suc (suc (suc (suc (suc zero))))))

{-# BUILTIN NATURAL ℕ #-}

_+_ : ℕ → ℕ → ℕ
infixl 6 _+_
zero + b = b
(suc a) + b = suc (a + b)

{-# BUILTIN NATPLUS _+_ #-}

+-id : ∀ (a : ℕ) → a + zero ≡ zero + a
+-id zero = refl
+-id (suc a) rewrite +-id a = refl

+-comm : ∀ (a b : ℕ) → a + b ≡ b + a
+-comm zero b rewrite +-id b = refl
+-comm (suc a) zero rewrite +-id (suc a) = refl
+-comm (suc a) (suc b)
    rewrite +-comm a (suc b)
    | +-comm b (suc a)
    | +-comm a b  = refl

+-asso : ∀ (a b c : ℕ) → a + b + c ≡ a + (b + c)
+-asso zero b c = refl
+-asso (suc a) zero c
    rewrite +-id (suc a)
    | +-id a = refl
+-asso (suc a) (suc b) zero
    rewrite +-id (suc a + suc b)
    | +-id b = refl
+-asso (suc a) (suc b) (suc c)
    rewrite (+-comm a (suc b))
    | +-comm (b + a) (suc c)
    | +-comm b a
    | +-comm c (a + b)
    | +-comm b (suc c)
    | +-comm a (suc (suc (c + b)))
    | +-comm c b
    | +-comm (b + c) a
    | +-asso a b c = refl

+-rear : ∀ (a b c d : ℕ) → a + b + (c + d) ≡ a + (b + c) + d
+-rear zero b c d rewrite +-asso b c d = refl
+-rear (suc a) b c d
    rewrite (+-asso (suc a) b (c + d))
    | +-asso a (b + c) d
    | +-asso b c d = refl

+-swap : ∀ (a b c : ℕ) → a + (b + c) ≡ b + (a + c)
+-swap a b c
    rewrite (+-comm a (b + c))
    | +-comm b (a + c)
    | +-asso a c b
    | +-comm c b
    | +-comm a (b + c) = refl

_*_ : ℕ → ℕ → ℕ
infixl 7 _*_
zero * b = zero
suc a * b = b + a * b

{-# BUILTIN NATTIMES _*_ #-}

*-id : ∀ (a : ℕ) → a * (suc zero) ≡ (suc zero) * a
*-id zero = refl
*-id (suc a)
    rewrite +-comm (suc zero) a
    | *-id a = refl

*-z : ∀ (a : ℕ) → a * zero ≡ zero * a
*-z zero = refl
*-z (suc a) rewrite *-z a = refl

*-comm : ∀ (a b : ℕ) → a * b ≡ b * a
*-comm zero b rewrite *-z b = refl
*-comm (suc a) zero rewrite *-z a = refl
*-comm (suc a) (suc b)
    rewrite (*-comm a (suc b))
    | (*-comm b (suc a))
    | (*-comm a b )
    | (+-comm b (a + b * a))
    | (+-comm a (b + b * a))
    | (+-comm a (b * a))
    | (+-comm b (b * a))
    | (+-asso (b * a) a b)
    | (+-asso (b * a) b a)
    | (+-comm a b) = refl

*-+-dist-r : ∀ (a b c : ℕ) → (a + b) * c ≡ a * c + b * c
*-+-dist-r zero b c = refl
*-+-dist-r (suc a) zero c
    rewrite (+-comm (suc a) zero)
    | +-comm a zero
    | +-asso c (a * c) zero
    | +-comm (a * c) zero = refl
*-+-dist-r (suc a) (suc b) c
    rewrite (+-comm a (suc b))
    | +-rear c (a * c) c (b * c)
    | +-comm (a * c) c
    | +-asso c (c + a * c) (b * c)
    | +-asso c (a * c) (b * c)
    | +-comm (a * c) (b * c)
    | *-+-dist-r b a c = refl

*-+-dist-l : ∀ (a b c : ℕ) → a * (b + c) ≡ a * b + a * c
*-+-dist-l a zero c rewrite (*-z a) = refl
*-+-dist-l a (suc b) zero
    rewrite (+-comm (suc b) zero)
    | *-z a
    | +-comm (a * suc b) zero = refl
*-+-dist-l a (suc b) (suc c)
    rewrite (+-comm b (suc c))
    | *-comm a (suc (suc (c + b)))
    | *-comm a (suc b)
    | *-comm a (suc c)
    | +-rear a (b * a) a (c * a)
    | +-comm (b * a) a
    | +-asso a (a + b * a) (c * a)
    | +-asso a (b * a) (c * a)
    | +-comm (b * a) (c * a)
    | *-comm (c + b) a
    | *-comm c a
    | *-comm b a
    | *-+-dist-l a c b = refl

*-asso : ∀ (a b c : ℕ) → a * b * c ≡ a * (b * c)
*-asso zero b c = refl
*-asso (suc a) zero c rewrite (*-asso a zero c) = refl
*-asso (suc a) (suc b) c
    rewrite (*-+-dist-r (suc b) (a * suc b) c)
    | *-asso a (suc b) c = refl

_^_ : ℕ → ℕ → ℕ
m ^ zero = suc zero
m ^ (suc n) = m * (m ^ n)

^-dist-+-*-l : ∀ (a b c : ℕ) →  a ^ (b + c) ≡ (a ^ b) * (a ^ c)
^-dist-+-*-l a zero c
    rewrite (+-comm zero (a ^ c))
    | +-asso (a ^ c) zero zero = refl
^-dist-+-*-l a (suc b) c
    rewrite *-asso a (a ^ b) (a ^ c)
    | ^-dist-+-*-l a b c = refl

^-dist-*-r : ∀ (a b c : ℕ) → (a * b) ^ c ≡ (a ^ c) * (b ^ c)
^-dist-*-r a b zero rewrite (+-comm (suc zero) zero) = refl
^-dist-*-r a b (suc c)
    rewrite (*-asso a (a ^ c) (b * (b ^ c)))
    | *-comm (a ^ c) (b * (b ^ c))
    | *-asso b (b ^ c) (a ^ c)
    | *-comm (b ^ c) (a ^ c)
    | *-asso a b ((a * b) ^ c)
    | ^-dist-*-r a b c = refl

^-asso-* : ∀ (a b c : ℕ) → (a ^ b) ^ c ≡ a ^ (b * c)
^-asso-* a b zero rewrite (*-comm b zero) = refl
^-asso-* a b (suc c)
    rewrite (*-comm b (suc c))
    | ^-dist-+-*-l a b (c * b)
    | *-comm c b
    | ^-asso-* a b c = refl

data Bin : Set where
    ⟨⟩ : Bin
    _O : Bin → Bin
    _I : Bin → Bin

inc : Bin → Bin
inc ⟨⟩ = ⟨⟩ I
inc (n O) = n I
inc (n I) = (inc n) O

to : ℕ → Bin
to zero = ⟨⟩ O
to (suc n) = inc (to n)

from : Bin → ℕ
from ⟨⟩ = zero
from (n O) = 2 * (from n)
from (n I) = suc (2 * (from n))

thm₁ : ∀ (b : Bin) → from (inc b) ≡ suc (from b)
thm₁ ⟨⟩ = refl
thm₁ (a O) = refl
thm₁ (a I)
    rewrite thm₁ a
    | +-comm (suc (from a)) zero
    | +-comm (from a) zero
    | +-comm (from a) (suc (from a)) = refl

-- thm₂ : ∀ (b : Bin) → to (from b) = b
-- 这是错误的，因为 Bin 中的 (⟨⟩ O) 和 (⟨⟩)
-- 都和 自然数 的 0 对应
-- from 并非单射

thm₃ : ∀ (n : ℕ) → from (to n) ≡ n
thm₃ zero = refl
thm₃ (suc n)
  rewrite thm₁ (to (suc n))
    | thm₁ (to n)
    | thm₃ n = refl


{-# OPTIONS --without-K #-}
module sets.fin.ordering where

open import equality.core
open import function.isomorphism
open import sets.core
open import sets.fin.core
open import sets.fin.properties
import sets.nat.ordering as N

_<_ : ∀ {n} → Fin n → Fin n → Set
i < j = toℕ i N.< toℕ j
infixr 4 _<_

ord-from-ℕ : ∀ {n} {i j : Fin n}
           → Ordering N._<_ (toℕ i) (toℕ j)
           → Ordering _<_ i j
ord-from-ℕ (lt p) = lt p
ord-from-ℕ (eq p) = eq (toℕ-inj p)
ord-from-ℕ (gt p) = gt p

compare : ∀ {n} → (i j : Fin n) → Ordering _<_ i j
compare i j = ord-from-ℕ (N.compare (toℕ i) (toℕ j))


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

open import Categories.Category.Core

module Categories.Object.Product.Limit {o ℓ e} (C : Category o ℓ e) where

open import Level
open import Data.Nat.Base using (ℕ)
open import Data.Fin.Base using (Fin)
open import Data.Fin.Patterns

open import Categories.Category.Lift
open import Categories.Category.Finite.Fin
open import Categories.Category.Finite.Fin.Construction.Discrete
open import Categories.Object.Product C
open import Categories.Diagram.Limit
open import Categories.Functor.Core

import Categories.Category.Construction.Cones as Co
import Categories.Morphism.Reasoning as MR

private
  module C = Category C
  open C
  open MR C
  open HomReasoning

module _ {o′ ℓ′ e′} {F : Functor (liftC o′ ℓ′ e′ (Discrete 2)) C} where
  private
    module F = Functor F
    open F

  limit⇒product : Limit F → Product (F₀ (lift 0F)) (F₀ (lift 1F))
  limit⇒product L = record
    { A×B      = apex
    ; π₁       = proj (lift 0F)
    ; π₂       = proj (lift 1F)
    ; ⟨_,_⟩    = λ f g → rep record
      { apex = record
        { ψ       = λ { (lift 0F) → f
                      ; (lift 1F) → g }
        ; commute = λ { {lift 0F} {lift 0F} (lift 0F) → elimˡ identity
                      ; {lift 1F} {lift 1F} (lift 0F) → elimˡ identity }
        }
      }
    ; project₁ = commute
    ; project₂ = commute
    ; unique   = λ {_} {h} eq eq′ → terminal.!-unique record
      { arr     = h
      ; commute = λ { {lift 0F} → eq
                    ; {lift 1F} → eq′ }
      }
    }
    where open Limit L

module _ o′ ℓ′ e′ A B where
  open Equiv

  product⇒limit-F : Functor (liftC o′ ℓ′ e′ (Discrete 2)) C
  product⇒limit-F = record
    { F₀           = λ { (lift 0F) → A
                       ; (lift 1F) → B }
    ; F₁           = λ { {lift 0F} {lift 0F} _ → C.id
                       ; {lift 1F} {lift 1F} _ → C.id }
    ; identity     = λ { {lift 0F} → refl
                       ; {lift 1F} → refl }
    ; homomorphism = λ { {lift 0F} {lift 0F} {lift 0F} → sym identity²
                       ; {lift 1F} {lift 1F} {lift 1F} → sym identity² }
    ; F-resp-≈     = λ { {lift 0F} {lift 0F} _ → refl
                       ; {lift 1F} {lift 1F} _ → refl }
    }

module _ o′ ℓ′ e′ {A B} (p : Product A B) where
  open Product p
  private
    F = product⇒limit-F o′ ℓ′ e′ A B
    open Functor F

  product⇒limit : Limit F
  product⇒limit = record
    { terminal = record
      { ⊤        = record
        { N    = A×B
        ; apex = record
          { ψ       = λ { (lift 0F) → π₁
                        ; (lift 1F) → π₂ }
          ; commute = λ { {lift 0F} {lift 0F} (lift 0F) → identityˡ
                        ; {lift 1F} {lift 1F} (lift 0F) → identityˡ }
          }
        }
      ; !        = λ {K} →
        let open Co.Cone F K
        in record
        { arr     = ⟨ ψ (lift 0F) , ψ (lift 1F) ⟩
        ; commute = λ { {lift 0F} → project₁
                      ; {lift 1F} → project₂ }
        }
      ; !-unique = λ {K} f →
        let module K = Co.Cone F K
            module f = Co.Cone⇒ F f
        in begin
          ⟨ K.ψ (lift 0F) , K.ψ (lift 1F) ⟩ ≈˘⟨ ⟨⟩-cong₂ f.commute f.commute ⟩
          ⟨ π₁ ∘ f.arr , π₂ ∘ f.arr ⟩       ≈⟨ g-η ⟩
          f.arr                             ∎
      }
    }


module Examples where

open import Prelude
open import Star
open import Modal

El : Set -> Rel True
El A _ _ = A

List : Set -> Set
List A = Star (El A) _ _

Nat = List True

zero : Nat
zero = ε

suc : Nat -> Nat
suc n = _ • n

-- Vectors

Vec : Set -> Nat -> Set
Vec A = All (\_ -> A)

infixr 40 _::_
_::_ : {A : Set}{n : Nat} -> A -> Vec A n -> Vec A (suc n)
x :: xs = check x • xs

-- Fin

Fin : Nat -> Set
Fin = Any (\_ -> True)

-- Turning a vector to a list

vecToList : {A : Set}{n : Nat} -> Vec A n -> List A
vecToList {A} = map ! uncheck

listToVec : {A : Set}(xs : List A) -> Vec A (length xs)
listToVec  ε       = ε
listToVec (x • xs) = x :: listToVec xs

-- span

test : Vec Nat (suc (suc (suc zero)))
test = zero :: suc zero :: suc (suc zero) :: ε


------------------------------------------------------------------------
-- Regular expressions
------------------------------------------------------------------------

open import Setoids

module RegExps (S : Setoid) where

infix  8 _⋆
infixl 7 _⊙_
infixl 6 _∣_
infix  1 _∈‿⟦_⟧

open import Prelude
private open module S' = Setoid S

------------------------------------------------------------------------
-- Regular expressions

data RegExp : Set where
  ∅   : RegExp                      -- Matches nothing.
  ε   : RegExp                      -- Matches the empty string.
  •   : RegExp                      -- Matches any single character.
  sym : carrier -> RegExp           -- Matches the given character.
  _⋆  : RegExp -> RegExp            -- Kleene star.
  _∣_ : RegExp -> RegExp -> RegExp  -- Choice.
  _⊙_ : RegExp -> RegExp -> RegExp  -- Sequencing.

------------------------------------------------------------------------
-- Size of a regular expression

size : RegExp -> ℕ
size (re ⋆)      = 1 + size re
size (re₁ ∣ re₂) = 1 + size re₁ + size re₂
size (re₁ ⊙ re₂) = 1 + size re₁ + size re₂
size _           = 1

------------------------------------------------------------------------
-- Semantics of regular expressions

-- The type xs ∈‿⟦ re ⟧ is inhabited iff xs matches the regular
-- expression re.

data _∈‿⟦_⟧ : [ carrier ] -> RegExp -> Set where
  matches-ε   : [] ∈‿⟦ ε ⟧
  matches-•   : forall {x} -> x ∷ [] ∈‿⟦ • ⟧
  matches-sym : forall {x y} -> x ≈ y -> x ∷ [] ∈‿⟦ sym y ⟧
  matches-⋆   : forall {xs re}
              -> xs ∈‿⟦ ε ∣ re ⊙ re ⋆ ⟧ -> xs ∈‿⟦ re ⋆ ⟧
  matches-∣ˡ   : forall {xs re₁ re₂}
              -> xs ∈‿⟦ re₁ ⟧ -> xs ∈‿⟦ re₁ ∣ re₂ ⟧
  matches-∣ʳ   : forall {xs re₁ re₂}
              -> xs ∈‿⟦ re₂ ⟧ -> xs ∈‿⟦ re₁ ∣ re₂ ⟧
  matches-⊙   : forall {xs₁ xs₂ re₁ re₂}
              -> xs₁ ∈‿⟦ re₁ ⟧ -> xs₂ ∈‿⟦ re₂ ⟧
              -> xs₁ ++ xs₂ ∈‿⟦ re₁ ⊙ re₂ ⟧

------------------------------------------------------------------------
-- Is the regular expression bypassable?

bypassable : (re : RegExp) -> Maybe ([] ∈‿⟦ re ⟧)
bypassable ∅           = nothing
bypassable ε           = just matches-ε
bypassable •           = nothing
bypassable (sym _)     = nothing
bypassable (re ⋆)      = just (matches-⋆ (matches-∣ˡ matches-ε))
bypassable (re₁ ∣ re₂) with bypassable re₁ | bypassable re₂
bypassable (re₁ ∣ re₂) | just m  | _       = just (matches-∣ˡ m)
bypassable (re₁ ∣ re₂) | nothing | just m  = just (matches-∣ʳ m)
bypassable (re₁ ∣ re₂) | nothing | nothing = nothing
bypassable (re₁ ⊙ re₂) with bypassable re₁ | bypassable re₂
bypassable (re₁ ⊙ re₂) | just m₁ | just m₂ = just (matches-⊙ m₁ m₂)
bypassable (re₁ ⊙ re₂) | _       | _       = nothing


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

open import Relation.Binary.Core

module Quasigroup.Definitions
  {a ℓ} {A : Set a}   -- The underlying set
  (_≈_ : Rel A ℓ)     -- The underlying equality
  where

open import Algebra.Core
open import Data.Product

LatinSquareProperty₁ : Op₂ A → Set _
LatinSquareProperty₁ _*_ = ∀ a b x  → (a * x) ≈ b

LatinSquareProperty₂ : Op₂ A → Set _
LatinSquareProperty₂ _*_ = ∀ a b y → (y * a) ≈ b

LatinSquareProperty : Op₂ A → Set _
LatinSquareProperty _*_ = (LatinSquareProperty₁ _*_) × (LatinSquareProperty₂ _*_)


module Lib.Prelude where

infixr 90 _∘_
infixr 1 _,_

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

_∘_ : {A : Set}{B : A -> Set}{C : {x : A} -> B x -> Set}
      (f : {x : A}(y : B x) -> C y)(g : (x : A) -> B x)(x : A) ->
      C (g x)
(f ∘ g) x = f (g x)

data Unit : Set where
  unit : Unit

{-# COMPILED_DATA Unit () () #-}

postulate String : Set

{-# BUILTIN STRING String #-}

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

{-# COMPILED_DATA _×_ (,) (,) #-}

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

snd : {A B : Set} -> A × B -> B
snd (x , y) = y


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

open import Level

open import Categories.Category
open import Categories.Category.Instance.One
open import Categories.Category.Product
open import Categories.Functor renaming (id to idF)
open import Categories.NaturalTransformation using (NaturalTransformation; ntHelper)
import Categories.Morphism.Reasoning as MR

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

const : (d : Category.Obj D) → Functor C D
const {D = D} d = record
  { F₀           = λ _ → d
  ; F₁           = λ _ → id
  ; identity     = refl
  ; homomorphism = sym identity²
  ; F-resp-≈     = λ _ → refl
  }
  where open Category D
        open Equiv

const! : (d : Category.Obj D) → Functor (One {0ℓ} {0ℓ} {0ℓ}) D
const! = const

constˡ : (c : Category.Obj C) → Functor D (Product C D)
constˡ c = const c ※ idF

constʳ : (c : Category.Obj C) → Functor D (Product D C)
constʳ c = idF ※ (const c)

constNat : ∀ {A B} → Category._⇒_ D A B → NaturalTransformation (const {D = D} {C = C} A) (const B)
constNat {D = D} f = ntHelper record
  { η       = λ _ → f
  ; commute = λ _ → MR.id-comm D
  }


open import Agda.Builtin.Nat

variable {n} : Nat

data Vec (A : Set) : Nat → Set where
  []  : Vec A 0
  _∷_ : A → Vec A n → Vec A (suc n)

cons : ∀ {m A} → A → Vec A m → Vec A (suc m)
cons = _∷_

module _ (A : Set) where
  data Vec' : Nat → Set where
    []  : Vec' 0
    _∷_ : A → Vec' n → Vec' (suc n)

cons' : ∀ {m A} → A → Vec' A m → Vec' A (suc m)
cons' = _∷_


module Structure.LinearAlgebra where

import      Lvl
open import Data
open import Data.Tuple
open import Functional hiding (id)
open import Function.Equals
open import Function.Proofs
open import Logic
open import Logic.Propositional
open import Logic.Propositional.Theorems
open import Logic.Predicate
open import Numeral.CoordinateVector as Vec using () renaming (Vector to Vec)
open import Numeral.Finite
open import Numeral.Natural
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Proofs
-- open import Relator.Equals
-- open import Relator.Equals.Proofs
open import Structure.Setoid
open import Structure.Setoid.Uniqueness
open import Structure.Setoid.Uniqueness.Proofs
open import Structure.Function.Domain
import      Structure.Function.Linear as Linear
open import Structure.Operator.Field
open import Structure.Operator.Group
open import Structure.Operator.Properties hiding (commutativity)
open import Structure.Operator.Vector
open import Syntax.Number
open import Type

-- Finite dimensional linear algebra
-- TODO: Apparently, most of linear algebra will not work in constructive logic

module _
  {ℓᵥ ℓₛ : Lvl.Level}
  {V : Type{ℓᵥ}}
  ⦃ equiv-V : Equiv(V) ⦄
  {S : Type{ℓₛ}}
  ⦃ equiv-S : Equiv(S) ⦄
  {_+ᵥ_ : V → V → V}
  {_⋅ₛᵥ_ : S → V → V}
  {_+ₛ_ _⋅ₛ_ : S → S → S}
  ⦃ vectorSpace : VectorSpace(_+ᵥ_)(_⋅ₛᵥ_)(_+ₛ_)(_⋅ₛ_) ⦄
  where

  module _ where
    open VectorSpace(vectorSpace)

    -- A list of scalars
    Scalars : ℕ → Type
    Scalars(n) = Vec(n)(S) -- TODO: Prove that this type is a group if its underlying type (S) is a group. THen proceed to prove that injective-kernelᵣ holds with LinearCombination(_) being a homomorphism, which one can deduce that LinearlyIndependent is equivalent to Injective.

    -- A list of vectors
    Vectors : ℕ → Type
    Vectors(n) = Vec(n)(V)

    module _ where
      -- TODO: Make this a record instead, and then define an "eval"-function and prove LinearCombination-addition for this eval function (homomorphism)
      -- A specific linear combination of vectors (specific as specified by scalars).
      -- Linear combination of 0 scalars and vectors are the zero vector.
      -- Linear combination of 1 scalar and vector is just scalar on vector multiplication.
      -- Example: LinearCombination {4} sf vf = (sf[0] ⋅ₛᵥ vf[0]) +ᵥ (sf[1] ⋅ₛᵥ vf[1]) +ᵥ (sf[2] ⋅ₛᵥ vf[2]) +ᵥ (sf[3] ⋅ₛᵥ vf[3])
      LinearCombination : ∀{n} → Vectors(n) → Scalars(n) → V
      LinearCombination {0}       _ _ = 𝟎ᵥ
      LinearCombination {1}       vf sf = Vec.proj(sf)(0) ⋅ₛᵥ Vec.proj(vf)(0)
      LinearCombination {𝐒(𝐒(n))} vf sf = (Vec.proj(sf)(0) ⋅ₛᵥ Vec.proj(vf)(0)) +ᵥ (LinearCombination {𝐒(n)} (Vec.tail vf) (Vec.tail sf))

      postulate LinearCombination-addition    : ∀{n}{sf₁ sf₂}{vf} → (LinearCombination{n}(vf)(sf₁) +ᵥ LinearCombination{n}(vf)(sf₂) ≡ LinearCombination{n}(vf)(sf₁ ⦗ Vec.map₂ (_+ₛ_) ⦘ sf₂))
      postulate LinearCombination-subtraction : ∀{n}{sf₁ sf₂}{vf} → (LinearCombination{n}(vf)(sf₁) −ᵥ LinearCombination{n}(vf)(sf₂) ≡ LinearCombination{n}(vf)(sf₁ ⦗ Vec.map₂ (_−ₛ_) ⦘ sf₂))

      -- Spanning(vf) ⇔ (VSP = Span(vf))
      -- A set of vectors is spanning the vector space when every vector in the vector space can be represented as a linear combination of the set of vectors.
      Spanning : ∀{n} → Vectors(n) → Stmt
      Spanning(vf) = (∀{v} → ∃(sf ↦ LinearCombination(vf)(sf) ≡ v))

      -- Basis(vf) ⇔ (vf is a basis)
      -- A set of vectors is a basis when every vector in the vector space can be represented as a unique linear combination of the set of vectors.
      -- A set of vectors is a basis when they span the vector space and is linearly independent.
      Basis : ∀{n} → Vectors(n) → Stmt
      Basis(vf) = (∀{v} → ∃!(sf ↦ LinearCombination(vf)(sf) ≡ v)) -- TODO: Should be some kind of set equality. Could be impossible to prove the uniqueness otherwise because one can just permute for commutative scalars

      -- A set of vectors is linearly independent when there is no vector that can be represented as a linear combination by the others.
      LinearlyIndependent : ∀{n} → Vectors(n) → Stmt
      LinearlyIndependent{n}(vf) = ∀{sf} → (LinearCombination(vf)(sf) ≡ 𝟎ᵥ) → (∀{i} → Vec.proj(sf)(i) ≡ 𝟎ₛ) -- sf ⊜ fill(𝟎ₛ)

      postulate independent-injective : ∀{n}{vf} → LinearlyIndependent{n}(vf) ↔ (∀{sf₁ sf₂} → (LinearCombination(vf)(sf₁) ≡ LinearCombination(vf)(sf₂)) → (∀{i}→ Vec.proj(sf₁)(i) ≡ Vec.proj(sf₂)(i))) -- TODO: Vec.proj(sf₁) ⊜ Vec.proj(sf₂)
      -- TODO: Is there some axioms that make this happen? I remember this pattern from somewhere, that injectivity is equivalent to stuff being the identity of something. Maybe it is usually expressed using a kernel? See the note written above
      -- TODO: Express this as injectivity when `Injective` is general over setoids

      basis-span-independent : ∀{n}{vf : Vectors(n)} → Basis(vf) ↔ (Spanning(vf) ∧ LinearlyIndependent(vf))
      basis-span-independent{n}{vf} = [↔]-intro (uncurry l) (([↔]-to-[←] [→][∧]-distributivityₗ) ([∧]-intro r₁ r₂)) where
        l : Spanning(vf) → LinearlyIndependent(vf) → Basis(vf)
        l spanning indep {v} = [∃!]-intro existence uniqueness where
          existence : ∃(sf ↦ LinearCombination(vf)(sf) ≡ v)
          existence = spanning

          postulate uniqueness : Unique(sf ↦ LinearCombination(vf)(sf) ≡ v)
          -- uniqueness = ([↔]-elimₗ Uniqueness-Injectivity) (([↔]-elimᵣ independent-injective) indep)
          -- TODO: `Injective` over setoids is blocking this proof. It is at the moment proving something incorrect

        r₁ : Basis(vf) → Spanning(vf)
        r₁(proof) {v} = [∃!]-existence(proof{v})

        postulate r₂ : Basis(vf) → LinearlyIndependent(vf)
        -- TODO: `Injective` over setoids is blocking this proof. It is at the moment proving something incorrect

      -- Cardinality of a set of linearly independent vectors is always less than the cardinality of a set of spanning vectors
      postulate independent-less-than-spanning : ∀{n₁ n₂} → ∀{vf₁} → LinearlyIndependent{n₁}(vf₁) → ∀{vf₂} → Spanning{n₂}(vf₂) → (n₁ ≤ n₂)

      -- Existence of a subset of spanning vectors which is a basis
      -- TODO: postulate basis-from-spanning : ∀{n}{vf} → ⦃ _ : Spanning{n}(vf) ⦄ → ∃(m ↦ (m ≤ n) ∧ ∃(f ↦ Basis{n}(vf ∘ f) ∧ Injective(f)))

      -- Existence of a finite set of vectors which spans the vector space
      -- A "finite dimensional vector space" is sometimes defined as a vector space which satisfies this proposition.
      postulate span-existence : ∃(n ↦ ∃(vf ↦ Spanning{n}(vf)))
      -- TODO: Usually, this exists because one can take the whole set

      -- Existence of a basis
      postulate basis-existence : ∃(n ↦ ∃(vf ↦ Basis{n}(vf)))

      -- A set of linearly independent vectors is smaller than a set of basis vectors
      postulate independent-lesser-than-basis-number : ∀{m n} → {vfₘ : Vectors(m)} → LinearlyIndependent(vfₘ) → {vfₙ : Vectors(n)} → Basis(vfₙ) → (m ≤ n)

      -- Every set of basis vectors are equal in size
      postulate basis-equal-number : ∀{m n} → {vfₘ : Vectors(m)} → Basis(vfₘ) → {vfₙ : Vectors(n)} → Basis(vfₙ) → (m ≡ n)

      -- The dimension of the vector space
      dim :  ℕ
      dim = [∃]-witness(basis-existence)

      -- Existence of a superset of linearly independent vectors which is a basis
      -- TODO: basis-from-linearly-independent : ∀{n}{vf} → ⦃ _ : Spanning{n}(vf) ⦄ → ∃(m ↦ (m ≥ n) ∧ ∃(f ↦ Basis{n}(vf ∘ f) ∧ Injective(f)))

      postulate basis-from-dim-spanning : ∀{vf} → Spanning{dim}(vf) → Basis{dim}(vf)

      postulate basis-from-dim-independent : ∀{vf} → LinearlyIndependent{dim}(vf) → Basis{dim}(vf)

      -- TODO: Move to some algebraic structure?
      -- Nilpotent(f) = ∃(n ↦ ∀{v} → (f ^ n ≡ 𝟎ᵥ))

    module _ where
      private LinearMap = Linear.LinearMap(_+ᵥ_)(_⋅ₛᵥ_)(_+ᵥ_)(_⋅ₛᵥ_)

      postulate linear-map-id : LinearMap(Function.id)

      -- v is a eigenvector for the eigenvalue 𝜆 of the linear transformation f
      Eigenvector : (V → V) → S → V → Stmt
      Eigenvector(f)(𝜆)(v) = ((v ≢ 𝟎ᵥ) → (f(v) ≡ 𝜆 ⋅ₛᵥ v))

      -- 𝜆 is a eigenvalue of the linear transformation f
      -- Multiplication by an eigenvalue can replace a linear transformation for certain vectors.
      Eigenvalue : (V → V) → S → Stmt
      Eigenvalue(f)(𝜆) = (∀{v : V} → Eigenvector(f)(𝜆)(v))

      -- Two linear mappings are similiar when there is a basis in which they are equal.
      -- Similiar : (f : V → V) → ⦃ _ : LinearMap(f) ⦄ → (g : V → V) → ⦃ _ : LinearMap(g) ⦄ → Stmt
      -- Similiar(f)(g) = (∀{v} → ∃(b ↦ Bijective(b) ∧ (f(v) ≡ (b ∘ g ∘ (inv(b)))(v))))

    record DotProductSpace (_∙_ : V → V → S) (_≤_ : S → S → Stmt) : Stmt where
      field
        commutativity     : Commutativity(_∙_)
        linearmapₗ        : ∀{v₂} → Linear.LinearMap(_+ᵥ_)(_⋅ₛᵥ_)(_+ₛ_)(_⋅ₛ_) (_∙ v₂)
        positive          : ∀{v} → (𝟎ₛ ≤ (v ∙ v))
        injective-zero    : ∀{v} → ((v ∙ v) ≡ 𝟎ₛ) → (v ≡ 𝟎ᵥ)

      postulate [⋅ₛᵥ]-commuting : ∀{s}{v₁ v₂} → ((s ⋅ₛᵥ v₁) ∙ v₂) ≡ (v₁ ∙ (s ⋅ₛᵥ v₂))
      postulate almost-injectivity-zeroₗ : ∀{v₁} → (∀{v₂} → ((v₁ ∙ v₂) ≡ 𝟎ₛ)) → (v₁ ≡ 𝟎ᵥ)
      postulate injectivityₗ : ∀{v₁ v₂} → (∀{v₃} → ((v₁ ∙ v₃) ≡ (v₂ ∙ v₃))) → (v₁ ≡ v₂)

      module Norm (√ : S → S) where
        -- The length of a vector
        norm : V → S
        norm(v) = √(v ∙ v)

        -- The positive part of a scalar
        abs : S → S
        abs(s) = √(s ⋅ₛ s)

        postulate homogeneity : ∀{s}{v} → norm(s ⋅ₛᵥ v) ≡ abs(s) ⋅ₛ norm(v)
        postulate triangle-inequality : ∀{v₁ v₂} → (norm(v₁ +ᵥ v₂) ≤ (norm(v₁) +ₛ norm(v₂)))
        postulate positivity : ∀{v} → (𝟎ₛ ≤ norm(v))
        postulate injectivity-zero : ∀{v} → (norm(v) ≡ 𝟎ₛ) → (v ≡ 𝟎ᵥ)
        postulate mult-inequality : ∀{v₁ v₂} → (abs(v₁ ∙ v₂) ≤ (norm(v₁) ⋅ₛ norm(v₂)))

        -- Two vectors are orthogonal when they are perpendicular.
        Orthogonal : V → V → Stmt
        Orthogonal(v₁)(v₂) = (v₁ ∙ v₂ ≡ 𝟎ₛ)

        {-
        OrthogonalAll : ∀{n} → Vectors(n) → Stmt
        OrthogonalAll{0}       (vf) = ⊤
        OrthogonalAll{1}       (vf) = Orthogonal(vf(0))(vf(1))
        OrthogonalAll{𝐒(𝐒(n))} (vf) = (OrthogonalAll{n} (vf)) ∧ Orthogonal(vf(n))(vf(𝐒(n)))
        -}

        postulate hypotenuse-length : ∀{v₁ v₂} → ⦃ _ : Orthogonal(v₁)(v₂) ⦄ → ((v₁ +ᵥ v₂) ∙ (v₁ +ᵥ v₂) ≡ (v₁ ∙ v₁) +ₛ (v₂ ∙ v₂))

        -- Transforms a vector to an unit vector in the same direction.
        normalize : (v : V) → ⦃ _ : v ≢ 𝟎ᵥ ⦄ → V
        normalize(v) ⦃ proof ⦄ = (⅟ₛ (norm(v)) ⦃ contrapositiveᵣ (injectivity-zero) (proof) ⦄) ⋅ₛᵥ v

        postulate norm-of-normalize : ∀{v} → ⦃ nonzero : (v ≢ 𝟎ᵥ) ⦄ → (norm(normalize(v) ⦃ nonzero ⦄) ≡ 𝟏ₛ)

--  -- TODO: Is it okay for VSP₂ to have a different scalar field compared to VSP? Some stuff will not be compatible (like addition for the same scalar type)?
--  module _ {V₂} ⦃ lang₂ ⦄ (VSP₂ : VectorSpace(V₂)(S) ⦃ lang₂ ⦄) where
--    open Language ⦃ ... ⦄
--    open VectorSpace ⦃ ... ⦄
--
--    private _+ᵥ₁_ = _+ᵥ_ ⦃ lang ⦄
--    private _⋅ₛᵥ₁_ = _⋅ₛᵥ_ ⦃ lang ⦄
--    private _+ᵥ₂_ = _+ᵥ_ ⦃ lang₂ ⦄
--    private _⋅ₛᵥ₂_ = _⋅ₛᵥ_ ⦃ lang₂ ⦄
--
--    private LinearMap₁₂ = Linear.LinearMap(_+ᵥ₁_)(_⋅ₛᵥ₁_)(_+ᵥ₂_)(_⋅ₛᵥ₂_)
--    private LinearMap₂₁ = Linear.LinearMap(_+ᵥ₂_)(_⋅ₛᵥ₂_)(_+ᵥ₁_)(_⋅ₛᵥ₁_)
--
--    module _ where
--      -- Kernel(f)(v) ⇔ (v ∈ Kernel(f))
--      Kernel : (f : V → V₂) → ⦃ _ : LinearMap₁₂(f) ⦄ → V → Stmt
--      Kernel(f)(v) = (f(v) ≡ 𝟎ᵥ ⦃ lang₂ ⦄ ⦃ VSP₂ ⦄)
--
--      -- TODO: Move away the module for two vector spaces from one so that dim is not bound to V
--      -- rank : (V → V₂) → ℕ
--      -- rank(_) = dim ⦃ VSP₂ ⦄
--
--    module _ where
--      postulate linear-map-const-zero : LinearMap₁₂(const(𝟎ᵥ ⦃ lang₂ ⦄ ⦃ VSP₂ ⦄))
--
--      -- The inverse of an invertible linear mapping is a linear mapping
--      postulate linear-inverse : ∀{f} → ⦃ _ : Bijective(f) ⦄ → LinearMap₁₂(f) → LinearMap₂₁(inv(f))
--
--      -- Injectivity for only the zero vector implies injectivity
--      postulate injective-zero : ∀{f} → ⦃ _ : LinearMap₁₂(f) ⦄ → (∀{v} → (f(v) ≡ 𝟎ᵥ ⦃ lang₂ ⦄ ⦃ VSP₂ ⦄) → (v ≡ 𝟎ᵥ ⦃ lang ⦄ ⦃ VSP ⦄)) → Injective(f)
--
--    -- module _ {_∙₁_ : V → V → S}{_≤₁_} {_∙₂_ : V₂ → V₂ → S}{_≤₂_} (DPSP₁ : DotProductSpace(_∙₁_)(_≤₁_)) (DPSP₂ : DotProductSpace(_∙₂_)(_≤₂_)) where
--    --   Adjoint : (f : V → V₂) → ⦃ _ : LinearMap₁₂(f) ⦄ → (g : V₂ → V) → ⦃ _ : LinearMap₂₁(g) ⦄ → Stmt
--    --   Adjoint(f)(g) = (∀{v₁ : V}{v₂ : V₂} → (f(v₁) ∙₂ v₂ ≡ v₁ ∙₁ g(v₂)))


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

module Binary where

data Bit : Set where
  O : Bit
  I : Bit

infixl 80 _<<_

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

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

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

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

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

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

infixl 60 _+_
infix  40 _==_

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

{-
test : (<<I << I << O << O << O) == (<<I << I << O << I) + (<<I << O << I << I)
test = refl
-}

{-
simple : (<<I << O) == (<<I) + (<<I)
simple = refl
-}

{-
t : Peano _
t = peano (<<I)
-}

{-
t : Pos
t = bsuc (<<I)
-}

{-
t : Pos
t = peano (<<I << O) <+> (<<I << I)
-- t = psuc pI <+> (<<I)
  where
    _<+>_ : {n : Pos} -> Peano n -> Pos -> Pos
    pI     <+> m = bsuc m
    psuc p <+> m = bsuc (p <+> m)
-}

t1 : Pos
t1 = (<<I << O) + (<<I << O)

t2 : (<<I) + (<<I) == (<<I) + (<<I)
t2 = refl


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

open import Categories.Category

module Categories.Functor.Hom.Properties.Contra {o ℓ e} (C : Category o ℓ e) where

private
  module C = Category C

open import Level
open import Function.Equality renaming (id to idFun)

open import Categories.Category.Instance.Setoids
open import Categories.Diagram.Limit
open import Categories.Diagram.Limit.Properties
open import Categories.Diagram.Colimit
open import Categories.Diagram.Duality
open import Categories.Functor
open import Categories.Functor.Hom
open import Categories.Functor.Hom.Properties.Covariant C.op
open import Categories.NaturalTransformation
open import Categories.NaturalTransformation.NaturalIsomorphism

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

open C
open Hom C

-- contravariant hom functor sends colimit of F to its limit.
module _ (W : Obj) {F : Functor J C} (col : Colimit F) where
  private
    module F = Functor F
    module J = Category J
    open HomReasoning

    HomF : Functor J.op (Setoids ℓ e)
    HomF = Hom[-, W ] ∘F F.op

  hom-colimit⇒limit : Limit HomF
  hom-colimit⇒limit = ≃-resp-lim (Hom≃ ⓘʳ F.op) (hom-resp-limit W (Colimit⇒coLimit _ col))
    where Hom≃ : Hom[ op ][ W ,-] ≃ Hom[-, W ]
          Hom≃ = record
            { F⇒G = ntHelper record
              { η       = λ _ → idFun
              ; commute = λ _ eq → C.∘-resp-≈ˡ (C.∘-resp-≈ʳ eq) ○ C.assoc
              }
            ; F⇐G = ntHelper record
              { η       = λ _ → idFun
              ; commute = λ _ eq → C.sym-assoc ○ C.∘-resp-≈ˡ (C.∘-resp-≈ʳ eq)
              }
            ; iso = λ _ → record
              { isoˡ = λ eq → eq
              ; isoʳ = λ eq → eq
              }
            }


{-
  Definition of various kinds of categories.

  This library follows the UniMath terminology, that is:

  Concept              Ob C   Hom C  Univalence

  Precategory          Type   Type   No
  Category             Type   Set    No
  Univalent Category   Type   Set    Yes

  This file also contains
    - pathToIso : Turns a path between two objects into an isomorphism between them
    - opposite categories

-}

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

module Cubical.Categories.Category where

open import Cubical.Categories.Category.Base public
open import Cubical.Categories.Category.Properties public


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.SymmetricGroup where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma
open import Cubical.Data.Nat using (ℕ ; suc ; zero)
open import Cubical.Data.Fin using (Fin ; isSetFin)
open import Cubical.Data.Empty
open import Cubical.Relation.Nullary using (¬_)

open import Cubical.Algebra.Group

private
  variable
    ℓ : Level

Symmetric-Group : (X : Type ℓ) → isSet X → Group {ℓ}
Symmetric-Group X isSetX = makeGroup (idEquiv X) compEquiv invEquiv (isOfHLevel≃ 2 isSetX isSetX)
  compEquiv-assoc compEquivEquivId compEquivIdEquiv invEquiv-is-rinv invEquiv-is-linv

-- Finite symmetrics groups

Sym : ℕ → Group
Sym n = Symmetric-Group (Fin n) isSetFin


------------------------------------------------------------------------
-- The Agda standard library
--
-- Closures of a unary relation with respect to a binary one.
------------------------------------------------------------------------

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

open import Relation.Binary

module Relation.Unary.Closure.Base {a b} {A : Set a} (R : Rel A b) where

open import Level
open import Relation.Unary using (Pred)

------------------------------------------------------------------------
-- Definitions

-- We start with the definition of □ ("box") which is named after the box
-- modality in modal logic. `□ T x` states that all the elements one step
-- away from `x` with respect to the relation R satisfy `T`.

□ : ∀ {t} → Pred A t → Pred A (a ⊔ b ⊔ t)
□ T x = ∀ {y} → R x y → T y

-- Use cases of □ include:
-- * The definition of the accessibility predicate corresponding to R:
--   data Acc (x : A) : Set (a ⊔ b) where
--     step : □ Acc x → Acc x

-- * The characterization of stability under weakening: picking R to be
--   `Data.List.Relation.Sublist.Inductive`, `∀ {Γ} → Tm Γ → □ T Γ`
--   corresponds to the fact that we have a notion of weakening for `Tm`.

-- Closed: whenever we have a value in one context, we can get one in any
-- related context.

record Closed {t} (T : Pred A t) : Set (a ⊔ b ⊔ t) where
  field next : ∀ {x} → T x → □ T x

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

module _ {t} {T : Pred A t} where

  reindex : Transitive R → ∀ {x y} → R x y → □ T x → □ T y
  reindex trans x∼y □Tx y∼z = □Tx (trans x∼y y∼z)

  -- Provided that R is reflexive and Transitive, □ is a comonad
  map : ∀ {u} {U : Pred A u} {x} → (∀ {x} → T x → U x) → □ T x → □ U x
  map f □Tx x~y = f (□Tx x~y)

  extract : Reflexive R → ∀ {x} → □ T x → T x
  extract refl □Tx = □Tx refl

  duplicate : Transitive R → ∀ {x} → □ T x → □ (□ T) x
  duplicate trans □Tx x∼y y∼z = □Tx (trans x∼y y∼z)

-- Provided that R is transitive, □ is the Closure operator
-- i.e. for any `T`, `□ T` is closed.
□-closed : Transitive R → ∀ {t} {T : Pred A t} → Closed (□ T)
□-closed trans = record { next = duplicate trans }


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

module Categories.Bicategory where

open import Level
open import Data.Product using (_,_)
open import Relation.Binary using (Rel)

open import Categories.Category using (Category; module Commutation)
open import Categories.Category.Monoidal.Instance.Cats using (module Product)
open import Categories.Enriched.Category using () renaming (Category to Enriched)
open import Categories.Functor using (module Functor)
open import Categories.NaturalTransformation.NaturalIsomorphism using (NaturalIsomorphism)

-- https://ncatlab.org/nlab/show/bicategory
-- notice that some axioms in nLab are inconsistent. they have been fixed in this definition.
record Bicategory o ℓ e t : Set (suc (o ⊔ ℓ ⊔ e ⊔ t)) where
  field
    enriched : Enriched (Product.Cats-Monoidal {o} {ℓ} {e}) t

  open Enriched enriched public
  module hom {A B} = Category (hom A B)
  module ComHom {A B} = Commutation (hom A B)

  infix 4 _⇒₁_ _⇒₂_ _≈_
  infixr 7 _∘ᵥ_ _∘₁_
  infixr 9 _▷_
  infixl 9 _◁_
  infixr 11 _⊚₀_ _⊚₁_  _∘ₕ_

  _⇒₁_ : Obj → Obj → Set o
  A ⇒₁ B = Category.Obj (hom A B)

  _⇒₂_ : {A B : Obj} → A ⇒₁ B → A ⇒₁ B → Set ℓ
  _⇒₂_ = hom._⇒_

  _⊚₀_ : {A B C : Obj} → B ⇒₁ C → A ⇒₁ B → A ⇒₁ C
  f ⊚₀ g = Functor.F₀ ⊚ (f , g)

  _⊚₁_ : {A B C : Obj} {f h : B ⇒₁ C} {g i : A ⇒₁ B} → f ⇒₂ h → g ⇒₂ i → f ⊚₀ g ⇒₂ h ⊚₀ i
  α ⊚₁ β = Functor.F₁ ⊚ (α , β)

  _≈_ : {A B : Obj} {f g : A ⇒₁ B} → Rel (f ⇒₂ g) e
  _≈_ = hom._≈_

  id₁ : {A : Obj} → A ⇒₁ A
  id₁ {_} = Functor.F₀ id _

  id₂ : {A B : Obj} {f : A ⇒₁ B} → f ⇒₂ f
  id₂ {A} {B} = Category.id (hom A B)

  -- 1-cell composition
  _∘₁_ : {A B C : Obj} → B ⇒₁ C → A ⇒₁ B → A ⇒₁ C
  _∘₁_ = _⊚₀_

  -- horizontal composition
  _∘ₕ_ : {A B C : Obj} {f h : B ⇒₁ C} {g i : A ⇒₁ B} → f ⇒₂ h → g ⇒₂ i → f ⊚₀ g ⇒₂ h ⊚₀ i
  _∘ₕ_ = _⊚₁_

  -- vertical composition
  _∘ᵥ_ : {A B : Obj} {f g h : A ⇒₁ B} (α : g ⇒₂ h) (β : f ⇒₂ g) → f ⇒₂ h
  _∘ᵥ_ = hom._∘_

  _◁_ : {A B C : Obj} {g h : B ⇒₁ C} (α : g ⇒₂ h) (f : A ⇒₁ B) → g ∘₁ f ⇒₂ h ∘₁ f
  α ◁ _ = α ⊚₁ id₂

  _▷_ : {A B C : Obj} {f g : A ⇒₁ B} (h : B ⇒₁ C) (α : f ⇒₂ g) → h ∘₁ f ⇒₂ h ∘₁ g
  _ ▷ α = id₂ ⊚₁ α

  private
    λ⇒ : {A B : Obj} {f : A ⇒₁ B} → id₁ ⊚₀ f hom.⇒ f
    λ⇒ {_} {_} {f} = NaturalIsomorphism.⇒.η unitˡ (_ , f)

    ρ⇒ : {A B : Obj} {f : A ⇒₁ B} → f ⊚₀ id₁ hom.⇒ f
    ρ⇒ {_} {_} {f} = NaturalIsomorphism.⇒.η unitʳ (f , _)

    α⇒ : {A B C D : Obj} {f : D ⇒₁ B} {g : C ⇒₁ D} {h : A ⇒₁ C} →
          ((f ⊚₀ g) ⊚₀ h) hom.⇒ (f ⊚₀ (g ⊚₀ h))
    α⇒ {_} {_} {_} {_} {f} {g} {h} = NaturalIsomorphism.⇒.η ⊚-assoc ((f , g) , h)

  field
    triangle : {A B C : Obj} {f : A ⇒₁ B} {g : B ⇒₁ C} →
                 let open ComHom {A} {C} in
                 [ (g ∘₁ id₁) ∘₁ f ⇒ g ∘₁ f ]⟨
                   α⇒                 ⇒⟨ g ∘₁ id₁ ∘₁ f ⟩
                   g ▷ λ⇒
                 ≈ ρ⇒ ◁ f
                 ⟩
    pentagon : {A B C D E : Obj} {f : A ⇒₁ B} {g : B ⇒₁ C} {h : C ⇒₁ D} {i : D ⇒₁ E} →
                 let open ComHom {A} {E} in
                 [ ((i ∘₁ h) ∘₁ g) ∘₁ f ⇒ i ∘₁ h ∘₁ g ∘₁ f ]⟨
                   α⇒ ◁ f                     ⇒⟨ (i ∘₁ h ∘₁ g) ∘₁ f ⟩
                   α⇒                         ⇒⟨ i ∘₁ (h ∘₁ g) ∘₁ f ⟩
                   i ▷ α⇒
                 ≈ α⇒                         ⇒⟨ (i ∘₁ h) ∘₁ g ∘₁ f ⟩
                   α⇒
                 ⟩


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

module Categories.Product where

open import Prelude hiding (_×_)
open import Categories

module _ {ℓ₁ ℓ₂} (C : Category ℓ₁ ℓ₂) where
  open Category C

  module _ (X Y : Ob) where
    record Product : Type (ℓ₁ ℓ⊔ ℓ₂) where
      field
        obj : Ob
        proj₁ : C [ obj , X ]
        proj₂ : C [ obj , Y ]
        ump : (f : C [ Z , X ]) (g : C [ Z , Y ]) →
              ∃![ f×g ] ((C [ proj₁ ∘ f×g ] ≡ f) Prelude.× (C [ proj₂ ∘ f×g ] ≡ g))
      _P[_×_] : ∀ {Z} → (π₁ : C [ Z , X ]) (π₂ : C [ Z , Y ]) →
                C [ Z , obj ]
      _P[_×_] π₁ π₂ = fst (ump π₁ π₂)

  record HasProducts : Type (ℓ₁ ℓ⊔ ℓ₂) where
    field product : (X Y : Ob) → Product X Y

    _×_ : Ob → Ob → Ob
    A × B = Product.obj (product A B)

    module _ {A A′ B B′ : Ob} where
      open Product using (_P[_×_])
      open Product (product A B) hiding (_P[_×_])

      _|×|_ : C [ A , A′ ] → C [ B , B′ ] → C [ Product.obj (product A B) , Product.obj (product A′ B′) ]
      f |×| g = product A′ B′ P[ C [ f ∘ proj₁ ] × C [ g ∘ proj₂ ] ]


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

open import Cubical.Core.Everything

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

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

open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv

isContr⊤ : isContr ⊤
isContr⊤ = tt , λ {tt → refl}

isProp⊤ : isProp ⊤
isProp⊤ _ _ i = tt -- definitionally equal to: isContr→isProp isContrUnit

isSet⊤ : isSet ⊤
isSet⊤ = isProp→isSet isProp⊤

isOfHLevel⊤ : (n : HLevel) → isOfHLevel n ⊤
isOfHLevel⊤ n = isContr→isOfHLevel n isContr⊤

diagonal-unit : ⊤ ≡ ⊤ × ⊤
diagonal-unit = isoToPath (iso (λ x → tt , tt) (λ x → tt) (λ {(tt , tt) i → tt , tt}) λ {tt i → tt})

fibId : ∀ {ℓ} (A : Type ℓ) → (fiber (λ (x : A) → tt) tt) ≡ A
fibId A = isoToPath
            (iso fst
                 (λ a → a , refl)
                 (λ _ → refl)
                 (λ a i → fst a
                         , isOfHLevelSuc 1 isProp⊤ _ _ (snd a) refl i))


{-# OPTIONS --cubical --no-import-sorts --no-exact-split --safe #-}
module Cubical.Experiments.NatMinusTwo.Base where

open import Cubical.Core.Primitives
open import Cubical.Data.Nat
open import Cubical.Data.Empty

record ℕ₋₂ : Type₀ where
  constructor -2+_
  field
    n : ℕ

pattern neg2 = -2+ zero
pattern neg1 = -2+ (suc zero)
pattern ℕ→ℕ₋₂ n = -2+ (suc (suc n))
pattern -1+_ n = -2+ (suc n)

2+_ : ℕ₋₂ → ℕ
2+ (-2+ n) = n

pred₋₂ : ℕ₋₂ → ℕ₋₂
pred₋₂ neg2 = neg2
pred₋₂ neg1 = neg2
pred₋₂ (ℕ→ℕ₋₂ zero) = neg1
pred₋₂ (ℕ→ℕ₋₂ (suc n)) = (ℕ→ℕ₋₂ n)

suc₋₂ : ℕ₋₂ → ℕ₋₂
suc₋₂ (-2+ n) = -2+ (suc n)

-- Natural number and negative integer literals for ℕ₋₂

open import Cubical.Data.Nat.Literals public

instance
  fromNatℕ₋₂ : HasFromNat ℕ₋₂
  fromNatℕ₋₂ = record { Constraint = λ _ → Unit ; fromNat = ℕ→ℕ₋₂ }

instance
  fromNegℕ₋₂ : HasFromNeg ℕ₋₂
  fromNegℕ₋₂ = record { Constraint = λ { (suc (suc (suc _))) → ⊥ ; _ → Unit }
                       ; fromNeg = λ { zero → 0 ; (suc zero) → neg1 ; (suc (suc zero)) → neg2 } }


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

open import Algebra.Structures.Bundles.Field

module Algebra.Linear.Construct.Matrix.Square
  {k ℓ} (K : Field k ℓ)
  where

open import Level using (_⊔_)
open import Data.Nat using (ℕ)
open import Data.Fin
open import Data.Product

open import Algebra.Structures.Field.Utils K
open import Algebra.Linear.Construct.Matrix K public

module F = Field K

private
  M : ℕ -> Set k
  M n = Matrix n n

  K' : Set k
  K' = F.Carrier

UpperTriangular : ℕ -> Set (k ⊔ ℓ)
UpperTriangular n = ∃ λ (A : M n) -> ∀ {i j} -> j ≤ i -> (A ⟪ i , j ⟫) F.≈ F.0#

LowerTriangular : ℕ -> Set (k ⊔ ℓ)
LowerTriangular n = ∃ λ (A : M n) -> ∀ {i j} -> i ≤ j -> (A ⟪ i , j ⟫) F.≈ F.0#

Invertible : ℕ -> Set (k ⊔ ℓ)
Invertible n = ∃₂ λ (A B : M n) -> (A * B) ≈ I n ×  (B * A) ≈ I n

trace : ∀ {n} -> M n n -> K'
trace A = vsum (V.tabulate λ i → A ⟪ i , i ⟫)

det : ∀ {n} -> M n -> K'
det A = {!!}


{-

Part 3: Transport and composition

- Cubical transport
- Subst as a special case of cubical transport
- Path induction from subst?
- Homogeneous composition (hcomp)
- Binary composition of paths as special case of hcomp

-}

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

open import Part1 public

-- Transport is more complex as ≡ isn't inductively defined (so we
-- can't define it by pattern-matching on p)
transport : {A B : Type ℓ} → A ≡ B → A → B
transport p a = transp (λ i → p i) i0 a

-- This lets us define subst (which is called "transport" in the HoTT book)
subst : {A : Type ℓ} (P : A → Type ℓ') {x y : A} (p : x ≡ y) → P x → P y
subst P p pa = transport (λ i → P (p i)) pa

-- The transp operation reduces differently for different types
-- formers. For paths it reduces to another primitive operation called
-- hcomp.

-- We can also define the J eliminator (aka path induction)
-- TODO: rewrite using subst?
-- TODO: talk about ∧
J : {A : Type ℓ} {B : A → Type ℓ'} {x : A}
    (P : (z : A) → x ≡ z → Type ℓ'')
    (d : P x refl) {y : A} (p : x ≡ y) → P y p
J P d p = transport (λ i → P (p i) (λ j → p (i ∧ j))) d

-- So J is provable, but it doesn't satisfy computation rule
-- definitionally. This is almost never a problem in practice as the
-- cubical primitives satisfy many new definitional equalities.


{-# OPTIONS --show-implicit #-}
-- {-# OPTIONS -v tc.data:25 #-}
-- {-# OPTIONS -v tc.conv.coerce:0 -v tc.with:25 #-}

module FilterSub where

open import Common.Level
open import Common.Equality

_∘_ : ∀ {a b c}
        {A : Set a} {B : A → Set b} {C : {x : A} → B x → Set c} →
      (∀ {x} (y : B x) → C y) → (g : (x : A) → B x) →
      ((x : A) → C (g x))
f ∘ g = λ x → f (g x)

data Bool : Set where
  true false : Bool

if_then_else_ : ∀ {a}{A : Set a} → Bool → A → A → A
if true  then t else e = t
if false then t else e = e

data Maybe {a} (A : Set a) : Set a where
  nothing : Maybe A
  just    : A → Maybe A

infixr 5 _∷_

data List {a} (A : Set a) : Set a where
  []  : List A
  _∷_ : (x : A) (xs : List A) → List A

data Any {a p} {A : Set a}
         (P : A → Set p) : List A → Set (a ⊔ p) where
  here  : ∀ {x xs} (px  : P x)      → Any P (x ∷ xs)
  there : ∀ {x xs} (pxs : Any P xs) → Any P (x ∷ xs)

infix 4 _⊆_ _∈_

_∈_ : ∀ {a}{A : Set a} → A → List A → Set _
x ∈ xs = Any (_≡_ x) xs

_⊆_ : ∀ {a}{A : Set a} → List A → List A → Set _
xs ⊆ ys = ∀ {x} → x ∈ xs → x ∈ ys

filter : ∀ {a} {A : Set a} → (A → Bool) → List A → List A
filter p []       = []
filter p (x ∷ xs) with p x
... | true  = x ∷ filter p xs
... | false =     filter p xs

filter-⊆ : ∀ {a} {A : Set a} (p : A → Bool) →
           (xs : List A) → filter p xs ⊆ xs
filter-⊆ _ []       = λ ()
filter-⊆ p (x ∷ xs) with p x | filter-⊆ p xs
... | false | hyp = there ∘ hyp
... | true  | hyp =
  λ { (here  eq)      → here eq
    ; (there ∈filter) → there (hyp ∈filter)
    }


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

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

open import Level
open import Function using (_$_; flip)
open import Data.Product using (Σ; _,_; uncurry)

open import Categories.Functor renaming (id to idF)
open import Categories.Functor.Bifunctor
open import Categories.NaturalTransformation hiding (id)
open import Categories.NaturalTransformation.Properties
open import Categories.Category.Cartesian 𝒞
open import Categories.Category.Monoidal.Closed
open import Categories.Object.Product 𝒞
  hiding (repack≡id; repack∘; repack-cancel; up-to-iso; transport-by-iso)
open import Categories.Object.Exponential 𝒞 hiding (repack)
open import Categories.Morphism 𝒞
open import Categories.Morphism.Reasoning 𝒞

private
  module 𝒞 = Category 𝒞
  open Category 𝒞
  open HomReasoning
  variable
    A B C   : Obj
    f g h i : A ⇒ B

-- Cartesian closed category
--   is a category with all products and exponentials
record CartesianClosed : Set (levelOfTerm 𝒞) where
  infixr 9 _^_
  -- an alternative notation for exponential, which emphasizes its internal hom natural
  infixr 5 _⇨_

  field
    cartesian : Cartesian
    exp       : Exponential A B

  module exp {A B} = Exponential (exp {A} {B})

  _^_ : Obj → Obj → Obj
  B ^ A = exp.B^A {A} {B}

  _⇨_ : Obj → Obj → Obj
  _⇨_ = flip _^_

  module cartesian = Cartesian cartesian

  open cartesian public

  B^A×A : ∀ B A → Product (B ^ A) A
  B^A×A B A = exp.product {A} {B}

  eval : Product.A×B (B^A×A B A) ⇒ B
  eval = exp.eval

  λg : C × A ⇒ B → C ⇒ B ^ A
  λg f = exp.λg product f

  λ-cong : f ≈ g → λg f ≈ λg g
  λ-cong eq = exp.λ-cong product eq

  _×id : (f : C ⇒ B ^ A) → C × A ⇒ [[ B^A×A B A ]]
  f ×id = [ product ⇒ exp.product ] f ×id

  β : eval ∘ λg f ×id ≈ f
  β = exp.β product

  η-exp : λg (eval ∘ f ×id) ≈ f
  η-exp = exp.η product

  λ-unique : eval ∘ f ×id ≈ g → f ≈ λg g
  λ-unique = exp.λ-unique product

  λ-unique₂ : eval ∘ f ×id ≈ eval ∘ g ×id → f ≈ g
  λ-unique₂ = exp.λ-unique′ product

  -- the annoying detail is that B^A×A is NOT the same as B ^ A × A, but they are isomorphic.
  -- make some infra so that the latter (which is more intuitive) can be used.

  B^A×A-iso : Product.A×B (B^A×A B A) ≅ B ^ A × A
  B^A×A-iso {B = B} {A = A} = record
    { from = repack exp.product product
    ; to   = repack product exp.product
    ; iso  = record
      { isoˡ = begin
        repack product exp.product ∘ repack exp.product product
          ≈⟨ [ exp.product ]⟨⟩∘ ⟩
        [ exp.product ]⟨ π₁ ∘ repack exp.product product , π₂ ∘ repack exp.product product ⟩
          ≈⟨ Product.⟨⟩-cong₂ exp.product project₁ project₂ ⟩
        [ exp.product ]⟨ [ exp.product ]π₁ , [ exp.product ]π₂ ⟩
          ≈⟨ Product.η exp.product ⟩
        id
          ∎
      ; isoʳ = begin
        repack exp.product product ∘ repack product exp.product
          ≈⟨ ⟨⟩∘ ⟩
        ⟨ [ exp.product ]π₁ ∘ repack product exp.product , [ exp.product ]π₂ ∘ repack product exp.product ⟩
          ≈⟨ ⟨⟩-cong₂ (Product.project₁ exp.product) (Product.project₂ exp.product) ⟩
        ⟨ π₁ , π₂ ⟩
          ≈⟨ η ⟩
        id
          ∎
      }
    }

  eval′ : B ^ A × A ⇒ B
  eval′ = eval ∘ to
    where open _≅_ B^A×A-iso

  λ-unique′ : eval′ ∘ (f ⁂ id) ≈ g → f ≈ λg g
  λ-unique′ eq = exp.λ-unique product (⟺ (pullʳ [ product ⇒ product ⇒ exp.product ]repack∘×) ○ eq)

  λ-unique₂′ : eval′ ∘ (f ⁂ id) ≈ eval′ ∘ (g ⁂ id) → f ≈ g
  λ-unique₂′ eq = (λ-unique′ eq) ○ ⟺ (λ-unique′ refl)

  β′ : eval′ ∘ (λg f ⁂ id) ≈ f
  β′ {f = f} = begin
    eval′ ∘ (λg f ⁂ id) ≈⟨ pullʳ [ product ⇒ product ⇒ exp.product ]repack∘× ⟩
    eval ∘ λg f ×id     ≈⟨ β ⟩
    f                   ∎

  η-exp′ : λg (eval′ ∘ (f ⁂ id)) ≈ f
  η-exp′ = sym (λ-unique′ refl)

  η-id′ : λg (eval′ {B = B} {A = A}) ≈ id
  η-id′ = sym (λ-unique′ (elimʳ (id×id product)))

  ⊤^A≅⊤ : ⊤ ^ A ≅ ⊤
  ⊤^A≅⊤ = record
    { from = !
    ; to   = λg !
    ; iso  = record
      { isoˡ = λ-unique₂ !-unique₂
      ; isoʳ = ⊤-id _
      }
    }

  A^⊤≅A : A ^ ⊤ ≅ A
  A^⊤≅A = record
    { from = let open _≅_ A×⊤≅A in eval′ ∘ to
    ; to   = let open _≅_ A×⊤≅A in λg from
    ; iso  = record
      { isoˡ = λ-unique₂′ $ begin
        eval′ ∘ ((λg π₁ ∘ eval′ ∘ ⟨ id , ! ⟩) ⁂ id)          ≈˘⟨ refl⟩∘⟨ first∘first ⟩
        eval′ ∘ ((λg π₁ ⁂ id) ∘ ((eval′ ∘ ⟨ id , ! ⟩) ⁂ id)) ≈⟨ pullˡ β′ ⟩
        π₁ ∘ ((eval′ ∘ ⟨ id , ! ⟩) ⁂ id)                     ≈⟨ helper ⟩
        eval′ ∘ (id ⁂ id)                                    ∎
      ; isoʳ = firstid ! $ begin
        ((eval′ ∘ ⟨ id , ! ⟩) ∘ λg π₁) ⁂ id                  ≈˘⟨ first∘first ⟩
        (eval′ ∘ ⟨ id , ! ⟩ ⁂ id) ∘ (λg π₁ ⁂ id)             ≈⟨ helper′ ⟩∘⟨refl ⟩
        (⟨ id , ! ⟩ ∘ eval′) ∘ (λg π₁ ⁂ id)                  ≈⟨ pullʳ β′ ⟩
        ⟨ id , ! ⟩ ∘ π₁                                      ≈⟨ ⟨⟩∘ ⟩
        ⟨ id ∘ π₁ , ! ∘ π₁ ⟩                                 ≈⟨ ⟨⟩-cong₂ identityˡ !-unique₂ ⟩
        ⟨ π₁ , π₂ ⟩                                          ≈⟨ η ⟩
        id                                                   ∎
      }
    }
    where helper = begin
            π₁ ∘ ((eval′ ∘ ⟨ id , ! ⟩) ⁂ id)                 ≈⟨ project₁ ⟩
            (eval′ ∘ ⟨ id , ! ⟩) ∘ π₁                        ≈⟨ pullʳ ⟨⟩∘ ⟩
            eval′ ∘ ⟨ id ∘ π₁ , ! ∘ π₁ ⟩                     ≈⟨ refl⟩∘⟨ ⟨⟩-congˡ !-unique₂ ⟩
            eval′ ∘ (id ⁂ id)                                ∎
          helper′ = let open _≅_ A×⊤≅A in begin
            (eval′ ∘ ⟨ id , ! ⟩) ⁂ id                        ≈⟨ introˡ isoˡ ⟩
            (⟨ id , ! ⟩ ∘ π₁) ∘ ((eval′ ∘ ⟨ id , ! ⟩) ⁂ id)  ≈⟨ pullʳ helper ⟩
            ⟨ id , ! ⟩ ∘ (eval′ ∘ (id ⁂ id))                 ≈⟨ refl⟩∘⟨ elimʳ (id×id product) ⟩
            ⟨ id , ! ⟩ ∘ eval′                               ∎

  -- we use -⇨- to represent the bifunctor.
  -- -^- would generate a bifunctor of type Bifunctor 𝒞 𝒞.op 𝒞 which is not very typical.
  -⇨- : Bifunctor 𝒞.op 𝒞 𝒞
  -⇨- = record
    { F₀           = uncurry _⇨_
    ; F₁           = λ where
      (f , g) → λg (g ∘ eval′ ∘ second f)
    ; identity     = λ-cong (identityˡ ○ (elimʳ (id×id product))) ○ η-id′
    ; homomorphism = λ-unique₂′ helper
    ; F-resp-≈     = λ where
      (eq₁ , eq₂) → λ-cong (∘-resp-≈ eq₂ (∘-resp-≈ʳ (⁂-cong₂ refl eq₁)))
    }
    where helper : eval′ ∘ first (λg ((g ∘ f) ∘ eval′ ∘ second (h ∘ i)))
                 ≈ eval′ ∘ first (λg (g ∘ eval′ ∘ second i) ∘ λg (f ∘ eval′ ∘ second h))
          helper {g = g} {f = f} {h = h} {i = i} = begin
            eval′ ∘ first (λg ((g ∘ f) ∘ eval′ ∘ second (h ∘ i)))                         ≈⟨ β′ ⟩
            (g ∘ f) ∘ eval′ ∘ second (h ∘ i)                                              ≈˘⟨ refl⟩∘⟨ pullʳ second∘second ⟩
            (g ∘ f) ∘ (eval′ ∘ second h) ∘ second i                                       ≈˘⟨ pullˡ refl ⟩
            g ∘ f ∘ (eval′ ∘ second h) ∘ second i                                         ≈˘⟨ refl⟩∘⟨ assoc ⟩
            g ∘ (f ∘ eval′ ∘ second h) ∘ second i                                         ≈˘⟨ refl⟩∘⟨ pullˡ β′ ⟩
            g ∘ eval′ ∘ first (λg (f ∘ eval′ ∘ second h)) ∘ second i                      ≈⟨ refl⟩∘⟨ pushʳ first↔second ⟩
            g ∘ (eval′ ∘ second i) ∘ first (λg (f ∘ eval′ ∘ second h))                    ≈˘⟨ assoc ⟩
            (g ∘ eval′ ∘ second i) ∘ first (λg (f ∘ eval′ ∘ second h))                    ≈˘⟨ pullˡ β′ ⟩
            eval′ ∘ first (λg (g ∘ eval′ ∘ second i)) ∘ first (λg (f ∘ eval′ ∘ second h)) ≈⟨ refl⟩∘⟨ first∘first ⟩
            eval′ ∘ first (λg (g ∘ eval′ ∘ second i) ∘ λg (f ∘ eval′ ∘ second h))         ∎

  _⇨- : Obj → Endofunctor 𝒞
  _⇨- = appˡ -⇨-

  -⇨_ : Obj → Functor 𝒞.op 𝒞
  -⇨_ = appʳ -⇨-

  module _ where
    private
      A⇨[-×A] : Obj → Endofunctor 𝒞
      A⇨[-×A] A = A ⇨- ∘F -× A

      module A⇨[-×A] {A} = Functor (A⇨[-×A] A)

      [A⇨-]×A : Obj → Endofunctor 𝒞
      [A⇨-]×A A = -× A ∘F A ⇨-

      module [A⇨-]×A {A} = Functor ([A⇨-]×A A)

    closedMonoidal : Closed monoidal
    closedMonoidal = record
      { [-,-]   = -⇨-
      ; adjoint = λ {A} → record
        { unit   = ntHelper record
          { η       = λ _ → λg id
          ; commute = λ f → λ-unique₂′ $ begin
            eval′ ∘ first (λg id ∘ f)                     ≈˘⟨ refl⟩∘⟨ first∘first ⟩
            eval′ ∘ first (λg id) ∘ first f               ≈⟨ cancelˡ β′ ⟩
            first f                                       ≈˘⟨ cancelʳ β′ ⟩
            (first f ∘ eval′)  ∘ first (λg id)            ≈˘⟨ ∘-resp-≈ʳ (elimʳ (id×id product)) ⟩∘⟨refl ⟩
            (first f ∘ eval′ ∘ first id)  ∘ first (λg id) ≈˘⟨ pullˡ β′ ⟩
            eval′ ∘ first (A⇨[-×A].F₁ f) ∘ first (λg id)  ≈⟨ refl⟩∘⟨ first∘first ⟩
            eval′ ∘ first (A⇨[-×A].F₁ f ∘ λg id)          ∎
          }
        ; counit = ntHelper record
          { η       = λ _ → eval′
          ; commute = λ f → begin
            eval′ ∘ [A⇨-]×A.F₁ f ≈⟨ β′ ⟩
            f ∘ eval′ ∘ first id ≈⟨ refl⟩∘⟨ elimʳ (id×id product) ⟩
            f ∘ eval′            ∎
          }
        ; zig    = β′
        ; zag    = λ-unique₂′ $ begin
          eval′ ∘ first (λg (eval′ ∘ eval′ ∘ second id) ∘ λg id)
                                          ≈˘⟨ refl⟩∘⟨ first∘first ⟩
          eval′ ∘ first (λg (eval′ ∘ eval′ ∘ second id)) ∘ first (λg id)
                                          ≈⟨ pullˡ β′ ⟩
          (eval′ ∘ eval′ ∘ second id) ∘ first (λg id)
                                          ≈⟨ ∘-resp-≈ʳ (elimʳ (id×id product)) ⟩∘⟨refl ⟩
          (eval′ ∘ eval′) ∘ first (λg id) ≈⟨ cancelʳ β′ ⟩
          eval′                           ≈˘⟨ elimʳ (id×id product) ⟩
          eval′ ∘ first id                ∎
        }
      ; mate    = λ {X Y} f → record
        { commute₁ = λ-unique₂′ $ begin
          eval′ ∘ first (λg (second f ∘ eval′ ∘ second id) ∘ λg id)         ≈˘⟨ refl⟩∘⟨ first∘first ⟩
          eval′ ∘ first (λg (second f ∘ eval′ ∘ second id)) ∘ first (λg id) ≈⟨ pullˡ β′ ⟩
          (second f ∘ eval′ ∘ second id) ∘ first (λg id)                    ≈⟨ ∘-resp-≈ʳ (elimʳ (id×id product)) ⟩∘⟨refl ⟩
          (second f ∘ eval′) ∘ first (λg id)                                ≈⟨ cancelʳ β′ ⟩
          second f                                                          ≈˘⟨ cancelˡ β′ ⟩
          eval′ ∘ first (λg id) ∘ second f                                  ≈⟨ pushʳ first↔second ⟩
          (eval′ ∘ second f) ∘ first (λg id)                                ≈˘⟨ identityˡ ⟩∘⟨refl ⟩
          (id ∘ eval′ ∘ second f) ∘ first (λg id)                           ≈˘⟨ pullˡ β′ ⟩
          eval′ ∘ first (λg (id ∘ eval′ ∘ second f)) ∘ first (λg id)        ≈⟨ refl⟩∘⟨ first∘first ⟩
          eval′ ∘ first (λg (id ∘ eval′ ∘ second f) ∘ λg id)                ∎
        ; commute₂ = begin
          eval′ ∘ first (λg (id ∘ eval′ ∘ second f)) ≈⟨ β′ ⟩
          id ∘ eval′ ∘ second f                      ≈⟨ identityˡ ⟩
          eval′ ∘ second f                           ∎
        }
      }

  module closedMonoidal = Closed closedMonoidal


-- Operator example

module Operators where

data True : Set where
  tt : True

data False : Set where

data Bool : Set where
  false : Bool
  true  : Bool

-- An operator is declared with '_' where the arguments go
if_then_else_ : Bool -> {A : Set} -> A -> A -> A
if true  then x else y = x
if false then x else y = y

-- The actual name of the operator is obtained by removing all the spaces from
-- the declared version.
infix 1 if_then_else_

-- This name can be used in normal applications, for instance, if a hidden argument
-- needs to be supplied.
_&&_ : Bool -> Bool -> Bool
x && y = if_then_else_ x {Bool} y false

-- Operators can be prefix...
¬_ : Bool -> Bool
¬ true  = false
¬ false = true

-- ...or postfix...
_valid : Bool -> Set
true  valid = True
false valid = False

-- ...or roundfix
⟦_⟧ : Bool -> Set
⟦ x ⟧ = x valid


{-

An simpler definition of truncation ∥ A ∥ n from n ≥ -1

Note that this uses the HoTT book's indexing, so it will be off
 from `∥_∥_` in HITs.Truncation.Base by -2

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.HITs.Truncation.FromNegOne.Base where

open import Cubical.Data.NatMinusOne renaming (suc₋₁ to suc)
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.HITs.Sn

data  ∥_∥_ {ℓ} (A : Type ℓ) (n : ℕ₋₁) : Type ℓ where
  ∣_∣ : A  → ∥ A ∥ n
  hub : (f : S (suc n) → ∥ A ∥ n) → ∥ A ∥ n
  spoke : (f : S (suc n) → ∥ A ∥ n) (x : S (suc n)) → hub f ≡ f x


-- This module is used to illustrate how to import a parameterised module.
module examples.syntax.ModuleB
	(A : Set)
	((==) : A -> A -> Prop)
	(refl : (x : A) -> x == x)
    where

  infix 5 /\

  module SubModule where
    postulate dummy : A

  data True : Prop where
    tt : True

  data False : Prop where

  data (/\) (P, Q : Prop) : Prop where
    andI : P -> Q -> P /\ Q

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

  eqList : List -> List -> Prop
  eqList nil         nil	  =  True
  eqList (cons x xs) nil          =  False
  eqList nil         (cons y ys)  =  False
  eqList (cons x xs) (cons y ys)  =  x == y /\ eqList xs ys

  reflEqList : (xs : List) -> eqList xs xs
  reflEqList nil	  = tt
  reflEqList (cons x xs)  = andI (refl x) (reflEqList xs)


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

open import LogicalFormulae
open import Numbers.Naturals.Definition
open import Maybe

module Numbers.Naturals.Subtraction where

_-N'_ : (a b : ℕ) → Maybe ℕ
zero -N' zero = yes 0
zero -N' succ b = no
succ a -N' zero = yes (succ a)
succ a -N' succ b = a -N' b

subtractZero : (a : ℕ) → a -N' 0 ≡ yes a
subtractZero zero = refl
subtractZero (succ a) = refl


module Miscellaneous.associative-side where

private variable T : Set
private variable _▫_ : T → T → T
private variable id : T

data _≡_ {ℓ}{T : Set(ℓ)} : T → T → Set(ℓ) where
  [≡]-intro : ∀{x : T} → (x ≡ x)

Associativity : (T → T → T) → Set
Associativity(_▫_) = ∀{a b c} → ((a ▫ (b ▫ c)) ≡ ((a ▫ b) ▫ c))

Identityₗ : (T → T → T) → T → Set
Identityₗ(_▫_)(id) = ∀{a} → ((id ▫ a) ≡ a)

Identityᵣ : (T → T → T) → T → Set
Identityᵣ(_▫_)(id) = ∀{a} → ((a ▫ id) ≡ a)

right-op₂-associativity : Associativity{T}(\x y → y)
right-op₂-associativity = [≡]-intro

right-op₂-identityₗ : Identityₗ{T}(\x y → y)(id)
right-op₂-identityₗ {a = a} = [≡]-intro

right-op₂-when-identityᵣₗ : (∀{a} → (id ≡ a)) → Identityᵣ{T}(\x y → y)(id)
right-op₂-when-identityᵣₗ p = p

right-op₂-when-identityᵣᵣ : Identityᵣ{T}(\x y → y)(id) → (∀{a} → (id ≡ a))
right-op₂-when-identityᵣᵣ p = p


{- SAMPLE PROGRAMS IN SOURCE LANGUAGE -}

{-# OPTIONS --no-termination-check #-}

open import Preliminaries
open import Source

module Samples where

  {- dbl (n : nat) : nat = 2 * n -}
  dbl : ∀ {Γ} → Γ |- (nat ->s nat)
  dbl = lam (rec (var i0) z (suc (suc (force (var (iS i0))))))

  {- add (m n : nat) : nat = m + n -}
  add : ∀ {Γ} → Γ |- (nat ->s (nat ->s nat))
  add = lam (lam (rec (var (iS i0)) (var i0) (suc (force (var (iS i0))))))

  {- mult (m n : nat) : nat = m * n -}
  mult : ∀ {Γ} → Γ |- (nat ->s (nat ->s nat))
  mult = lam (lam (rec (var (iS i0)) z (app (app add (var (iS (iS i0)))) (force (var (iS i0))))))

  -- hack : instead of having bool case analysis just do natural number recursion and return 1/0

  {- iszero (n : nat) : nat = z -> 1 | _ -> 0 -}
  isz : ∀ {Γ} → Γ |- (nat ->s nat)
  isz = lam (rec (var i0) (suc z) z)

  {- leq (m n : nat) : nat = m ≤ n -}
  leq : ∀ {Γ} → Γ |- (nat ->s (nat ->s nat))
  leq = lam (lam (rec (var (iS i0))
          (app isz (var (iS i0)))
          (rec (var (iS (iS (iS i0)))) (suc z) (force (var (iS i0))))))

  {- len (l : list τ) : nat = [] -> z | x :: xs -> 1 + len xs -}
  len : ∀ {Γ τ} → Γ |- (list τ ->s nat)
  len = lam (listrec (var i0) z (suc (force (var (iS (iS i0))))))

  {- insert (l : list nat) (el : nat) : list nat = [] -> [el] | x :: xs -> (leq el x -> el :: x :: xs | x :: (insert el xs)) -}
  insert : ∀ {Γ} → Γ |- (list nat ->s (nat ->s list nat))
  insert = lam (lam (listrec (var (iS i0))
             (var i0 ::s nil)
             (rec (app (app leq (var (iS (iS (iS i0))))) (var i0))
               (var i0 ::s force (var (iS (iS i0))))
               (var (iS (iS (iS (iS (iS i0))))) ::s var (iS (iS (iS (iS (iS (iS i0))))))))))

  {- insertion sort (l : list nat) : list nat = [] -> [] | x :: xs -> insert x (isort xs) -}
  isort : ∀ {Γ} → Γ |- (list nat ->s list nat)
  isort = lam (listrec (var i0) nil (app (app insert (force (var (iS (iS i0))))) (var i0)))

  {- halve (l : list nat) : (list nat * list nat) = splits a list in half -}
  halve : ∀ {Γ} → Γ |- (list nat ->s (list nat ×s list nat))
  halve = lam (listrec (var i0)
            (prod nil nil)
            (listrec (var (iS i0))
              (prod (var i0 ::s nil) nil)
              (prod (var (iS (iS (iS i0))) ::s split (force (var (iS (iS i0)))) (var i0)) (var i0 ::s split (force (var (iS (iS i0)))) (var (iS i0))))))

  {- merge (l1 l2 : list nat) : list nat =
       match l1 with
       [] -> l2
       x :: xs ->
         match l2 with
           [] -> x :: xs
           y :: ys ->
             x <= y -> x :: merge xs l2
             _ -> y :: merge l1 ys -}
  merge : ∀ {Γ} → Γ |- ((list nat ×s list nat) ->s list nat)
  merge = lam (listrec (split (var i0) (var i0))
            (split (var i0) (var (iS i0)))
            (listrec (split (var (iS (iS (iS i0)))) (var (iS i0)))
              (split (var (iS (iS (iS i0)))) (var i0))
              (rec (app (app leq (var (iS (iS (iS i0))))) (var i0))
                (var (iS (iS (iS i0))) ::s force (var (iS (iS (iS (iS (iS i0)))))))
                (var i0 ::s app merge (prod (split (var (iS (iS (iS (iS (iS (iS (iS (iS i0))))))))) (var (iS i0))) (var (iS (iS (iS i0)))))))))

  {- mergesort (l : list nat) : list nat -}
  msort : ∀ {Γ} → Γ |- (list nat ->s list nat)
  msort = lam (listrec (var i0)
            nil
            (listrec (var (iS i0))
              (var i0 ::s nil)
              (app merge (prod
                (app msort (split (app halve (var (iS (iS (iS (iS (iS (iS i0)))))))) (var i0)))
                (app msort (split (app halve (var (iS (iS (iS (iS (iS (iS i0)))))))) (var (iS i0))))))))


module +-example where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _∎)
open import Naturals using (suc; _+_)

+-example : 3 + 4 ≡ 7
+-example =
  begin
    3 + 4
  ≡⟨⟩
    suc (2 + 4)
  ≡⟨⟩
    suc (suc (1 + 4))
  ≡⟨⟩
    suc (suc (suc (0 + 4)))
  ≡⟨⟩
    suc (suc (suc 4))
  ≡⟨⟩
    7
  ∎


------------------------------------------------------------------------
-- Definitions of functions that generate list
------------------------------------------------------------------------

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

module Math.Combinatorics.ListFunction where

open import Data.List
open import Data.List.NonEmpty as NE using (List⁺)
open import Data.Nat
open import Data.Product as Prod using (_×_; _,_)
open import Function
open import Relation.Binary.PropositionalEquality hiding ([_])

module _ {a} {A : Set a} where
  -- applyEach (_+ 10) (upTo 3)
  -- >>> (10 ∷ 1 ∷ 2 ∷ []) ∷ (0 ∷ 11 ∷ 2 ∷ []) ∷ (0 ∷ 1 ∷ 12 ∷ []) ∷ []
  applyEach : (A → A) → List A → List (List A)
  applyEach f []       = []
  applyEach f (x ∷ xs) = (f x ∷ xs) ∷ map (x ∷_) (applyEach f xs)

module _ {a} {A : Set a} where
  -- Combinations
  -- combinations 2 (upTo 3)
  -- >>> (0 ∷ 1 ∷ []) ∷ (0 ∷ 2 ∷ []) ∷
  -- >>> (0 ∷ 3 ∷ []) ∷ (1 ∷ 2 ∷ []) ∷ (1 ∷ 3 ∷ []) ∷ (2 ∷ 3 ∷ []) ∷ []
  combinations : ℕ → List A → List (List A)
  combinations 0       xs       = [ [] ]
  combinations (suc k) []       = []
  combinations (suc k) (x ∷ xs) =
    map (x ∷_) (combinations k xs) ++ combinations (suc k) xs

  -- combinationsWithComplement 2 (upTo 2)
  -- >>> (0 ∷ 1 ∷ [] , 2 ∷ []) ∷
  -- >>> (0 ∷ 2 ∷ [] , 1 ∷ []) ∷ (1 ∷ 2 ∷ [] , 0 ∷ []) ∷ []
  combinationsWithComplement : ℕ → List A → List (List A × List A)
  combinationsWithComplement 0       xs       = [ [] , xs ]
  combinationsWithComplement (suc k) []       = []
  combinationsWithComplement (suc k) (x ∷ xs) =
    map (Prod.map₁ (x ∷_)) (combinationsWithComplement k xs) ++
    map (Prod.map₂ (x ∷_)) (combinationsWithComplement (suc k) xs)

  -- split list into two list (include empty list and order is preserved)
  -- splits₂ (upTo 3)
  -- >>> ([] , 0 ∷ 1 ∷ 2 ∷ []) ∷
  -- >>> (0 ∷ [] , 1 ∷ 2 ∷ []) ∷
  -- >>> (0 ∷ 1 ∷ [] , 2 ∷ []) ∷ (0 ∷ 1 ∷ 2 ∷ [] , []) ∷ []
  splits₂ : List A → List (List A × List A)
  splits₂ []       = ([] , []) ∷ []
  splits₂ (x ∷ xs) = ([] , x ∷ xs) ∷ map (Prod.map₁ (x ∷_)) (splits₂ xs)

  splits : ℕ → List A → List (List (List A))
  splits 0             xs = []
  splits 1             xs = [ xs ∷ [] ]
  splits (suc (suc k)) xs = concatMap f (splits (suc k) xs)
    where
    f : List (List A) → List (List (List A))
    f []         = []
    f (ys ∷ yss) = map (λ { (as , bs) → as ∷ bs ∷ yss }) (splits₂ ys)

  splits⁺₂Acc : A → List A → List (List⁺ A × List⁺ A)
  splits⁺₂Acc x []       = []
  splits⁺₂Acc x (y ∷ xs) = (x NE.∷ [] , y NE.∷ xs) ∷
                           map (Prod.map₁ (x NE.∷⁺_)) (splits⁺₂Acc y xs)

  -- split list into two list (exclude empty list and order is preserved)
  splits⁺₂ : List⁺ A → List (List⁺ A × List⁺ A)
  splits⁺₂ (x NE.∷ xs) = splits⁺₂Acc x xs

  splits⁺ : ℕ → List⁺ A → List (List (List⁺ A))
  splits⁺ 0             xs = []
  splits⁺ 1             xs = [ xs ∷ [] ]
  splits⁺ (suc (suc k)) xs = concatMap f (splits⁺ (suc k) xs)
    where
    f : List (List⁺ A) → List (List (List⁺ A))
    f []         = []
    f (ys ∷ yss) =
      map (λ { (as , bs) → as ∷ bs ∷ yss }) (splits⁺₂ ys)

  splits⁺AllAcc : A → List A → List⁺ (List⁺ (List⁺ A))
  splits⁺AllAcc x []       = ((x NE.∷ []) NE.∷ []) NE.∷ []
  splits⁺AllAcc x (y ∷ xs) =
    NE.map (λ zs → (x NE.∷ []) NE.∷⁺ zs) yss NE.⁺++⁺
    NE.map (λ { (z NE.∷ zs) → (x NE.∷⁺ z) NE.∷ zs} ) yss
    where yss = splits⁺AllAcc y xs

  splits⁺All : List⁺ A → List⁺ (List⁺ (List⁺ A))
  splits⁺All (x NE.∷ xs) = splits⁺AllAcc x xs

  -- Partition of set
  -- Generalization of `combinationsWithComplement`
  -- partitions 2 (upTo 3)
  -- >>> ((0 ∷ []) ∷ (1 ∷ 2 ∷ []) ∷ []) ∷
  -- >>> ((0 ∷ 1 ∷ []) ∷ (2 ∷ []) ∷ []) ∷
  -- >>> ((1 ∷ []) ∷ (0 ∷ 2 ∷ []) ∷ []) ∷ []
  partitions : ℕ → List A → List (List (List A))
  partitions 0       []       = [ [] ]
  partitions 0       (x ∷ xs) = []
  partitions (suc k) []       = []
  partitions (suc k) (x ∷ xs) =
    map ([ x ] ∷_) (partitions k xs) ++
    concatMap (applyEach (x ∷_)) (partitions (suc k) xs)

  partitionsAll : List A → List (List (List A))
  partitionsAll []       = [ [] ]
  partitionsAll (x ∷ xs) =
    map ([ x ] ∷_) yss ++ concatMap (applyEach (x ∷_)) yss
    where yss = partitionsAll xs

module _ {a} {A : Set a} where
  -- insertEverywhere 100 (upTo 2)
  -- >>> (100 ∷ 0 ∷ 1 ∷ []) ∷ (0 ∷ 100 ∷ 1 ∷ []) ∷ (0 ∷ 1 ∷ 100 ∷ []) ∷ []
  insertEverywhere : A → List A → List (List A)
  insertEverywhere x []       = [ [ x ] ]
  insertEverywhere x (y ∷ ys) = (x ∷ y ∷ ys) ∷ map (y ∷_) (insertEverywhere x ys)

module _ {a} {A : Set a} where
  -- permutations (upTo 2)
  -- >>> (0 ∷ 1 ∷ []) ∷ (1 ∷ 0 ∷ []) ∷ []
  permutations : List A → List (List A)
  permutations []       = [ [] ]
  permutations (x ∷ xs) = concatMap (insertEverywhere x) (permutations xs)