open import Level using (Level; suc; zero; _⊔_)
open import Algebra.Structures
open import Algebra.FunctionProperties as FunctionProperties using (Op₁; Op₂)
open import Relation.Binary

-- Definition of an ordered monoid, which adds the law that ∙ must
-- preserve the partial order ≤ (or, equivalently, that an ordering x
-- ≤ y must allow for the substitution of y for x in a more complex
-- ordering) to an existing monoid and partial order.
module Algebra.OrderedMonoid where

record IsOrderedMonoid {a ℓ₁ ℓ₂} {A : Set a} (≈ : Rel A ℓ₁) (≤ : Rel A ℓ₂) (∙ : Op₂ A) (ε : A) : Set (a ⊔ ℓ₁ ⊔ ℓ₂) where
  field
    isMonoid       : IsMonoid ≈ ∙ ε
    isPartialOrder : IsPartialOrder ≈ ≤
    compatibility  : ∙ Preserves₂ ≤ ⟶ ≤ ⟶ ≤

  open IsMonoid isMonoid public
       hiding (isEquivalence)
  open IsPartialOrder isPartialOrder public
       renaming (refl to ≤-refl; trans to ≤-trans; reflexive to ≤-reflexive)

record OrderedMonoid c ℓ₁ ℓ₂ : Set (suc (c ⊔ ℓ₁ ⊔ ℓ₂)) where
  infixl 7 _∙_
  infix  4 _≈_
  infix  4 _≤_
  field
    Carrier         : Set c
    _≈_             : Rel Carrier ℓ₁
    _≤_             : Rel Carrier ℓ₂
    _∙_             : Op₂ Carrier
    ε               : Carrier
    isOrderedMonoid : IsOrderedMonoid _≈_ _≤_ _∙_ ε

  open IsOrderedMonoid isOrderedMonoid public

  substitutivity : ∀ {x y z w} → x ≤ y → z ∙ x ∙ w ≤ z ∙ y ∙ w
  substitutivity x≤y = compatibility (compatibility ≤-refl x≤y) ≤-refl


module Bool where

import Logic
open Logic

data Bool : Set where
  false : Bool
  true  : Bool

infixr 5 _&&_

_&&_ : Bool -> Bool -> Bool
true  && x = x
false && _ = false

not : Bool -> Bool
not true  = false
not false = true

IsTrue : Bool -> Set
IsTrue true  = True
IsTrue false = False

IsFalse : Bool -> Set
IsFalse x = IsTrue (not x)

module BoolEq where

  _==_ : Bool -> Bool -> Bool
  true  == x = x
  false == x = not x

  subst : {x y : Bool}(P : Bool -> Set) -> IsTrue (x == y) -> P x -> P y
  subst {true}{true}   _ _ px = px
  subst {false}{false} _ _ px = px
  subst {true}{false}  _ () _
  subst {false}{true}  _ () _

  isTrue== : {x : Bool} -> IsTrue x -> IsTrue (x == true)
  isTrue== {true} _ = tt
  isTrue== {false} ()

infix 1 if_then_else_

if_then_else_ : {A : Set} -> Bool -> A -> A -> A
if true  then x else y = x
if false then x else y = y

open BoolEq

if'_then_else_ : {A : Set} -> (x : Bool) -> (IsTrue x -> A) -> (IsFalse x -> A) -> A
if' true  then f else g = f tt
if' false then f else  g = g tt

isTrue&&₁ : {x y : Bool} -> IsTrue (x && y) -> IsTrue x
isTrue&&₁ {true} _ = tt
isTrue&&₁ {false} ()

isTrue&&₂ : {x y : Bool} -> IsTrue (x && y) -> IsTrue y
isTrue&&₂ {true} p = p
isTrue&&₂ {false} ()


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Data.Vec.NAry where

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

open import Cubical.Data.Nat
open import Cubical.Data.Vec.Base

private
  variable
    ℓ ℓ' : Level
    A : Type ℓ
    B : Type ℓ'

nAryLevel : Level → Level → ℕ → Level
nAryLevel ℓ₁ ℓ₂ zero    = ℓ₂
nAryLevel ℓ₁ ℓ₂ (suc n) = ℓ-max ℓ₁ (nAryLevel ℓ₁ ℓ₂ n)

nAryOp : (n : ℕ) → Type ℓ → Type ℓ' → Type (nAryLevel ℓ ℓ' n)
nAryOp zero A B    = B
nAryOp (suc n) A B = A → nAryOp n A B

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

curryⁿ : ∀ {n} → (Vec A n → B) → nAryOp n A B
curryⁿ {n = zero}  f   = f []
curryⁿ {n = suc n} f x = curryⁿ (λ xs → f (x ∷ xs))

$ⁿ-curryⁿ : ∀ {n} (f : Vec A n → B) → _$ⁿ_ (curryⁿ f) ≡ f
$ⁿ-curryⁿ {n = zero} f  = funExt λ { [] → refl }
$ⁿ-curryⁿ {n = suc n} f = funExt λ { (x ∷ xs) i → $ⁿ-curryⁿ {n = n} (λ ys → f (x ∷ ys)) i xs}

curryⁿ-$ⁿ : ∀ {n} (f : nAryOp {ℓ = ℓ} {ℓ' = ℓ'} n A B) → curryⁿ {A = A} {B = B} (_$ⁿ_ f) ≡ f
curryⁿ-$ⁿ {n = zero} f  = refl
curryⁿ-$ⁿ {n = suc n} f = funExt λ x → curryⁿ-$ⁿ {n = n} (f x)

nAryOp≃VecFun : ∀ {n} → nAryOp n A B ≃ (Vec A n → B)
nAryOp≃VecFun {n = n} = isoToEquiv f
  where
  f : Iso (nAryOp n A B) (Vec A n → B)
  Iso.fun f      = _$ⁿ_
  Iso.inv f      = curryⁿ
  Iso.rightInv f = $ⁿ-curryⁿ
  Iso.leftInv f  = curryⁿ-$ⁿ {n = n}

-- In order to apply ua to nAryOp≃VecFun we probably need to change
-- the base-case of nAryLevel to "ℓ-max ℓ₁ ℓ₂". This will make it
-- necessary to add lots of Lifts in zero cases so it's not done yet,
-- but if the Path is ever needed then it might be worth to do.


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

open import Level

-- The main definitions are in:
open import Categories.Category.Core public

private
  variable
    o ℓ e : Level

-- Convenience functions for working over mupliple categories at once:
-- C [ x , y ] (for x y objects of C) - Hom_C(x , y)
-- C [ f ≈ g ] (for f g arrows of C)  - that f and g are equivalent arrows
-- C [ f ∘ g ] (for f g composables arrows of C) - composition in C
infix 10  _[_,_] _[_≈_] _[_∘_]

_[_,_] : (C : Category o ℓ e) → (X : Category.Obj C) → (Y : Category.Obj C) → Set ℓ
_[_,_] = Category._⇒_

_[_≈_] : (C : Category o ℓ e) → ∀ {X Y} (f g : C [ X , Y ]) → Set e
_[_≈_] = Category._≈_

_[_∘_] : (C : Category o ℓ e) → ∀ {X Y Z} (f : C [ Y , Z ]) → (g : C [ X , Y ]) → C [ X , Z ]
_[_∘_] = Category._∘_

module Definitions (𝓒 : Category o ℓ e) where
  open Category 𝓒

  CommutativeSquare : {A B C D : Obj} → (f : A ⇒ B) (g : A ⇒ C) (h : B ⇒ D) (i : C ⇒ D) → Set _
  CommutativeSquare f g h i = h ∘ f ≈ i ∘ g

-- Combinators for commutative diagram
-- The idea is to use the combinators to write commutations in a more readable way.
-- It starts with [_⇒_]⟨_≈_⟩, and within the third and fourth places, use _⇒⟨_⟩_ to
-- connect morphisms with the intermediate object specified.
module Commutation (𝓒 : Category o ℓ e) where
  open Category 𝓒

  infix 1 [_⇒_]⟨_≈_⟩
  [_⇒_]⟨_≈_⟩ : ∀ (A B : Obj) → A ⇒ B → A ⇒ B → Set _
  [ A ⇒ B ]⟨ f ≈ g ⟩ = f ≈ g

  infixl 2 connect
  connect : ∀ {A C : Obj} (B : Obj) → A ⇒ B → B ⇒ C → A ⇒ C
  connect B f g = g ∘ f

  syntax connect B f g = f ⇒⟨ B ⟩ g


-- Quicksort

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

module Algorithms.List.Sort.Quick where

-- agda-stdlib
open import Level
open import Data.List
import      Data.List.Properties as Listₚ
open import Data.Product
import      Data.Nat as ℕ
open import Data.Nat.Induction as Ind
open import Relation.Binary as B
open import Relation.Binary.PropositionalEquality as P using (_≡_)
open import Relation.Unary as U
import      Relation.Unary.Properties as Uₚ
open import Function.Base
open import Induction.WellFounded

private
  variable
    a p r : Level

module _ {A : Set a} {P : U.Pred A p} (P? : U.Decidable P) where
  partition₁-defn : ∀ xs → proj₁ (partition P? xs) ≡ filter P? xs
  partition₁-defn xs = P.cong proj₁ (Listₚ.partition-defn P? xs)

  partition₂-defn : ∀ xs → proj₂ (partition P? xs) ≡ filter (Uₚ.∁? P?) xs
  partition₂-defn xs = P.cong proj₂ (Listₚ.partition-defn P? xs)

  length-partition₁ : ∀ xs → length (proj₁ (partition P? xs)) ℕ.≤ length xs
  length-partition₁ xs =
    P.subst (ℕ._≤ length xs)
            (P.sym $ P.cong length $ partition₁-defn xs)
            (Listₚ.length-filter P? xs)

  length-partition₂ : ∀ xs → length (proj₂ (partition P? xs)) ℕ.≤ length xs
  length-partition₂ xs =
    P.subst (ℕ._≤ length xs)
            (P.sym $ P.cong length $ partition₂-defn xs)
            (Listₚ.length-filter (Uₚ.∁? P?) xs)

module Quicksort {A : Set a} {_≤_ : Rel A r} (_≤?_ : B.Decidable _≤_) where
  split : A → List A → List A × List A
  split x xs = partition (λ y → y ≤? x) xs

  _L<_ : Rel (List A) _
  _L<_ = ℕ._<_ on length

  sort-acc : ∀ xs → Acc _L<_ xs → List A
  sort-acc []       _        = []
  sort-acc (x ∷ xs) (acc rs) =
    sort-acc ys (rs _ (ℕ.s≤s $ length-partition₁ (_≤? x) xs)) ++
    [ x ] ++
    sort-acc zs (rs _ (ℕ.s≤s $ length-partition₂ (_≤? x) xs))
    where
    splitted = split x xs
    ys = proj₁ splitted
    zs = proj₂ splitted

  L<-wf : WellFounded _L<_
  L<-wf = InverseImage.wellFounded length Ind.<-wellFounded

  -- Quicksort
  sort : List A → List A
  sort xs = sort-acc xs (L<-wf xs)


module FunctionsInIndices where

open import Prelude
open import Eq

data Tree (a : Set) : ℕ -> Set where
  leaf : a -> Tree a 1
  node : forall n₁ n₂ -> Tree a n₁ -> Tree a n₂ -> Tree a (n₁ + n₂)

-- This does not work:

-- leftmost : forall {a} n -> Tree a (suc n) -> a
-- leftmost .0         (leaf x)                     = x
-- leftmost .n₂        (node zero     (suc n₂) l r) = leftmost l
-- leftmost .(n₁ + n₂) (node (suc n₁) n₂       l r) = leftmost l

module Workaround1 where

  private

    T : Set -> ℕ -> Set
    T a zero    = ⊤
    T a (suc n) = a

    leftmost' : forall {a n} -> Tree a n -> T a n
    leftmost' (leaf x)                     = x
    leftmost' (node zero     zero     l r) = tt
    leftmost' (node zero     (suc n₂) l r) = leftmost' r
    leftmost' (node (suc n₁) n₂       l r) = leftmost' l

  leftmost : forall {a n} -> Tree a (suc n) -> a
  leftmost = leftmost'

module Workaround2 where

  private

    leftmost' : forall {a n m} -> Tree a m -> m ≡ suc n -> a
    leftmost' (leaf x)                     _  = x
    leftmost' (node zero     (suc n₂) l r) _  = leftmost' r refl
    leftmost' (node (suc n₁) n₂       l r) _  = leftmost' l refl

  leftmost : forall {a n} -> Tree a (suc n) -> a
  leftmost t = leftmost' t refl


module irreflexive where

open import Data.Nat using (ℕ; zero; suc)

open import Negation using (¬_)

infix 4 _<_
data _<_ : ℕ → ℕ → Set where
  z<s : ∀ {n : ℕ}
      ------------
    → zero < suc n

  s<s : ∀ {m n : ℕ}
    → m < n
      -------------
    → suc m < suc n

-- n が非反射律 ∀ n ∈ ℕ, ¬(n < n) を満たすことの証明
<-irreflexive : ∀ (n : ℕ) → ¬ (n < n)
<-irreflexive zero ()
<-irreflexive (suc n) (s<s n<n) = <-irreflexive n n<n


open import Data.Nat using ( zero ; suc ) renaming ( ℕ to ♭ℕ ; _+_ to add )
open import Function using () renaming ( _∘′_ to _∘_ )
open import Relation.Binary.PropositionalEquality using ( _≡_ ; refl ; sym ; trans ; cong ; cong₂ )

open import AssocFree.Util using ( ≡-relevant )

module AssocFree.DNat where

open Relation.Binary.PropositionalEquality.≡-Reasoning using ( begin_ ; _≡⟨_⟩_ ; _∎ )

infixr 5 _,_
infixr 5 _+_

_+♭_ = add

add-unit : ∀ n → (add n 0) ≡ n
add-unit zero    = refl
add-unit (suc n) = cong suc (add-unit n)

add-assoc : ∀ m n → (add (add m n) ≡ ((add m) ∘ (add n)))
add-assoc zero    n = refl
add-assoc (suc m) n = cong (_∘_ suc) (add-assoc m n)

-- "Difference nats" are isomorphic to ℕ but have _+_ associative up
-- to beta-reduction, not just up to _≡_.

record ℕ : Set where
  constructor _,_
  field
    fun : ♭ℕ → ♭ℕ
    .fun✓ : fun ≡ add (fun 0)

open ℕ public

-- Convert ℕ to ♭ℕ and back

♯ : ♭ℕ → ℕ
♯ n = (add n , cong add (sym (add-unit n)))

♭ : ℕ → ♭ℕ
♭ (f , f✓) = f 0

-- Constants

♯0 = ♯ 0
♯1 = ♯ 1

-- Addition

_+_ : ℕ → ℕ → ℕ
(f , f✓) + (g , g✓) = ((f ∘ g) , f∘g✓) where
  .f∘g✓ : (f ∘ g) ≡ add (f (g 0))
  f∘g✓ = begin
      f ∘ g
    ≡⟨ cong₂ _∘_ f✓ g✓ ⟩
      add (f 0) ∘ add (g 0)
    ≡⟨ sym (add-assoc (f 0) (g 0)) ⟩
      add (add (f 0) (g 0))
    ≡⟨ cong (λ X → add (X (g 0))) (sym f✓) ⟩
      add (f (g 0))
    ∎

--Isomorphism which respects +

inject : ∀ m n → (fun m ≡ fun n) → (m ≡ n)
inject (f , f✓) (.f , g✓) refl = refl

iso : ∀ n → ♯ (♭ n) ≡ n
iso n = inject (♯ (♭ n)) n (sym (≡-relevant (fun✓ n)))

iso⁻¹ : ∀ n → ♭ (♯ n) ≡ n
iso⁻¹ = add-unit

iso-resp-+ : ∀ m n → ♭ (m + n) ≡ (♭ m +♭ ♭ n)
iso-resp-+ (f , f✓) (g , g✓) = cong (λ X → X (g 0)) (≡-relevant f✓)

-- Addition forms a monoid on the nose

+-assoc : ∀ l m n → (((l + m) + n) ≡ (l + (m + n)))
+-assoc l m n = refl

+-unit₁ : ∀ n → ((♯0 + n) ≡ n)
+-unit₁ n = refl

+-unit₂ : ∀ n → ((n + ♯0) ≡ n)
+-unit₂ n = refl


{-# OPTIONS --safe #-}
module RevRev where

open import Relation.Binary.PropositionalEquality
open import Data.List
open import Data.List.Properties

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

lemma : ∀ {ℓ} {A : Set ℓ} (a b : List A) → rev (a ++ b) ≡ rev b ++ rev a
lemma [] b rewrite ++-identityʳ (rev b) = refl
lemma (x ∷ a) b rewrite lemma a b | ++-assoc (rev b) (rev a) (x ∷ []) = refl

revrevid : ∀ {ℓ} {A : Set ℓ} (a : List A) → rev (rev a) ≡ a
revrevid [] = refl
revrevid (x ∷ a) rewrite lemma (rev a) (x ∷ []) | revrevid a = refl


module #2 where

open import Relation.Binary.PropositionalEquality
open import #1

{-
Exercise 2.2. Show that the three equalities of proofs constructed in the previous exercise form a
commutative triangle. In other words, if the three definitions of concatenation are denoted by
(p ∘ q), (p ∘ q), and (p ∘ q), then the concatenated equality

         (p ∘ q) = (p ∘ q) = (p ∘ q)

is equal to the equality (p ∘ q) = (p ∘ q).
-}

composite-commutative-triangle : ∀ {i} {A : Set i}{x y z : A} → (p : x ≡ y) (q : y ≡ z) →
    composite (composite=composite' p q) (composite'=composite'' p q) ≡ composite=composite'' p q
composite-commutative-triangle refl refl = refl


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

  _+_ : ℕ → ℕ → ℕ
  zero + n = n
  (suc n) + m = suc (n + m)

  -- if_then_else_ : ∀ { a } → Bool → a → a → a

  data _even : ℕ → Set where
    ZERO : zero even
    STEP : ∀ {x} → x even → suc (suc x) even

  proof₁ : suc (suc (suc (suc zero))) even
  proof₁ = STEP (STEP ZERO)

  proof₂′ : (A : Set) → A → A
  proof₂′ _ x = x

  proof₂ : ℕ → ℕ
  proof₂ = proof₂′ ℕ


open import Sec4

data ℕ : Set where
  Z : ℕ
  S : ℕ → ℕ

-- Now ≥ relation
_≥_ : ∀ (m : ℕ) → ∀ (n : ℕ) → Prop
Z ≥ Z = ⊤
S m ≥ Z = ⊤
Z ≥ S n = ⊥
S m ≥ S n = m ≥ n

-- Example proof
-- eqqr : ((S (S (S Z))) ≥ (S (S Z))) → ((S (S Z)) ≥ (S (S (S Z))))
-- eqqr ()

-- -- Now is ≥ equivalence relation?
-- relfexivity
reflexivity : ∀ (m : ℕ) → (m ≥ m)
reflexivity  Z = ⋆
reflexivity  (S m) = reflexivity m

-- -- -- Now symmetry
-- sym : ∀ (m : ℕ) → ∀ (n : ℕ) → m ≥ n → n ≥ m
-- sym Z Z p = ⋆
-- sym Z (S n) p = ⋆
-- sym (S m) Z ⋆ = {!!}
-- sym (S m) (S n) p = sym m n p

-- -- -- Now transitivity
trans'' : ∀ (m : ℕ) → ∀ (n : ℕ) → ∀ (p : ℕ) → m ≥ n → n ≥ p → m ≥ p
trans'' Z Z p p0 p1 = p1
trans'' Z (S n) p () p1
trans'' (S m) n Z p0 p1 = ⋆
trans'' (S m) Z (S p) p0 ()
trans'' (S m) (S n) (S p) p0 p1 = trans'' m n p p0 p1

-- Given the above three are satisfied, we know that it is an
-- equivalence relation!

-- Now let us try strictly greater than (>)

-- Definition of >
_>_ : ∀ (m : ℕ) → ∀ (n : ℕ) → Prop
Z > Z =  ⊥
Z > S n = ⊥
S m > Z = ⊤
S m > S n = m > n

-- Now let us see of > is an equivalence relation

-- reflixvity of > not possible!
-- refl-> : ∀ (m : ℕ) → m > m
-- refl-> Z = {!!}
-- refl-> (S m) = refl-> m

-- equality
_==_ : ∀ (m : ℕ) → ∀ (n : ℕ) → Prop
Z == Z =  ⊤
Z == S n = ⊥
S m == Z = ⊥
S m == S n = m == n

-- Is equiality an equivalence relation?

-- reflexivity
refl-≡ : ∀ (m : ℕ) → m == m
refl-≡ Z = ⋆
refl-≡ (S m) = refl-≡ m

-- Symmetry
sym-≡ : ∀ (m : ℕ) → ∀ (n : ℕ) → m == n → n == m
sym-≡ Z Z h = ⋆
sym-≡ Z (S n) ()
sym-≡ (S m) Z ()
sym-≡ (S m) (S n) h = sym-≡ m n h

-- Transitivity
trans-≡ : ∀ (m n p : ℕ) → m == n → n == p → m == p
trans-≡ Z n Z h0 h1 = ⋆
trans-≡ Z Z (S p) h0 h1 = h1
trans-≡ Z (S n) (S p) () h1
trans-≡ (S m) Z Z () h1
trans-≡ (S m) (S n) Z h0 ()
trans-≡ (S m) Z (S p) () h1
trans-≡ (S m) (S n) (S p) h0 h1 = trans-≡ m n p h0 h1

-- Homework ≤ on natural numbers

-- Addition of natural numbers
_+_ : ∀ (m n : ℕ) → ℕ
Z + n = n
S m + n = S (m + n)

-- Use equality, 2 + 3 == 3 + 2
eqq : ((S (S Z)) + (S ( S ( S Z)))) == ((S ( S ( S Z))) + (S (S Z)))
eqq = ⋆

infix 4 _≡_
data _≡_ {a} {A : Set a} (x : A) : A → Set a where
  refl : x ≡ x
{-# BUILTIN EQUALITY _≡_  #-}
{-# BUILTIN REFL     refl #-}

eqq2 : ((S (S Z)) + (S ( S ( S Z)))) ≡ ((S ( S ( S Z))) + (S (S Z)))
eqq2 = refl

cong : ∀ (n m : ℕ) → n ≡ m → S n ≡ S m
cong n .n refl = refl

-lemma-+ : ∀ (n : ℕ) → n ≡ (n + Z)
-lemma-+ Z = refl
-lemma-+ (S n) with -lemma-+ n
-lemma-+ (S n) | h = cong n (n + Z) h

lem2 : ∀ (m n : ℕ) → (m + S n) ≡ S (m + n)
lem2 Z n = refl
lem2 (S m) n = cong (m + S n) (S (m + n)) (lem2 m n)

-- Now prove commutativity of addition
commute-+ : ∀ (m n : ℕ) → (m + n) ≡ (n + m)
commute-+ Z n = -lemma-+ n
commute-+ (S m) n with (n + S m) | (lem2 n m)
commute-+ (S m) n | .(S (n + m)) | refl = cong (m + n) (n + m) (commute-+ m n)

_<_ : ∀ (m n : ℕ) → Prop
Z < Z = ⊥
Z < S n = ⊥
S m < Z = ⊤
S m < S n = m < n

-- refl-< : ∀ (m : ℕ) → m < m
-- refl-< Z = !!
-- refl-< (S m) = !!

-- Define booleans
data 𝔹 : Set where
 True : 𝔹
 False : 𝔹

-- Define &&
_&&_ : ∀ (A B : 𝔹) → 𝔹
True && True = True
True && False = False
False && B = False

-- Define ||
_||_ : ∀ (A B : 𝔹) → 𝔹
True || B = True
False || True = True
False || False = False

-- Prove equivalence of two hardware functions g and f
g : ∀ (A B C : 𝔹) → 𝔹
g A B C = B && (A || C)

ff : ∀ (A B C : 𝔹) → 𝔹
ff A B C = (A && B) || ((B && C) && (B || C))

-- Equality of booleans
_==̰_ : ∀ (A B : 𝔹) → Prop
True ==̰ True = ⊤
True ==̰ False = ⊥
False ==̰ True = ⊥
False ==̰ False = ⊤

-- Now prove that for any input A B C, g ≡ ff
g≃ff : ∀ (A B C : 𝔹) → (g A B C) ==̰ (ff A B C)
g≃ff True True True = ⋆
g≃ff True True False = ⋆
g≃ff True False C = ⋆
g≃ff False True True = ⋆
g≃ff False True False = ⋆
g≃ff False False C = ⋆

_≤_ : ∀ (m n : ℕ) → Prop
Z ≤ n = ⊤
S m ≤ Z = ⊥
S m ≤ S n = m ≤ n

-- Symmetry on ≤
-- sym-≤ : ∀ (m n : ℕ) → (m ≤ n) → (n ≤ m)
-- sym-≤ Z Z ⋆ = ⋆
-- sym-≤ Z (S n) ⋆ = {!!}
-- sym-≤ (S m) Z ()
-- sym-≤ (S m) (S n) p = sym-≤ m n p

-- ≠
_≠_ : ∀ (m n : ℕ) → Prop
Z ≠ Z = ⊥
Z ≠ S n = ⊤
S m ≠ Z = ⊤
S m ≠ S n = m ≠ n

-- -- Is ≠ an equivalence relation?
-- ≠-refl
-- ≠-relf : ∀ (m : ℕ) → (m ≠ m)
-- ≠-relf Z = {!!}
-- ≠-relf (S m) = ≠-relf m

-- -- Symmetry
≠-sym : ∀ (m n : ℕ) → (m ≠ n) → (n ≠ m)
≠-sym Z Z ()
≠-sym Z (S n) p = ⋆
≠-sym (S m) Z p = ⋆
≠-sym (S m) (S n) p = ≠-sym m n p

-- -- Transitivity
-- ≠-trans : ∀ (m n p : ℕ) → (m ≠ n) → (n ≠ p) → (m ≠ p)
-- ≠-trans Z Z Z h0 ()
-- ≠-trans Z (S n) Z ⋆ ⋆ = {!!}
-- ≠-trans Z n (S p) h0 h1 = ⋆
-- ≠-trans (S m) n Z h0 h1 = ⋆
-- ≠-trans (S m) Z (S p) ⋆ ⋆ = {!!}
-- ≠-trans (S m) (S n) (S p) h0 h1 = ≠-trans m n p h0 h1

de1 : {A B : Prop} → ((¬ A) ∨ (¬ B)) ⇒ ¬ (A ∧ B)
de1 = impl (λ x → neg (impl (λ x₁ →
                               let y = elim1-∧ x₁
                                   z = elim2-∧ x₁
                               in
                               elim-∨ x (λ x₃ → elim-neg y x₃) (λ x₂ → elim-neg z x₂))))

de2 : {A B : Prop} → ((¬ A) ∧ (¬ B)) ⇒ (¬ (A ∨ B))
de2 = impl (λ x → neg (impl (λ x₁ → elim-∨ x₁ (λ x₂ → elim-neg x₂ (elim1-∧ x))
                                             (λ x₂ → elim-neg x₂ (elim2-∧ x)))))

-- Multiplication of naturals
_*_ : ∀ (m n : ℕ) → ℕ
Z * n = Z
S m * n = n + (m * n)

-- Square relation on two naturals
_r²_ : ∀ (m n : ℕ) → Prop
m r² n = (m * m) ≡ (n * n)

-- reflexivity of r²
refl-r² : ∀ (m : ℕ) → (m r² m)
refl-r² Z = refl
refl-r² (S m) = refl

sym-r² : ∀ (m n : ℕ) → (m r² n) → (n r² m)
sym-r² Z Z p = refl
sym-r² Z (S n) ()
sym-r² (S m) Z ()
sym-r² (S m) (S n) p rewrite p = refl

trans-r² : ∀ (m n p : ℕ) → (m r² n) → (n r² p) → (m r² p)
trans-r² Z n Z h0 h1 = refl
trans-r² Z Z (S p) refl ()
trans-r² Z (S n) (S p) () h1
trans-r² (S m) Z Z () h1
trans-r² (S m) (S n) Z h0 ()
trans-r² (S m) Z (S p) () h1
trans-r² (S m) (S n) (S p) h0 h1 rewrite h0
                                        | h1 = refl


module Data.Bin.Props where

  open import Data.Bin
  import Data.Nat
  import Data.Nat.Properties
  open Data.Nat using (ℕ)
  open import Data.List
  open import Relation.Binary.PropositionalEquality
  open import Function using (_⟨_⟩_)
  open import Algebra.Structures using (IsCommutativeMonoid; module IsCommutativeMonoid; module IsCommutativeSemiring)

  import Data.Bin.Addition

  bin-+-is-comm-monoid = Data.Bin.Addition.is-commutativeMonoid

  open import Data.Bin.Bijection using (fromℕ-bijection)

  import Algebra.Lifting
  module Lifting = Algebra.Lifting _ _ fromℕ-bijection

  open import Data.Bin.Multiplication

  bin-*-is-comm-monoid : IsCommutativeMonoid _≡_ _*_ ([] 1#)
  bin-*-is-comm-monoid = lift-isCommutativeMonoid 1 *-isCommutativeMonoid
   where
     open IsCommutativeSemiring Data.Nat.Properties.isCommutativeSemiring using(*-isCommutativeMonoid)
     open Lifting.WithOp₂ Data.Nat._*_ _*_ *-is-multiplication

  open IsCommutativeMonoid bin-*-is-comm-monoid using () renaming (comm to *-comm)

  *2-is-2* : ∀ x → x *2 ≡ (fromℕ 2) * x
  *2-is-2* 0# = refl
  *2-is-2* (bs 1#) = refl

  *-distrib : ∀ {a b c} → (a + b) * c ≡ a * c + b * c
  *-distrib {a} {b} {c} = Data.Bin.Multiplication.*-distribʳ a b c

  *2-distrib : ∀ a b → (a + b) *2 ≡ a *2 + b *2
  *2-distrib a b = *2-is-*2-bin (a + b) ⟨ trans ⟩ *-distrib {a} {b} {fromℕ 2} ⟨ trans ⟩ cong₂ _+_ (sym (*2-is-*2-bin a)) (sym (*2-is-*2-bin b))
   where
    *2-is-*2-bin : ∀ a → a *2 ≡ a * fromℕ 2
    *2-is-*2-bin a = *2-is-2* a ⟨ trans ⟩ *-comm (fromℕ 2) a

  open import Function
  open import Data.Empty
  1+≢0 : ∀ l → toℕ (l 1#) ≢ 0
  1+≢0 l eq = case Data.Bin.Bijection.toℕ-inj {l 1#} {0#} eq of (λ ())

  z<nzℕ : ∀ {n} → n ≢ 0 → Data.Nat._<_ 0 n
  z<nzℕ {Data.Bin.0b} neq = ⊥-elim (neq refl)
  z<nzℕ {Data.Bin.Bijection.1+ n} neq = Data.Nat.s≤s Data.Nat.z≤n

  z<nz : ∀ l → 0# < l 1#
  z<nz l = Data.Bin.less (z<nzℕ (1+≢0 l))


------------------------------------------------------------------------
-- The Agda standard library
--
-- Showing natural numbers
------------------------------------------------------------------------

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

module Data.Nat.Show where

open import Data.Char as Char using (Char)
open import Data.Digit using (showDigit; toDigits; toNatDigits)
open import Function using (_∘_; _$_)
open import Data.List.Base using (List; []; _∷_; map; reverse)
open import Data.Nat
open import Data.Product using (proj₁)
open import Data.String as String using (String)
open import Relation.Nullary.Decidable using (True)

------------------------------------------------------------------------
-- Conversion from unary representation to the representation by the
-- given base.

toDigitChar : (n : ℕ) → Char
toDigitChar n = Char.fromℕ (n + (Char.toℕ '0'))

toDecimalChars : ℕ → List Char
toDecimalChars = map toDigitChar ∘ toNatDigits 10

------------------------------------------------------------------------
-- Show

-- Time complexity is O(log₁₀(n))

show : ℕ → String
show = String.fromList ∘ toDecimalChars

-- Warning: when compiled the time complexity of `showInBase b n` is
-- O(n) instead of the expected O(log(n)).

showInBase : (base : ℕ)
             {base≥2 : True (2 ≤? base)}
             {base≤16 : True (base ≤? 16)} →
             ℕ → String
showInBase base {base≥2} {base≤16} n =
  String.fromList $
  map (showDigit {base≤16 = base≤16}) $
  reverse $
  proj₁ $ toDigits base {base≥2 = base≥2} n


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

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

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

open Category 𝒞
open HomReasoning

import Categories.Morphism as M
open M 𝒞
open import Categories.Morphism.Reasoning 𝒞

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

module _ (iso : Iso f g) where

  open Iso iso

  Iso-resp-≈ : f ≈ h → g ≈ i → Iso h i
  Iso-resp-≈ {h = h} {i = i} eq₁ eq₂ = record
    { isoˡ = begin
      i ∘ h ≈˘⟨ eq₂ ⟩∘⟨ eq₁ ⟩
      g ∘ f ≈⟨ isoˡ ⟩
      id    ∎
    ; isoʳ = begin
      h ∘ i ≈˘⟨ eq₁ ⟩∘⟨ eq₂ ⟩
      f ∘ g ≈⟨ isoʳ ⟩
      id    ∎
    }

  Iso-swap : Iso g f
  Iso-swap = record
    { isoˡ = isoʳ
    ; isoʳ = isoˡ
    }

  Iso⇒Mono : Mono f
  Iso⇒Mono h i eq = begin
    h           ≈⟨ introˡ isoˡ ⟩
    (g ∘ f) ∘ h ≈⟨ pullʳ eq ⟩
    g ∘ f ∘ i   ≈⟨ cancelˡ isoˡ ⟩
    i           ∎

  Iso⇒Epi : Epi f
  Iso⇒Epi h i eq = begin
    h           ≈⟨ introʳ isoʳ ⟩
    h ∘ f ∘ g   ≈⟨ pullˡ eq ⟩
    (i ∘ f) ∘ g ≈⟨ cancelʳ isoʳ ⟩
    i           ∎

Iso-∘ : Iso f g → Iso h i → Iso (h ∘ f) (g ∘ i)
Iso-∘ {f = f} {g = g} {h = h} {i = i} iso iso′ = record
  { isoˡ = begin
    (g ∘ i) ∘ h ∘ f ≈⟨ cancelInner (isoˡ iso′) ⟩
    g ∘ f           ≈⟨ isoˡ iso ⟩
    id              ∎
  ; isoʳ = begin
    (h ∘ f) ∘ g ∘ i ≈⟨ cancelInner (isoʳ iso) ⟩
    h ∘ i           ≈⟨ isoʳ iso′ ⟩
    id              ∎
  }
  where open Iso

Iso-≈ : f ≈ h → Iso f g → Iso h i → g ≈ i
Iso-≈ {f = f} {h = h} {g = g} {i = i} eq iso iso′ = begin
  g           ≈⟨ introˡ (isoˡ iso′) ⟩
  (i ∘ h) ∘ g ≈˘⟨ (refl ⟩∘⟨ eq) ⟩∘⟨refl ⟩
  (i ∘ f) ∘ g ≈⟨ cancelʳ (isoʳ iso) ⟩
  i           ∎
  where open Iso

module _ where
  open _≅_

  isos×≈⇒≈ : ∀ {f g : A ⇒ B} → h ≈ i → (iso₁ : A ≅ C) → (iso₂ : B ≅ D) →
               CommutativeSquare f (from iso₁) (from iso₂) h →
               CommutativeSquare g (from iso₁) (from iso₂) i →
               f ≈ g
  isos×≈⇒≈ {h = h} {i = i} {f = f} {g = g} eq iso₁ iso₂ sq₁ sq₂ = begin
    f ≈⟨ switch-fromtoˡ iso₂ sq₁ ⟩
    to iso₂ ∘ h ∘ from iso₁ ≈⟨ refl⟩∘⟨ (eq ⟩∘⟨refl ) ⟩
    to iso₂ ∘ i ∘ from iso₁ ≈˘⟨ switch-fromtoˡ iso₂ sq₂ ⟩
    g ∎


{-
  Finitely presented algebras.
  An R-algebra A is finitely presented, if there merely is an exact sequence
  of R-modules:

    (f₁,⋯,fₘ) → R[X₁,⋯,Xₙ] → A → 0

  (where f₁,⋯,fₘ ∈ R[X₁,⋯,Xₙ])
-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.CommAlgebra.FPAlgebra where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Powerset
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure

open import Cubical.Data.FinData
open import Cubical.Data.Nat
open import Cubical.Data.Vec
open import Cubical.Data.Sigma
open import Cubical.Data.Empty

open import Cubical.HITs.PropositionalTruncation

open import Cubical.Algebra.CommRing
open import Cubical.Algebra.CommRing.FGIdeal using (inclOfFGIdeal)
open import Cubical.Algebra.CommAlgebra
open import Cubical.Algebra.CommAlgebra.FreeCommAlgebra
  renaming (inducedHom to freeInducedHom)
open import Cubical.Algebra.CommAlgebra.QuotientAlgebra
  renaming (inducedHom to quotientInducedHom)
open import Cubical.Algebra.CommAlgebra.Ideal
open import Cubical.Algebra.CommAlgebra.FGIdeal
open import Cubical.Algebra.CommAlgebra.Instances.Initial
open import Cubical.Algebra.CommAlgebra.Instances.Unit
  renaming (UnitCommAlgebra to TerminalCAlg)
open import Cubical.Algebra.CommAlgebra.Kernel
open import Cubical.Algebra.Algebra.Properties
open import Cubical.Algebra.Algebra

private
  variable
    ℓ : Level

module _ {R : CommRing ℓ} where
  open Construction using (var)
  Polynomials : (n : ℕ) → CommAlgebra R ℓ
  Polynomials n = R [ Fin n ]

  evPoly : {n : ℕ} (A : CommAlgebra R ℓ) → ⟨ Polynomials n ⟩ → FinVec ⟨ A ⟩ n → ⟨ A ⟩
  evPoly A P values = fst (freeInducedHom A values) P

  evPolyPoly : {n : ℕ} (P : ⟨ Polynomials n ⟩) → evPoly (Polynomials n) P var ≡ P
  evPolyPoly {n = n} P = cong (λ u → fst u P) (inducedHomVar R (Fin n))

  evPolyHomomorphic : {n : ℕ} (A B : CommAlgebra R ℓ) (f : CommAlgebraHom A B)
                     → (P : ⟨ Polynomials n ⟩) → (values : FinVec ⟨ A ⟩ n)
                     → (fst f) (evPoly A P values) ≡ evPoly B P (fst f ∘ values)
  evPolyHomomorphic A B f P values =
    (fst f) (evPoly A P values)                         ≡⟨ refl ⟩
    (fst f) (fst (freeInducedHom A values) P)           ≡⟨ refl ⟩
    fst (f ∘a freeInducedHom A values) P                ≡⟨ cong (λ u → fst u P) (natIndHomR f values) ⟩
    fst (freeInducedHom B (fst f ∘ values)) P           ≡⟨ refl ⟩
    evPoly B P (fst f ∘ values) ∎
    where open AlgebraHoms

  module _ {m : ℕ} (n : ℕ) (relation : FinVec ⟨ Polynomials n ⟩ m) where
    open CommAlgebraStr using (0a)
    open Cubical.Algebra.Algebra.Properties.AlgebraHoms

    relationsIdeal = generatedIdeal (Polynomials n) relation

    abstract
      {-
        The following definitions are abstract because of type checking speed
        problems - complete unfolding of FPAlgebra is triggered otherwise.
        This also means, the where blocks contain more type declarations than usual.
      -}
      FPAlgebra : CommAlgebra R ℓ
      FPAlgebra = Polynomials n / relationsIdeal

      modRelations : CommAlgebraHom (Polynomials n) (Polynomials n / relationsIdeal)
      modRelations = quotientMap (Polynomials n) relationsIdeal

      generator : (i : Fin n) → ⟨ FPAlgebra ⟩
      generator = fst modRelations ∘ var

      relationsHold : (i : Fin m) → evPoly FPAlgebra (relation i) generator ≡ 0a (snd FPAlgebra)
      relationsHold i =
        evPoly FPAlgebra (relation i) generator
        ≡⟨ sym (evPolyHomomorphic (Polynomials n) FPAlgebra modRelations (relation i) var) ⟩
        fst modRelations (evPoly (Polynomials n) (relation i) var)
        ≡⟨ cong (λ u → fst modRelations u) (evPolyPoly (relation i)) ⟩
        fst modRelations (relation i)
        ≡⟨ isZeroFromIdeal {R = R}
                           {A = (Polynomials n)}
                           {I = relationsIdeal}
                           (relation i)
                           (incInIdeal (Polynomials n) relation i ) ⟩
        0a (snd FPAlgebra) ∎

      inducedHom :
        (A : CommAlgebra R ℓ)
        (values : FinVec ⟨ A ⟩ n)
        (relationsHold : (i : Fin m) → evPoly A (relation i) values ≡ 0a (snd A))
        → CommAlgebraHom FPAlgebra A
      inducedHom A values relationsHold =
        quotientInducedHom
          (Polynomials n)
          relationsIdeal
          A
          freeHom
          isInKernel
        where
          freeHom : CommAlgebraHom (Polynomials n) A
          freeHom = freeInducedHom A values
          isInKernel :   fst (generatedIdeal (Polynomials n) relation)
                       ⊆ fst (kernel (Polynomials n) A freeHom)
          isInKernel = inclOfFGIdeal
                         (CommAlgebra→CommRing (Polynomials n))
                         relation
                         (kernel (Polynomials n) A freeHom)
                         relationsHold

      inducedHomOnGenerators :
        (A : CommAlgebra R ℓ)
        (values : FinVec ⟨ A ⟩ n)
        (relationsHold : (i : Fin m) → evPoly A (relation i) values ≡ 0a (snd A))
        (i : Fin n)
        → fst (inducedHom A values relationsHold) (generator i) ≡ values i
      inducedHomOnGenerators _ _ _ _ = refl

      unique :
             {A : CommAlgebra R ℓ}
             (values : FinVec ⟨ A ⟩ n)
             (relationsHold : (i : Fin m) → evPoly A (relation i) values ≡ 0a (snd A))
             (f : CommAlgebraHom FPAlgebra A)
             → ((i : Fin n) → fst f (generator i) ≡ values i)
             → inducedHom A values relationsHold ≡ f
      unique {A = A} values relationsHold f hasCorrectValues =
        injectivePrecomp
          (Polynomials n)
          relationsIdeal
          A
          (inducedHom A values relationsHold)
          f
          (sym (
           f'     ≡⟨ sym (inv f') ⟩
           freeInducedHom A (evaluateAt A f')    ≡⟨ cong (freeInducedHom A) (funExt hasCorrectValues) ⟩
           freeInducedHom A values               ≡⟨ cong (freeInducedHom A) refl ⟩
           freeInducedHom A (evaluateAt A iHom') ≡⟨ inv iHom' ⟩
           iHom' ∎))
        where
          {-
                     Poly n
                      |    \
            modRelations    f'
                      ↓      ↘
                 FPAlgebra ─f→ A
          -}
          f' iHom' : CommAlgebraHom (Polynomials n) A
          f' = compAlgebraHom modRelations f
          iHom' = compAlgebraHom modRelations (inducedHom A values relationsHold)

          inv : retract (Iso.fun (homMapIso {I = Fin n} A)) (Iso.inv (homMapIso A))
          inv = Iso.leftInv (homMapIso {R = R} {I = Fin n} A)

      {- ∀ A : Comm-R-Algebra,
         ∀ J : Finitely-generated-Ideal,
         Hom(R[I]/J,A) is isomorphic to the Set of roots of the generators of J
      -}

      zeroLocus : (A : CommAlgebra R ℓ) → Type ℓ
      zeroLocus A = Σ[ v ∈ FinVec ⟨ A ⟩ n ] ((i : Fin m) → evPoly A (relation i) v ≡ 0a (snd A))

      inducedHomFP : (A : CommAlgebra R ℓ) →
                      zeroLocus A → CommAlgebraHom FPAlgebra A
      inducedHomFP A d = inducedHom A (fst d) (snd d)

      evaluateAtFP : {A : CommAlgebra R ℓ} →
                      CommAlgebraHom FPAlgebra A → zeroLocus A
      evaluateAtFP {A} f = value ,
                      λ i →  evPoly A (relation i) value                            ≡⟨ step1 (relation i) ⟩
                             fst compHom (evPoly (Polynomials n) (relation i) var)  ≡⟨ refl ⟩
                             (fst f) ((fst modRelations)
                                        (evPoly (Polynomials n) (relation i) var))  ≡⟨ cong (fst f)
                                                                                (evPolyHomomorphic
                                                                                (Polynomials n)
                                                                                FPAlgebra
                                                                                modRelations
                                                                                (relation i) var) ⟩
                             (fst f) (evPoly FPAlgebra (relation i) generator)      ≡⟨ cong (fst f) (relationsHold i) ⟩
                             (fst f) (0a (snd FPAlgebra))                           ≡⟨ IsAlgebraHom.pres0 (snd f) ⟩
                             0a (snd A) ∎
        where
          compHom : CommAlgebraHom (Polynomials n) A
          compHom = CommAlgebraHoms.compCommAlgebraHom (Polynomials n) FPAlgebra A modRelations f
          value : FinVec ⟨ A ⟩ n
          value = (Iso.fun (homMapIso A)) compHom
          step1 : (x : ⟨ Polynomials n ⟩) → evPoly A x value ≡ fst compHom (evPoly (Polynomials n) x var)
          step1 x = sym (evPolyHomomorphic (Polynomials n) A compHom x var)

      FPHomIso : {A : CommAlgebra R ℓ} →
                  Iso (CommAlgebraHom FPAlgebra A) (zeroLocus A)
      Iso.fun FPHomIso = evaluateAtFP
      Iso.inv FPHomIso = inducedHomFP _
      Iso.rightInv (FPHomIso {A}) =
        λ b → Σ≡Prop
                (λ x → isPropΠ
                  (λ i → isSetCommAlgebra A
                          (evPoly A (relation i) x)
                          (0a (snd A))))
                refl
      Iso.leftInv (FPHomIso {A}) =
        λ a → Σ≡Prop (λ f → isPropIsCommAlgebraHom {ℓ} {R} {ℓ} {ℓ} {FPAlgebra} {A} f)
                 λ i → fst (unique {A}
                             (fst (evaluateAtFP {A} a))
                             (snd (evaluateAtFP a))
                             a
                             (λ j → refl)
                             i)

      homMapPathFP : (A : CommAlgebra R ℓ)→ CommAlgebraHom FPAlgebra A ≡ zeroLocus A
      homMapPathFP A = isoToPath (FPHomIso {A})

      isSetZeroLocus : (A : CommAlgebra R ℓ) → isSet (zeroLocus A)
      isSetZeroLocus A =  J (λ y _ → isSet y)
                       (isSetAlgebraHom (CommAlgebra→Algebra FPAlgebra) (CommAlgebra→Algebra A))
                       (homMapPathFP A)

  record FinitePresentation (A : CommAlgebra R ℓ) : Type ℓ where
    field
      n : ℕ
      m : ℕ
      relations : FinVec ⟨ Polynomials n ⟩ m
      equiv : CommAlgebraEquiv (FPAlgebra n relations) A

  isFPAlgebra : (A : CommAlgebra R ℓ) → Type _
  isFPAlgebra A = ∥ FinitePresentation A ∥₁

  isFPAlgebraIsProp : {A : CommAlgebra R ℓ} → isProp (isFPAlgebra A)
  isFPAlgebraIsProp = isPropPropTrunc

module Instances {R : CommRing ℓ} where
  open FinitePresentation

  {- Every (multivariate) polynomial algebra is finitely presented -}
  module _ (n : ℕ) where
    private
      A : CommAlgebra R ℓ
      A = Polynomials n

      emptyGen : FinVec (fst A) 0
      emptyGen = λ ()

      B : CommAlgebra R ℓ
      B = FPAlgebra n emptyGen

    polynomialAlgFP : FinitePresentation A
    FinitePresentation.n polynomialAlgFP = n
    m polynomialAlgFP = 0
    relations polynomialAlgFP = emptyGen
    equiv polynomialAlgFP =
      -- Idea: A and B enjoy the same universal property.
      toAAsEquiv , snd toA
      where
        toA : CommAlgebraHom B A
        toA = inducedHom n emptyGen A Construction.var (λ ())
        fromA : CommAlgebraHom A B
        fromA = freeInducedHom B (generator _ _)
        open AlgebraHoms
        inverse1 : fromA ∘a toA ≡ idAlgebraHom _
        inverse1 =
          fromA ∘a toA
            ≡⟨ sym (unique _ _ _ _ _ (λ i → cong (fst fromA) (
                 fst toA (generator n emptyGen i)
                   ≡⟨ inducedHomOnGenerators _ _ _ _ _ _ ⟩
                 Construction.var i
                   ∎))) ⟩
          inducedHom n emptyGen B (generator _ _) (relationsHold _ _)
            ≡⟨ unique _ _ _ _ _ (λ i → refl) ⟩
          idAlgebraHom _
            ∎
        inverse2 : toA ∘a fromA ≡ idAlgebraHom _
        inverse2 = isoFunInjective (homMapIso A) _ _ (
          evaluateAt A (toA ∘a fromA)   ≡⟨ sym (naturalEvR {A = B} {B = A} toA fromA) ⟩
          fst toA ∘ evaluateAt B fromA  ≡⟨ refl ⟩
          fst toA ∘ generator _ _       ≡⟨ funExt (inducedHomOnGenerators _ _ _ _ _)⟩
          Construction.var              ∎)
        toAAsEquiv : ⟨ B ⟩ ≃ ⟨ A ⟩
        toAAsEquiv = isoToEquiv (iso (fst toA)
                                     (fst fromA)
                                     (λ a i → fst (inverse2 i) a)
                                     (λ b i → fst (inverse1 i) b))

  {- The initial R-algebra is finitely presented -}
  private
    R[⊥] : CommAlgebra R ℓ
    R[⊥] = Polynomials 0

    emptyGen : FinVec (fst R[⊥]) 0
    emptyGen = λ ()

    R[⊥]/⟨0⟩ : CommAlgebra R ℓ
    R[⊥]/⟨0⟩ = FPAlgebra 0 emptyGen

  R[⊥]/⟨0⟩IsInitial : (B : CommAlgebra R ℓ)
                     → isContr (CommAlgebraHom R[⊥]/⟨0⟩ B)
  R[⊥]/⟨0⟩IsInitial B = iHom , uniqueness
    where
      iHom : CommAlgebraHom R[⊥]/⟨0⟩ B
      iHom = inducedHom 0 emptyGen B (λ ()) (λ ())
      uniqueness : (f : CommAlgebraHom R[⊥]/⟨0⟩ B) →
                   iHom ≡ f
      uniqueness f = unique 0 emptyGen {A = B} (λ ()) (λ ()) f (λ ())

  initialCAlgFP : FinitePresentation (initialCAlg R)
  n initialCAlgFP = 0
  m initialCAlgFP = 0
  relations initialCAlgFP = emptyGen
  equiv initialCAlgFP =
    equivByInitiality R R[⊥]/⟨0⟩ R[⊥]/⟨0⟩IsInitial

  {- The terminal R-algebra is finitely presented -}
  private
    unitGen : FinVec (fst R[⊥]) 1
    unitGen zero = 1a
      where open CommAlgebraStr (snd R[⊥])

    R[⊥]/⟨1⟩ : CommAlgebra R ℓ
    R[⊥]/⟨1⟩ = FPAlgebra 0 unitGen

  terminalCAlgFP : FinitePresentation (TerminalCAlg R)
  n terminalCAlgFP = 0
  m terminalCAlgFP = 1
  relations terminalCAlgFP = unitGen
  equiv terminalCAlgFP = equivFrom1≡0 R R[⊥]/⟨1⟩ (sym (⋆-lid 1a) ∙ relationsHold 0 unitGen zero)
    where open CommAlgebraStr (snd R[⊥]/⟨1⟩)


import      Lvl
open import Structure.Operator.Vector
open import Structure.Setoid
open import Type

module Structure.Operator.Vector.Eigen
  {ℓᵥ ℓₛ ℓᵥₑ ℓₛₑ}
  {V : Type{ℓᵥ}} ⦃ equiv-V : Equiv{ℓᵥₑ}(V) ⦄
  {S : Type{ℓₛ}} ⦃ equiv-S : Equiv{ℓₛₑ}(S) ⦄
  (_+ᵥ_ : V → V → V)
  (_⋅ₛᵥ_ : S → V → V)
  (_+ₛ_ _⋅ₛ_ : S → S → S)
  ⦃ vectorSpace : VectorSpace(_+ᵥ_)(_⋅ₛᵥ_)(_+ₛ_)(_⋅ₛ_) ⦄
  where

open VectorSpace(vectorSpace)

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

-- v is a eigenvector for the eigenvalue 𝜆 of the linear transformation f.
-- Multiplication by an eigenvalue can replace a linear transformation for certain vectors.
Eigenpair : (V → V) → S → V → Stmt
Eigenpair(f)(𝜆)(v) = ((v ≢ 𝟎ᵥ) ∧ (f(v) ≡ 𝜆 ⋅ₛᵥ v))

Eigenvector : (V → V) → V → Stmt
Eigenvector(f)(v) = ∃(𝜆 ↦ Eigenpair(f)(𝜆)(v))

Eigenvalue : (V → V) → S → Stmt
Eigenvalue(f)(𝜆) = ∃(v ↦ Eigenpair(f)(𝜆)(v))


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

open import Categories.Category.Core

-- Idempotents and Split Idempotents
module Categories.Morphism.Idempotent {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level

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

open Category 𝒞
open HomReasoning

record Idempotent (A : Obj) : Set (ℓ ⊔ e) where
  field
    idem       : A ⇒ A
    idempotent : idem ∘ idem ≈ idem

record IsSplitIdempotent {A : Obj} (i : A ⇒ A) : Set (o ⊔ ℓ ⊔ e) where
  field
    {obj}    : Obj
    retract  : A ⇒ obj
    section  : obj ⇒ A
    retracts : retract ∘ section ≈ id
    splits   : section ∘ retract ≈ i

  retract-absorb : retract ∘ i ≈ retract
  retract-absorb = begin
    retract ∘ i                 ≈˘⟨ refl⟩∘⟨ splits ⟩
    retract ∘ section ∘ retract ≈⟨ cancelˡ retracts ⟩
    retract                     ∎

  section-absorb : i ∘ section ≈ section
  section-absorb = begin
    i ∘ section                   ≈˘⟨ splits ⟩∘⟨refl ⟩
    (section ∘ retract) ∘ section ≈⟨ cancelʳ retracts ⟩
    section                       ∎

  idempotent : i ∘ i ≈ i
  idempotent = begin
    i ∘ i                                     ≈˘⟨ splits ⟩∘⟨ splits ⟩
    (section ∘ retract) ∘ (section ∘ retract) ≈⟨ cancelInner retracts ⟩
    section ∘ retract                         ≈⟨ splits ⟩
    i                                         ∎

record SplitIdempotent (A : Obj) : Set (o ⊔ ℓ ⊔ e) where
  field
    idem : A ⇒ A
    isSplitIdempotent : IsSplitIdempotent idem

  open IsSplitIdempotent isSplitIdempotent public

-- All split idempotents are idempotent
SplitIdempotent⇒Idempotent : ∀ {A} → SplitIdempotent A → Idempotent A
SplitIdempotent⇒Idempotent Split = record { Split }
  where
    module Split = SplitIdempotent Split

module _ {A} {f : A ⇒ A} (S T : IsSplitIdempotent f) where
  private
    module S = IsSplitIdempotent S
    module T = IsSplitIdempotent T

  split-idempotent-unique : S.obj ≅ T.obj
  split-idempotent-unique = record
    { from = T.retract ∘ S.section
    ; to = S.retract ∘ T.section
    ; iso = record
      { isoˡ = begin
        (S.retract ∘ T.section) ∘ (T.retract ∘ S.section) ≈⟨ center T.splits ⟩
        S.retract ∘ f ∘ S.section                         ≈⟨ pullˡ S.retract-absorb ⟩
        S.retract ∘ S.section                             ≈⟨ S.retracts ⟩
        id                                                ∎
      ; isoʳ = begin
        (T.retract ∘ S.section) ∘ (S.retract ∘ T.section) ≈⟨ center S.splits ⟩
        T.retract ∘ f ∘ T.section                         ≈⟨ pullˡ T.retract-absorb ⟩
        T.retract ∘ T.section                             ≈⟨ T.retracts ⟩
        id                                                ∎
      }
    }


module DifferentArities where

open import Common.Equality
open import Common.Prelude

f : Nat → Nat → Nat
f zero      = λ x → x
f (suc n) m = f n (suc m)

testf1 : f zero ≡ λ x → x
testf1 = refl

testf2 : ∀ {n m} → f (suc n) m ≡ f n (suc m)
testf2 = refl

testf3 : f 4 5 ≡ 9
testf3 = refl


-- Nils' suggestion

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)
open import Data.Nat.Properties.Simple using (+-suc)
open import Relation.Nullary using (¬_)
open import Function using (_∘_; id)
open import Data.Product using (_×_; _,_; proj₁; proj₂; map; ∃; ∃-syntax)
open import Data.Sum using (_⊎_; inj₁; inj₂)

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 ] (n ≡ m * 2)
∃-odd  : ∀ {n : ℕ} →  odd n → ∃[ m ] (n ≡ 1 + m * 2)

∃-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


module CS410-Vec where

open import CS410-Prelude
open import CS410-Nat

data Vec (X : Set) : Nat -> Set where
  []   : Vec X 0
  _::_ : forall {n} ->
         X -> Vec X n -> Vec X (suc n)
infixr 3 _::_

_+V_ : forall {X m n} -> Vec X m -> Vec X n -> Vec X (m +N n)
[] +V ys = ys
(x :: xs) +V ys = x :: xs +V ys
infixr 3 _+V_

data Choppable {X : Set}(m n : Nat) : Vec X (m +N n) -> Set where
  chopTo : (xs : Vec X m)(ys : Vec X n) -> Choppable m n (xs +V ys)

chop : {X : Set}(m n : Nat)(xs : Vec X (m +N n)) -> Choppable m n xs
chop zero n xs = chopTo [] xs
chop (suc m) n (x :: xs) with chop m n xs
chop (suc m) n (x :: .(xs +V ys)) | chopTo xs ys = chopTo (x :: xs) ys

chopParts : {X : Set}(m n : Nat)(xs : Vec X (m +N n)) -> Vec X m * Vec X n
chopParts m n xs with chop m n xs
chopParts m n .(xs +V ys) | chopTo xs ys = xs , ys

vec : forall {n X} -> X -> Vec X n
vec {zero}   x = []
vec {suc n}  x = x :: vec x

vapp : forall {n X Y} -> Vec (X -> Y) n -> Vec X n -> Vec Y n
vapp [] [] = []
vapp (f :: fs) (x :: xs) = f x :: vapp fs xs


------------------------------------------------------------------------
-- The Agda standard library
--
-- An either-or-both data type, basic type and operations
------------------------------------------------------------------------

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

module Data.These.Base where

open import Level
open import Data.Sum.Base using (_⊎_; [_,_]′)
open import Function.Base

private
  variable
    a b c d e f : Level
    A : Set a
    B : Set b
    C : Set c
    D : Set d
    E : Set e
    F : Set f

data These {a b} (A : Set a) (B : Set b) : Set (a ⊔ b) where
  this  : A     → These A B
  that  :     B → These A B
  these : A → B → These A B

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

-- injection

fromSum : A ⊎ B → These A B
fromSum = [ this , that ]′

-- map

map : (f : A → B) (g : C → D) → These A C → These B D
map f g (this a)    = this (f a)
map f g (that b)    = that (g b)
map f g (these a b) = these (f a) (g b)

map₁ : (f : A → B) → These A C → These B C
map₁ f = map f id

map₂ : (g : B → C) → These A B → These A C
map₂ = map id

-- fold

fold : (A → C) → (B → C) → (A → B → C) → These A B → C
fold l r lr (this a)    = l a
fold l r lr (that b)    = r b
fold l r lr (these a b) = lr a b

foldWithDefaults : A → B → (A → B → C) → These A B → C
foldWithDefaults a b lr = fold (flip lr b) (lr a) lr

-- swap

swap : These A B → These B A
swap = fold that this (flip these)

-- align

alignWith : (These A C → E) → (These B D → F) → These A B → These C D → These E F
alignWith f g (this a)    (this c)    = this (f (these a c))
alignWith f g (this a)    (that d)    = these (f (this a)) (g (that d))
alignWith f g (this a)    (these c d) = these (f (these a c)) (g (that d))
alignWith f g (that b)    (this c)    = these (f (that c)) (g (this b))
alignWith f g (that b)    (that d)    = that (g (these b d))
alignWith f g (that b)    (these c d) = these (f (that c)) (g (these b d))
alignWith f g (these a b) (this c)    = these (f (these a c)) (g (this b))
alignWith f g (these a b) (that d)    = these (f (this a)) (g (these b d))
alignWith f g (these a b) (these c d) = these (f (these a c)) (g (these b d))

align : These A B → These C D → These (These A C) (These B D)
align = alignWith id id


{-# OPTIONS --cubical-compatible #-}
module Common.Equality where

open import Agda.Builtin.Equality public
open import Common.Level

subst : ∀ {a p}{A : Set a}(P : A → Set p){x y : A} → x ≡ y → P x → P y
subst P refl t = t

cong : ∀ {a b}{A : Set a}{B : Set b}(f : A → B){x y : A} → x ≡ y → f x ≡ f y
cong f refl = refl

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

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


------------------------------------------------------------------------
-- The Agda standard library
--
-- Basic definitions for morphisms between algebraic structures
------------------------------------------------------------------------

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

open import Relation.Binary.Core

module Relation.Binary.Morphism.Definitions
  {a} (A : Set a)     -- The domain of the morphism
  {b} (B : Set b)     -- The codomain of the morphism
  where

open import Algebra.Core
open import Function.Base
open import Level using (Level)

private
  variable
    ℓ₁ ℓ₂ : Level

------------------------------------------------------------------------
-- Basic definitions

Homomorphic₂ : Rel A ℓ₁ → Rel B ℓ₂ → (A → B) → Set _
Homomorphic₂ _∼₁_ _∼₂_ ⟦_⟧ = ∀ {x y} → x ∼₁ y → ⟦ x ⟧ ∼₂ ⟦ y ⟧

------------------------------------------------------------------------
-- DEPRECATED NAMES
------------------------------------------------------------------------
-- Please use the new names as continuing support for the old names is
-- not guaranteed.

-- Version 1.3

Morphism : Set _
Morphism = A → B

{-# WARNING_ON_USAGE Morphism
"Warning: Morphism was deprecated in v1.3.
Please use the standard function notation (e.g. A → B) instead."
#-}


module Stable where

open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)

open import Negation using (¬_; ¬¬¬-elim)

Stable : Set → Set
Stable A = ¬ ¬ A → A

¬-stable : ∀ {A : Set} → Stable (¬ A)
¬-stable = λ ¬¬¬a → (λ a → ¬¬¬a (λ ¬a → ¬a a))
-- ¬-stable = ¬¬¬-elim

×-stable : ∀ {A B : Set} → Stable A → Stable B → Stable (A × B)
×-stable sa sb = λ ¬¬a×b →
  ⟨ (sa λ{ ¬a → ¬¬a×b λ{ a×b → ¬a (proj₁ a×b) }})
  , (sb λ{ ¬b → ¬¬a×b λ{ a×b → ¬b (proj₂ a×b) }})
  ⟩


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

open import Cubical.Core.Everything

open import Cubical.Foundations.Prelude

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

open import Cubical.Relation.Nullary
open import Cubical.Relation.Nullary.DecidableEq

open import Cubical.Data.Nat.Algebra public

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

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

+-comm : ∀ m n → m + n ≡ n + m
+-comm m zero = +-zero m
+-comm m (suc n) = (+-suc m n) ∙ (cong suc (+-comm m n))

-- Addition is associative
+-assoc : ∀ m n o → m + (n + o) ≡ (m + n) + o
+-assoc zero _ _    = refl
+-assoc (suc m) n o = cong suc (+-assoc m n o)

private
  variable
    l m n : ℕ

znots : ¬ (0 ≡ suc n)
znots eq = subst (caseNat ℕ ⊥) eq 0

snotz : ¬ (suc n ≡ 0)
snotz eq = subst (caseNat ⊥ ℕ) eq 0

injSuc : suc m ≡ suc n → m ≡ n
injSuc p = cong predℕ p

inj-m+ : m + l ≡ m + n → l ≡ n
inj-m+ {zero} p = p
inj-m+ {suc m} p = inj-m+ (injSuc p)

inj-+m : l + m ≡ n + m → l ≡ n
inj-+m {l} {m} {n} p = inj-m+ ((+-comm m l) ∙ (p ∙ (+-comm n m)))

m+n≡n→m≡0 : m + n ≡ n → m ≡ 0
m+n≡n→m≡0 {n = zero} = λ p → (sym (+-zero _)) ∙ p
m+n≡n→m≡0 {n = suc n} p = m+n≡n→m≡0 (injSuc ((sym (+-suc _ n)) ∙ p))

m+n≡0→m≡0×n≡0 : m + n ≡ 0 → (m ≡ 0) × (n ≡ 0)
m+n≡0→m≡0×n≡0 {zero} = refl ,_
m+n≡0→m≡0×n≡0 {suc m} p = ⊥-elim (snotz p)

discreteℕ : Discrete ℕ
discreteℕ zero zero = yes refl
discreteℕ zero (suc n) = no znots
discreteℕ (suc m) zero = no snotz
discreteℕ (suc m) (suc n) with discreteℕ m n
... | yes p = yes (cong suc p)
... | no p = no (λ x → p (injSuc x))

isSetℕ : isSet ℕ
isSetℕ = Discrete→isSet discreteℕ

0≡m*0 : ∀ m → 0 ≡ m * 0
0≡m*0 zero = refl
0≡m*0 (suc m) = 0≡m*0 m

*-suc : ∀ m n → m * suc n ≡ m + m * n
*-suc zero n = refl
*-suc (suc m) n
  = cong suc
  ( n + m * suc n ≡⟨ cong (n +_) (*-suc m n) ⟩
    n + (m + m * n) ≡⟨ +-assoc n m (m * n) ⟩
    (n + m) + m * n ≡⟨ cong (_+ m * n) (+-comm n m) ⟩
    (m + n) + m * n ≡⟨ sym (+-assoc m n (m * n)) ⟩
    m + (n + m * n) ∎
  )

*-comm : ∀ m n → m * n ≡ n * m
*-comm zero n = 0≡m*0 n
*-comm (suc m) n = cong (n +_) (*-comm m n) ∙ sym (*-suc n m)

0≡n*sm→0≡n : 0 ≡ n * suc m → 0 ≡ n
0≡n*sm→0≡n {n = zero} p = refl
0≡n*sm→0≡n {n = suc n} p = ⊥-elim (znots p)

inj-*sm : l * suc m ≡ n * suc m → l ≡ n
inj-*sm {zero} {m} {n} p = 0≡n*sm→0≡n p
inj-*sm {l} {m} {zero} p = sym (0≡n*sm→0≡n (sym p))
inj-*sm {suc l} {m} {suc n} p = cong suc (inj-*sm (inj-m+ {m = suc m} p))

inj-sm* : suc m * l ≡ suc m * n → l ≡ n
inj-sm* {m} {l} {n} p = inj-*sm (*-comm l (suc m) ∙ p ∙ *-comm (suc m) n)


open import prelude
open import ch6 using (Term  ; var ; fun ; _$_ ; two ; four)

-- A stack is a list of values
-- Values are either closures or errors

data Value : Set where
  error : Value
  closure : List(Value) → Term → Value

Stack = List(Value)

lookup : (s : Stack) → (x : Nat) → Value
lookup nil x = error
lookup (v :: s) zero = v
lookup (v :: s) (suc x) = lookup s x

-- Big step sematics

data _▷_⇓_ : Stack → Term → Value → Set where

  E─Var : ∀ {s x} →

    --------------------------
    s ▷ (var x) ⇓ (lookup s x)

  E─Fun : ∀ {s t} →

    ---------------------------
    s ▷ (fun t) ⇓ (closure s t)

  E─App : ∀ {s s′ t t′ u u′ v} →

    s ▷ t ⇓ (closure s′ t′) →
    s ▷ u ⇓ u′ →
    (u′ :: s′) ▷ t′ ⇓ v →
    -------------------
    s ▷ (t $ u) ⇓ v

  E─AppErr : ∀ {s t u} →

    s ▷ t ⇓ error →
    -------------------
    s ▷ (t $ u) ⇓ error

-- An interpreter result

data Result : Stack → Term → Set where

  result : ∀ {s t} →

    (v : Value) →
    (s ▷ t ⇓ v) →
    -------------
    Result s t

{-# NON_TERMINATING #-}
interpret : (s : Stack) → (t : Term) → Result s t
interpret s (var x) = result (lookup s x) E─Var
interpret s (fun t) = result (closure s t) E─Fun
interpret s (t₁ $ t₂) = helper₁ (interpret s t₁) where

  helper₃ : ∀ {s′ t′ u′} → (s ▷ t₁ ⇓ (closure s′ t′)) → (s ▷ t₂ ⇓ u′) → Result (u′ :: s′) t′ → Result s (t₁ $ t₂)
  helper₃ p q (result v r) = result v (E─App p q r)

  helper₂ : ∀ {s′ t′} → (s ▷ t₁ ⇓ (closure s′ t′)) → Result s t₂ → Result s (t₁ $ t₂)
  helper₂ {s′} {t′} p (result u′ q) = helper₃ p q (interpret (u′ :: s′) t′)

  helper₁ : Result s t₁ → Result s (t₁ $ t₂)
  helper₁ (result error           p) = result error (E─AppErr p)
  helper₁ (result (closure s′ t′) p) = helper₂ p (interpret s t₂)

-- Shorthand for starting from the empty stack

i = interpret nil


module Prelude.Nat.Core where

open import Prelude.Unit
open import Prelude.Empty
open import Prelude.Number
open import Prelude.Semiring

open import Agda.Builtin.Nat public
  renaming ( _+_        to _+N_
           ; _*_        to _*N_
           ; _-_        to _-N_
           ; _==_       to eqNat
           ; _<_        to lessNat
           ; div-helper to divAux
           ; mod-helper to modAux )

{-# DISPLAY _+N_ = _+_ #-}
{-# DISPLAY _-N_ = _-_ #-}
{-# DISPLAY _*N_ = _*_ #-}

--- Semiring ---

instance
  NumberNat : Number Nat
  Number.Constraint NumberNat _ = ⊤
  Number.fromNat    NumberNat n = n

  SemiringNat : Semiring Nat
  zro {{SemiringNat}} = 0
  one {{SemiringNat}} = 1
  _+_ {{SemiringNat}} = _+N_
  _*_ {{SemiringNat}} = _*N_

  SubtractiveNat : Subtractive Nat
  _-_    {{SubtractiveNat}}   = _-N_
  negate {{SubtractiveNat}} _ = 0

--- Division and modulo ---

NonZero : Nat → Set
NonZero zero    = ⊥
NonZero (suc _) = ⊤

infixl 7 natDiv natMod
syntax natDiv m n = n div m
natDiv : (m : Nat) {{nz : NonZero m}} → Nat → Nat
natDiv zero {{}} n
natDiv (suc m) n = divAux 0 m n m

syntax natMod m n = n mod m
natMod : (m : Nat) {{nz : NonZero m}} → Nat → Nat
natMod zero {{}} n
natMod (suc m) n = modAux 0 m n m

{-# INLINE natMod #-}
{-# INLINE natDiv #-}


------------------------------------------------------------------------------
-- Testing Agsy arithmetic properties used by the McCarthy 91 function
------------------------------------------------------------------------------

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

-- Tested with the development version of the Agda standard library on
-- 02 February 2012.

module Agsy.McCarthy91.Arithmetic where

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

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

91≡[100+11∸10]∸10 : (100 + 11 ∸ 10) ∸ 10 ≡ 91
91≡[100+11∸10]∸10 = refl

20>19 : 20 > 19  -- via Agsy
20>19 = s≤s
          (s≤s
           (s≤s
            (s≤s
             (s≤s
              (s≤s
               (s≤s
                (s≤s
                 (s≤s
                  (s≤s
                   (s≤s
                    (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))))))))))))))))

50>49 : 50 > 49  -- via Agsy {-t 30}
50>49 = s≤s
          (s≤s
           (s≤s
            (s≤s
             (s≤s
              (s≤s
               (s≤s
                (s≤s
                 (s≤s
                  (s≤s
                   (s≤s
                    (s≤s
                     (s≤s
                      (s≤s
                       (s≤s
                        (s≤s
                         (s≤s
                          (s≤s
                           (s≤s
                            (s≤s
                             (s≤s
                              (s≤s
                               (s≤s
                                (s≤s
                                 (s≤s
                                  (s≤s
                                   (s≤s
                                    (s≤s
                                     (s≤s
                                      (s≤s
                                       (s≤s
                                        (s≤s
                                         (s≤s
                                          (s≤s
                                           (s≤s
                                            (s≤s
                                             (s≤s
                                              (s≤s
                                               (s≤s
                                                (s≤s
                                                 (s≤s
                                                  (s≤s
                                                   (s≤s
                                                    (s≤s
                                                     (s≤s
                                                      (s≤s
                                                       (s≤s
                                                        (s≤s
                                                         (s≤s
                                                          (s≤s
                                                           z≤n)))))))))))))))))))))))))))))))))))))))))))))))))

75>74 : 75 > 74  -- via Agsy {-t 180}
75>74 = s≤s
          (s≤s
           (s≤s
            (s≤s
             (s≤s
              (s≤s
               (s≤s
                (s≤s
                 (s≤s
                  (s≤s
                   (s≤s
                    (s≤s
                     (s≤s
                      (s≤s
                       (s≤s
                        (s≤s
                         (s≤s
                          (s≤s
                           (s≤s
                            (s≤s
                             (s≤s
                              (s≤s
                               (s≤s
                                (s≤s
                                 (s≤s
                                  (s≤s
                                   (s≤s
                                    (s≤s
                                     (s≤s
                                      (s≤s
                                       (s≤s
                                        (s≤s
                                         (s≤s
                                          (s≤s
                                           (s≤s
                                            (s≤s
                                             (s≤s
                                              (s≤s
                                               (s≤s
                                                (s≤s
                                                 (s≤s
                                                  (s≤s
                                                   (s≤s
                                                    (s≤s
                                                     (s≤s
                                                      (s≤s
                                                       (s≤s
                                                        (s≤s
                                                         (s≤s
                                                          (s≤s
                                                           (s≤s
                                                            (s≤s
                                                             (s≤s
                                                              (s≤s
                                                               (s≤s
                                                                (s≤s
                                                                 (s≤s
                                                                  (s≤s
                                                                   (s≤s
                                                                    (s≤s
                                                                     (s≤s
                                                                      (s≤s
                                                                       (s≤s
                                                                        (s≤s
                                                                         (s≤s
                                                                          (s≤s
                                                                           (s≤s
                                                                            (s≤s
                                                                             (s≤s
                                                                              (s≤s
                                                                               (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                z≤n))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

101>100 : 101 > 100  -- via Agsy {-t 600}
101>100 = s≤s
          (s≤s
           (s≤s
            (s≤s
             (s≤s
              (s≤s
               (s≤s
                (s≤s
                 (s≤s
                  (s≤s
                   (s≤s
                    (s≤s
                     (s≤s
                      (s≤s
                       (s≤s
                        (s≤s
                         (s≤s
                          (s≤s
                           (s≤s
                            (s≤s
                             (s≤s
                              (s≤s
                               (s≤s
                                (s≤s
                                 (s≤s
                                  (s≤s
                                   (s≤s
                                    (s≤s
                                     (s≤s
                                      (s≤s
                                       (s≤s
                                        (s≤s
                                         (s≤s
                                          (s≤s
                                           (s≤s
                                            (s≤s
                                             (s≤s
                                              (s≤s
                                               (s≤s
                                                (s≤s
                                                 (s≤s
                                                  (s≤s
                                                   (s≤s
                                                    (s≤s
                                                     (s≤s
                                                      (s≤s
                                                       (s≤s
                                                        (s≤s
                                                         (s≤s
                                                          (s≤s
                                                           (s≤s
                                                            (s≤s
                                                             (s≤s
                                                              (s≤s
                                                               (s≤s
                                                                (s≤s
                                                                 (s≤s
                                                                  (s≤s
                                                                   (s≤s
                                                                    (s≤s
                                                                     (s≤s
                                                                      (s≤s
                                                                       (s≤s
                                                                        (s≤s
                                                                         (s≤s
                                                                          (s≤s
                                                                           (s≤s
                                                                            (s≤s
                                                                             (s≤s
                                                                              (s≤s
                                                                               (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                (s≤s
                                                                                z≤n))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))


module Oscar.Data.Equality where

open import Agda.Builtin.Equality public using (_≡_; refl) public
open import Relation.Binary.PropositionalEquality public using (_≢_) public
open import Relation.Binary.PropositionalEquality public using (cong; cong₂; cong-app; subst; subst₂; sym; trans) public

open import Oscar.Level
open import Oscar.Function
open import Oscar.Relation

infix 4 _≡̇_
_≡̇_ : ∀ {a} {A : Set a} {b} {B : A → Set b} → ((x : A) → B x) → ((x : A) → B x) → Set (a ⊔ b)
f ≡̇ g = ∀ x → f x ≡ g x

≡̇-refl : ∀ {a} {A : Set a} {b} {B : A → Set b} (f : (x : A) → B x) → f ≡̇ f
≡̇-refl _ _ = refl

≡̇-sym : ∀ {a} {A : Set a} {b} {B : A → Set b} {f g : (x : A) → B x} → f ≡̇ g → g ≡̇ f
≡̇-sym f≡̇g = sym ∘ f≡̇g

≡̇-trans : ∀ {a} {A : Set a} {b} {B : A → Set b} {f g : (x : A) → B x} → f ≡̇ g → {h : (x : A) → B x} → g ⟨ _≡̇ h ⟩→ f
≡̇-trans f≡̇g g≡̇h x = trans (f≡̇g x) (g≡̇h x)

open import Oscar.Category

≡-setoid : ∀ {a} (A : Set a) → Setoid A a
Setoid._≋_ (≡-setoid A) = _≡_
Setoid.≋-reflexivity (≡-setoid A) = refl
Setoid.≋-symmetry (≡-setoid A) = sym
Setoid.≋-transitivity (≡-setoid A) x≡y = trans x≡y

≡̇-setoid : ∀ {a} {A : Set a} {b} (B : A → Set b) → Setoid ((x : A) → B x) (a ⊔ b)
Setoid._≋_ (≡̇-setoid B) = _≡̇_
Setoid.≋-reflexivity (≡̇-setoid B) = ≡̇-refl _
Setoid.≋-symmetry (≡̇-setoid B) = ≡̇-sym
Setoid.≋-transitivity (≡̇-setoid B) = ≡̇-trans


module with-equalities where

open import Agda.Builtin.List

open import Common.Bool
open import Common.Equality

module _ {A : Set} where

  filter : (A → Bool) → List A → List A
  filter p []       = []
  filter p (x ∷ xs) =
    if p x then x ∷ filter p xs else filter p xs

  filter-filter : ∀ p xs → filter p (filter p xs) ≡ filter p xs
  filter-filter p []       = refl
  filter-filter p (x ∷ xs) with p x in eq
  ... | false = filter-filter p xs -- easy
  ... | true -- second filter stuck on `p x`: rewrite by `eq`!
    rewrite eq = cong (x ∷_) (filter-filter p xs)

open import Agda.Builtin.Nat
open import Agda.Builtin.Sigma

double : Nat → Set
double m = Σ Nat λ n → n + n ≡ m

-- 2*_ : Nat → Σ Nat double
-- 2*_ n with m ← n + n = m , n , {!!}
--  At this point we do not remember that m ≡ n + n and cannot
--  conclude the proof.

-- If only we could give a name to the proof that
-- `p ≡ e` after a `with p ← e` clause !

2*_ : Nat → Σ Nat double
2*_ n with m ← n + n in eq = m , n , eq

data ⊥ : Set where
⊥-elim : ⊥ → {A : Set} → A
⊥-elim ()

¬odd0 : ∀ n → 2 * n + 1 ≡ 0 → ⊥
¬odd0 zero    ()
¬odd0 (suc n) ()

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

module _ {A : Set} where

  oddhead : ∀ {n} → Vec A (2 * n + 1) → A
  oddhead {n} xs
    -- here we cannot split on `xs` because Agda does not know
    -- whether `2 * n + 1` can unify with `0` or not

    -- A possible solution: abstract over p and then match on xs.
--      with p ← (2 * n + 1) | xs
--  ... | x ∷ _ = x
--  ... | []    = {!!}

    -- The problem however is that Agda insists we should consider
    -- two cases: `xs = []` and `xs = x ∷ _`. And in the `[]` branch
    -- we only know that:
    -- p  : Nat
    -- n  : Nat
    -- xs : Vec A 0
    -- If only we had somehow recorded that `p ← (2 * n + 1)` happened!
    -- This is what the inspect construct allows us to do.

    with p ← (2 * n + 1) in eq | xs
  ... | x ∷ _ = x
  -- we can now use this equality proof to dismiss the impossible case.
  ... | []    = ⊥-elim (¬odd0 n eq)

  -- If you do not want to name the nat corresponding to `2 * n + 1`,
  -- you can use inspect together with an implicit with

  oddhead' : ∀ {n} → Vec A (2 * n + 1) → A
  oddhead' {n} xs with {2 * n + 1} in eq | xs
  ... | x ∷ _ = x
  ... | []    = ⊥-elim (¬odd0 n eq)


{-# OPTIONS --without-K #-}
module Computability.Enumeration.Base where

open import Computability.Prelude
open import Computability.Function

record Enumerable (A : Set) : Set where
  field
    enum : ℕ → A
    bijective : Bijective enum

open Enumerable

ℕ-Enumerable : Enumerable ℕ
enum ℕ-Enumerable n = n
proj₁ (bijective ℕ-Enumerable) eq = eq
proj₁ (proj₂ (bijective ℕ-Enumerable) y) = y
proj₂ (proj₂ (bijective ℕ-Enumerable) y) = refl


module Thesis.IntChanges where

open import Data.Integer.Base
open import Relation.Binary.PropositionalEquality

open import Thesis.Changes
open import Theorem.Groups-Nehemiah

private
  intCh = ℤ
instance
  intCS : ChangeStructure ℤ
intCS = record
  { Ch = ℤ
  ; ch_from_to_ = λ dv v1 v2 → v1 + dv ≡ v2
  ; isCompChangeStructure = record
    { isChangeStructure = record
      { _⊕_ = _+_
      ; fromto→⊕ = λ dv v1 v2 v2≡v1+dv → v2≡v1+dv
      ; _⊝_ = _-_
      ; ⊝-fromto = λ a b → n+[m-n]=m {a} {b}
      }
    ; _⊚_ = λ da1 da2 → da1 + da2
    ; ⊚-fromto = i⊚-fromto
    }
  }
  where
    i⊚-fromto : (a1 a2 a3 : ℤ) (da1 da2 : intCh) →
      a1 + da1 ≡ a2 → a2 + da2 ≡ a3 → a1 + (da1 + da2) ≡ a3
    i⊚-fromto a1 a2 a3 da1 da2 a1+da1≡a2 a2+da2≡a3
      rewrite sym (associative-int a1 da1 da2) | a1+da1≡a2 = a2+da2≡a3


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

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

open import Cubical.Structures.Group
open import Cubical.Structures.NAryOp

private
  variable
    ℓ ℓ' : Level

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

-- Finite symmetrics groups

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


------------------------------------------------------------------------------
-- Axiomatic Peano arithmetic base
------------------------------------------------------------------------------

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

-- Mendelson's axioms for first-order Peano arithmetic [Mendelson,
-- 1977, p. 155].

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

-- NB. These axioms formalize the propositional equality.

module PA.Axiomatic.Mendelson.Base where

infixl 7 _*_
infixl 6 _+_
infix  4 _≈_ _≉_

------------------------------------------------------------------------------
-- First-order logic (without equality)
open import Common.FOL.FOL public renaming ( D to ℕ )

-- Non-logical constants
postulate
  zero    : ℕ
  succ    : ℕ → ℕ
  _+_ _*_ : ℕ → ℕ → ℕ

-- The PA equality.
--
-- N.B. We use the symbol _≈_ for avoiding to use the
-- --no-internal-equality Apia option.
postulate _≈_ : ℕ → ℕ → Set

-- Inequality.
_≉_ : ℕ → ℕ → Set
x ≉ y = ¬ x ≈ y
{-# ATP definition _≉_ #-}

-- Proper axioms

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

postulate
  S₁ : ∀ {m n o} → m ≈ n → m ≈ o → n ≈ o
  S₂ : ∀ {m n} → m ≈ n → succ m ≈ succ n
  S₃ : ∀ {n} → zero ≉ succ n
  S₄ : ∀ {m n} → succ m ≈ succ n → m ≈ n
  S₅ : ∀ n → zero + n ≈ n
  S₆ : ∀ m n → succ m + n ≈ succ (m + n)
  S₇ : ∀ n → zero * n ≈ zero
  S₈ : ∀ m n → succ m * n ≈ n + m * n
{-# ATP axioms S₁ S₂ S₃ S₄ S₅ S₆ S₇ S₈ #-}

-- S₉ is an axiom schema, therefore we do not translate it to TPTP.
postulate S₉ : (A : ℕ → Set) → A zero → (∀ n → A n → A (succ n)) → ∀ n → A n


module Lists where

open import Nats
open import Bools

open import Agda.Builtin.List public
  using (List; []; _∷_)

infixr 5 _++_ _∷ʳ_

[_] : ∀ {a} {A : Set a} → A → List A
[ x ] = x ∷ []

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

_∷ʳ_ : ∀ {a} {A : Set a} → List A → A → List A
xs ∷ʳ x = xs ++ [ x ]

null : ∀ {a} {A : Set a} → List A → 𝔹
null []       = true
null (x ∷ xs) = false

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

replicate : ∀ {a} {A : Set a} → (n : ℕ) → A → List A
replicate zero    x = []
replicate (suc n) x = x ∷ replicate n x


{-# OPTIONS --type-in-type --no-pattern-matching #-}
open import Spire.IDarkwingDuck.Primitive
open import Spire.IDarkwingDuck.Derived
module Spire.IDarkwingDuck.Examples where

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

ℕR : Data
ℕR = Decl End End
  ("zero" ∷ "suc" ∷ [])
  (End tt , Rec tt (End tt) , tt)

ℕ : Set
ℕ = Form ℕR

zero : ℕ
zero = inj ℕR here

suc : ℕ → ℕ
suc = inj ℕR (there here)

VecR : Data
VecR = Decl
  (Arg Set λ _ → End)
  (λ _ → Arg ℕ λ _ → End)
  ("nil" ∷ "cons" ∷ [])
  (λ A →
    End (zero , tt)
  , IArg ℕ (λ n → Arg A λ _ → Rec (n , tt) (End (suc n , tt)))
  , tt
  )

Vec : (A : Set) → ℕ → Set
Vec = Form VecR

nil : {A : Set} → Vec A zero
nil = inj VecR here

cons : {A : Set} {n : ℕ} (x : A) (xs : Vec A n) → Vec A (suc n)
cons = inj VecR (there here)

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

add : ℕ → ℕ → ℕ
add = elim ℕR
  (λ n → ℕ → ℕ)
  (λ n → n)
  (λ m ih n → suc (ih n))

mult : ℕ → ℕ → ℕ
mult = elim ℕR
  (λ n → ℕ → ℕ)
  (λ n → zero)
  (λ m ih n → add n (ih n))

append : {A : Set} {m n : ℕ} (xs : Vec A m) (ys : Vec A n) → Vec A (add m n)
append {A} {m} {n} = elim VecR
  (λ m xs → (ys : Vec A n) → Vec A (add m n))
  (λ ys → ys)
  (λ x xs ih ys → cons x (ih ys))
  m

concat : {A : Set} {m n : ℕ} (xss : Vec (Vec A m) n) → Vec A (mult n m)
concat {A} {m} {n} = elim VecR
  (λ n xss → Vec A (mult n m))
  nil
  (λ xs xss ih → append xs ih)
  n

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

one : ℕ
one = suc zero

two : ℕ
two = suc one

three : ℕ
three = suc two

[1,2] : Vec ℕ two
[1,2] = cons one (cons two nil)

[3] : Vec ℕ one
[3] = cons three nil

[1,2,3] : Vec ℕ three
[1,2,3] = cons one (cons two (cons three nil))

test-append : [1,2,3] ≡ append [1,2] [3]
test-append = refl

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


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

module Deltaplus where

{- Chapter 9.2: Semi-Simplicial Types

   This file contains the definition of the index category
   for semi-simplicial with judgmental categorical laws: Δ₊
   In other words, we check Proposition 9.2.1.

   We want to keep it independent of the other files,
   so we do not import anything. -}

{- For simplicity, we only use the lowest universe
   (totally sufficient) -}
Type = Set

-- the empty type
data Empty : Type where

-- the unit type
data ⊤ : Type where
  * : ⊤

-- the natural numbers
data ℕ : Type where
  O : ℕ
  S : (n : ℕ) → ℕ

{- Finite types: these are the

   ===  OBJECTS of Δ₊ ===

-}
data Fin : ℕ → Type where
  fz : {n : ℕ} → Fin (S n)
  fs : {n : ℕ} → Fin n → Fin (S n)

-- >-relation on finite types
_>fin_ : {n : ℕ} → (i j : Fin n) → Set
fz >fin i = Empty
fs j >fin fz = ⊤
fs j >fin fs i = j >fin i

{- the proposition [we do not need to prove propositionality here, but
   we could prove it easily] that a function is increasing;
   this is the tricky part: it needs to be done in a way which ensures
   that composition will behave nicely (strictly associative etc) later -}
is-increasing : {m n : ℕ} → (Fin m → Fin n) → Type
is-increasing {m} {n} f = {j i : Fin m} → (j >fin i) → ((f j) >fin (f i))

infixr 1 _,_

record Σ (A : Type) (B : A → Type) : Type where
  constructor _,_
  field
    fst : A
    snd : B fst

{- Strictly increasing maps: these are the

   === MORPHISMS of Δ₊ ===

-}
_⇒+_ : ℕ → ℕ → Set
m ⇒+ n = Σ (Fin m → Fin n) is-increasing

_∘+_ : {l m n : ℕ} → (m ⇒+ n) → (l ⇒+ m) → (l ⇒+ n)
(g , p₂) ∘+ (f , p₁) = (λ i → g(f(i))) , (λ p → p₂ (p₁ p))

-- === IDENTITY MORPHISMS of Δ₊ ===

idΔ₊ : ∀ {n} → n ⇒+ n
idΔ₊ = (λ x → x) , (λ p → p)

{- Now, let us check that the categorical laws hold judgmentally.
   To do this, we use the usual notion of equality. -}

infix 3 _==_

data _==_ {A : Type} (a : A) : A → Type where
  idp : a == a

-- === IDENTITY LAWS ===

id-comp : ∀ {m n} → (f : m ⇒+ n) → (idΔ₊ ∘+ f) == f
id-comp f = idp

comp-id : ∀ {m n} → (f : m ⇒+ n) → (f ∘+ idΔ₊) == f
comp-id f = idp

-- === ASSOCIATIVITY LAW ===

comp-assoc : ∀ {i j m n} → (f : i ⇒+ j) → (g : j ⇒+ m) → (h : m ⇒+ n)
             → h ∘+ (g ∘+ f) == (h ∘+ g) ∘+ f
comp-assoc f g h = idp


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

open import Categories.Category

module Categories.Morphism.Duality {o ℓ e} (C : Category o ℓ e) where

open Category C

import Categories.Morphism as M
private
  module Op = M op
open M C

open import Categories.Morphism.Properties C

private
  variable
    A B X Y : Obj
    f g h : A ⇒ B

Mono⇒op-Epi : Mono f → Op.Epi f
Mono⇒op-Epi mono = mono

Epi⇒op-Mono : Epi f → Op.Mono f
Epi⇒op-Mono epi = epi

Iso⇒op-Iso : Iso f g → Op.Iso g f
Iso⇒op-Iso iso = record
  { isoˡ = isoˡ
  ; isoʳ = isoʳ
  }
  where open Iso iso

op-Iso⇒Iso : Op.Iso g f → Iso f g
op-Iso⇒Iso iso = record
  { isoˡ = isoˡ
  ; isoʳ = isoʳ
  }
  where open Op.Iso iso

≅⇒op-≅ : A ≅ B → A Op.≅ B
≅⇒op-≅ A≅B = record
  { from = to
  ; to   = from
  ; iso  = record -- I don't understand why Agda doesn't allow me to apply Iso⇒op-Iso
    { isoˡ = isoˡ
    ; isoʳ = isoʳ
    }
  }
  where open _≅_ A≅B

op-≅⇒≅ : A Op.≅ B → A ≅ B
op-≅⇒≅ A≅B = record
  { from = to
  ; to   = from
  ; iso  = record
    { isoˡ = isoˡ
    ; isoʳ = isoʳ
    }
  }
  where open Op._≅_ A≅B


module BBHeap.Equality {A : Set}(_≤_ : A → A → Set) where

open import BBHeap _≤_
open import Bound.Lower A
open import Bound.Lower.Order _≤_

data _≈_ {b b' : Bound} : BBHeap b → BBHeap b' → Set where
  ≈leaf : leaf {b} ≈ leaf {b'}
  ≈left : {x x' : A}{l r : BBHeap (val x)}{l' r' : BBHeap (val x')}
                   (b≤x : LeB b (val x))
                   (b'≤x' : LeB b' (val x'))
                   (l⋘r : l ⋘ r)
                   (l'⋘r' : l' ⋘ r')
                   → l ≈ l'
                   → r ≈ r'
                   → left b≤x l⋘r ≈ left b'≤x' l'⋘r'
  ≈right : {x x' : A}{l r : BBHeap (val x)}{l' r' : BBHeap (val x')}
                   (b≤x : LeB b (val x))
                   (b'≤x' : LeB b' (val x'))
                   (l⋙r : l ⋙ r)
                   (l'⋙r' : l' ⋙ r')
                   → l ≈ l'
                   → r ≈ r'
                   → right b≤x l⋙r ≈ right b'≤x' l'⋙r'


module Lib.Vec where

open import Common.Nat renaming (zero to Z; suc to S)
open import Lib.Fin
open import Common.Unit
import Common.List -- using (List ; [] ; _∷_)

data Vec (A : Set) :  Nat -> Set where
  _∷_ : forall {n} -> A -> Vec A n -> Vec A (S n)
  []   : Vec A Z

infixr 30 _++_

_++_ : {A : Set}{m n : Nat} -> Vec A m -> Vec A n -> Vec A (m + n)
[]        ++ ys = ys
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)

snoc : {A : Set}{n : Nat} -> Vec A n -> A -> Vec A (S n)
snoc []        e = e ∷ []
snoc (x ∷ xs) e = x ∷ snoc xs e

length : {A : Set}{n : Nat} -> Vec A n -> Nat
length [] = Z
length (x ∷ xs) = 1 + length xs

length' : {A : Set}{n : Nat} -> Vec A n -> Nat
length' {n = n} _ = n

zipWith3 : ∀ {A B C D n} -> (A -> B -> C -> D) -> Vec A n -> Vec B n -> Vec C n -> Vec D n
zipWith3 f []        []        []        = []
zipWith3 f (x ∷ xs) (y ∷ ys) (z ∷ zs) = f x y z ∷ zipWith3 f xs ys zs

zipWith : ∀ {A B C n} -> (A -> B -> C) -> Vec A n -> Vec B n -> {u : Unit} -> Vec C n
zipWith _ [] [] = []
zipWith f (x ∷ xs) (y ∷ ys) = f x y ∷ zipWith f xs ys {u = unit}

_!_ : ∀ {A n} -> Vec A n -> Fin n -> A
(x ∷ xs) ! fz = x
(_ ∷ xs) ! fs n = xs ! n
[] ! ()

_[_]=_ : {A : Set}{n : Nat} -> Vec A n -> Fin n -> A -> Vec A n
(a ∷ as) [ fz ]= e = e ∷ as
(a ∷ as) [ fs n ]= e = a ∷ (as [ n ]= e)
[] [ () ]= e

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

forgetL : {A : Set}{n : Nat} -> Vec A n -> Common.List.List A
forgetL [] = Common.List.[]
forgetL (x ∷ xs) = x Common.List.∷ forgetL xs

rem : {A : Set}(xs : Common.List.List A) -> Vec A (Common.List.length xs)
rem Common.List.[] = []
rem (x Common.List.∷ xs) = x ∷ rem xs


module Nat where

  import Prelude
  import Equiv
  import Datoid

  open Prelude
  open Equiv
  open Datoid

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

  one : Nat
  one = suc zero

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

  private
    eqNat : Nat -> Nat -> Bool
    eqNat zero    zero    = True
    eqNat (suc m) (suc n) = eqNat m n
    eqNat _       _       = False

    refl' : (x : Nat) -> T (eqNat x x)
    refl' zero    = unit
    refl' (suc n) = refl' n

    sym' : (x y : Nat) -> T (eqNat x y) -> T (eqNat y x)
    sym' zero     zero     _     = unit
    sym' (suc n1) (suc n2) eq    = sym' n1 n2 eq
    sym' (suc _)  zero     wrong = wrong
    sym' zero     (suc _)  wrong = wrong

    trans' : (x y z : Nat) -> T (eqNat x y) -> T (eqNat y z) -> T (eqNat x z)
    trans' zero     _        zero     _     _     = unit
    trans' (suc n1) (suc n2) (suc n3) eq12  eq23  = trans' n1 n2 n3 eq12 eq23
    trans' zero     (suc _)  _        wrong _     = absurdElim wrong
    trans' _        zero     (suc _)  _     wrong = absurdElim wrong
    trans' (suc _)  zero     _        wrong _     = absurdElim wrong
    trans' _        (suc _)  zero     _     wrong = absurdElim wrong

  decidableEquiv : DecidableEquiv Nat
  decidableEquiv = decEquiv (equiv (T' eqNat) refl' sym' trans')
                            (boolFunctionsDecidable eqNat)

  natDatoid : Datoid
  natDatoid = datoid Nat decidableEquiv


------------------------------------------------------------------------
-- Definitions of functions that generate list or vector
------------------------------------------------------------------------

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

module Math.Combinatorics.VecFunction where

-- agda-stdlib
open import Data.List
open import Data.List.NonEmpty as NE using (List⁺)
open import Data.Nat
import Data.Nat.Properties as ℕₚ
open import Data.Product as Prod using (_×_; _,_)
open import Data.Vec as Vec using (Vec; []; _∷_)
open import Function
open import Relation.Binary.PropositionalEquality hiding ([_])

-- agda-combinatorics
import Math.Combinatorics.ListFunction as ListFun

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

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

module _ {a} {A : Set a} where
  -- combinations
  combinations : ∀ k → List A → List (Vec A k)
  combinations 0       xs       = [ [] ]
  combinations (suc k) []       = []
  combinations (suc k) (x ∷ xs) =
    map (x ∷_) (combinations k xs) ++ combinations (suc k) xs

  combinationsWithComplement : ∀ m {n} → Vec A (m + n) →
                               List (Vec A m × Vec A n)
  combinationsWithComplement 0                 xs       = [ [] , xs ]
  combinationsWithComplement m@(suc _) {0}     xs       =
    [ subst (Vec A) (ℕₚ.+-identityʳ m) xs , [] ]
  combinationsWithComplement (suc m)   {suc n} (x ∷ xs) =
    map (Prod.map₁ (x ∷_)) (combinationsWithComplement m xs) ++
    map (Prod.map₂ (x ∷_)) (combinationsWithComplement (suc m) xs′)
      where xs′ = subst (Vec A) (ℕₚ.+-suc m n) xs

  splits₂ : ∀ {n} → Vec A n → Vec (List A × List A) (1 + n)
  splits₂ []           = ([] , []) ∷ []
  splits₂ xxs@(x ∷ xs) = ([] , Vec.toList xxs) ∷
                         Vec.map (Prod.map₁ (x ∷_)) (splits₂ xs)

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

  splits⁺₂ : ∀ {n} → Vec A (1 + n) → Vec (List⁺ A × List⁺ A) n
  splits⁺₂ (x ∷ [])     = []
  splits⁺₂ (x ∷ y ∷ xs) =
    (x NE.∷ [] , y NE.∷ Vec.toList xs) ∷
    Vec.map (Prod.map₁ (x NE.∷⁺_)) (splits⁺₂ (y ∷ xs))

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

  partitions : ∀ k → List A → List (Vec (List A) k)
  partitions 0       []       = [ [] ]
  partitions 0       (x ∷ xs) = []
  partitions (suc k) []       = []
  partitions (suc k) (x ∷ xs) =
    map ([ x ] ∷_) (partitions k xs) ++
    concatMap (Vec.toList ∘ applyEach (x ∷_)) (partitions (suc k) xs)


{-# OPTIONS --cubical-compatible #-}

data Bool : Set where
  true  : Bool
  false : Bool

data ℕ : Set where
  zero : ℕ
  suc  : (n : ℕ) → ℕ

data Fin : ℕ → Set where
  zero : {n : ℕ} → Fin (suc n)
  suc  : {n : ℕ} (i : Fin n) → Fin (suc n)

infixr 5 _∷_

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

infix 4 _[_]=_

data _[_]=_ {a} {A : Set a} :
            {n : ℕ} → Vec A n → Fin n → A → Set a where
  here  : ∀ {n}     {x}   {xs : Vec A n} → x ∷ xs [ zero ]= x
  there : ∀ {n} {i} {x y} {xs : Vec A n}
          (xs[i]=x : xs [ i ]= x) → y ∷ xs [ suc i ]= x

Subset : ℕ → Set
Subset = Vec Bool

infix 4 _∈_

_∈_ : ∀ {n} → Fin n → Subset n → Set
x ∈ p = p [ x ]= true

drop-there : ∀ {s n x} {p : Subset n} → suc x ∈ s ∷ p → x ∈ p
drop-there (there x∈p) = x∈p

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

data ⊥ : Set where

infix 3 ¬_

¬_ : ∀ {ℓ} → Set ℓ → Set ℓ
¬ P = P → ⊥

data Dec {p} (P : Set p) : Set p where
  yes : ( p :   P) → Dec P
  no  : (¬p : ¬ P) → Dec P

infix 4 _∈?_

_∈?_ : ∀ {n} x (p : Subset n) → Dec (x ∈ p)
zero  ∈? true  ∷ p = yes here
zero  ∈? false ∷ p = no  λ()
suc n ∈? s ∷ p       with n ∈? p
...                  | yes n∈p = yes (there n∈p)
...                  | no  n∉p = no  (n∉p ∘ drop-there)


module Logic where

data Bool : Set where
  true : Bool
  false : Bool

_∧_ : Bool → Bool → Bool
false ∧ _ = false
true ∧ b = b

_∨_ : Bool → Bool → Bool
true ∨ _ = true
false ∨ b = b


------------------------------------------------------------------------
-- List equality
------------------------------------------------------------------------

module Data.List.Equality where

open import Data.List
open import Relation.Nullary
open import Relation.Binary

module Equality (S : Setoid) where

  open Setoid S renaming (_≈_ to _≊_)

  infixr 5 _∷_
  infix  4 _≈_

  data _≈_ : List carrier → List carrier → Set where
    []  : [] ≈ []
    _∷_ : ∀ {x xs y ys} (x≈y : x ≊ y) (xs≈ys : xs ≈ ys) →
          x ∷ xs ≈ y ∷ ys

  setoid : Setoid
  setoid = record
    { carrier = List carrier
    ; _≈_     = _≈_
    ; isEquivalence = record
      { refl  = refl'
      ; sym   = sym'
      ; trans = trans'
      }
    }
    where
    refl' : Reflexive _≈_
    refl' {[]}     = []
    refl' {x ∷ xs} = refl ∷ refl' {xs}

    sym' : Symmetric _≈_
    sym' []            = []
    sym' (x≈y ∷ xs≈ys) = sym x≈y ∷ sym' xs≈ys

    trans' : Transitive _≈_
    trans' []            []            = []
    trans' (x≈y ∷ xs≈ys) (y≈z ∷ ys≈zs) =
      trans x≈y y≈z ∷ trans' xs≈ys ys≈zs

  open Setoid setoid public hiding (_≈_)

module DecidableEquality (D : DecSetoid) where

  open DecSetoid D hiding (_≈_)
  open Equality setoid renaming (setoid to List-setoid)

  decSetoid : DecSetoid
  decSetoid = record
    { isDecEquivalence = record
      { isEquivalence = Setoid.isEquivalence List-setoid
      ; _≟_           = dec
      }
    }
    where
    dec : Decidable _≈_
    dec []       []       = yes []
    dec (x ∷ xs) (y ∷ ys) with x ≟ y | dec xs ys
    ... | yes x≈y | yes xs≈ys = yes (x≈y ∷ xs≈ys)
    ... | no ¬x≈y | _         = no helper
      where
      helper : ¬ _≈_ (x ∷ xs) (y ∷ ys)
      helper (x≈y ∷ _) = ¬x≈y x≈y
    ... | _       | no ¬xs≈ys = no helper
      where
      helper : ¬ _≈_ (x ∷ xs) (y ∷ ys)
      helper (_ ∷ xs≈ys) = ¬xs≈ys xs≈ys
    dec []       (y ∷ ys) = no λ()
    dec (x ∷ xs) []       = no λ()

  open DecSetoid decSetoid public

module PropositionalEquality {A : Set} where

  open import Relation.Binary.PropositionalEquality as PropEq
    using (_≡_) renaming (refl to ≡-refl)
  open Equality (PropEq.setoid A) public

  ≈⇒≡ : _≈_ ⇒ _≡_
  ≈⇒≡ []               = ≡-refl
  ≈⇒≡ (≡-refl ∷ xs≈ys) with ≈⇒≡ xs≈ys
  ≈⇒≡ (≡-refl ∷ xs≈ys) | ≡-refl = ≡-refl


module half where

open import Relation.Binary.PropositionalEquality using (_≡_ ; refl)
open import Size

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

{-# BUILTIN NATURAL ℕ #-}

half : ℕ → ℕ
half zero = zero
half (suc zero) = zero
half (suc (suc i)) = suc (half i)

_ : half 5 ≡ 2
_ = refl

data ℕₛ (n : Size) : Set where
  zero : ℕₛ n
  suc : (m : Size< n) → ℕₛ m → ℕₛ n

_ : ∀ {n} → ℕₛ n
_ = zero

_ : ∀ {n} (m : Size< n) → ℕₛ m → ℕₛ n
_ = suc

halfₛ : ∀ n → ℕₛ n → ℕₛ n
halfₛ n zero = zero
halfₛ n (suc m zero) = zero
halfₛ n (suc m (suc k i)) = suc k (halfₛ k i)


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

open import Data.Nat        using (ℕ; zero; suc; _+_; _*_; _≤_ ; _>_; _<_; _≥_; z≤n; s≤s)
open import Data.Sum        using (_⊎_; inj₁; inj₂)

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

module Nat where

-- Useful functions for natural numbers

_-_ : (n m : ℕ) → {m ≤ n} → ℕ
(n     - zero)  {z≤n}   = n
(suc n - suc m) {s≤s p} = _-_ n m {p}

_-_⟨_⟩ : (n m : ℕ) → (m ≤ n) → ℕ
_-_⟨_⟩ n m m≤n = _-_ n m {m≤n}

m+n-m=n : (m n : ℕ) → {m≤n : m ≤ n} → m + (n - m ⟨ m≤n ⟩) ≡ n
m+n-m=n zero    n       {z≤n}     = refl
m+n-m=n (suc m) (suc n) {s≤s m≤n} = cong suc (m+n-m=n m n {m≤n})

<-∨-≥ : (m n : ℕ) → m < n ⊎ m ≥ n
<-∨-≥ zero    zero    = inj₂ z≤n
<-∨-≥ zero    (suc n) = inj₁ (s≤s z≤n)
<-∨-≥ (suc m) zero    = inj₂ z≤n
<-∨-≥ (suc m) (suc n) with <-∨-≥ m n
... | inj₁ m<n = inj₁ (s≤s m<n)
... | inj₂ m≥n = inj₂ (s≤s m≥n)


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

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

module Boolean.Lemmas where

notNot : (x : Bool) → not (not x) ≡ x
notNot BoolTrue = refl
notNot BoolFalse = refl

notXor : (x y : Bool) → not (xor x y) ≡ xor (not x) y
notXor BoolTrue BoolTrue = refl
notXor BoolTrue BoolFalse = refl
notXor BoolFalse BoolTrue = refl
notXor BoolFalse BoolFalse = refl


open import Data.Nat using (ℕ; zero; suc)
open import Data.Bool using (Bool; true; false)

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

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

mutual
  data even′ : ℕ → Set where
    zero : even′ zero
    suc : ∀ {n : ℕ} → odd′ n → even′ (suc n)
  data odd′ : ℕ → Set where
    suc : ∀ {n : ℕ} → even′ n → odd′ (suc n)

{-
/Users/wadler/sf/src/extra/Mutual.agda:3,6-10
Missing definition for even
-}


module Type.Properties.Singleton {ℓ ℓₑ} where

import      Lvl
open import Lang.Instance
open import Structure.Setoid
open import Type

-- A type is a singleton type when it has exactly one inhabitant (there is only one object with this type).
-- In other words: There is an unique inhabitant of type T.
-- Also called:
-- • "singleton type"
-- • "unit type"
-- • "contractible"
record IsUnit (T : Type{ℓ}) ⦃ _ : Equiv{ℓₑ}(T) ⦄ : Type{ℓ Lvl.⊔ ℓₑ} where
  constructor intro
  field
    unit : T
    uniqueness : ∀{x : T} → (x ≡ unit)
open IsUnit ⦃ ... ⦄ using (unit)


------------------------------------------------------------------------
-- Simple regular expression matcher
------------------------------------------------------------------------

open import Eq
open import Setoids
open import Prelude
import RegExps

module SimpleMatcher (D : Datoid) where

private
  open module D' = Datoid D
  open module S' = Setoid setoid
  open module R  = RegExps setoid

infix 4 _∈‿⟦_⟧¿

------------------------------------------------------------------------
-- A lemma

private

  lemma : forall {a x xs₂}
    -> (xs₁ : [ a ]) -> (xs₁ ++ x ∷ []) ++ xs₂ ≡ xs₁ ++ x ∷ xs₂
  lemma []       = refl
  lemma (x ∷ xs) = cong (\ys -> x ∷ ys) (lemma xs)

------------------------------------------------------------------------
-- Regular expression matcher

-- The type of _∈‿⟦_⟧¿ documents its soundness (assuming that the code
-- is terminating). To prove completeness more work is necessary.

matches-⊙¿ : forall xs₁ xs₂ re₁ re₂
             -> Maybe (xs₁ ++ xs₂ ∈‿⟦ re₁ ⊙ re₂ ⟧)

_∈‿⟦_⟧¿ : (xs : [ carrier ]) -> (re : RegExp) -> Maybe (xs ∈‿⟦ re ⟧)
[]     ∈‿⟦ ε ⟧¿         = just matches-ε
_ ∷ [] ∈‿⟦ • ⟧¿         = just matches-•
x ∷ [] ∈‿⟦ sym y ⟧¿     with x ≟ y
x ∷ [] ∈‿⟦ sym y ⟧¿     | yes eq = just (matches-sym eq)
x ∷ [] ∈‿⟦ sym y ⟧¿     | no _   = nothing
xs     ∈‿⟦ re₁ ∣ re₂ ⟧¿ with xs ∈‿⟦ re₁ ⟧¿
xs     ∈‿⟦ re₁ ∣ re₂ ⟧¿ | just m  = just (matches-∣ˡ m)
xs     ∈‿⟦ re₁ ∣ re₂ ⟧¿ | nothing with xs ∈‿⟦ re₂ ⟧¿
xs     ∈‿⟦ re₁ ∣ re₂ ⟧¿ | nothing | just m  = just (matches-∣ʳ m)
xs     ∈‿⟦ re₁ ∣ re₂ ⟧¿ | nothing | nothing = nothing
xs     ∈‿⟦ re₁ ⊙ re₂ ⟧¿ = matches-⊙¿ [] xs re₁ re₂
[]     ∈‿⟦ re ⋆ ⟧¿      = just (matches-⋆ (matches-∣ˡ matches-ε))
x ∷ xs ∈‿⟦ re ⋆ ⟧¿      with matches-⊙¿ (x ∷ []) xs re (re ⋆)
x ∷ xs ∈‿⟦ re ⋆ ⟧¿      | just m  = just (matches-⋆ (matches-∣ʳ m))
x ∷ xs ∈‿⟦ re ⋆ ⟧¿      | nothing = nothing
_      ∈‿⟦ _ ⟧¿         = nothing

matches-⊙¿ xs₁ xs₂ re₁ re₂ with xs₁ ∈‿⟦ re₁ ⟧¿ | xs₂ ∈‿⟦ re₂ ⟧¿
matches-⊙¿ xs₁ xs₂ re₁ re₂ | just m₁ | just m₂ = just (matches-⊙ m₁ m₂)
matches-⊙¿ xs₁ [] re₁ re₂ | _ | _ = nothing
matches-⊙¿ xs₁ (x ∷ xs₂) re₁ re₂ | _ | _ =
  subst (\xs -> Maybe (xs ∈‿⟦ re₁ ⊙ re₂ ⟧))
        (lemma xs₁)
        (matches-⊙¿ (xs₁ ++ x ∷ []) xs₂ re₁ re₂)


open import FRP.JS.Time.Core using ( Time )

module FRP.JS.RSet where

infixr 1 _⇒_

RSet : Set₁
RSet = Time → Set

_⇒_ : RSet → RSet → RSet
(A ⇒ B) t = A t → B t

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

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