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

open import Level

open import Categories.Category
open import Categories.Functor
open import Categories.Functor.Properties
open import Categories.Object.Terminal
open import Categories.Object.Initial

open import Categories.Diagram.Limit
open import Categories.Diagram.Colimit
open import Categories.Diagram.Cone.Properties
open import Categories.Diagram.Cocone.Properties

open import Categories.Category.Construction.Cones
open import Categories.Category.Construction.Cocones

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

module _ (F : Functor 𝒞 𝒟) {J : Functor ℐ 𝒞} where

  PreservesLimit : (L : Limit J) → Set _
  PreservesLimit L = IsTerminal (Cones (F ∘F J)) (F-map-Coneˡ F limit)
    where open Limit L

  PreservesColimit : (L : Colimit J) → Set _
  PreservesColimit L = IsInitial (Cocones (F ∘F J)) (F-map-Coconeˡ F colimit)
    where open Colimit L

  ReflectsLimits : Set _
  ReflectsLimits = ∀ (K : Cone J) → IsTerminal (Cones (F ∘F J)) (F-map-Coneˡ F K) → IsTerminal (Cones J) K

  ReflectsColimits : Set _
  ReflectsColimits = ∀ (K : Cocone J) → IsInitial (Cocones (F ∘F J)) (F-map-Coconeˡ F K) → IsInitial (Cocones J) K

--   record CreatesLimits : Set (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′ ⊔ o″ ⊔ ℓ″) where
--     field
--       preserves-limits : PreservesLimit
--       reflects-limits  : ReflectsLimits

--   record CreatesColimits : Set (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′ ⊔ o″ ⊔ ℓ″) where
--     field
--       preserves-colimits : PreservesColimit
--       reflects-colimits  : ReflectsColimits

Continuous : ∀ o ℓ e → (F : Functor 𝒞 𝒟) → Set _
Continuous {𝒞 = 𝒞} o ℓ e F = ∀ {𝒥 : Category o ℓ e} {J : Functor 𝒥 𝒞} (L : Limit J) → PreservesLimit F L

Cocontinuous : ∀ o ℓ e → (F : Functor 𝒞 𝒟) → Set _
Cocontinuous {𝒞 = 𝒞} o ℓ e F = ∀ {𝒥 : Category o ℓ e} {J : Functor 𝒥 𝒞} (L : Colimit J) → PreservesColimit F L


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

-- Given a predicate on the objects of a Category C, build another category
-- with just those that satisfy a pr

module Categories.Category.Construction.ObjectRestriction where

open import Level
open import Data.Product using (Σ; proj₁)
open import Relation.Unary using (Pred)
open import Function using (_on_) renaming (id to id→)

open import Categories.Category.Core

private
  variable
    o ℓ e ℓ′ : Level

ObjectRestriction : (C : Category o ℓ e) → Pred (Category.Obj C) ℓ′ → Category (o ⊔ ℓ′) ℓ e
ObjectRestriction C R = record
  { Obj = Σ Obj R
  ; _⇒_ = _⇒_ on proj₁
  ; _≈_ = _≈_
  ; id = id
  ; _∘_ = _∘_
  ; assoc = assoc
  ; sym-assoc = sym-assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; identity² = identity²
  ; equiv = equiv
  ; ∘-resp-≈ = ∘-resp-≈
  }
  where open Category C


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

open import Level

-- ⊥ is Initial

module Categories.Category.Instance.Zero where

open import Data.Empty using (⊥; ⊥-elim)
open import Function renaming (id to idf)

open import Categories.Category
open import Categories.Functor
open import Categories.Category.Instance.Cats
import Categories.Object.Initial as Init

-- Unlike for ⊤ being Terminal, Agda can't deduce these, need to be explicit
module _ {o ℓ e : Level} where
  open Init (Cats o ℓ e)

  Zero : Category o ℓ e
  Zero = record
    { Obj       = Lift o ⊥
    ; _⇒_       = λ _ _ → Lift ℓ ⊥
    ; _≈_       = λ _ _ → Lift e ⊥
    ; id        = λ { { lift () } }
    ; _∘_       = λ a _ → a -- left-biased rather than strict
    ; assoc     = λ { {lift () } }
    ; sym-assoc = λ { {lift () } }
    ; identityˡ = λ { {()} }
    ; identityʳ = λ { {()} }
    ; identity² = λ { {()} }
    ; ∘-resp-≈  = λ { () }
    ; equiv     = record
      { refl = λ { {()} }
      ; sym = idf
      ; trans = λ a _ → a
      }
    }

  Zero-⊥ : Initial
  Zero-⊥ = record
    { ⊥ = Zero
    ; ! = record
      { F₀ = λ { (lift x) → ⊥-elim x }
      ; F₁ = λ { (lift ()) }
      ; identity = λ { {lift ()} }
      ; homomorphism = λ { {lift ()} }
      ; F-resp-≈ = λ { () }
      }
    ; !-unique = λ f → record
      { F⇒G = record { η = λ { () } ; commute = λ { () } ; sym-commute = λ { () } }
      ; F⇐G = record { η = λ { () } ; commute = λ { () } ; sym-commute = λ { () } }
      ; iso = λ { (lift ()) }
      }
    }


{-# OPTIONS --safe #-}
module Relation.Ternary.Separation.Construct.List {a} (A : Set a) where

open import Level
open import Data.Product
open import Data.List
open import Data.List.Properties using (++-isMonoid)
open import Data.List.Relation.Ternary.Interleaving.Propositional as I public
open import Data.List.Relation.Ternary.Interleaving.Properties
open import Data.List.Relation.Binary.Equality.Propositional
open import Data.List.Relation.Binary.Permutation.Inductive

open import Relation.Binary.PropositionalEquality as P hiding ([_])
open import Relation.Unary hiding (_∈_; _⊢_)
open import Relation.Ternary.Separation

private C = List A

instance separation : RawSep C
separation = record { _⊎_≣_ = Interleaving }

-- TODO add to stdlib
interleaving-assoc : ∀ {a b ab c abc : List A} →
          Interleaving a b ab → Interleaving ab c abc →
          ∃ λ bc → Interleaving a bc abc × Interleaving b c bc
interleaving-assoc l (consʳ r)         = let _ , p , q = interleaving-assoc l r in -, consʳ p , consʳ q
interleaving-assoc (consˡ l) (consˡ r) = let _ , p , q = interleaving-assoc l r in -, consˡ p , q
interleaving-assoc (consʳ l) (consˡ r) = let _ , p , q = interleaving-assoc l r in -, consʳ p , consˡ q
interleaving-assoc [] []               = [] , [] , []

instance list-has-sep : IsSep separation
list-has-sep = record
  { ⊎-comm = I.swap
  ; ⊎-assoc = interleaving-assoc
  }

instance list-is-unital : IsUnitalSep _ _
IsUnitalSep.isSep list-is-unital               = list-has-sep
IsUnitalSep.⊎-idˡ list-is-unital               = right (≡⇒≋ P.refl)
IsUnitalSep.⊎-id⁻ˡ list-is-unital []           = refl
IsUnitalSep.⊎-id⁻ˡ list-is-unital (refl ∷ʳ px) = cong (_ ∷_) (⊎-id⁻ˡ px)

instance list-has-concat : IsConcattative separation
IsConcattative._∙_ list-has-concat = _++_
IsConcattative.⊎-∙ₗ list-has-concat {Φₑ = []} ps = ps
IsConcattative.⊎-∙ₗ list-has-concat {Φₑ = x ∷ Φₑ} ps = consˡ (⊎-∙ₗ ps)

instance list-unitalsep : UnitalSep _
list-unitalsep = record
  { isUnitalSep = list-is-unital }

instance list-resource : MonoidalSep _
list-resource = record
  { sep = separation
  ; isSep = list-has-sep
  ; isUnitalSep   = list-is-unital
  ; isConcat      = list-has-concat
  ; monoid = ++-isMonoid }

instance list-positive : IsPositive separation
list-positive = record
  { ⊎-εˡ = λ where [] → refl }


module Dave.LeibnizEquality where
    open import Dave.Equality public

    _≐_ : ∀ {A : Set} (x y : A) → Set₁
    _≐_ {A} x y = ∀ (P : A → Set) → P x → P y

    refl-≐ : ∀ {A : Set} {x : A} → x ≐ x
    refl-≐ P Px = Px

    trans-≐ : ∀ {A : Set} {x y z : A} → x ≐ y → y ≐ z → x ≐ z
    trans-≐ x≐y y≐z P Px = y≐z P (x≐y P Px)

    sym-≐ : ∀ {A : Set} {x y : A} → x ≐ y → y ≐ x
    sym-≐ {A} {x} {y} x≐y P = Qy
        where
            Q : A → Set
            Q z = P z → P x
            Qx : Q x
            Qx = refl-≐ P
            Qy : Q y
            Qy = x≐y Q Qx

    ≡→≐ : ∀ {A : Set} {x y : A} → x ≡ y → x ≐ y
    ≡→≐ x≡y P = subst P x≡y

    ≐→≡ : ∀ {A : Set} {x y : A} → x ≐ y → x ≡ y
    ≐→≡ {A} {x} {y} x≐y = Qy
        where
            Q : A → Set
            Q z = x ≡ z
            Qx : Q x
            Qx = refl
            Qy : Q y
            Qy = x≐y Q Qx


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

-- Category where all arrows are inhabited by a single element
open import Level
open import Data.Unit

open import Categories.Category

open import Relation.Binary.PropositionalEquality as ≡

Indiscrete : ∀ {o ℓ} (A : Set o) → Category o ℓ ℓ
Indiscrete {_} {ℓ} A = record
  { Obj       = A
  ; _⇒_       = λ _ _ → Lift ℓ ⊤
  ; _≈_       = _≡_
  ; id        = _
  ; _∘_       = _
  ; assoc     = refl
  ; sym-assoc = refl
  ; identityˡ = refl
  ; identityʳ = refl
  ; identity² = refl
  ; equiv     = isEquivalence
  ; ∘-resp-≈  = λ where
    refl refl → refl
  }


module Integer.Difference where

open import Data.Product as Σ
open import Data.Product.Relation.Pointwise.NonDependent
open import Data.Unit
open import Equality
open import Natural as ℕ
open import Quotient as /
open import Relation.Binary
open import Syntax

infixl 6 _–_
pattern _–_ a b = _,_ a b

⟦ℤ⟧ = ℕ × ℕ
⟦ℤ²⟧ = ⟦ℤ⟧ × ⟦ℤ⟧

_≈_ : ⟦ℤ⟧ → ⟦ℤ⟧ → Set
(a – b) ≈ (c – d) = a + d ≡ c + b

≈-refl : ∀ {x} → x ≈ x
≈-refl = refl

ℤ = ⟦ℤ⟧ / _≈_
ℤ² = ⟦ℤ²⟧ / Pointwise _≈_ _≈_

instance
  ⟦ℤ⟧-Number : Number ⟦ℤ⟧
  ⟦ℤ⟧-Number = record { Constraint = λ _ → ⊤ ; fromNat = λ x → x – 0 }

  ℤ-Number : Number ℤ
  ℤ-Number = record { Constraint = λ _ → ⊤ ; fromNat = λ x → ⟦ fromNat x ⟧ }

  ⟦ℤ⟧-Negative : Negative ⟦ℤ⟧
  ⟦ℤ⟧-Negative = record { Constraint = λ _ → ⊤ ; fromNeg = λ x → 0 – x }

  ℤ-Negative : Negative ℤ
  ℤ-Negative = record { Constraint = λ _ → ⊤ ; fromNeg = λ x → ⟦ fromNeg x ⟧ }

suc–suc-injective : ∀ a b → Path ℤ ⟦ suc a – suc b ⟧ ⟦ a – b ⟧
suc–suc-injective a b = equiv (suc a – suc b) (a – b) (sym (+-suc a b ))

⟦negate⟧ : ⟦ℤ⟧ → ⟦ℤ⟧
⟦negate⟧ (a – b) = b – a

negate : ℤ → ℤ
negate =
  ⟦negate⟧ // λ where
    (a – b) (c – d) p →
      ⟨ +-comm b c ⟩ ≫ sym p ≫ ⟨ +-comm a d ⟩

⟦plus⟧ : ⟦ℤ²⟧ → ⟦ℤ⟧
⟦plus⟧ ((a – b) , (c – d)) = (a + c) – (d + b)

plus : ℤ² → ℤ
plus =
  ⟦plus⟧ // λ where
    ((a – b) , (c – d)) ((e – f) , (g – h)) (p , q) →
        (a + c) + (h + f)
      ≡⟨ sym (ℕ.+-assoc a _ _) ⟩
        a + (c + (h + f))
      ≡⟨ cong (a +_) (ℕ.+-assoc c _ _) ⟩
        a + ((c + h) + f)
      ≡⟨ cong (λ z → a + (z + f)) q ⟩
        a + ((g + d) + f)
      ≡⟨ cong (a +_) ⟨ ℕ.+-comm (g + d) _ ⟩ ⟩
        a + (f + (g + d))
      ≡⟨ ℕ.+-assoc a _ _ ⟩
        (a + f) + (g + d)
      ≡⟨ cong (_+ (g + d)) p ⟩
        (e + b) + (g + d)
      ≡⟨ ℕ.+-cross e _ _ _ ⟩
        (e + g) + (b + d)
      ≡⟨ cong ((e + g) +_) ⟨ ℕ.+-comm b _ ⟩ ⟩
        (e + g) + (d + b)
      ∎

instance
  ⟦ℤ⟧-plus-syntax : plus-syntax-simple ⟦ℤ⟧ ⟦ℤ⟧ ⟦ℤ⟧
  ⟦ℤ⟧-plus-syntax = λ where ._+_ x y → ⟦plus⟧ (x , y)

  ⟦ℤ⟧-minus-syntax : minus-syntax-simple ⟦ℤ⟧ ⟦ℤ⟧ ⟦ℤ⟧
  ⟦ℤ⟧-minus-syntax = λ where ._-_ x y → ⟦plus⟧ (x , ⟦negate⟧ y)

  ℕ-⟦ℤ⟧-minus-syntax : minus-syntax-simple ℕ ℕ ⟦ℤ⟧
  ℕ-⟦ℤ⟧-minus-syntax = λ where ._-_ → _–_

  ℤ-plus-syntax : plus-syntax-simple ℤ ℤ ℤ
  ℤ-plus-syntax = λ where ._+_ → /.uncurry refl refl plus

  ℤ-minus-syntax : minus-syntax-simple ℤ ℤ ℤ
  ℤ-minus-syntax = λ where ._-_ x y → x + negate y

  ℕ-ℤ-minus-syntax : minus-syntax-simple ℕ ℕ ℤ
  ℕ-ℤ-minus-syntax = λ where ._-_ x y → ⟦ x – y ⟧


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

module Data.Nat.PredExp2 where

open import Data.Nat
open import Data.Nat.Properties

open import Relation.Nullary
open import Relation.Nullary.Negation
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl; _≢_; module ≡-Reasoning)

open import Data.Nat.Log2 using (⌈log₂_⌉)

pred[2^_] : ℕ → ℕ
pred[2^ n ] = pred (2 ^ n)

lemma/2^suc : ∀ n → 2 ^ n + 2 ^ n ≡ 2 ^ suc n
lemma/2^suc n =
  begin
    2 ^ n + 2 ^ n
  ≡˘⟨ Eq.cong ((2 ^ n) +_) (*-identityˡ (2 ^ n)) ⟩
    2 ^ n + (2 ^ n + 0)
  ≡⟨⟩
    2 ^ n + (2 ^ n + 0 * (2 ^ n))
  ≡⟨⟩
    2 * (2 ^ n)
  ≡⟨⟩
    2 ^ suc n
  ∎
    where open ≡-Reasoning

private
  lemma/1≤2^n : ∀ n → 1 ≤ 2 ^ n
  lemma/1≤2^n zero    = ≤-refl {1}
  lemma/1≤2^n (suc n) =
    begin
      1
    ≤⟨ s≤s z≤n ⟩
      1 + 1
    ≤⟨ +-mono-≤ (lemma/1≤2^n n) (lemma/1≤2^n n) ⟩
      2 ^ n + 2 ^ n
    ≡⟨ lemma/2^suc n ⟩
      2 ^ suc n
    ∎
      where open ≤-Reasoning

  lemma/2^n≢0 : ∀ n → 2 ^ n ≢ zero
  lemma/2^n≢0 n 2^n≡0 with 2 ^ n | lemma/1≤2^n n
  ... | zero | ()

pred[2^]-mono : pred[2^_] Preserves _≤_ ⟶ _≤_
pred[2^]-mono m≤n = pred-mono (2^-mono m≤n)
  where
    2^-mono : (2 ^_) Preserves _≤_ ⟶ _≤_
    2^-mono {y = y} z≤n = lemma/1≤2^n y
    2^-mono (s≤s m≤n) = *-monoʳ-≤ 2 (2^-mono m≤n)

pred[2^suc[n]] : (n : ℕ) → suc (pred[2^ n ] + pred[2^ n ]) ≡ pred[2^ suc n ]
pred[2^suc[n]] n =
  begin
    suc (pred[2^ n ] + pred[2^ n ])
  ≡⟨⟩
    suc (pred (2 ^ n) + pred (2 ^ n))
  ≡˘⟨ +-suc (pred (2 ^ n)) (pred (2 ^ n)) ⟩
    pred (2 ^ n) + suc (pred (2 ^ n))
  ≡⟨ Eq.cong (pred (2 ^ n) +_) (suc[pred[n]]≡n (lemma/2^n≢0 n)) ⟩
    pred (2 ^ n) + 2 ^ n
  ≡⟨ lemma/pred-+ (2 ^ n) (2 ^ n) (lemma/2^n≢0 n) ⟩
    pred (2 ^ n + 2 ^ n)
  ≡⟨ Eq.cong pred (lemma/2^suc n) ⟩
    pred (2 ^ suc n)
  ≡⟨⟩
    pred[2^ suc n ]
  ∎
    where
      open ≡-Reasoning

      lemma/pred-+ : ∀ m n → m ≢ zero → pred m + n ≡ pred (m + n)
      lemma/pred-+ zero    n m≢zero = contradiction refl m≢zero
      lemma/pred-+ (suc m) n m≢zero = refl

pred[2^log₂] : (n : ℕ) → pred[2^ ⌈log₂ suc ⌈ n /2⌉ ⌉ ] ≤ n
pred[2^log₂] n = strong-induction n n ≤-refl
  where
    strong-induction : (n m : ℕ) → m ≤ n → pred[2^ ⌈log₂ suc ⌈ m /2⌉ ⌉ ] ≤ m
    strong-induction n zero    h = z≤n
    strong-induction n (suc zero) h = s≤s z≤n
    strong-induction (suc (suc n)) (suc (suc m)) (s≤s (s≤s h)) =
      begin
        pred[2^ ⌈log₂ suc ⌈ suc (suc m) /2⌉ ⌉ ]
      ≡⟨⟩
        pred[2^ suc ⌈log₂ ⌈ suc ⌈ suc (suc m) /2⌉ /2⌉ ⌉ ]
      ≡˘⟨ pred[2^suc[n]] ⌈log₂ ⌈ suc ⌈ suc (suc m) /2⌉ /2⌉ ⌉ ⟩
        suc (pred[2^ ⌈log₂ ⌈ suc ⌈ suc (suc m) /2⌉ /2⌉ ⌉ ] + pred[2^ ⌈log₂ ⌈ suc ⌈ suc (suc m) /2⌉ /2⌉ ⌉ ])
      ≡⟨⟩
        suc (pred[2^ ⌈log₂ ⌈ suc (suc ⌈ m /2⌉) /2⌉ ⌉ ] + pred[2^ ⌈log₂ ⌈ suc (suc ⌈ m /2⌉) /2⌉ ⌉ ])
      ≡⟨⟩
        suc (pred[2^ ⌈log₂ suc ⌈ ⌈ m /2⌉ /2⌉ ⌉ ] + pred[2^ ⌈log₂ suc ⌈ ⌈ m /2⌉ /2⌉ ⌉ ])
      ≤⟨
        s≤s (
          +-mono-≤
            (strong-induction (suc n) ⌈ m /2⌉ (≤-trans (⌊n/2⌋≤n (suc m)) (s≤s h)))
            (strong-induction (suc n) ⌈ m /2⌉ (≤-trans (⌊n/2⌋≤n (suc m)) (s≤s h)))
        )
      ⟩
        suc (⌈ m /2⌉ + ⌈ m /2⌉)
      ≡⟨⟩
        suc (⌊ suc m /2⌋ + ⌈ m /2⌉)
      ≤⟨ s≤s (+-monoʳ-≤ ⌊ suc m /2⌋ (⌈n/2⌉-mono (n≤1+n m))) ⟩
        suc (⌊ suc m /2⌋ + ⌈ suc m /2⌉)
      ≡⟨ Eq.cong suc (⌊n/2⌋+⌈n/2⌉≡n (suc m)) ⟩
        suc (suc m)
      ∎
        where open ≤-Reasoning


module Relation.Equality.Extensionality where

open import Relation.Equality
open import Data.Inductive.Higher.Interval
open import Relation.Path.Operation

funext : ∀ {a b}{A : Set a}{B : A → Set b}{f g : (x : A) → B x} → (∀ x → f x ≡ g x) → f ≡ g
funext {A = A}{B = B} {f = f}{g = g} p = ap {f = h} path-seg
  where
    h : I → (x : A) → B x
    h i x = interval-rec (f x) (g x) (p x) i


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

module Relation.Binary.Construct.Closure.SymmetricTransitive where

open import Level
open import Function
open import Relation.Binary

private
  variable
    a ℓ ℓ′ : Level
    A B    : Set a

module _ {A : Set a} (_≤_ : Rel A ℓ) where
  private
    variable
      x y z : A

  data Plus⇔ : Rel A (a ⊔ ℓ) where
    forth  : x ≤ y → Plus⇔ x y
    back   : y ≤ x → Plus⇔ x y
    forth⁺ : x ≤ y → Plus⇔ y z → Plus⇔ x z
    back⁺  : y ≤ x → Plus⇔ y z → Plus⇔ x z

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

  trans : Transitive (Plus⇔ _∼_)
  trans (forth r) rel′      = forth⁺ r rel′
  trans (back r) rel′       = back⁺ r rel′
  trans (forth⁺ r rel) rel′ = forth⁺ r (trans rel rel′)
  trans (back⁺ r rel) rel′  = back⁺ r (trans rel rel′)

  sym : Symmetric (Plus⇔ _∼_)
  sym (forth r)      = back r
  sym (back r)       = forth r
  sym (forth⁺ r rel) = trans (sym rel) (back r)
  sym (back⁺ r rel)  = trans (sym rel) (forth r)

  isPartialEquivalence : IsPartialEquivalence (Plus⇔ _∼_)
  isPartialEquivalence = record
    { sym   = sym
    ; trans = trans
    }

  partialSetoid : PartialSetoid _ _
  partialSetoid = record
    { Carrier              = A
    ; _≈_                  = Plus⇔ _∼_
    ; isPartialEquivalence = isPartialEquivalence
    }

  module _ (refl : Reflexive _∼_) where

    isEquivalence : IsEquivalence (Plus⇔ _∼_)
    isEquivalence = record
      { refl  = forth refl
      ; sym   = sym
      ; trans = trans
      }

    setoid : Setoid _ _
    setoid = record
      { Carrier       = A
      ; _≈_           = Plus⇔ _∼_
      ; isEquivalence = isEquivalence
      }

  module _ {c e} (S : Setoid c e) where
    private
      module S = Setoid S

    minimal : (f : A → Setoid.Carrier S) →
              _∼_ =[ f ]⇒ Setoid._≈_ S →
              Plus⇔ _∼_ =[ f ]⇒ Setoid._≈_ S
    minimal f inj (forth r)      = inj r
    minimal f inj (back r)       = S.sym (inj r)
    minimal f inj (forth⁺ r rel) = S.trans (inj r) (minimal f inj rel)
    minimal f inj (back⁺ r rel)  = S.trans (S.sym (inj r)) (minimal f inj rel)

module Plus⇔Reasoning (_≤_ : Rel A ℓ) where
  infix  3 forth-syntax back-syntax
  infixr 2 forth⁺-syntax back⁺-syntax

  forth-syntax : ∀ x y → x ≤ y → Plus⇔ _≤_ x y
  forth-syntax _ _ = forth

  syntax forth-syntax x y x≤y = x ⇒⟨ x≤y ⟩∎ y ∎

  back-syntax : ∀ x y → y ≤ x → Plus⇔ _≤_ x y
  back-syntax _ _ = back

  syntax back-syntax x y y≤x = x ⇐⟨ y≤x ⟩∎ y ∎

  forth⁺-syntax : ∀ x {y z} → x ≤ y → Plus⇔ _≤_ y z → Plus⇔ _≤_ x z
  forth⁺-syntax _ = forth⁺

  syntax forth⁺-syntax x x≤y y⇔z = x ⇒⟨ x≤y ⟩ y⇔z

  back⁺-syntax : ∀ x {y z} → y ≤ x → Plus⇔ _≤_ y z → Plus⇔ _≤_ x z
  back⁺-syntax _ = back⁺

  syntax back⁺-syntax x y≤x y⇔z = x ⇐⟨ y≤x ⟩ y⇔z

module _ {_≤_ : Rel A ℓ} {_≼_ : Rel B ℓ′} (f : A → B) where

  module _ (inj : _≤_ =[ f ]⇒ _≼_) where

    gmap : Plus⇔ _≤_ =[ f ]⇒ Plus⇔ _≼_
    gmap (forth r)      = forth (inj r)
    gmap (back r)       = back (inj r)
    gmap (forth⁺ r rel) = forth⁺ (inj r) (gmap rel)
    gmap (back⁺ r rel)  = back⁺ (inj r) (gmap rel)

map : {_≤_ : Rel A ℓ} {_≼_ : Rel A ℓ′} (inj : _≤_ ⇒ _≼_) → Plus⇔ _≤_ ⇒ Plus⇔ _≼_
map = gmap id


{-# OPTIONS --with-K #-}

open import Agda.Builtin.Equality
open import Agda.Builtin.Nat

single : {m n : Nat} → suc m ≡ suc n → n ≡ m
single p with refl ← p = refl

double : {m n p : Nat} → suc m ≡ n → suc n ≡ 2 + p → m ≡ p
double p q with refl ← p | refl ← q = refl

_∋_ : (A : Set) → A → A
A ∋ a = a

-- The second equality proof is only well-typed
-- after the first one has been used

tele : {m n : Nat} → suc m ≡ suc n → m ≡ n
tele {m} {n} p
  with refl ← p
  with refl ← (n ≡ m) ∋ refl
       = refl

tele' : {m n : Nat} → m ≡ n → m ≡ n
tele' {m} {n} p with refl ← p with (n ≡ m) ∋ refl
... | q = refl

-- Further splitting after a using & with

tele'' : {m n : Nat} → m ≡ n → Nat → Nat
tele'' {m} {n} p r with refl ← p | (n ≡ m) ∋ refl
tele'' {m} {m} p zero    | q = m
tele'' {m} {m} p (suc r) | q = r

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

module _ {a} {A : Set a} {n} where

  head : Vec A (suc n) → A
  head xs with (x ∷ _) ← xs = x

  tail : Vec A (suc n) → Vec A n
  tail xs with (_ ∷ xs) ← xs = xs -- pattern shadows variable with'd on

castVec : ∀ {m n} → m ≡ n → Vec Nat m → Vec Nat n
castVec eq ms with refl ← eq = ms

data All (P : Nat → Set) : ∀ {n} → Vec Nat n → Set where
  []  : All P []
  _∷_ : ∀ {n x xs} → P x → All P {n} xs → All P (x ∷ xs)

open import Agda.Builtin.Sigma

castAll : ∀ {P m n xs ys} → Σ (m ≡ n) (λ eq → castVec eq xs ≡ ys) →
          All P xs → All P ys
castAll (refl , refl) all = all

-- faking rewrite with the dependent irrefutable with
postulate +-comm : ∀ m n → m + n ≡ n + m

rew : ∀ m n p q → m + (p + q) + n ≡ m + (q + p) + n
rew m n p q with p+q ← p + q | refl ← +-comm p q {- : p + q ≡ q + p -} = refl

-- Note that the following does not work because
-- p+q is not abstracted over in `+-comm p q` which means
-- Agda gets stuck trying to unify `p + q` and `q + p`

-- Cf. test/Fail/UsingEq.agda

-- rew' : ∀ m n p q → m + (p + q) + n ≡ m + (q + p) + n
-- rew' m n p q with p+q ← p + q with refl ← +-comm p q = refl


{-# OPTIONS --universe-polymorphism #-}
module Categories.Support.PropositionalEquality where

open import Function using (flip; id)
open import Relation.Binary.PropositionalEquality public using () renaming (_≡_ to _≣_; refl to ≣-refl; trans to ≣-trans; sym to ≣-sym; cong to ≣-cong; cong₂ to ≣-cong₂; subst to ≣-subst; subst₂ to ≣-subst₂; isEquivalence to ≣-isEquivalence; setoid to ≣-setoid)

module ≣-reasoning = Relation.Binary.PropositionalEquality.≡-Reasoning renaming (_≡⟨_⟩_ to _≣⟨_⟩_)

≣-app : ∀ {a} {A : Set a} {b} {B : A → Set b} {f g : (x : A) → B x} → f ≣ g → (x : A) → f x ≣ g x
≣-app {f = f} {g} = flip (λ x → ≣-cong (flip id x))

≣-appʰ : ∀ {a} {A : Set a} {b} {B : A → Set b} {f g : ∀ {x} → B x} → (λ {x} → f) ≣ g → ∀ {x} → f {x} ≣ g {x}
≣-appʰ {f = f} {g} = λ pf {x} → ≣-cong (λ h → h {x}) pf

≣-subst₂-breakdown-lr : ∀ {a} {A : Set a} {b} {B : Set b} {ℓ} (f : A → B → Set ℓ) {a₁ a₂ : A} (a₁≣a₂ : a₁ ≣ a₂) {b₁ b₂ : B} (b₁≣b₂ : b₁ ≣ b₂) (x : f a₁ b₁) → ≣-subst₂ f a₁≣a₂ b₁≣b₂ x ≣ ≣-subst (f a₂) b₁≣b₂ (≣-subst (λ y → f y b₁) a₁≣a₂ x)
≣-subst₂-breakdown-lr f ≣-refl ≣-refl x = ≣-refl

≣-subst₂-breakdown-rl : ∀ {a} {A : Set a} {b} {B : Set b} {ℓ} (f : A → B → Set ℓ) {a₁ a₂ : A} (a₁≣a₂ : a₁ ≣ a₂) {b₁ b₂ : B} (b₁≣b₂ : b₁ ≣ b₂) (x : f a₁ b₁) → ≣-subst₂ f a₁≣a₂ b₁≣b₂ x ≣ ≣-subst (λ y → f y b₂) a₁≣a₂ (≣-subst (f a₁) b₁≣b₂ x)
≣-subst₂-breakdown-rl f ≣-refl ≣-refl x = ≣-refl

≣-subst-trans : ∀ {a} {A : Set a} {ℓ} (f : A → Set ℓ) {a₁ a₂ a₃ : A} (a₁≣a₂ : a₁ ≣ a₂) (a₂≣a₃ : a₂ ≣ a₃) (x : f a₁) → ≣-subst f (≣-trans a₁≣a₂ a₂≣a₃) x ≣ ≣-subst f a₂≣a₃ (≣-subst f a₁≣a₂ x)
≣-subst-trans f ≣-refl ≣-refl x = ≣-refl

≣-cong₂₊ : ∀ {a b c r} {A : Set a} {B : Set b} {C : A → B → Set c} {R : Set r} (f : (x : A) → (u : B) → .(z : C x u) → R) {x y : A} {u v : B} .(z : C x u) → (x≣y : x ≣ y) (u≣v : u ≣ v) → f x u z ≣ f y v (≣-subst₂ C x≣y u≣v z)
≣-cong₂₊ f z ≣-refl ≣-refl = ≣-refl


------------------------------------------------------------------------
-- Some properties about integers
------------------------------------------------------------------------

module Data.Integer.Properties where

open import Algebra
import Algebra.Morphism as Morphism
open import Data.Empty
open import Data.Function
open import Data.Integer hiding (suc)
open import Data.Nat as ℕ renaming (_*_ to _ℕ*_)
import Data.Nat.Properties as ℕ
open import Data.Sign as Sign using () renaming (_*_ to _S*_)
import Data.Sign.Properties as SignProp
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

open Morphism.Definitions ℤ ℕ _≡_

-- Some properties relating sign and ∣_∣ to _◃_.

sign-◃ : ∀ s n → sign (s ◃ suc n) ≡ s
sign-◃ Sign.- _ = refl
sign-◃ Sign.+ _ = refl

sign-cong : ∀ {s₁ s₂ n₁ n₂} →
            s₁ ◃ suc n₁ ≡ s₂ ◃ suc n₂ → s₁ ≡ s₂
sign-cong {s₁} {s₂} {n₁} {n₂} eq = begin
  s₁                  ≡⟨ sym $ sign-◃ s₁ n₁ ⟩
  sign (s₁ ◃ suc n₁)  ≡⟨ cong sign eq ⟩
  sign (s₂ ◃ suc n₂)  ≡⟨ sign-◃ s₂ n₂ ⟩
  s₂                  ∎

abs-◃ : ∀ s n → ∣ s ◃ n ∣ ≡ n
abs-◃ _      zero    = refl
abs-◃ Sign.- (suc n) = refl
abs-◃ Sign.+ (suc n) = refl

abs-cong : ∀ {s₁ s₂ n₁ n₂} →
           s₁ ◃ n₁ ≡ s₂ ◃ n₂ → n₁ ≡ n₂
abs-cong {s₁} {s₂} {n₁} {n₂} eq = begin
  n₁           ≡⟨ sym $ abs-◃ s₁ n₁ ⟩
  ∣ s₁ ◃ n₁ ∣  ≡⟨ cong ∣_∣ eq ⟩
  ∣ s₂ ◃ n₂ ∣  ≡⟨ abs-◃ s₂ n₂ ⟩
  n₂           ∎

-- ∣_∣ commutes with multiplication.

abs-*-commute : Homomorphic₂ ∣_∣ _*_ _ℕ*_
abs-*-commute i j = abs-◃ _ _

-- Multiplication is right cancellative for non-zero integers.

cancel-*-right : ∀ i j k →
                 k ≢ + 0 → i * k ≡ j * k → i ≡ j
cancel-*-right i j k            ≢0 eq with signAbs k
cancel-*-right i j .(+ 0)       ≢0 eq | s ◂ zero  = ⊥-elim (≢0 refl)
cancel-*-right i j .(s ◃ suc n) ≢0 eq | s ◂ suc n
  with ∣ s ◃ suc n ∣ | abs-◃ s (suc n) | sign (s ◃ suc n) | sign-◃ s n
...  | .(suc n)      | refl            | .s               | refl =
  ◃-cong (sign-i≡sign-j i j eq) $
         ℕ.cancel-*-right ∣ i ∣ ∣ j ∣ $ abs-cong eq
  where
  sign-i≡sign-j : ∀ i j →
                  sign i S* s ◃ ∣ i ∣ ℕ* suc n ≡
                  sign j S* s ◃ ∣ j ∣ ℕ* suc n →
                  sign i ≡ sign j
  sign-i≡sign-j i              j              eq with signAbs i | signAbs j
  sign-i≡sign-j .(+ 0)         .(+ 0)         eq | s₁ ◂ zero   | s₂ ◂ zero   = refl
  sign-i≡sign-j .(+ 0)         .(s₂ ◃ suc n₂) eq | s₁ ◂ zero   | s₂ ◂ suc n₂
    with ∣ s₂ ◃ suc n₂ ∣ | abs-◃ s₂ (suc n₂)
  ... | .(suc n₂) | refl
    with abs-cong {s₁} {sign (s₂ ◃ suc n₂) S* s} {0} {suc n₂ ℕ* suc n} eq
  ...   | ()
  sign-i≡sign-j .(s₁ ◃ suc n₁) .(+ 0)         eq | s₁ ◂ suc n₁ | s₂ ◂ zero
    with ∣ s₁ ◃ suc n₁ ∣ | abs-◃ s₁ (suc n₁)
  ... | .(suc n₁) | refl
    with abs-cong {sign (s₁ ◃ suc n₁) S* s} {s₁} {suc n₁ ℕ* suc n} {0} eq
  ...   | ()
  sign-i≡sign-j .(s₁ ◃ suc n₁) .(s₂ ◃ suc n₂) eq | s₁ ◂ suc n₁ | s₂ ◂ suc n₂
    with ∣ s₁ ◃ suc n₁ ∣ | abs-◃ s₁ (suc n₁)
       | sign (s₁ ◃ suc n₁) | sign-◃ s₁ n₁
       | ∣ s₂ ◃ suc n₂ ∣ | abs-◃ s₂ (suc n₂)
       | sign (s₂ ◃ suc n₂) | sign-◃ s₂ n₂
  ... | .(suc n₁) | refl | .s₁ | refl | .(suc n₂) | refl | .s₂ | refl =
    SignProp.cancel-*-right s₁ s₂ (sign-cong eq)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Pairs of lists that share no common elements (setoid equality)
------------------------------------------------------------------------

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

open import Relation.Binary

module Data.List.Relation.Binary.Disjoint.Setoid {c ℓ} (S : Setoid c ℓ) where

open import Level using (_⊔_)
open import Relation.Nullary using (¬_)
open import Function using (_∘_)
open import Data.List.Base using (List; []; [_]; _∷_)
open import Data.List.Relation.Unary.Any using (here; there)
open import Data.Product using (_×_; _,_)

open Setoid S renaming (Carrier to A)
open import Data.List.Membership.Setoid S using (_∈_; _∉_)

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

Disjoint : Rel (List A) (ℓ ⊔ c)
Disjoint xs ys = ∀ {v} → ¬ (v ∈ xs × v ∈ ys)

------------------------------------------------------------------------
-- Operations

contractₗ : ∀ {x xs ys} → Disjoint (x ∷ xs) ys → Disjoint xs ys
contractₗ x∷xs∩ys=∅ (v∈xs , v∈ys) = x∷xs∩ys=∅ (there v∈xs , v∈ys)

contractᵣ : ∀ {xs y ys} → Disjoint xs (y ∷ ys) → Disjoint xs ys
contractᵣ xs#y∷ys (v∈xs , v∈ys) = xs#y∷ys (v∈xs , there v∈ys)


-- notes-03-wednesday.agda

open import mylib

{-
  Classical vs intuitionistic logic
  In classical logica, we assume that each proposition is either true or false.
  Excluded middle, tertium non datur (the third is not given).
  To prove P, assume not P and derive a contradiction: indirect proof, reduction
  ad absurdum, reduction to the absurd.

-}

TND : prop → prop
TND P = P ∨ ¬ P

deMorgan' : TND P → ¬ (P ∧ Q) ⇔ ¬ P ∨ ¬ Q
proj₁ (deMorgan' (inj₁ p)) h = inj₂ (λ q → h (p , q))
proj₁ (deMorgan' (inj₂ np)) h = inj₁ np
proj₂ (deMorgan' tnd) (inj₁ np) (p , q) = np p
proj₂ (deMorgan' _)  (inj₂ nq) (p , q) = nq q

RAA : prop → prop
RAA P = ¬ ¬ P → P

tnd→raa : TND P → RAA P
tnd→raa (inj₁ p) nnp = p
tnd→raa (inj₂ np) nnp = case⊥ (nnp np)

{-
raa→tnd : RAA P → TND P
is not provable.
-}

nntnd : ¬ ¬ (P ∨ ¬ P)
nntnd h = h (inj₂ (λ p → h (inj₁ p)))

raa→tnd : ({P : prop} → RAA P) → {Q : prop} → TND Q
raa→tnd raa = raa nntnd

{-
  Datatypes, infinite types
  ℕ - natural numbers, Peano
  Every natural number is either 0 or a successor of a number.
  Peano arithmetic.
-}

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

one : ℕ
one = suc zero

two : ℕ
two = suc one

{-# BUILTIN NATURAL ℕ #-}

fifteen : ℕ
fifteen = 15

infixl 2 _+_
_+_ : ℕ → ℕ → ℕ -- structural recursive definition
zero + n = n
suc m + n = suc (m + n)

infixl 4 _*_
_*_ : ℕ → ℕ → ℕ
zero * n = 0
suc m * n = m * n + n

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

-- ℕ = List ⊤

_++_ : List A → List A → List A -- append
[] ++ ys = ys
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)

-- _++'_ : List A \to List B \to List (A \vee B)?

-- recursive but not inductive
{-# NO_POSITIVITY_CHECK #-}
data Λ : Set where
  lam : (Λ → Λ) → Λ

app : Λ → Λ → Λ
app (lam f) x = f x

self-apply : Λ
self-apply = lam λ x → app x x

Ω : Λ
Ω = app self-apply self-apply
-- normalisation doesn't terminate

data Ord : Set where
  zero : Ord
  suc : Ord → Ord
  lim : (ℕ → Ord) → Ord

-- strictly positive

{-# NO_POSITIVITY_CHECK #-}
data Reynolds : Set where
  inn : ((Reynolds → Bool) → Bool) → Reynolds

{-
  Inconsistent with classical logic
  It doesn't adhere to the intuitionistic explanation of inductive datatypes.
  Hence we reject types like this.
  - strictly positive = recursive type only appears on the right of an arrow
    type.
  - strictly positive = container / polynomial functors.
-}


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

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma

open import Cubical.Algebra
open import Cubical.Algebra.Semigroup.Morphism
open import Cubical.Algebra.Magma.Submagma

open import Cubical.Relation.Unary
open import Cubical.Relation.Unary.Subtype

record IsSubsemigroup {c ℓ} (S : Semigroup c) (Member : Pred ⟨ S ⟩ ℓ) : Type (ℓ-max c ℓ) where
  constructor issubsemigroup

  private module S = Semigroup S

  field
    closed : S._•_ Preserves₂ Member

  isSubmagma : IsSubmagma S.magma Member
  isSubmagma = record { closed = closed }

  open IsSubmagma isSubmagma hiding (closed) public

  assoc : Associative _•_
  assoc _ _ _ = ΣPathTransport→PathΣ _ _ (S.assoc _ _ _ , isProp[ Member ] _ _ _)

  isSemigroup : IsSemigroup Carrier _•_
  isSemigroup = record
    { isMagma = isMagma
    ; assoc = assoc
    }

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

  open Semigroup semigroup using (_^_) public

record Subsemigroup {c} (S : Semigroup c) ℓ : Type (ℓ-max c (ℓ-suc ℓ)) where
  constructor mksubsemigroup

  private module S = Semigroup S

  field
    Member : Pred ⟨ S ⟩ ℓ
    isSubsemigroup : IsSubsemigroup S Member

  open IsSubsemigroup isSubsemigroup public

  submagma : Submagma S.magma ℓ
  submagma = record { isSubmagma = isSubmagma }

instance
  SubsemigroupCarrier : ∀ {c ℓ} {S : Semigroup c} → HasCarrier (Subsemigroup S ℓ) _
  SubsemigroupCarrier = record { ⟨_⟩ = Subsemigroup.Carrier }

module _ {ℓ} (S : Semigroup ℓ) where
  open Semigroup S

  ∅-isSubsemigroup : IsSubsemigroup S ∅
  ∅-isSubsemigroup = record { closed = λ () }

  ∅-subsemigroup : Subsemigroup S _
  ∅-subsemigroup = record { isSubsemigroup = ∅-isSubsemigroup }

  U-isSubsemigroup : IsSubsemigroup S U
  U-isSubsemigroup = record {} -- trivial

  U-subsemigroup : Subsemigroup S _
  U-subsemigroup = record { isSubsemigroup = U-isSubsemigroup }


module eq where

open import level

----------------------------------------------------------------------
-- datatypes
----------------------------------------------------------------------

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

{-# BUILTIN EQUALITY _≡_ #-}

----------------------------------------------------------------------
-- syntax
----------------------------------------------------------------------

infix 4 _≡_

----------------------------------------------------------------------
-- operations
----------------------------------------------------------------------

sym : ∀ {ℓ}{A : Set ℓ}{x y : A} → x ≡ y → y ≡ x
sym refl = refl

trans : ∀ {ℓ}{A : Set ℓ}{x y z : A} → x ≡ y → y ≡ z → x ≡ z
trans refl refl = refl

cong : ∀ {ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'}(p : A → B) {x y : A} → x ≡ y → p x ≡ p y
cong p refl = refl

congf : ∀{l l' : Level}{A : Set l}{B : Set l'}{f f' : A → B}{b c : A} → f ≡ f' → b ≡ c → (f b) ≡ (f' c)
congf refl refl = refl

congf2 : ∀{l l' l'' : Level}{A : Set l}{B : Set l'}{C : Set l''}{f f' : A → B → C}{b c : A}{d e : B} → f ≡ f' → b ≡ c → d ≡ e → (f b d) ≡ (f' c e)
congf2 refl refl refl = refl

cong2 : ∀{i j k}{A : Set i}{B : Set j}{C : Set k}{a a' : A}{b b' : B}
  → (f : A → B → C)
  → a ≡ a'
  → b ≡ b'
  → f a b ≡ f a' b'
cong2 f refl refl = refl

cong3 : ∀{i j k l}{A : Set i}{B : Set j}{C : Set k}{D : Set l}{a a' : A}{b b' : B}{c c' : C}
  → (f : A → B → C → D)
  → a ≡ a'
  → b ≡ b'
  → c ≡ c'
  → f a b c ≡ f a' b' c'
cong3 f refl refl refl = refl


------------------------------------------------------------------------------
-- Definition of the gcd of two natural numbers using the Euclid's algorithm
------------------------------------------------------------------------------

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

module FOTC.Program.GCD.Partial.GCD where

open import FOTC.Base
open import FOTC.Base.Loop
open import FOTC.Data.Nat
open import FOTC.Data.Nat.Inequalities

------------------------------------------------------------------------------
-- In GHC ≤ 7.0.4 the gcd is a partial function, i.e. gcd 0 0 = undefined.

postulate
  gcd    : D → D → D
  gcd-eq : ∀ m n → gcd m n ≡
           (if (iszero₁ n)
              then (if (iszero₁ m)
                      then error
                      else m)
              else (if (iszero₁ m)
                      then n
                      else (if (gt m n)
                              then gcd (m ∸ n) n
                              else gcd m (n ∸ m))))
{-# ATP axiom gcd-eq #-}


------------------------------------------------------------------------
-- The Agda standard library
--
-- Indexed unary relations
------------------------------------------------------------------------

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

module Relation.Unary.Indexed  where

open import Data.Product using (∃; _×_)
open import Level
open import Relation.Nullary using (¬_)

IPred : ∀ {i a} {I : Set i} → (I → Set a) → (ℓ : Level) → Set _
IPred A ℓ = ∀ {i} → A i → Set ℓ

module _ {i a} {I : Set i} {A : I → Set a} where

  _∈_ : ∀ {ℓ} → (∀ i → A i) → IPred A ℓ → Set _
  x ∈ P = ∀ i → P (x i)

  _∉_ : ∀ {ℓ} → (∀ i → A i) → IPred A ℓ → Set _
  t ∉ P = ¬ (t ∈ P)


----------------------------------------------------------------
-- This file contains the definition of categories.           --
----------------------------------------------------------------
module Category.Category where

open import Level public renaming (suc to lsuc)
open import Data.Product

open import Setoid.Total public
open import Relation.Relation

open Setoid public

record Cat {l : Level} : Set (lsuc l) where
  field
    Obj     : Set l
    Hom     : Obj → Obj → Setoid {l}
    comp    : {A B C : Obj} → BinSetoidFun (Hom A B) (Hom B C) (Hom A C)
    id      : {A : Obj} → el (Hom A A)
    assocPf : ∀{A B C D}{f : el (Hom A B)}{g : el (Hom B C)}{h : el (Hom C D)}
               → ⟨ Hom A D ⟩[ f ○[ comp ] (g ○[ comp ] h)  ≡  (f ○[ comp ] g) ○[ comp ] h ]
    idPfCom : ∀{A B}{f : el (Hom A B)} → ⟨ Hom A B ⟩[ id ○[ comp ] f ≡ f ○[ comp ] id  ]
    idPf    : ∀{A B}{f : el (Hom A B)} → ⟨ Hom A B ⟩[ id ○[ comp ] f ≡ f ]

open Cat public

objectSetoid : {l : Level} → (ℂ : Cat {l}) → Setoid {l}
objectSetoid {l} ℂ = record { el = Obj ℂ;
                              eq = λ a b → _≅_ a b;
                           eqRpf = record { parEqPf = record { symPf = λ x₁ → sym x₁ ; transPf = λ x₁ x₂ → trans x₁ x₂ } ; refPf = refl }
                 }

-- Identities composed on the left cancel.
idPf-left : ∀{l}{ℂ : Cat {l}}{A B : Obj ℂ}{f : el (Hom ℂ A B)} → ⟨ Hom ℂ A B ⟩[ f ○[ comp ℂ ] id ℂ ≡ f ]
idPf-left {_}{ℂ}{A}{B}{f} =
  transPf (parEqPf (eqRpf (Hom ℂ A B)))
          (symPf (parEqPf (eqRpf (Hom ℂ A B))) (idPfCom ℂ {A} {B} {f}))
          (idPf ℂ)

-- Congruence results for composition.
eq-comp-right : ∀{l}
    {ℂ : Cat {l}}
    {A B C : Obj ℂ}
    {f : el (Hom ℂ A B)}
    {g₁ g₂ : el (Hom ℂ B C)}
  → ⟨ Hom ℂ B C ⟩[ g₁ ≡ g₂ ]
  → ⟨ Hom ℂ A C ⟩[ f ○[ comp ℂ ] g₁ ≡ f ○[ comp ℂ ] g₂ ]
eq-comp-right {_}{ℂ}{A}{B}{C}{f}{g₁}{g₂} eq =
  extT (appT {_}{_}{Hom ℂ A B}{SetoidFunSpace (Hom ℂ B C) (Hom ℂ A C)} (comp ℂ) f) eq

eq-comp-left : ∀{l}
    {ℂ : Cat {l}}
    {A B C : Obj ℂ}
    {f₁ f₂ : el (Hom ℂ A B)}
    {g : el (Hom ℂ B C)}
  → ⟨ Hom ℂ A B ⟩[ f₁ ≡ f₂ ]
  → ⟨ Hom ℂ A C ⟩[ f₁ ○[ comp ℂ ] g ≡ f₂ ○[ comp ℂ ] g ]
eq-comp-left {_}{ℂ}{A}{B}{C}{f₁}{f₂}{g} eq = extT (comp ℂ) {f₁}{f₂} eq g

eq-comp-all : ∀{l}
    {ℂ : Cat {l}}
    {A B C : Obj ℂ}
    {f₁ f₂ : el (Hom ℂ A B)}
    {g₁ g₂ : el (Hom ℂ B C)}
  → ⟨ Hom ℂ A B ⟩[ f₁ ≡ f₂ ]
  → ⟨ Hom ℂ B C ⟩[ g₁ ≡ g₂ ]
  → ⟨ Hom ℂ A C ⟩[ f₁ ○[ comp ℂ ] g₁ ≡ f₂ ○[ comp ℂ ] g₂ ]
eq-comp-all {_}{ℂ}{A}{B}{C}{f₁}{f₂}{g₁}{g₂} eq₁ eq₂
  with eq-comp-left {_}{ℂ}{A}{B}{C}{f₁}{f₂}{g₁} eq₁ |
       eq-comp-right {_}{ℂ}{A}{B}{C}{f₂}{g₁}{g₂} eq₂
... | eq₃ | eq₄ = transPf (parEqPf (eqRpf (Hom ℂ A C))) eq₃ eq₄


{-

This file contains:

- Properties of groupoid truncations

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.HITs.GroupoidTruncation.Properties where

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

open import Cubical.HITs.GroupoidTruncation.Base

private
  variable
    ℓ : Level
    A : Type ℓ

rec : ∀ {B : Type ℓ} → isGroupoid B → (A → B) → ∥ A ∥₃ → B
rec gB f ∣ x ∣₃ = f x
rec gB f (squash₃ x y p q r s i j k) =
  gB _ _ _ _ (λ m n → rec gB f (r m n)) (λ m n → rec gB f (s m n)) i j k

elim : {B : ∥ A ∥₃ → Type ℓ}
       (bG : (x : ∥ A ∥₃) → isGroupoid (B x))
       (f : (x : A) → B ∣ x ∣₃) (x : ∥ A ∥₃) → B x
elim bG f (∣ x ∣₃) = f x
elim bG f (squash₃ x y p q r s i j k) =
  isOfHLevel→isOfHLevelDep 3 bG _ _ _ _
    (λ j k → elim bG f (r j k)) (λ j k → elim bG f (s j k))
    (squash₃ x y p q r s)
    i j k

elim2 : {B : ∥ A ∥₃ → ∥ A ∥₃ → Type ℓ}
        (gB : ((x y : ∥ A ∥₃) → isGroupoid (B x y)))
        (g : (a b : A) → B ∣ a ∣₃ ∣ b ∣₃)
        (x y : ∥ A ∥₃) → B x y
elim2 gB g = elim (λ _ → isGroupoidΠ (λ _ → gB _ _))
                  (λ a → elim (λ _ → gB _ _) (g a))

elim3 : {B : (x y z : ∥ A ∥₃) → Type ℓ}
        (gB : ((x y z : ∥ A ∥₃) → isGroupoid (B x y z)))
        (g : (a b c : A) → B ∣ a ∣₃ ∣ b ∣₃ ∣ c ∣₃)
        (x y z : ∥ A ∥₃) → B x y z
elim3 gB g = elim2 (λ _ _ → isGroupoidΠ (λ _ → gB _ _ _))
                   (λ a b → elim (λ _ → gB _ _ _) (g a b))

groupoidTruncIsGroupoid : isGroupoid ∥ A ∥₃
groupoidTruncIsGroupoid a b p q r s = squash₃ a b p q r s

groupoidTruncIdempotent≃ : isGroupoid A → ∥ A ∥₃ ≃ A
groupoidTruncIdempotent≃ {A = A} hA = isoToEquiv f
  where
  f : Iso ∥ A ∥₃ A
  Iso.fun f = rec hA (idfun A)
  Iso.inv f x = ∣ x ∣₃
  Iso.rightInv f _ = refl
  Iso.leftInv f = elim (λ _ → isGroupoid→is2Groupoid groupoidTruncIsGroupoid _ _) (λ _ → refl)

groupoidTruncIdempotent : isGroupoid A → ∥ A ∥₃ ≡ A
groupoidTruncIdempotent hA = ua (groupoidTruncIdempotent≃ hA)


-- This module introduces parameterised modules.

module Introduction.Modules.Parameterised where

-- First some familiar datatypes.

data Bool : Set where
  false : Bool
  true  : Bool

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

infixr 15 _::_    -- see 'Introduction.Operators' for information on infix
                  -- declarations

-- Agda supports parameterised modules. A parameterised module is declared by
-- giving the parameters after the module name.

module Sorting {A : Set}(_<_ : A -> A -> Bool) where

  insert : A -> List A -> List A
  insert x  nil      = x :: nil
  insert x (y :: ys) = ins (x < y)
    where
      ins : Bool -> List A      -- local functions can do pattern matching and
      ins true  = x :: y :: ys  -- be recursive
      ins false = y :: insert x ys

  sort : List A -> List A
  sort  nil      = nil
  sort (x :: xs) = insert x (sort xs)

-- Before a parameterised module can be used it has to be instantiated. So, we
-- need something to instantiate it with.

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

_<_ : Nat -> Nat -> Bool
zero  < zero  = false
zero  < suc _ = true
suc _ < zero  = false
suc n < suc m = n < m

-- To instantiate a module you define a new module in terms of the
-- parameterised module. Module instantiation also supports the using, hiding
-- and renaming modifiers.
module SortNat = Sorting _<_

sort' : {A : Set}(_<_ : A -> A -> Bool) -> List A -> List A
sort' less = Sort'.sort
  where
    module Sort' = Sorting less

-- Now the instantiated module can be opened and we can use the sorting
-- function.
open SortNat

test = sort (suc zero :: zero :: suc (suc zero) :: nil)


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Data.Nat.Order.Recursive where

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

open import Cubical.Data.Empty
open import Cubical.Data.Unit

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

open import Cubical.Relation.Nullary

infix 4 _≤_ _<_

_≤_ : ℕ → ℕ → Type₀
zero ≤ _ = Unit
suc m ≤ zero = ⊥
suc m ≤ suc n = m ≤ n

_<_ : ℕ → ℕ → Type₀
m < n = suc m ≤ n

data Trichotomy (m n : ℕ) : Type₀ where
  lt : m < n → Trichotomy m n
  eq : m ≡ n → Trichotomy m n
  gt : n < m → Trichotomy m n

private
  variable
    k l m n : ℕ

m≤n-isProp : isProp (m ≤ n)
m≤n-isProp {zero} = isPropUnit
m≤n-isProp {suc m} {zero}  = isProp⊥
m≤n-isProp {suc m} {suc n} = m≤n-isProp {m} {n}

≤-k+ : m ≤ n → k + m ≤ k + n
≤-k+ {k = zero}  m≤n = m≤n
≤-k+ {k = suc k} m≤n = ≤-k+ {k = k} m≤n

≤-+k : m ≤ n → m + k ≤ n + k
≤-+k {m} {n} {k} m≤n
  = transport (λ i → +-comm k m i ≤ +-comm k n i) (≤-k+ {m} {n} {k} m≤n)

≤-refl : ∀ m → m ≤ m
≤-refl zero = _
≤-refl (suc m) = ≤-refl m

≤-trans : k ≤ m → m ≤ n → k ≤ n
≤-trans {zero} _ _ = _
≤-trans {suc k} {suc m} {suc n} = ≤-trans {k} {m} {n}

≤-antisym : m ≤ n → n ≤ m → m ≡ n
≤-antisym {zero} {zero} _ _ = refl
≤-antisym {suc m} {suc n} m≤n n≤m = cong suc (≤-antisym m≤n n≤m)

≤-k+-cancel : k + m ≤ k + n → m ≤ n
≤-k+-cancel {k =  zero} m≤n = m≤n
≤-k+-cancel {k = suc k} m≤n = ≤-k+-cancel {k} m≤n

≤-+k-cancel : m + k ≤ n + k → m ≤ n
≤-+k-cancel {m} {k} {n}
  = ≤-k+-cancel {k} {m} {n} ∘ transport λ i → +-comm m k i ≤ +-comm n k i

¬m<m : ¬ m < m
¬m<m {suc m} = ¬m<m {m}

≤0→≡0 : n ≤ 0 → n ≡ 0
≤0→≡0 {zero} _ = refl

¬m+n<m : ¬ m + n < m
¬m+n<m {suc m} = ¬m+n<m {m}

<-weaken : m < n → m ≤ n
<-weaken {zero} _ = _
<-weaken {suc m} {suc n} = <-weaken {m}

Trichotomy-suc : Trichotomy m n → Trichotomy (suc m) (suc n)
Trichotomy-suc (lt m<n) = lt m<n
Trichotomy-suc (eq m≡n) = eq (cong suc m≡n)
Trichotomy-suc (gt n<m) = gt n<m

_≟_ : ∀ m n → Trichotomy m n
zero  ≟ zero = eq refl
zero  ≟ suc n = lt _
suc m ≟ zero = gt _
suc m ≟ suc n = Trichotomy-suc (m ≟ n)

k≤k+n : ∀ k → k ≤ k + n
k≤k+n zero    = _
k≤k+n (suc k) = k≤k+n k

n≤k+n : ∀ n → n ≤ k + n
n≤k+n {k} n = transport (λ i → n ≤ +-comm n k i) (k≤k+n n)


-- Andreas, 2017-01-12, issue #2386

open import Agda.Primitive

data _≡_ {a b} {A : Set (a ⊔ b)} : (x y : A) → Set where
  refl : (x : A) → x ≡ x

{-# BUILTIN EQUALITY _≡_ #-}

-- Should be accepted

-- The type of primErase has to match the flavor of EQUALITY

primitive primEraseEquality : ∀ {a b}{A : Set (a ⊔ b)} {x y : A} → _≡_ x y → _≡_ x y

testTM : ∀ {a b} {A : Set (a ⊔ b)} {x : A} (eq : _≡_ {a} {b} x x) → primEraseEquality {x = x} {y = x} eq ≡ refl _
testTM _ = refl _

-- Testing rewrite

subst : ∀{ℓ}{A : Set ℓ} {P : A → Set}{a b : A} → _≡_ {a = ℓ} {b = ℓ} a b → P a → P b
subst eq p rewrite eq = p


open import Level
module ordinal where

open import logic
open import nat
open import Data.Nat renaming ( zero to Zero ; suc to Suc ;  ℕ to Nat ; _⊔_ to _n⊔_ )
open import Data.Empty
open import Relation.Binary.PropositionalEquality
open import Relation.Binary.Definitions
open import Data.Nat.Properties
open import Relation.Nullary
open import Relation.Binary.Core

----
--
-- Countable Ordinals
--

data OrdinalD {n : Level} :  (lv : Nat) → Set n where
   Φ : (lv : Nat) → OrdinalD  lv
   OSuc : (lv : Nat) → OrdinalD {n} lv → OrdinalD lv

record Ordinal {n : Level} : Set n where
   constructor ordinal
   field
     lv : Nat
     ord : OrdinalD {n} lv

data _d<_ {n : Level} :   {lx ly : Nat} → OrdinalD {n} lx  →  OrdinalD {n} ly  → Set n where
   Φ<  : {lx : Nat} → {x : OrdinalD {n} lx}  →  Φ lx d< OSuc lx x
   s<  : {lx : Nat} → {x y : OrdinalD {n} lx}  →  x d< y  → OSuc  lx x d< OSuc  lx y

open Ordinal

_o<_ : {n : Level} ( x y : Ordinal ) → Set n
_o<_ x y =  (lv x < lv y )  ∨ ( ord x d< ord y )

s<refl : {n : Level } {lx : Nat } { x : OrdinalD {n} lx } → x d< OSuc lx x
s<refl {n} {lv} {Φ lv}  = Φ<
s<refl {n} {lv} {OSuc lv x}  = s< s<refl

trio<> : {n : Level} →  {lx : Nat} {x  : OrdinalD {n} lx } { y : OrdinalD  lx }  →  y d< x → x d< y → ⊥
trio<>  {n} {lx} {.(OSuc lx _)} {.(OSuc lx _)} (s< s) (s< t) = trio<> s t
trio<> {n} {lx} {.(OSuc lx _)} {.(Φ lx)} Φ< ()

d<→lv : {n : Level} {x y  : Ordinal {n}}   → ord x d< ord y → lv x ≡ lv y
d<→lv Φ< = refl
d<→lv (s< lt) = refl

o∅ : {n : Level} → Ordinal {n}
o∅  = record { lv = Zero ; ord = Φ Zero }

open import Relation.Binary.HeterogeneousEquality using (_≅_;refl)

ordinal-cong : {n : Level} {x y : Ordinal {n}}  →
      lv x  ≡ lv y → ord x ≅ ord y →  x ≡ y
ordinal-cong refl refl = refl

≡→¬d< : {n : Level} →  {lv : Nat} → {x  : OrdinalD {n}  lv }  → x d< x → ⊥
≡→¬d<  {n} {lx} {OSuc lx y} (s< t) = ≡→¬d< t

trio<≡ : {n : Level} →  {lx : Nat} {x  : OrdinalD {n} lx } { y : OrdinalD  lx }  → x ≡ y  → x d< y → ⊥
trio<≡ refl = ≡→¬d<

trio>≡ : {n : Level} →  {lx : Nat} {x  : OrdinalD {n} lx } { y : OrdinalD  lx }  → x ≡ y  → y d< x → ⊥
trio>≡ refl = ≡→¬d<

triOrdd : {n : Level} →  {lx : Nat}   → Trichotomous  _≡_ ( _d<_  {n} {lx} {lx} )
triOrdd  {_} {lv} (Φ lv) (Φ lv) = tri≈ ≡→¬d< refl ≡→¬d<
triOrdd  {_} {lv} (Φ lv) (OSuc lv y) = tri< Φ< (λ ()) ( λ lt → trio<> lt Φ< )
triOrdd  {_} {lv} (OSuc lv x) (Φ lv) = tri> (λ lt → trio<> lt Φ<) (λ ()) Φ<
triOrdd  {_} {lv} (OSuc lv x) (OSuc lv y) with triOrdd x y
triOrdd  {_} {lv} (OSuc lv x) (OSuc lv y) | tri< a ¬b ¬c = tri< (s< a) (λ tx=ty → trio<≡ tx=ty (s< a) )  (  λ lt → trio<> lt (s< a) )
triOrdd  {_} {lv} (OSuc lv x) (OSuc lv x) | tri≈ ¬a refl ¬c = tri≈ ≡→¬d< refl ≡→¬d<
triOrdd  {_} {lv} (OSuc lv x) (OSuc lv y) | tri> ¬a ¬b c = tri> (  λ lt → trio<> lt (s< c) ) (λ tx=ty → trio>≡ tx=ty (s< c) ) (s< c)

osuc : {n : Level} ( x : Ordinal {n} ) → Ordinal {n}
osuc record { lv = lx ; ord = ox } = record { lv = lx ; ord = OSuc lx ox }

<-osuc : {n : Level} { x : Ordinal {n} } → x o< osuc x
<-osuc {n} {record { lv = lx ; ord = Φ .lx }} =  case2 Φ<
<-osuc {n} {record { lv = lx ; ord = OSuc .lx ox }} = case2 ( s< s<refl )

o<¬≡ : {n : Level } { ox oy : Ordinal {suc n}} → ox ≡ oy  → ox o< oy  → ⊥
o<¬≡ {_} {ox} {ox} refl (case1 lt) =  =→¬< lt
o<¬≡ {_} {ox} {ox} refl (case2 (s< lt)) = trio<≡ refl lt

¬x<0 : {n : Level} →  { x  : Ordinal {suc n} } → ¬ ( x o< o∅ {suc n} )
¬x<0 {n} {x} (case1 ())
¬x<0 {n} {x} (case2 ())

o<> : {n : Level} →  {x y : Ordinal {n}  }  →  y o< x → x o< y → ⊥
o<> {n} {x} {y} (case1 x₁) (case1 x₂) = nat-<>  x₁ x₂
o<> {n} {x} {y} (case1 x₁) (case2 x₂) = nat-≡< (sym (d<→lv x₂)) x₁
o<> {n} {x} {y} (case2 x₁) (case1 x₂) = nat-≡< (sym (d<→lv x₁)) x₂
o<> {n} {record { lv = lv₁ ; ord = .(OSuc lv₁ _) }} {record { lv = .lv₁ ; ord = .(Φ lv₁) }} (case2 Φ<) (case2 ())
o<> {n} {record { lv = lv₁ ; ord = .(OSuc lv₁ _) }} {record { lv = .lv₁ ; ord = .(OSuc lv₁ _) }} (case2 (s< y<x)) (case2 (s< x<y)) =
   o<> (case2 y<x) (case2 x<y)

orddtrans : {n : Level} {lx : Nat} {x y z : OrdinalD {n}  lx }   → x d< y → y d< z → x d< z
orddtrans {_} {lx} {.(Φ lx)} {.(OSuc lx _)} {.(OSuc lx _)} Φ< (s< y<z) = Φ<
orddtrans {_} {lx} {.(OSuc lx _)} {.(OSuc lx _)} {.(OSuc lx _)} (s< x<y) (s< y<z) = s< ( orddtrans x<y y<z )

osuc-≡< : {n : Level} { a x : Ordinal {n} } → x o< osuc a  →  (x ≡ a ) ∨ (x o< a)
osuc-≡< {n} {a} {x} (case1 lt) = case2 (case1 lt)
osuc-≡< {n} {record { lv = lv₁ ; ord = Φ .lv₁ }} {record { lv = .lv₁ ; ord = .(Φ lv₁) }} (case2 Φ<) = case1 refl
osuc-≡< {n} {record { lv = lv₁ ; ord = OSuc .lv₁ ord₁ }} {record { lv = .lv₁ ; ord = .(Φ lv₁) }} (case2 Φ<) = case2 (case2 Φ<)
osuc-≡< {n} {record { lv = lv₁ ; ord = Φ .lv₁ }} {record { lv = .lv₁ ; ord = .(OSuc lv₁ _) }} (case2 (s< ()))
osuc-≡< {n} {record { lv = la ; ord = OSuc la oa }} {record { lv = la ; ord = (OSuc la ox) }} (case2 (s< lt)) with
      osuc-≡< {n} {record { lv = la ; ord = oa }} {record { lv = la ; ord = ox }} (case2 lt )
... | case1 refl = case1 refl
... | case2 (case2 x) = case2 (case2( s< x) )
... | case2 (case1 x) = ⊥-elim (¬a≤a  x)

osuc-< : {n : Level} { x y : Ordinal {n} } → y o< osuc x  → x o< y → ⊥
osuc-< {n} {x} {y} y<ox x<y with osuc-≡< y<ox
osuc-< {n} {x} {x} y<ox (case1 x₁) | case1 refl = ⊥-elim (¬a≤a x₁)
osuc-< {n} {x} {x} (case1 x₂) (case2 x₁) | case1 refl = ⊥-elim (¬a≤a x₂)
osuc-< {n} {x} {x} (case2 x₂) (case2 x₁) | case1 refl = ≡→¬d<  x₁
osuc-< {n} {x} {y} y<ox (case1 x₂) | case2 (case1 x₁) = nat-<> x₂ x₁
osuc-< {n} {x} {y} y<ox (case1 x₂) | case2 (case2 x₁) = nat-≡< (sym (d<→lv x₁)) x₂
osuc-< {n} {x} {y} y<ox (case2 x<y) | case2 y<x = o<> (case2 x<y) y<x

ordtrans : {n : Level} {x y z : Ordinal {n} }   → x o< y → y o< z → x o< z
ordtrans {n} {x} {y} {z} (case1 x₁) (case1 x₂) = case1 ( <-trans x₁ x₂ )
ordtrans {n} {x} {y} {z} (case1 x₁) (case2 x₂) with  d<→lv x₂
... | refl = case1 x₁
ordtrans {n} {x} {y} {z} (case2 x₁) (case1 x₂)  with  d<→lv x₁
... | refl = case1 x₂
ordtrans {n} {x} {y} {z} (case2 x₁) (case2 x₂) with d<→lv x₁ | d<→lv x₂
... | refl | refl = case2 ( orddtrans x₁ x₂ )

trio< : {n : Level } → Trichotomous {suc n} _≡_  _o<_
trio< a b with <-cmp (lv a) (lv b)
trio< a b | tri< a₁ ¬b ¬c = tri< (case1  a₁) (λ refl → ¬b (cong ( λ x → lv x ) refl ) ) lemma1 where
   lemma1 : ¬ (Suc (lv b) ≤ lv a) ∨ (ord b d< ord a)
   lemma1 (case1 x) = ¬c x
   lemma1 (case2 x) = ⊥-elim (nat-≡< (sym ( d<→lv x )) a₁  )
trio< a b | tri> ¬a ¬b c = tri> lemma1 (λ refl → ¬b (cong ( λ x → lv x ) refl ) ) (case1 c) where
   lemma1 : ¬ (Suc (lv a) ≤ lv b) ∨ (ord a d< ord b)
   lemma1 (case1 x) = ¬a x
   lemma1 (case2 x) = ⊥-elim (nat-≡< (sym ( d<→lv x )) c  )
trio< a b | tri≈ ¬a refl ¬c with triOrdd ( ord a ) ( ord b )
trio< record { lv = .(lv b) ; ord = x } b | tri≈ ¬a refl ¬c | tri< a ¬b ¬c₁ = tri< (case2 a) (λ refl → ¬b (lemma1 refl )) lemma2 where
   lemma1 :  (record { lv = _ ; ord = x }) ≡ b →  x ≡ ord b
   lemma1 refl = refl
   lemma2 : ¬ (Suc (lv b) ≤ lv b) ∨ (ord b d< x)
   lemma2 (case1 x) = ¬a x
   lemma2 (case2 x) = trio<> x a
trio< record { lv = .(lv b) ; ord = x } b | tri≈ ¬a refl ¬c | tri> ¬a₁ ¬b c = tri> lemma2 (λ refl → ¬b (lemma1 refl )) (case2 c) where
   lemma1 :  (record { lv = _ ; ord = x }) ≡ b →  x ≡ ord b
   lemma1 refl = refl
   lemma2 : ¬ (Suc (lv b) ≤ lv b) ∨ (x d< ord b)
   lemma2 (case1 x) = ¬a x
   lemma2 (case2 x) = trio<> x c
trio< record { lv = .(lv b) ; ord = x } b | tri≈ ¬a refl ¬c | tri≈ ¬a₁ refl ¬c₁ = tri≈ lemma1 refl lemma1 where
   lemma1 : ¬ (Suc (lv b) ≤ lv b) ∨ (ord b d< ord b)
   lemma1 (case1 x) = ¬a x
   lemma1 (case2 x) = ≡→¬d< x

open _∧_

TransFinite : {n m : Level} → { ψ : Ordinal {suc n} → Set m }
  → ( ∀ (lx : Nat ) → ( (x : Ordinal {suc n} ) → x o< ordinal lx (Φ lx)  → ψ x ) → ψ ( record { lv = lx ; ord = Φ lx } ) )
  → ( ∀ (lx : Nat ) → (x : OrdinalD lx ) → ( (y : Ordinal {suc n} ) → y o< ordinal lx (OSuc lx x)  → ψ y )   → ψ ( record { lv = lx ; ord = OSuc lx x } ) )
  →  ∀ (x : Ordinal)  → ψ x
TransFinite {n} {m} {ψ} caseΦ caseOSuc x = proj1 (TransFinite1 (lv x) (ord x) ) where
  TransFinite1 : (lx : Nat) (ox : OrdinalD lx ) → ψ (ordinal lx ox) ∧ ( ( (x : Ordinal {suc n} ) → x o< ordinal lx ox  → ψ x ) )
  TransFinite1 Zero (Φ 0) = ⟪  caseΦ Zero lemma , lemma1 ⟫ where
      lemma : (x : Ordinal) → x o< ordinal Zero (Φ Zero) → ψ x
      lemma x (case1 ())
      lemma x (case2 ())
      lemma1 : (x : Ordinal) → x o< ordinal Zero (Φ Zero) → ψ x
      lemma1 x (case1 ())
      lemma1 x (case2 ())
  TransFinite1 (Suc lx) (Φ (Suc lx)) = ⟪ caseΦ (Suc lx) (λ x → lemma (lv x) (ord x)) , (λ x → lemma (lv x) (ord x)) ⟫ where
      lemma0 : (ly : Nat) (oy : OrdinalD ly ) → ordinal ly oy  o< ordinal lx (Φ lx) → ψ (ordinal ly oy)
      lemma0 ly oy lt = proj2 ( TransFinite1 lx (Φ lx) ) (ordinal ly oy) lt
      lemma : (ly : Nat) (oy : OrdinalD ly ) → ordinal ly oy  o< ordinal (Suc lx) (Φ (Suc lx)) → ψ (ordinal ly oy)
      lemma lx1 ox1            (case1 lt) with <-∨ lt
      lemma lx (Φ lx)          (case1 lt) | case1 refl = proj1 ( TransFinite1 lx (Φ lx) )
      lemma lx (Φ lx)          (case1 lt) | case2 lt1 = lemma0  lx (Φ lx) (case1 lt1)
      lemma lx (OSuc lx ox1)   (case1 lt) | case1 refl = caseOSuc lx ox1 lemma2 where
          lemma2 : (y : Ordinal) → (Suc (lv y) ≤ lx) ∨ (ord y d< OSuc lx ox1) → ψ y
          lemma2 y lt1 with osuc-≡< lt1
          lemma2 y lt1 | case1 refl = lemma lx ox1 (case1 a<sa)
          lemma2 y lt1 | case2 t = proj2 (TransFinite1 lx ox1) y t
      lemma lx1 (OSuc lx1 ox1) (case1 lt) | case2 lt1 = caseOSuc lx1 ox1 lemma2 where
          lemma2 : (y : Ordinal) → (Suc (lv y) ≤ lx1) ∨ (ord y d< OSuc lx1 ox1) → ψ y
          lemma2 y lt2 with osuc-≡< lt2
          lemma2 y lt2 | case1 refl = lemma lx1 ox1 (ordtrans lt2 (case1 lt))
          lemma2 y lt2 | case2 (case1 lt3) = proj2 (TransFinite1 lx (Φ lx)) y (case1 (<-trans lt3 lt1 ))
          lemma2 y lt2 | case2 (case2 lt3) with d<→lv lt3
          ... | refl = proj2 (TransFinite1 lx (Φ lx)) y (case1 lt1)
  TransFinite1 lx (OSuc lx ox)  = ⟪ caseOSuc lx ox lemma , lemma ⟫ where
      lemma : (y : Ordinal) → y o< ordinal lx (OSuc lx ox) → ψ y
      lemma y lt with osuc-≡< lt
      lemma y lt | case1 refl = proj1 ( TransFinite1 lx ox )
      lemma y lt | case2 lt1 = proj2 ( TransFinite1 lx ox ) y lt1

--  record CountableOrdinal {n : Level} : Set (suc (suc n)) where
--     field
--         ctl→ : Nat → Ordinal {suc n}
--         ctl← : Ordinal → Nat
--         ctl-iso→ : { x : Ordinal } → ctl→ (ctl← x ) ≡ x
--         ctl-iso← : { x : Nat }  → ctl← (ctl→ x ) ≡ x
--
--  is-C-Ordinal : {n : Level} → CountableOrdinal {n}
--  is-C-Ordinal {n} = record {
--         ctl→ = {!!}
--      ;  ctl← = λ x → TransFinite {n} (λ lx lt → Zero ) ctl01 x
--      ;  ctl-iso→ = {!!}
--      ;  ctl-iso← = {!!}
--    } where
--        ctl01 : (lx : Nat) (x : OrdinalD lx) → ((y : Ordinal) → y o< ordinal lx (OSuc lx x) → Nat) → Nat
--        ctl01 Zero (Φ Zero) prev = Zero
--        ctl01 Zero (OSuc Zero x) prev = Suc ( prev (ordinal Zero x) (ordtrans <-osuc <-osuc ))
--        ctl01 (Suc lx) (Φ (Suc lx)) prev = Suc ( prev (ordinal lx {!!}) {!!})
--        ctl01 (Suc lx) (OSuc (Suc lx) x) prev = Suc ( prev (ordinal (Suc lx) x) (ordtrans <-osuc <-osuc ))

open import Ordinals

C-Ordinal : {n : Level} →  Ordinals {suc n}
C-Ordinal {n} = record {
     Ordinal = Ordinal {suc n}
   ; o∅ = o∅
   ; osuc = osuc
   ; _o<_ = _o<_
   ; next = next
   ; isOrdinal = record {
       ordtrans = ordtrans
     ; trio< = trio<
     ; ¬x<0 = ¬x<0
     ; <-osuc = <-osuc
     ; osuc-≡< = osuc-≡<
     ; TransFinite = TransFinite2
     ; Oprev-p  = Oprev-p
   } ;
   isNext = record {
        x<nx = x<nx
      ; osuc<nx = λ {x} {y} → osuc<nx {x} {y}
      ; ¬nx<nx = ¬nx<nx
   }
  } where
     next : Ordinal {suc n} → Ordinal {suc n}
     next (ordinal lv ord) = ordinal (Suc lv) (Φ (Suc lv))
     x<nx :    { y : Ordinal } → (y o< next y )
     x<nx = case1 a<sa
     osuc<nx : { x y : Ordinal } → x o< next y → osuc x o< next y
     osuc<nx (case1 lt) = case1 lt
     ¬nx<nx :  {x y : Ordinal} → y o< x → x o< next y →  ¬ ((z : Ordinal) → ¬ (x ≡ osuc z))
     ¬nx<nx {x} {y} = lemma2 x where
         lemma2 : (x : Ordinal) → y o< x → x o< next y → ¬ ((z : Ordinal) → ¬ x ≡ osuc z)
         lemma2 (ordinal Zero (Φ 0)) (case2 ()) (case1 (s≤s z≤n)) not
         lemma2 (ordinal Zero (OSuc 0 dx)) (case2 Φ<) (case1 (s≤s z≤n)) not = not _ refl
         lemma2 (ordinal Zero (OSuc 0 dx)) (case2 (s< x)) (case1 (s≤s z≤n)) not = not _ refl
         lemma2 (ordinal (Suc lx) (OSuc (Suc lx) ox)) y<x (case1 (s≤s (s≤s lt))) not = not _ refl
         lemma2 (ordinal (Suc lx) (Φ (Suc lx))) (case1 x) (case1 (s≤s (s≤s lt))) not = lemma3 x lt where
             lemma3 : {n l : Nat} → (Suc (Suc n) ≤ Suc l) → l ≤ n → ⊥
             lemma3   (s≤s sn≤l) (s≤s l≤n) = lemma3 sn≤l l≤n
     open Oprev
     Oprev-p  : (x : Ordinal) → Dec ( Oprev (Ordinal {suc n})  osuc x )
     Oprev-p  (ordinal lv (Φ lv)) = no (λ not → lemma (oprev not) (oprev=x not) ) where
          lemma : (x : Ordinal) → osuc x ≡ (ordinal lv (Φ lv)) → ⊥
          lemma x ()
     Oprev-p  (ordinal lv (OSuc lv ox)) = yes record { oprev = ordinal lv ox ; oprev=x = refl }
     ord1 : Set (suc n)
     ord1 = Ordinal {suc n}
     TransFinite2 : { ψ : ord1  → Set (suc (suc n)) }
          → ( (x : ord1)  → ( (y : ord1  ) → y o< x → ψ y ) → ψ x )
          →  ∀ (x : ord1)  → ψ x
     TransFinite2 {ψ} lt x = TransFinite {n} {suc (suc n)} {ψ} caseΦ caseOSuc x where
        caseΦ : (lx : Nat) → ((x₁ : Ordinal) → x₁ o< ordinal lx (Φ lx) → ψ x₁) →
            ψ (record { lv = lx ; ord = Φ lx })
        caseΦ lx prev = lt (ordinal lx (Φ lx) ) prev
        caseOSuc :  (lx : Nat) (x₁ : OrdinalD lx) → ((y : Ordinal) → y o< ordinal lx (OSuc lx x₁) → ψ y) →
            ψ (record { lv = lx ; ord = OSuc lx x₁ })
        caseOSuc lx ox prev = lt (ordinal lx (OSuc lx ox)) prev


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

open import LogicalFormulae
open import Setoids.Setoids
open import Rings.Definition

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

module Rings.Units.Definition {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ _*_ : A → A → A} (R : Ring S _+_ _*_) where

open Setoid S
open Ring R

Unit : A → Set (a ⊔ b)
Unit r = Sg A (λ s → (r * s) ∼ 1R)


module Equality where

  postulate _==_ : {A : Set} -> A -> A -> Set
	    refl : {A : Set}{x : A} -> x == x

  {-# BUILTIN EQUAL _==_ #-}
  {-# BUILTIN REFL  refl #-}

  private
   primitive
    primEqElim : {A : Set}(x : A)(C : (y : A) -> x == y -> Set) ->
		 C x refl -> (y : A) -> (p : x == y) -> C y p

  elim-== = \{A : Set} -> primEqElim {A}

  subst : {A : Set}(C : A -> Set){x y : A} -> x == y -> C y -> C x
  subst C {x}{y} p Cy = elim-== x (\z _ -> C z -> C x) (\Cx -> Cx) y p Cy

  sym : {A : Set}{x y : A} -> x == y -> y == x
  sym {x = x}{y = y} p = subst (\z -> y == z) p refl

  trans : {A : Set}{x y z : A} -> x == y -> y == z -> x == z
  trans {x = x}{y = y}{z = z} xy yz = subst (\w -> w == z) xy yz

  cong : {A B : Set}{x y : A}(f : A -> B) -> x == y -> f x == f y
  cong {y = y} f xy = subst (\ ∙ -> f ∙ == f y) xy refl


{-# OPTIONS --termination-depth=2 #-}
module plfa-code.Quantifiers where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)
open import Relation.Nullary using (¬_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import plfa-code.Isomorphism using (_≃_; extensionality)

∀-elim : ∀ {A : Set} {B : A → Set}
  → (L : ∀ (x : A) → B x)
  → (M : A)
    --------------------------
  → B M
∀-elim L M = L M

---------- practice ----------
∀-distrib-× : ∀ {A : Set} {B C : A → Set} →
  (∀ (x : A) → B x × C x) ≃ (∀ (x : A) → B x) × (∀ (x : A) → C x)
∀-distrib-× =
  record
  { to      = λ fₗ → ⟨ (λ a → proj₁ (fₗ a)) , (λ a → proj₂ (fₗ a)) ⟩
  ; from    = λ x a → ⟨ (proj₁ x a) , (proj₂ x a) ⟩
  ; from∘to = λ fₗ → refl
  ; to∘from = λ x  → refl
  }

⊎∀-implies-∀⊎ : ∀ {A : Set} {B C : A → Set} →
    (∀ (x : A) → B x) ⊎ (∀ (x : A) → C x)  →  ∀ (x : A) → B x ⊎ C x
⊎∀-implies-∀⊎ (inj₁ f₁) a = inj₁ (f₁ a)
⊎∀-implies-∀⊎ (inj₂ f₂) a = inj₂ (f₂ a)

-- the converse doesn't hold. If we construct a function
-- '∀ (x : A) → B x', we could build a '∀ (x : A) → B x ⊎ C x',
-- but '∀ (x : A) → C x' maybe doesn't hold.

data Tri : Set where
  aa : Tri
  bb : Tri
  cc : Tri

postulate
  ∀-extensionality :
    ∀ {A : Set} {B : A → Set} (f g : ∀ (x : A) → B x)
    → (∀ (x : A) → (f x ≡ g x))
    → f ≡ g

∀-× : {B : Tri → Set} → (∀ (x : Tri) → B x) ≃ (B aa × B bb × B cc)
∀-× {B} =
  record
  { to      = to′
  ; from    = from′
  ; from∘to = λ f → ∀-extensionality (from′ ⟨ f aa , ⟨ f bb , f cc ⟩ ⟩) f
                                     λ{aa → refl; bb → refl; cc → refl}
  ; to∘from = λ xx → refl
  }
  where
  to′ : (∀ (x : Tri) → B x) → (B aa × B bb × B cc)
  to′ f = ⟨ f aa , ⟨ f bb , f cc ⟩ ⟩
  from′ : (B aa × B bb × B cc) → (∀ (x : Tri) → B x)
  from′ xx aa = proj₁ xx
  from′ xx bb = proj₁ (proj₂ xx)
  from′ xx cc = proj₂ (proj₂ xx)

-- every λ expression has different types , wtf
------------------------------

data Σ (A : Set) (B : A → Set) : Set where
  ⟨_,_⟩ : (x : A) → B x → Σ A B

Σ-syntax = Σ
infix 2 Σ-syntax
syntax Σ-syntax A (λ x → B) = Σ[ x ∈ A ] B

record Σ′ (A : Set) (B : A → Set) : Set where
  field
    proj₁′ : A
    proj₂′ : B proj₁′

∃ : ∀ {A : Set} (B : A → Set) → Set
∃ {A} B = Σ A B

∃-syntax = ∃
syntax ∃-syntax (λ x → B) = ∃[ x ] B

∃-elim : ∀ {A : Set} {B : A → Set} {C : Set}
  → (∀ x → B x → C)
  → ∃[ x ] B x
    ---------------
  → C
∃-elim f ⟨ x , y ⟩ = f x y

∀∃-currying : ∀ {A : Set} {B : A → Set} {C : Set}
  → (∀ x → B x → C) ≃ (∃[ x ] B x → C)
∀∃-currying =
  record
  { to      = λ{ f → λ{ ⟨ x , y ⟩ → f x y }}
  ; from    = λ{ g → λ{ x → λ{ y → g ⟨ x , y ⟩ }}}
  ; from∘to = λ f → refl
  ; to∘from = λ g → extensionality (λ{ ⟨ x , y ⟩ → refl})
  }

---------- practice ----------
∃-distrib-⊎ : ∀ {A : Set} {B C : A → Set} →
  ∃[ x ] (B x ⊎ C x) ≃ (∃[ x ] B x) ⊎ (∃[ x ] C x)
∃-distrib-⊎ =
  record
  { to      = λ{ ⟨ a , inj₁ b ⟩ → inj₁ ⟨ a , b ⟩
               ; ⟨ a , inj₂ c ⟩ → inj₂ ⟨ a , c ⟩
               }
  ; from    = λ{ (inj₁ ⟨ a , b ⟩) → ⟨ a , inj₁ b ⟩
               ; (inj₂ ⟨ a , c ⟩) → ⟨ a , inj₂ c ⟩
               }
  ; from∘to = λ{ ⟨ a , inj₁ b ⟩ → refl
               ; ⟨ a , inj₂ c ⟩ → refl
               }
  ; to∘from = λ{ (inj₁ ⟨ a , b ⟩) → refl
               ; (inj₂ ⟨ a , c ⟩) → refl
               }
  }

∃×-implies-×∃ : ∀ {A : Set} {B C : A → Set} →
  ∃[ x ] (B x × C x) → (∃[ x ] B x) × (∃[ x ] C x)
∃×-implies-×∃ ⟨ a , ⟨ b , c ⟩ ⟩ = ⟨ ⟨ a , b ⟩ , ⟨ a , c ⟩ ⟩

-- the converse doesn't hold, because the x in ∃[ x ] B x is maybe not
-- the same 'x' in ∃[ x ] C x

∃-⊎ : ∀ {B : Tri → Set} → ∃[ x ] B x ≃ B aa ⊎ B bb ⊎ B cc
∃-⊎ =
  record
  { to      = λ{ ⟨ aa , a ⟩ → inj₁ a
               ; ⟨ bb , b ⟩ → inj₂ (inj₁ b)
               ; ⟨ cc , c ⟩ → inj₂ (inj₂ c)
               }
  ; from    = λ{ (inj₁ a) → ⟨ aa , a ⟩
               ; (inj₂ (inj₁ b)) → ⟨ bb , b ⟩
               ; (inj₂ (inj₂ c)) → ⟨ cc , c ⟩
               }
  ; from∘to = λ{ ⟨ aa , a ⟩ → refl
               ; ⟨ bb , b ⟩ → refl
               ; ⟨ cc , c ⟩ → refl
               }
  ; to∘from = λ{ (inj₁ a) → refl
               ; (inj₂ (inj₁ b)) → refl
               ; (inj₂ (inj₂ c)) → refl
               }
  }

data even : ℕ → Set
data odd  : ℕ → Set

data even where

  even-zero : even zero

  even-suc : ∀ {n : ℕ}
    → odd n
      ------------
    → even (suc n)

data odd where
  odd-suc : ∀ {n : ℕ}
    → even n
      -----------
    → odd (suc n)

even-∃ : ∀ {n : ℕ} → even n → ∃[ m ] (    m * 2 ≡ n)
odd-∃  : ∀ {n : ℕ} →  odd n → ∃[ m ] (1 + m * 2 ≡ n)

even-∃ even-zero                       =  ⟨ zero  , refl ⟩
even-∃ (even-suc o) with odd-∃ o
...                    | ⟨ m , refl ⟩  =  ⟨ suc m , refl ⟩

odd-∃  (odd-suc e)  with even-∃ e
...                    | ⟨ m , refl ⟩  =  ⟨ m , refl ⟩

∃-even : ∀ {n : ℕ} → ∃[ m ] (    m * 2 ≡ n) → even n
∃-odd  : ∀ {n : ℕ} → ∃[ m ] (1 + m * 2 ≡ n) →  odd n

∃-even ⟨  zero , refl ⟩  =  even-zero
∃-even ⟨ suc m , refl ⟩  =  even-suc (∃-odd ⟨ m , refl ⟩)

∃-odd  ⟨     m , refl ⟩  =  odd-suc (∃-even ⟨ m , refl ⟩)

--------- practice ----------
open import Data.Nat.Properties using (+-identityʳ; +-suc; +-assoc)
open Eq using (cong; sym; trans)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_)

open import plfa-code.Reasoning-legacy

∃-even′ : ∀ {n : ℕ} → ∃[ m ] (    2 * m ≡ n) → even n
∃-odd′  : ∀ {n : ℕ} → ∃[ m ] (2 * m + 1 ≡ n) →  odd n

dbl≡2* : ∀ n → n + n ≡ 2 * n
dbl≡2* n = cong (n +_) (sym (+-identityʳ n))

∃-even′ ⟨ zero , refl ⟩ = even-zero
∃-even′ ⟨ suc m , refl ⟩
  rewrite +-identityʳ m | +-suc m m | dbl≡2* m
                  = even-suc (odd-suc (∃-even′ ⟨ m , refl ⟩))

∃-odd′ ⟨ m , refl ⟩ rewrite +-suc (2 * m) 0
                          | +-identityʳ m
                          | +-identityʳ (m + m)
                          | dbl≡2* m           = odd-suc (∃-even′ ⟨ m , refl ⟩)

-- it's more difficult far away ...

open Data.Nat using (_≤_; z≤n; s≤s)
open Data.Nat.Properties using (≤-pred)

∃+⇒≤ : ∀ (y z : ℕ) → ∃[ x ] (x + y ≡ z) → y ≤ z
∃+⇒≤ zero .(x + 0) ⟨ x , refl ⟩ = z≤n
∃+⇒≤ (suc y) .(x + suc y) ⟨ x , refl ⟩ rewrite +-suc x y
                                = s≤s (∃+⇒≤ y (x + y) ⟨ x , refl ⟩)

≤⇒∃+ : ∀ (y z : ℕ) → y ≤ z → ∃[ x ] (x + y ≡ z)
≤⇒∃+ zero z y≤z = ⟨ z , (+-identityʳ z) ⟩
≤⇒∃+ (suc y) (suc z) y≤z with ≤⇒∃+ y z (≤-pred y≤z)
...         | ⟨ x , x+y≡z ⟩ = ⟨ x , trans (+-suc x y) (cong suc x+y≡z) ⟩

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

¬∃≃∀¬ : ∀ {A : Set} {B : A → Set}
  → (¬ ∃[ x ] B x) ≃ ∀ x → ¬ B x
¬∃≃∀¬ =
  record
    { to      = λ{ ¬∃xy x y → ¬∃xy ⟨ x , y ⟩ }
    ; from    = λ{ ∀¬xy ⟨ x , y ⟩ → ∀¬xy x y }
    ; from∘to = λ{ ¬∃xy → extensionality λ{ ⟨ x , y ⟩ → refl } }
    ; to∘from = λ{ ∀¬xy → refl }
    }

---------- practice ----------
∃¬-implies-¬∀ : ∀ {A : Set} {B : A → Set}
  → ∃[ x ] (¬ B x)
    --------------
  → ¬ (∀ x → B x)
∃¬-implies-¬∀ ⟨ a , ¬b ⟩ = λ a→b → ¬b (a→b a)
-- the converse doesn't hold. we couldn't get a instance
-- of A to construct ∃[ x ] (¬ B x)

open import plfa-code.Bin using (Bin; Can; One;
                                zero; can-one; x0_; x1_; nil; one;
                                from; to; can-to-n; can-tf-eq; from-to-const)
open Eq using (subst₂; cong₂)
open import Data.Empty using (⊥-elim)
open import Function using (_∘_)

one-assim : ∀ {b : Bin} → (x : One b) → (y : One b) → x ≡ y
one-assim one one = refl
one-assim (x0 x) (x0 y) = sym (cong x0_ (one-assim y x))
one-assim (x1 x) (x1 y) = sym (cong x1_ (one-assim y x))

can-assim : ∀ {b : Bin} → (x : Can b) → (y : Can b) → x ≡ y
can-assim zero zero = refl
can-assim zero (can-one (x0 ()))
can-assim (can-one (x0 ())) zero
can-assim (can-one one) (can-one one) = refl
can-assim (can-one (x0 x)) (can-one (x0 y)) = cong (can-one ∘ x0_) (one-assim x y)
can-assim (can-one (x1 x)) (can-one (x1 y)) = cong (can-one ∘ x1_) (one-assim x y)

∃-proj₁ : {A : Set} {B : A → Set} → ∃[ x ] B x → A
∃-proj₁ ⟨ x , _ ⟩ = x

∃≡ : ∀ {A : Set} {B : A → Set} (p₁ : ∃[ x ](B x)) (p₂ : ∃[ y ](B y))
  → ∃-proj₁ p₁ ≡ ∃-proj₁ p₂ → (∀ (x) → (b₁ : B x) → (b₂ : B x) → b₁ ≡ b₂)
  → p₁ ≡ p₂
∃≡ ⟨ x , bx ⟩ ⟨ .x , by ⟩ refl f = sym (cong (⟨_,_⟩ x) (f x by bx))

Bin-isomorphism : ℕ ≃ ∃[ x ](Can x)
Bin-isomorphism =
  record
  { to      = to′
  ; from    = from′
  ; from∘to = from-to-const
  ; to∘from = to∘from′
  }
  where
  to′ : ℕ → ∃[ x ](Can x)
  to′ n = ⟨ to n , can-to-n n ⟩
  from′ : ∃[ x ](Can x) → ℕ
  from′ ⟨ b , can-b ⟩ = from b
  to∘from′ : ∀ y → to′ (from′ y) ≡ y
  to∘from′ ⟨ b , can-b ⟩  = ∃≡ ⟨ to (from b) , can-to-n (from b) ⟩ ⟨ b , can-b ⟩ (can-tf-eq can-b) (λ x → can-assim {x})


module Lectures.Two where

-- Introduce imports
open import Lectures.One

-- Introduce type parameters

module List-types where

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

  _ : List Set
  _ = ⊥ ∷ (ℕ ∷ (⊤ ∷ []))

module List {ℓ} where

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

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

  map : {A B : Set ℓ} → (A → B) → List A → List B
  map f [] = []
  map f (x ∷ xs) = f x ∷ map f xs

open List using (List; []; _∷_)

_ : List ℕ
_ = 0 ∷ (1 ∷ (2 ∷ []))

-- Introduce type families

module Vec where
  data Vec (A : Set) : ℕ → Set where
    []  : Vec A zero
    _∷_ : ∀ {n} → A → Vec A n → Vec A (suc n)

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

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

  map : ∀ {A B n} → (A → B) → Vec A n → Vec B n
  map f [] = []
  map f (x ∷ xs) = f x ∷ map f xs

  zipWith : ∀ {A B C : Set} {n} (f : A → B → C)
          → Vec A n → Vec B n → Vec C n
  zipWith f [] [] = []
  zipWith f (x ∷ xs) (y ∷ ys) = f x y ∷ zipWith f xs ys

--  \u+
data _⊎_ (A : Set) (B : Set) : Set where
  inj₁ : A → A ⊎ B
  inj₂ : B → A ⊎ B

Dec : Set → Set
Dec B = B ⊎ (¬ B)

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

  record _×''_ (A : Set) (B : Set) : Set where
    constructor _,''_
    field
      proj₁ : A
      proj₂ : B

-- \Sigma
record Σ {ℓ} (A : Set ℓ) (B : A → Set ℓ) : Set ℓ where
  constructor _,_
  field
    proj₁ : A
    proj₂ : B proj₁

open Σ public

_ : Σ ℕ _isEven
_ = 0 , tt

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


-- This module closely follows a section of Martín Escardó's HoTT lecture notes:
-- https://www.cs.bham.ac.uk/~mhe/HoTT-UF-in-Agda-Lecture-Notes/HoTT-UF-Agda.html#equivalenceinduction
{-# OPTIONS --without-K #-}
module Util.HoTT.Equiv.Induction where

open import Util.HoTT.HLevel.Core
open import Util.HoTT.Equiv
open import Util.HoTT.Univalence.ContrFormulation
open import Util.Prelude

private
  variable
    α β γ : Level

G-≃ : {A : Set α} (P : Σ[ B ∈ Set α ] (A ≃ B) → Set β)
  → P (A , ≃-refl)
  → ∀ {B} (A≃B : A ≃ B)
  → P (B , A≃B)
G-≃ {A = A} P p {B} A≃B = subst P (univalenceProp A (A , ≃-refl) (B , A≃B)) p

abstract
  G-≃-β : {A : Set α} (P : Σ[ B ∈ Set α ] (A ≃ B) → Set β)
    → (p : P (A , ≃-refl))
    → G-≃ P p ≃-refl ≡ p
  G-≃-β {A = A} P p = subst (λ q → subst P q p ≡ p) (sym go) refl
    where
      go : univalenceProp A (A , ≃-refl) (A , ≃-refl) ≡ refl
      go = IsContr→IsSet (univalenceContr A) _ _

H-≃ : {A : Set α} (P : (B : Set α) → A ≃ B → Set β)
  → P A ≃-refl
  → ∀ {B} (A≃B : A ≃ B)
  → P B A≃B
H-≃ P p A≃B = G-≃ (λ { (B , A≃B) → P B A≃B }) p A≃B

abstract
  H-≃-β : {A : Set α} (P : (B : Set α) → A ≃ B → Set β)
    → (p : P A ≃-refl)
    → H-≃ P p ≃-refl ≡ p
  H-≃-β P p = G-≃-β (λ { (B , A≃B) → P B A≃B }) p

J-≃ : (P : (A B : Set α) → A ≃ B → Set β)
  → (∀ A → P A A ≃-refl)
  → ∀ {A B} (A≃B : A ≃ B)
  → P A B A≃B
J-≃ P p {A} {B} A≃B = H-≃ (λ B A≃B → P A B A≃B) (p A) A≃B

abstract
  J-≃-β : (P : (A B : Set α) → A ≃ B → Set β)
    → (p : ∀ A → P A A ≃-refl)
    → ∀ {A}
    → J-≃ P p ≃-refl ≡ p A
  J-≃-β P p {A} = H-≃-β (λ B A≃B → P A B A≃B) (p A)

H-IsEquiv : {A : Set α} (P : (B : Set α) → (A → B) → Set β)
  → P A id
  → ∀ {B} (f : A → B)
  → IsEquiv f
  → P B f
H-IsEquiv P p f f-equiv
  = H-≃ (λ B A≃B → P B (A≃B .forth)) p
      (record { forth = f ; isEquiv = f-equiv })

J-IsEquiv : (P : (A B : Set α) → (A → B) → Set β)
  → (∀ A → P A A id)
  → ∀ {A B} (f : A → B)
  → IsEquiv f
  → P A B f
J-IsEquiv P p f f-equiv
  = J-≃ (λ A B A≃B → P A B (A≃B .forth)) p
      (record { forth = f ; isEquiv = f-equiv })


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

open import Groups.Abelian.Definition
open import Groups.Definition
open import Setoids.Setoids
open import Sets.EquivalenceRelations
open import Lists.Lists

module Groups.Polynomials.Group {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ : A → A → A} (G : Group S _+_) where

open import Groups.Polynomials.Definition G
open import Groups.Polynomials.Addition G public
open Setoid S
open Equivalence eq

polyGroup : Group naivePolySetoid _+P_
Group.+WellDefined polyGroup = +PwellDefined
Group.0G polyGroup = []
Group.inverse polyGroup = inverse'
Group.+Associative polyGroup {a} {b} {c} = assoc {a} {b} {c}
Group.identRight polyGroup = PidentRight
Group.identLeft polyGroup = PidentLeft
Group.invLeft polyGroup {a} = invLeft' {a}
Group.invRight polyGroup {a} = invRight' {a}

abelian : AbelianGroup G → AbelianGroup polyGroup
AbelianGroup.commutative (abelian ab) {x} {y} = comm ab {x} {y}


------------------------------------------------------------------------
-- The Agda standard library
--
-- A bunch of properties
------------------------------------------------------------------------

module Data.Bool.Properties where

open import Data.Bool as Bool
open import Data.Fin
open import Function
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence
  using (_⇔_; equivalence; module Equivalence)
open import Algebra
open import Algebra.Structures
import Algebra.RingSolver.Simple as Solver
import Algebra.RingSolver.AlmostCommutativeRing as ACR
open import Relation.Binary.PropositionalEquality as P
  using (_≡_; _≢_; refl)
open P.≡-Reasoning
import Algebra.FunctionProperties as FP; open FP (_≡_ {A = Bool})
open import Data.Product
open import Data.Sum
open import Data.Empty

------------------------------------------------------------------------
-- Duality

-- Can we take advantage of duality in some (nice) way?

------------------------------------------------------------------------
-- (Bool, ∨, ∧, false, true) forms a commutative semiring

private

  ∨-assoc : Associative _∨_
  ∨-assoc true  y z = refl
  ∨-assoc false y z = refl

  ∧-assoc : Associative _∧_
  ∧-assoc true  y z = refl
  ∧-assoc false y z = refl

  ∨-comm : Commutative _∨_
  ∨-comm true  true  = refl
  ∨-comm true  false = refl
  ∨-comm false true  = refl
  ∨-comm false false = refl

  ∧-comm : Commutative _∧_
  ∧-comm true  true  = refl
  ∧-comm true  false = refl
  ∧-comm false true  = refl
  ∧-comm false false = refl

  distrib-∧-∨ : _∧_ DistributesOver _∨_
  distrib-∧-∨ = distˡ , distʳ
    where
    distˡ : _∧_ DistributesOverˡ _∨_
    distˡ true  y z = refl
    distˡ false y z = refl

    distʳ : _∧_ DistributesOverʳ _∨_
    distʳ x y z =
                      begin
       (y ∨ z) ∧ x
                      ≡⟨ ∧-comm (y ∨ z) x ⟩
       x ∧ (y ∨ z)
                      ≡⟨ distˡ x y z ⟩
       x ∧ y ∨ x ∧ z
                      ≡⟨ P.cong₂ _∨_ (∧-comm x y) (∧-comm x z) ⟩
       y ∧ x ∨ z ∧ x
                      ∎

isCommutativeSemiring-∨-∧
  : IsCommutativeSemiring _≡_ _∨_ _∧_ false true
isCommutativeSemiring-∨-∧ = record
  { +-isCommutativeMonoid = record
    { isSemigroup = record
      { isEquivalence = P.isEquivalence
      ; assoc         = ∨-assoc
      ; ∙-cong        = P.cong₂ _∨_
      }
    ; identityˡ = λ _ → refl
    ; comm      = ∨-comm
    }
  ; *-isCommutativeMonoid = record
    { isSemigroup = record
      { isEquivalence = P.isEquivalence
      ; assoc         = ∧-assoc
      ; ∙-cong        = P.cong₂ _∧_
      }
      ; identityˡ = λ _ → refl
    ; comm      = ∧-comm
    }
  ; distribʳ = proj₂ distrib-∧-∨
  ; zeroˡ    = λ _ → refl
  }

commutativeSemiring-∨-∧ : CommutativeSemiring _ _
commutativeSemiring-∨-∧ = record
  { _+_                   = _∨_
  ; _*_                   = _∧_
  ; 0#                    = false
  ; 1#                    = true
  ; isCommutativeSemiring = isCommutativeSemiring-∨-∧
  }

module RingSolver =
  Solver (ACR.fromCommutativeSemiring commutativeSemiring-∨-∧) _≟_

------------------------------------------------------------------------
-- (Bool, ∧, ∨, true, false) forms a commutative semiring

private

  distrib-∨-∧ : _∨_ DistributesOver _∧_
  distrib-∨-∧ = distˡ , distʳ
    where
    distˡ : _∨_ DistributesOverˡ _∧_
    distˡ true  y z = refl
    distˡ false y z = refl

    distʳ : _∨_ DistributesOverʳ _∧_
    distʳ x y z =
                          begin
       (y ∧ z) ∨ x
                          ≡⟨ ∨-comm (y ∧ z) x ⟩
       x ∨ (y ∧ z)
                          ≡⟨ distˡ x y z ⟩
       (x ∨ y) ∧ (x ∨ z)
                          ≡⟨ P.cong₂ _∧_ (∨-comm x y) (∨-comm x z) ⟩
       (y ∨ x) ∧ (z ∨ x)
                          ∎

isCommutativeSemiring-∧-∨
  : IsCommutativeSemiring _≡_ _∧_ _∨_ true false
isCommutativeSemiring-∧-∨ = record
  { +-isCommutativeMonoid = record
    { isSemigroup = record
      { isEquivalence = P.isEquivalence
      ; assoc         = ∧-assoc
      ; ∙-cong        = P.cong₂ _∧_
      }
    ; identityˡ = λ _ → refl
    ; comm      = ∧-comm
    }
  ; *-isCommutativeMonoid = record
    { isSemigroup = record
      { isEquivalence = P.isEquivalence
      ; assoc         = ∨-assoc
      ; ∙-cong        = P.cong₂ _∨_
      }
    ; identityˡ = λ _ → refl
    ; comm      = ∨-comm
    }
  ; distribʳ = proj₂ distrib-∨-∧
  ; zeroˡ    = λ _ → refl
  }

commutativeSemiring-∧-∨ : CommutativeSemiring _ _
commutativeSemiring-∧-∨ = record
  { _+_                   = _∧_
  ; _*_                   = _∨_
  ; 0#                    = true
  ; 1#                    = false
  ; isCommutativeSemiring = isCommutativeSemiring-∧-∨
  }

------------------------------------------------------------------------
-- (Bool, ∨, ∧, not, true, false) is a boolean algebra

private

  absorptive : Absorptive _∨_ _∧_
  absorptive = abs-∨-∧ , abs-∧-∨
    where
    abs-∨-∧ : _∨_ Absorbs _∧_
    abs-∨-∧ true  y = refl
    abs-∨-∧ false y = refl

    abs-∧-∨ : _∧_ Absorbs _∨_
    abs-∧-∨ true  y = refl
    abs-∧-∨ false y = refl

  not-∧-inverse : Inverse false not _∧_
  not-∧-inverse =
    ¬x∧x≡⊥ , (λ x → ∧-comm x (not x) ⟨ P.trans ⟩ ¬x∧x≡⊥ x)
    where
    ¬x∧x≡⊥ : LeftInverse false not _∧_
    ¬x∧x≡⊥ false = refl
    ¬x∧x≡⊥ true  = refl

  not-∨-inverse : Inverse true not _∨_
  not-∨-inverse =
    ¬x∨x≡⊤ , (λ x → ∨-comm x (not x) ⟨ P.trans ⟩ ¬x∨x≡⊤ x)
    where
    ¬x∨x≡⊤ : LeftInverse true not _∨_
    ¬x∨x≡⊤ false = refl
    ¬x∨x≡⊤ true  = refl

isBooleanAlgebra : IsBooleanAlgebra _≡_ _∨_ _∧_ not true false
isBooleanAlgebra = record
  { isDistributiveLattice = record
      { isLattice = record
          { isEquivalence = P.isEquivalence
          ; ∨-comm        = ∨-comm
          ; ∨-assoc       = ∨-assoc
          ; ∨-cong        = P.cong₂ _∨_
          ; ∧-comm        = ∧-comm
          ; ∧-assoc       = ∧-assoc
          ; ∧-cong        = P.cong₂ _∧_
          ; absorptive    = absorptive
          }
      ; ∨-∧-distribʳ = proj₂ distrib-∨-∧
      }
  ; ∨-complementʳ = proj₂ not-∨-inverse
  ; ∧-complementʳ = proj₂ not-∧-inverse
  ; ¬-cong        = P.cong not
  }

booleanAlgebra : BooleanAlgebra _ _
booleanAlgebra = record
  { _∨_              = _∨_
  ; _∧_              = _∧_
  ; ¬_               = not
  ; ⊤                = true
  ; ⊥                = false
  ; isBooleanAlgebra = isBooleanAlgebra
  }

------------------------------------------------------------------------
-- (Bool, xor, ∧, id, false, true) forms a commutative ring

private

  xor-is-ok : ∀ x y → x xor y ≡ (x ∨ y) ∧ not (x ∧ y)
  xor-is-ok true  y = refl
  xor-is-ok false y = P.sym $ proj₂ CS.*-identity _
    where module CS = CommutativeSemiring commutativeSemiring-∨-∧

commutativeRing-xor-∧ : CommutativeRing _ _
commutativeRing-xor-∧ = commutativeRing
  where
  import Algebra.Properties.BooleanAlgebra as BA
  open BA booleanAlgebra
  open XorRing _xor_ xor-is-ok

module XorRingSolver =
  Solver (ACR.fromCommutativeRing commutativeRing-xor-∧) _≟_

------------------------------------------------------------------------
-- Miscellaneous other properties

not-involutive : Involutive not
not-involutive true  = refl
not-involutive false = refl

not-¬ : ∀ {x y} → x ≡ y → x ≢ not y
not-¬ {true}  refl ()
not-¬ {false} refl ()

¬-not : ∀ {x y} → x ≢ y → x ≡ not y
¬-not {true}  {true}  x≢y = ⊥-elim (x≢y refl)
¬-not {true}  {false} _   = refl
¬-not {false} {true}  _   = refl
¬-not {false} {false} x≢y = ⊥-elim (x≢y refl)

⇔→≡ : {b₁ b₂ b : Bool} → b₁ ≡ b ⇔ b₂ ≡ b → b₁ ≡ b₂
⇔→≡ {true } {true }         hyp = refl
⇔→≡ {true } {false} {true } hyp = P.sym (Equivalence.to hyp ⟨$⟩ refl)
⇔→≡ {true } {false} {false} hyp = Equivalence.from hyp ⟨$⟩ refl
⇔→≡ {false} {true } {true } hyp = Equivalence.from hyp ⟨$⟩ refl
⇔→≡ {false} {true } {false} hyp = P.sym (Equivalence.to hyp ⟨$⟩ refl)
⇔→≡ {false} {false}         hyp = refl

T-≡ : ∀ {b} → T b ⇔ b ≡ true
T-≡ {false} = equivalence (λ ())       (λ ())
T-≡ {true}  = equivalence (const refl) (const _)

T-not-≡ : ∀ {b} → T (not b) ⇔ b ≡ false
T-not-≡ {false} = equivalence (const refl) (const _)
T-not-≡ {true}  = equivalence (λ ())       (λ ())

T-∧ : ∀ {b₁ b₂} → T (b₁ ∧ b₂) ⇔ (T b₁ × T b₂)
T-∧ {true}  {true}  = equivalence (const (_ , _)) (const _)
T-∧ {true}  {false} = equivalence (λ ())          proj₂
T-∧ {false} {_}     = equivalence (λ ())          proj₁

T-∨ : ∀ {b₁ b₂} → T (b₁ ∨ b₂) ⇔ (T b₁ ⊎ T b₂)
T-∨ {true}  {b₂}    = equivalence inj₁ (const _)
T-∨ {false} {true}  = equivalence inj₂ (const _)
T-∨ {false} {false} = equivalence inj₁ [ id , id ]

proof-irrelevance : ∀ {b} (p q : T b) → p ≡ q
proof-irrelevance {true}  _  _  = refl
proof-irrelevance {false} () ()

push-function-into-if :
  ∀ {a b} {A : Set a} {B : Set b} (f : A → B) x {y z} →
  f (if x then y else z) ≡ (if x then f y else f z)
push-function-into-if _ true  = P.refl
push-function-into-if _ false = P.refl


module Numeral.Matrix where

import      Lvl
open import Syntax.Number
open import Data
open import Data.Boolean
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Functional using (const)
open import Numeral.Finite
open import Numeral.Finite.Bound
open import Numeral.Finite.Oper
open import Numeral.Finite.Oper.Comparisons
open import Numeral.Natural
open import Numeral.CoordinateVector as Vector using (Vector)
open import Type

-- Accessor of data in 2-dimensional finite space (Implies bounded).
-- Like a data table.
record Matrix {ℓ} (s : ℕ ⨯ ℕ) (T : Type{ℓ}) : Type{ℓ} where
  constructor mat

  -- Type of elements in the matrix.
  Element : Type
  Element = T

  -- Width of the matrix (Number of columns).
  width : ℕ
  width = Tuple.left(s)

  -- Height of the matrix (Number of rows).
  height : ℕ
  height = Tuple.right(s)

  field
    -- Projection of a matrix.
    -- A cell in the matrix.
    proj : (𝕟(width) ⨯ 𝕟(height)) → T

  -- Vector of a row in the matrix.
  row : 𝕟(height) → Vector(width)(T)
  (row(y))(x) = proj(x , y)

  -- Vector of a column in the matrix.
  col : 𝕟(width) → Vector(height)(T)
  (col(x))(y) = proj(x , y)

  -- Transpose (Reflection on main diagonal).
  ⬔_ : Matrix(height , width)(T)
  proj(⬔_)(x , y) = proj(y , x)

module Rows where
  module _ {ℓ} {w}{h} {T : Type{ℓ}} where
    -- A matrix with two rows swapped.
    swap : 𝕟(h) → 𝕟(h) → Matrix(w , h)(T) → Matrix(w , h)(T)
    Matrix.proj(swap(y₁)(y₂)(M))(x , y) =
      if      (y ≡? y₁) then Matrix.proj(M)(x , y₂)
      else if (y ≡? y₂) then Matrix.proj(M)(x , y₁)
      else                   Matrix.proj(M)(x , y)

  module _ {ℓ₁ ℓ₂} {w₁ w₂}{h} {A : Type{ℓ₁}} {B : Type{ℓ₂}} where
    -- A matrix where a function has been applied to every row.
    map : (Vector(w₁)(A) → Vector(w₂)(B)) → Matrix(w₁ , h)(A) → Matrix(w₂ , h)(B)
    Matrix.proj(map f(M))(x , y) = Vector.proj(f(Matrix.row(M)(y)))(x)

  module _ {ℓ} {w}{h} {T : Type{ℓ}} where
    -- A matrix where a function has been applied to every element of the specified row.
    mapSingle : 𝕟(h) → (T → T) → Matrix(w , h)(T) → Matrix(w , h)(T)
    Matrix.proj(mapSingle target f(M))(x , y) =
      if      (y ≡? target) then f(Matrix.proj(M)(x , y))
      else                       Matrix.proj(M)(x , y)

    -- A matrix where a function has been applied to the specified row.
    applyOn : 𝕟(h) → (Vector(w)(T) → Vector(w)(T)) → Matrix(w , h)(T) → Matrix(w , h)(T)
    Matrix.proj(applyOn target f(M))(x , y) =
      if      (y ≡? target) then Vector.proj(f(Matrix.row(M)(y)))(x)
      else                       Matrix.proj(M)(x , y)

module Cols where
  module _ {ℓ} {w}{h} {T : Type{ℓ}} where
    -- A matrix with two columns swapped.
    swap : 𝕟(w) → 𝕟(w) → Matrix(w , h)(T) → Matrix(w , h)(T)
    Matrix.proj(swap(x₁)(x₂)(M))(x , y) =
      if      (x ≡? x₁) then Matrix.proj(M)(x₂ , y)
      else if (x ≡? x₂) then Matrix.proj(M)(x₁ , y)
      else                   Matrix.proj(M)(x , y)

  module _ {ℓ₁ ℓ₂} {w}{h₁ h₂} {A : Type{ℓ₁}} {B : Type{ℓ₂}} where
    -- A matrix where a function has been applied to every column.
    map : (Vector(h₁)(A) → Vector(h₂)(B)) → Matrix(w , h₁)(A) → Matrix(w , h₂)(B)
    Matrix.proj(map f(M))(x , y) = Vector.proj(f(Matrix.col(M)(x)))(y)

  module _ {ℓ} {w}{h} {T : Type{ℓ}} where
    -- A matrix where a function has been applied to every element of the specified column.
    mapSingle : 𝕟(w) → (T → T) → Matrix(w , h)(T) → Matrix(w , h)(T)
    Matrix.proj(mapSingle target f(M))(x , y) =
      if      (y ≡? target) then f(Matrix.proj(M)(x , y))
      else                       Matrix.proj(M)(x , y)

    -- A matrix where a function has been applied to the specified column.
    applyOn : 𝕟(w) → (Vector(h)(T) → Vector(h)(T)) → Matrix(w , h)(T) → Matrix(w , h)(T)
    Matrix.proj(applyOn target f(M))(x , y) =
      if      (x ≡? target) then Vector.proj(f(Matrix.col(M)(x)))(y)
      else                       Matrix.proj(M)(x , y)

module _ {ℓ₁ ℓ₂} {s} {A : Type{ℓ₁}} {B : Type{ℓ₂}} where
  -- A matrix where a function has been applied to every element.
  map : (A → B) → Matrix(s)(A) → Matrix(s)(B) -- TODO: Same implementation in Vector.agda. Generalize. Maybe like in Haskell? With Applicative, Functor and stuff?
  Matrix.proj(map f(m))(x , y) = f(Matrix.proj(m)(x , y))

module _ {ℓ₁ ℓ₂ ℓ₃} {s} {A : Type{ℓ₁}} {B : Type{ℓ₂}} {C : Type{ℓ₃}} where
  -- A matrix where a binary operator has been pairwise applied to every element of the given matrices at the same positions.
  -- This can be used to construct a component-wise operator.
  map₂ : (A → B → C) → Matrix(s)(A) → Matrix(s)(B) → Matrix(s)(C)
  Matrix.proj(map₂(_▫_) (v₁)(v₂))(x , y) = Matrix.proj(v₁)(x , y) ▫ Matrix.proj(v₂)(x , y)

module _ {ℓ} {w}{h} {T : Type{ℓ}} where
  -- A matrix from a vector of vectors. The inner vectors becomes rows.
  rowMat : Vector(h)(Vector(w)(T)) → Matrix(w , h)(T)
  Matrix.proj(rowMat(vs))(x , y) = Vector.proj(Vector.proj(vs)(y))(x)

  -- A matrix from a vector of vectors. The inner vectors becomes columns.
  colMat : Vector(w)(Vector(h)(T)) → Matrix(w , h)(T)
  Matrix.proj(colMat(vs))(x , y) = Vector.proj(Vector.proj(vs)(x))(y)

  -- A matrix represented as a vector of vectors where the inner vectors are the rows of the matrix.
  rows : Matrix(w , h)(T) → Vector(h)(Vector(w)(T))
  ((rows(M))(y))(x) = Matrix.proj(M)(x , y)

  -- A matrix represented as a vector of vectors where the inner vectors are the columns of the matrix.
  cols : Matrix(w , h)(T) → Vector(w)(Vector(h)(T))
  ((cols(M))(x))(y) = Matrix.proj(M)(x , y)

  -- Matrix with one row and one column removed.
  minor : Matrix(𝐒(w) , 𝐒(h))(T) → (𝕟(𝐒(w)) ⨯ 𝕟(𝐒(h))) → Matrix(w , h)(T)
  Matrix.proj(minor(M)(X , Y))(x , y) = Matrix.proj(M)(new-x , new-y) where
    new-x = if(x <? X) then bound-𝐒(x) else 𝐒(x)
    new-y = if(y <? Y) then bound-𝐒(y) else 𝐒(y)

module _ {ℓ} {s} {T : Type{ℓ}} where
  -- A matrix filled with a single element.
  fill : T → Matrix(s)(T)
  Matrix.proj(fill(elem)) = const(elem)

  -- submatrix : Matrix(w , h)(T) → ((X , Y) : (𝕟(w) ⨯ 𝕟(h))) → ((W , H) : (𝕟(w −₀ X) ⨯ 𝕟(h −₀ Y))) → Matrix(W −₀ X , H −₀ Y)(T)

-- A square matrix is a matrix with equal length in both directions.
SquareMatrix : ∀{ℓ} → ℕ → Type{ℓ} → Type{ℓ}
SquareMatrix(d)(T) = Matrix(d , d)(T)
module SquareMatrix {ℓ} {d} {T : Type{ℓ}} where
  module _ (m : SquareMatrix(d)(T)) where
    -- The diagonal vector.
    -- The vector consisting of the elements in the main diagonal of the matrix.
    diag : Vector(d)(T)
    (diag)(i) = Matrix.proj(m)(i , i)

    -- The maximum number of dimensions of a space that the matrix can describe linear transformations in.
    -- The width/height of the matrix.
    dim : ℕ
    dim = d

  -- The diagonal matrix from a vector.
  -- The matrix consisting of the elements from the vector in the main diagonal and a default element (zero) in the rest of the positions.
  diagMat : T → Vector(d)(T) → SquareMatrix(d)(T)
  Matrix.proj(diagMat(zero)(v))(x , y) = if (x ≡? y) then Vector.proj(v)(x) else zero

  -- Scalar matrix.
  -- The matrix consisting of a constant element in the main diagonal and a default element (zero) in the rest of the positions.
  scalarMat : T → T → SquareMatrix(d)(T)
  scalarMat(zero)(elem) = diagMat(zero)(Vector.fill(elem))

module _ {ℓ} where
  RowVector : ℕ → Type{ℓ} → Type{ℓ}
  RowVector(d)(T) = Matrix(d , 1)(T)
  module RowVector {d}{T} where
    rowVecMat : Vector(d)(T) → RowVector(d)(T)
    Matrix.proj(rowVecMat(v))(x , _) = Vector.proj(v)(x)

  ColVector : ℕ → Type{ℓ} → Type{ℓ}
  ColVector(d)(T) = Matrix(1 , d)(T)
  module ColVector {d}{T} where
    colVecMat : Vector(d)(T) → ColVector(d)(T)
    Matrix.proj(colVecMat(v))(_ , y) = Vector.proj(v)(y)

module _ {ℓ₁ ℓ₂ ℓ₃ ℓ₄} {A : Type{ℓ₁}} {B : Type{ℓ₂}} {C : Type{ℓ₃}} {D : Type{ℓ₄}} where
  multPattern : ∀{x y z} → (C → D → D) → (A → B → C) → D → Matrix(y , z)(A) → Matrix(x , y)(B) → Matrix(x , z)(D)
  Matrix.proj(multPattern (_+_) (_⋅_) (zero) M₁ M₂)(x , y) = Vector.foldᵣ(_+_) zero (Vector.map₂(_⋅_) (Matrix.row(M₁)(y)) (Matrix.col(M₂)(x)))

{-
module _ {ℓ} {T : Type{ℓ}} where
  detPatternX : T → ∀{d} → SquareMatrix(d)(T) → 𝕟(d) → T
  detPatternX _    {𝐒(𝟎)}    M _ = Matrix.proj M(0 , 0)
  detPatternX zero {𝐒(𝐒(d))} M y = Vector.foldᵣ {!+_!} zero (Vector.map () (Matrix.row M(y)))
-}


-- Agda program using the Iowa Agda library

open import bool

module PROOF-permlength
  (Choice : Set)
  (choose : Choice → 𝔹)
  (lchoice : Choice → Choice)
  (rchoice : Choice → Choice)
  where

open import eq
open import bool
open import nat
open import list
open import maybe

---------------------------------------------------------------------------
-- Translated Curry operations:

insert : {a : Set} → Choice → a → 𝕃 a → 𝕃 a
insert c1 x [] = x :: []
insert c1 y (z :: u) = if choose c1 then y :: (z :: u) else z :: (insert (lchoice c1) y u)

perm : {a : Set} → Choice → 𝕃 a → 𝕃 a
perm c1 [] = []
perm c1 (x :: y) = insert c1 x (perm (lchoice c1) y)

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

insert-inc-length : ∀ {a : Set} → (ch : Choice) (x : a) (xs : 𝕃 a)
                 → length (insert ch x xs) ≡ suc (length xs)
insert-inc-length ch x [] = refl
insert-inc-length ch x (y :: ys) with choose ch
... | tt = refl
... | ff rewrite insert-inc-length (lchoice ch) x ys = refl

permlength : {a : Set} → (c1 : Choice) → (x : 𝕃 a) → (length x) ≡ (length (perm c1 x))
permlength c1 [] = refl
permlength c1 (x :: xs)
 rewrite insert-inc-length c1 x (perm (lchoice c1) xs)
         | permlength (lchoice c1) xs
  = refl

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


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

module Data.Fin.Properties where

open import Prelude
open import Data.Fin.Base
import Data.Nat.Properties as ℕ
open import Data.Nat.Properties using (+-comm)
open import Data.Nat
open import Function.Injective
open import Agda.Builtin.Nat renaming (_<_ to _<ᵇ_)

private
  variable
    n m : ℕ

suc-natfin : Σ[ m ⦂ ℕ ] × (m ℕ.< n) → Σ[ m ⦂ ℕ ] × (m ℕ.< suc n)
suc-natfin (m , p) = suc m , p

Fin-to-Nat-lt : Fin n → Σ[ m ⦂ ℕ ] × (m ℕ.< n)
Fin-to-Nat-lt {n = suc n} f0 = zero , tt
Fin-to-Nat-lt {n = suc n} (fs x) = suc-natfin (Fin-to-Nat-lt x)

Fin-from-Nat-lt : ∀ m → m ℕ.< n → Fin n
Fin-from-Nat-lt {n = suc n} zero p = f0
Fin-from-Nat-lt {n = suc n} (suc m) p = fs (Fin-from-Nat-lt m p)

Fin-Nat-lt-rightInv : ∀ m → (p : m ℕ.< n) → Fin-to-Nat-lt {n = n} (Fin-from-Nat-lt m p) ≡ (m , p)
Fin-Nat-lt-rightInv {n = suc n} zero p = refl
Fin-Nat-lt-rightInv {n = suc n} (suc m) p = cong (suc-natfin {n = n}) (Fin-Nat-lt-rightInv {n = n} m p)

Fin-Nat-lt-leftInv : (x : Fin n) → uncurry Fin-from-Nat-lt (Fin-to-Nat-lt x) ≡ x
Fin-Nat-lt-leftInv {n = suc n} f0 = refl
Fin-Nat-lt-leftInv {n = suc n} (fs x) = cong fs (Fin-Nat-lt-leftInv x)

Fin-Nat-lt : Fin n ⇔ Σ[ m ⦂ ℕ ] × (m ℕ.< n)
Fin-Nat-lt .fun = Fin-to-Nat-lt
Fin-Nat-lt .inv = uncurry Fin-from-Nat-lt
Fin-Nat-lt .rightInv = uncurry Fin-Nat-lt-rightInv
Fin-Nat-lt .leftInv = Fin-Nat-lt-leftInv

FinToℕ : Fin n → ℕ
FinToℕ {n = suc n} f0     = zero
FinToℕ {n = suc n} (fs x)  = suc (FinToℕ x)

FinToℕ-injective : ∀ {k} {m n : Fin k} → FinToℕ m ≡ FinToℕ n → m ≡ n
FinToℕ-injective {suc k} {f0}  {f0}  _ = refl
FinToℕ-injective {suc k} {f0}  {fs x} p = ⊥-elim (ℕ.znots p)
FinToℕ-injective {suc k} {fs m} {f0}  p = ⊥-elim (ℕ.snotz p)
FinToℕ-injective {suc k} {fs m} {fs x} p = cong fs (FinToℕ-injective (ℕ.injSuc p))

pred : Fin (suc n) → Fin (suc (ℕ.pred n))
pred f0 = f0
pred {n = suc n} (fs m) = m

discreteFin : ∀ {k} → Discrete (Fin k)
discreteFin {k = suc _} f0 f0 = yes refl
discreteFin {k = suc _} f0 (fs fk) = no (ℕ.znots ∘ cong FinToℕ)
discreteFin {k = suc _} (fs fj) f0 = no (ℕ.snotz ∘ cong FinToℕ)
discreteFin {k = suc _} (fs fj) (fs fk) =
  iff-dec (cong fs iff cong (λ { f0 → fk ; (fs x) → x})) (discreteFin fj fk)

isSetFin : isSet (Fin n)
isSetFin = Discrete→isSet discreteFin

FinFromℕ : (n m : ℕ) → T (n <ᵇ m) → Fin m
FinFromℕ zero (suc m) p = f0
FinFromℕ (suc n) (suc m) p = fs (FinFromℕ n m p)


{-# OPTIONS --copatterns #-}
module Tree where

data Bool : Set where
  true false : Bool

record Tree (A : Set) : Set where
  field
    label : A
    child : Bool -> Tree A
open Tree

-- corecursive function defined by copattern matching
alternate : {A : Set}(a b : A) -> Tree A
-- deep copatterns:
label (child (alternate a b) false)       = b
child (child (alternate a b) false) true  = alternate a b
child (child (alternate a b) false) false = alternate a b
-- shallow copatterns
child {A = A} (alternate a b) true = alternate b a
label {A = A} (alternate a b)      = a

{- Delivers an infinite tree

                 a
            b        b
          a   a    a   a
         b b b b  b b b b
               ...
-}

infixr 5 _::_

data List (A : Set) : Set where
  []   : List A
  _::_ : A -> List A -> List A

collect : List Bool -> {A : Set} -> Tree A -> List A
collect []       t = []
collect (b :: l) t = label t :: collect l (child t b)

test : List Bool
test = collect (true :: true :: true :: []) (alternate true false)
-- should give true :: false : true :: []


open import FRP.LTL.Time using ( Time ; _≤_ ; _<_ )

module FRP.LTL.RSet.Core where

-- Reactive types

RSet : Set₁
RSet = Time → Set

⟨_⟩ : Set → RSet
⟨ A ⟩ t = A

⟦_⟧ : RSet → Set
⟦ A ⟧ = ∀ {t} → (A t)

-- Reactive sets over an interval

_[_,_] : RSet → Time → Time → Set
A [ s , u ] = ∀ {t} → s ≤ t → t ≤ u → A t

_[_,_⟩ : RSet → Time → Time → Set
A [ s , u ⟩ = ∀ {t} → s ≤ t → t < u → A t


module #3 where

open import Relation.Binary.PropositionalEquality

{-
  Exercise 2.3 Give a fourth, different, proof of Lemma 2.1.2, and prove that it is equal to the others.
-}

based-ind₌ : ∀ {i} {A : Set i}{a : A} → (C : (x : A) → (a ≡ x) → Set i) → C a refl → {x : A} → (p : a ≡ x) → C x p
based-ind₌ C c p rewrite p = c

-- Uses based path induction
composite''' : ∀ {i} {A : Set i}{x y z : A} → (x ≡ y) → (y ≡ z) → (x ≡ z)
composite''' {i} {A} {x}{y}{_} p = based-ind₌ D d where
  D : (z : A) → (q : y ≡ z) → Set i
  D z _ = x ≡ z

  d : D _ refl
  d = p