module CombinatoryLogic.Semantics where

open import Relation.Binary using (Rel)

open import CombinatoryLogic.Syntax

-- Kapitel 1, Abschnitt C, §5 (Axiome)
data Axiom : Combinator → Set where
  Q : Axiom (Π ∙ (W ∙ (C ∙ Q)))
  B : Axiom (C ∙ (B ∙ B ∙ (B ∙ B ∙ B)) ∙ B == B ∙ (B ∙ B) ∙ B)
  C : Axiom (C ∙ (B ∙ B ∙ (B ∙ B ∙ B)) ∙ W ∙ C == B ∙ (B ∙ C) ∙ (B ∙ B ∙ B))
  W : Axiom (C ∙ (B ∙ B ∙ B) ∙ W == B ∙ (B ∙ W) ∙ (B ∙ B ∙ B))
  -- NOTE (Curry): this axiom can be proved from the others.
  I₁ : Axiom (C ∙ (B ∙ B ∙ B) ∙ K == B ∙ (B ∙ K) ∙ I)
  BC : Axiom (B ∙ B ∙ C == B ∙ (B ∙ (B ∙ C) ∙ C) ∙ (B ∙ B))
  BW : Axiom (B ∙ B ∙ W == B ∙ (B ∙ (B ∙ (B ∙ (B ∙ W) ∙ W) ∙ (B ∙ C)) ∙ B ∙ (B ∙ B)) ∙ B)
  BK : Axiom (B ∙ B ∙ K == B ∙ K ∙ K)
  CC₁ : Axiom (B ∙ C ∙ C ∙ B ∙ (B ∙ I))
  CC₂ : Axiom (B ∙ (B ∙ (B ∙ C) ∙ C) ∙ (B ∙ C) == B ∙ (B ∙ C ∙ (B ∙ C)) ∙ C)
  CW : Axiom (B ∙ C ∙ W == B ∙ (B ∙ (B ∙ W) ∙ C) ∙ (B ∙ C))
  CK : Axiom (B ∙ C ∙ K == B ∙ K)
  WC : Axiom (B ∙ W ∙ C == W)
  WW : Axiom (B ∙ W ∙ W == B ∙ W ∙ (B ∙ W))
  WK : Axiom (B ∙ W ∙ K == B ∙ I)
  I₂ : Axiom (B ∙ I == I)

-- Kapitel 1, Abschnitt C, §4 (Symbolische Festsetzungen), Festsetzung 1
infix 4 ⊢_
data ⊢_ : Combinator → Set where
  ax : ∀ {X} → Axiom X → ⊢ X

  -- Kapitel 1, Abschnitt C, §6 (Regeln)
  Q₁ : ∀ {X Y} → ⊢ X → ⊢ X == Y → ⊢ Y
  Q₂ : ∀ {X Y Z} → ⊢ X == Y → ⊢ Z ∙ X == Z ∙ Y
  Π : ∀ {X Y} → ⊢ Π ∙ X → ⊢ X ∙ Y
  B : ∀ {X Y Z} → ⊢ B ∙ X ∙ Y ∙ Z == X ∙ (Y ∙ Z)
  C : ∀ {X Y Z} → ⊢ C ∙ X ∙ Y ∙ Z == X ∙ Z ∙ Y
  W : ∀ {X Y} → ⊢ W ∙ X ∙ Y == X ∙ Y ∙ Y
  K : ∀ {X Y} → ⊢ K ∙ X ∙ Y == X
  P : ∀ {X Y} → ⊢ X → ⊢ P ∙ X ∙ Y → ⊢ Y
  ∧ : ∀ {X Y} → ⊢ X → ⊢ Y → ⊢ ∧ ∙ X ∙ Y

-- We introduce convenience notation for the equality defined in Kapitel 1,
-- Abschnitt C, §4 (Symbolische Festsetzungen), Festsetzung 3 (Gleichheit).
_≈_ : Rel Combinator _
X ≈ Y = ⊢ X == Y

infix 0 _[_]

-- An operator that helps write proofs in the style of Curry. Where Curry writes
--   ⟨statement⟩ (⟨rule⟩)
-- we write
--   ⟨statement⟩ [ ⟨rule⟩ ]
--
-- Later, we can also use the Agda standard library's reasoning combinators
-- (e.g. _≈⟨_⟩_) for proving equalities, but not before it is shown that the
-- equality _≈_ is an equivalence relation, which Curry does in propositions 1,
-- 2 and 3 of Kapitel 1, Abschnitt D (Die Eigenschaften der Gleichheit).
_[_] : ∀ {a} (A : Set a) (x : A) → A
_ [ x ] = x


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

-- Monoidal natural transformations between lax and strong symmetric
-- monoidal functors.
--
-- NOTE. Symmetric monoidal natural transformations are really just
-- monoidal natural transformations that happen to go between
-- symmetric monoidal functors.  No additional conditions are
-- necessary.  Nevertheless, the definitions in this module are useful
-- when one is working in a symmetric monoidal setting.  They also
-- help Agda's type checker by bundling the (symmetric monoidal)
-- categories and functors involved.
--
-- See
--  * John Baez, Some definitions everyone should know,
--    https://math.ucr.edu/home/baez/qg-fall2004/definitions.pdf
--  * https://ncatlab.org/nlab/show/monoidal+natural+transformation

module Categories.NaturalTransformation.Monoidal.Symmetric where

open import Level

open import Categories.Category.Monoidal using (SymmetricMonoidalCategory)
import Categories.Functor.Monoidal.Symmetric as BMF
open import Categories.Functor.Monoidal.Properties using ()
  renaming (∘-SymmetricMonoidal to _∘Fˡ_; ∘-StrongSymmetricMonoidal to _∘Fˢ_)
open import Categories.NaturalTransformation as NT using (NaturalTransformation)
import Categories.NaturalTransformation.Monoidal as MNT

module Lax where
  open BMF.Lax using (SymmetricMonoidalFunctor)
  open MNT.Lax using (IsMonoidalNaturalTransformation)
  open SymmetricMonoidalFunctor using ()
    renaming (F to UF; monoidalFunctor to MF)

  module _ {o ℓ e o′ ℓ′ e′}
           {C : SymmetricMonoidalCategory o ℓ e}
           {D : SymmetricMonoidalCategory o′ ℓ′ e′} where

    -- Monoidal natural transformations between symmetric monoidal functors.

    record SymmetricMonoidalNaturalTransformation
           (F G : SymmetricMonoidalFunctor C D) : Set (o ⊔ ℓ ⊔ ℓ′ ⊔ e′) where

      field
        U          : NaturalTransformation (UF F) (UF G)
        isMonoidal : IsMonoidalNaturalTransformation (MF F) (MF G) U

      open NaturalTransformation           U          public
      open IsMonoidalNaturalTransformation isMonoidal public

  -- To shorten some definitions

  private
    _⇛_ = SymmetricMonoidalNaturalTransformation
    module U = MNT.Lax

  module _ {o ℓ e o′ ℓ′ e′}
           {C : SymmetricMonoidalCategory o ℓ e}
           {D : SymmetricMonoidalCategory o′ ℓ′ e′} where

    -- Conversions

    ⌊_⌋ : {F G : SymmetricMonoidalFunctor C D} →
          F ⇛ G → U.MonoidalNaturalTransformation (MF F) (MF G)
    ⌊ α ⌋ = record { U = U ; isMonoidal = isMonoidal }
      where open SymmetricMonoidalNaturalTransformation α

    ⌈_⌉ : {F G : SymmetricMonoidalFunctor C D} →
          U.MonoidalNaturalTransformation (MF F) (MF G) → F ⇛ G
    ⌈ α ⌉ = record { U = U ; isMonoidal = isMonoidal }
      where open U.MonoidalNaturalTransformation α

    -- Identity and compositions

    infixr 9 _∘ᵥ_

    id : {F : SymmetricMonoidalFunctor C D} → F ⇛ F
    id = ⌈ U.id ⌉

    _∘ᵥ_ : {F G H : SymmetricMonoidalFunctor C D} → G ⇛ H → F ⇛ G → F ⇛ H
    α ∘ᵥ β   = ⌈ ⌊ α ⌋ U.∘ᵥ ⌊ β ⌋ ⌉

  module _ {o ℓ e o′ ℓ′ e′ o″ ℓ″ e″}
           {C : SymmetricMonoidalCategory o ℓ e}
           {D : SymmetricMonoidalCategory o′ ℓ′ e′}
           {E : SymmetricMonoidalCategory o″ ℓ″ e″} where

    infixr 9 _∘ₕ_ _∘ˡ_ _∘ʳ_

    _∘ₕ_ : {F G : SymmetricMonoidalFunctor C D}
           {H I : SymmetricMonoidalFunctor D E} →
           H ⇛ I → F ⇛ G → (H ∘Fˡ F) ⇛ (I ∘Fˡ G)
    α ∘ₕ β = ⌈ ⌊ α ⌋ U.∘ₕ ⌊ β ⌋ ⌉

    _∘ˡ_ : {F G : SymmetricMonoidalFunctor C D}
           (H : SymmetricMonoidalFunctor D E) → F ⇛ G → (H ∘Fˡ F) ⇛ (H ∘Fˡ G)
    H ∘ˡ α = id {F = H} ∘ₕ α

    _∘ʳ_ : {G H : SymmetricMonoidalFunctor D E} →
           G ⇛ H → (F : SymmetricMonoidalFunctor C D) → (G ∘Fˡ F) ⇛ (H ∘Fˡ F)
    α ∘ʳ F = α ∘ₕ id {F = F}

module Strong where
  open BMF.Strong using (SymmetricMonoidalFunctor)
  open MNT.Strong using (IsMonoidalNaturalTransformation)
  open SymmetricMonoidalFunctor using () renaming
    ( F                         to UF
    ; monoidalFunctor           to MF
    ; laxSymmetricMonoidalFunctor to laxBMF
    )

  module _ {o ℓ e o′ ℓ′ e′}
           {C : SymmetricMonoidalCategory o ℓ e}
           {D : SymmetricMonoidalCategory o′ ℓ′ e′} where

    -- Monoidal natural transformations between symmetric strong
    -- monoidal functors.

    record SymmetricMonoidalNaturalTransformation
           (F G : SymmetricMonoidalFunctor C D) : Set (o ⊔ ℓ ⊔ ℓ′ ⊔ e′) where

      field
        U          : NaturalTransformation (UF F) (UF G)
        isMonoidal : IsMonoidalNaturalTransformation (MF F) (MF G) U

      laxBNT : Lax.SymmetricMonoidalNaturalTransformation (laxBMF F) (laxBMF G)
      laxBNT = record { U = U ; isMonoidal = isMonoidal }
      open Lax.SymmetricMonoidalNaturalTransformation laxBNT public
        hiding (U; isMonoidal)

  -- To shorten some definitions

  private
    _⇛_ = SymmetricMonoidalNaturalTransformation
    module U = MNT.Strong

  module _ {o ℓ e o′ ℓ′ e′}
           {C : SymmetricMonoidalCategory o ℓ e}
           {D : SymmetricMonoidalCategory o′ ℓ′ e′} where

    -- Conversions

    ⌊_⌋ : {F G : SymmetricMonoidalFunctor C D} →
          F ⇛ G → U.MonoidalNaturalTransformation (MF F) (MF G)
    ⌊ α ⌋ = record { U = U ; isMonoidal = isMonoidal }
      where open SymmetricMonoidalNaturalTransformation α

    ⌈_⌉ : {F G : SymmetricMonoidalFunctor C D} →
          U.MonoidalNaturalTransformation (MF F) (MF G) → F ⇛ G
    ⌈ α ⌉ = record { U = U ; isMonoidal = isMonoidal }
      where open U.MonoidalNaturalTransformation α

    -- Identity and compositions

    infixr 9 _∘ᵥ_

    id : {F : SymmetricMonoidalFunctor C D} → F ⇛ F
    id = ⌈ U.id ⌉

    _∘ᵥ_ : {F G H : SymmetricMonoidalFunctor C D} → G ⇛ H → F ⇛ G → F ⇛ H
    α ∘ᵥ β   = ⌈ ⌊ α ⌋ U.∘ᵥ ⌊ β ⌋ ⌉

  module _ {o ℓ e o′ ℓ′ e′ o″ ℓ″ e″}
           {C : SymmetricMonoidalCategory o ℓ e}
           {D : SymmetricMonoidalCategory o′ ℓ′ e′}
           {E : SymmetricMonoidalCategory o″ ℓ″ e″} where

    infixr 9 _∘ₕ_ _∘ˡ_ _∘ʳ_

    _∘ₕ_ : {F G : SymmetricMonoidalFunctor C D}
           {H I : SymmetricMonoidalFunctor D E} →
           H ⇛ I → F ⇛ G → (H ∘Fˢ F) ⇛ (I ∘Fˢ G)
    -- NOTE: this definition is clearly equivalent to
    --
    --   α ∘ₕ β = ⌈ ⌊ α ⌋ U.∘ₕ ⌊ β ⌋ ⌉
    --
    -- but the latter takes an unreasonably long time to typecheck,
    -- while the unfolded version typechecks almost immediately.
    α ∘ₕ β = record
      { U               = C.U
      ; isMonoidal      = record
        { ε-compat      = C.ε-compat
        ; ⊗-homo-compat = C.⊗-homo-compat
        }
      }
      where module C = U.MonoidalNaturalTransformation (⌊ α ⌋ U.∘ₕ ⌊ β ⌋)

    _∘ˡ_ : {F G : SymmetricMonoidalFunctor C D}
           (H : SymmetricMonoidalFunctor D E) → F ⇛ G → (H ∘Fˢ F) ⇛ (H ∘Fˢ G)
    H ∘ˡ α = id {F = H} ∘ₕ α

    _∘ʳ_ : {G H : SymmetricMonoidalFunctor D E} →
           G ⇛ H → (F : SymmetricMonoidalFunctor C D) → (G ∘Fˢ F) ⇛ (H ∘Fˢ F)
    α ∘ʳ F = α ∘ₕ id {F = F}


module AbstractInterfaces where

open import Prelude public

-- Process identifiers.

record IsProc : Set₁ where
  field
    Proc    : Set
    _≡ₚ?_   : Decidable (_≡_ {A = Proc})
    _<ₚ_    : Proc → Proc → Set
    trans<ₚ : Transitive _<ₚ_
    tri<ₚ   : Trichotomous _≡_ _<ₚ_

  _≮ₚ_ : Proc → Proc → Set
  P ≮ₚ P′ = ¬ (P <ₚ P′)

open IsProc {{…}} public

-- Process clocks, message timestamps, and event timestamps.

record IsTime : Set₁ where
  field
    Time      : Set
    _≡ₜ?_     : Decidable (_≡_ {A = Time})
    _<ₜ_      : Time → Time → Set
    trans<ₜ   : Transitive _<ₜ_
    tri<ₜ     : Trichotomous _≡_ _<ₜ_
    irrefl<ₜ  : Irreflexive _<ₜ_
    sucₜ      : Time → Time
    _⊔ₜ_      : Time → Time → Time
    n<s[n⊔m]ₜ : ∀ T T′ → T <ₜ sucₜ (T ⊔ₜ T′)

  _≮ₜ_ : Time → Time → Set
  T ≮ₜ T′ = ¬ (T <ₜ T′)

open IsTime {{…}} public

-- Messages.

record IsMsg {{_ : IsProc}} {{_ : IsTime}} : Set₁ where
  field
    Msg : (Pᵢ Pⱼ : Proc) (Tₘ : Time) → Set

open IsMsg {{…}} public

-- Events within one process.

record IsEvent {{_ : IsProc}} {{_ : IsTime}} {{_ : IsMsg}} : Set₁ where
  field
    Event   : Proc → Time → Set

    isSendₑ : ∀ {Cᵢ Pᵢ Pⱼ Tₘ} {{_ : Tₘ ≡ sucₜ Cᵢ}} →
              Msg Pᵢ Pⱼ Tₘ → Event Pᵢ Tₘ → Set

    isRecvₑ : ∀ {Cⱼ Pᵢ Pⱼ Tₘ Tⱼ} {{_ : Tⱼ ≡ sucₜ (Tₘ ⊔ₜ Cⱼ)}} →
              Msg Pᵢ Pⱼ Tₘ → Event Pⱼ Tⱼ → Set

    absurdₑ : ∀ {Cᵢ Cⱼ P T} {m : Msg P P T} {a : Event P T} →
              {{_ : T ≡ sucₜ Cᵢ}} {{_ : T ≡ sucₜ (T ⊔ₜ Cⱼ)}} →
              ¬ (isSendₑ {Cᵢ} m a × isRecvₑ {Cⱼ} m a)

open IsEvent {{…}} public


open import Relation.Nullary.Decidable using (False)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; sym; cong; module ≡-Reasoning)

open import Data.List using (List)
open List
open import Data.Unit using (tt)

module AKS.Binary.Base where

open import Polynomial.Simple.AlmostCommutativeRing using (AlmostCommutativeRing)
open import Polynomial.Simple.AlmostCommutativeRing.Instances using (module Nat)
open Nat.Reflection using (∀⟨_⟩)

open import AKS.Nat using (ℕ; _+_; _*_; _≟_; _<_; lte; suc-mono-≤)
open ℕ
open import AKS.Nat using (ℕ⁺; ℕ+; ⟅_⇑⟆)
open import AKS.Nat using (Euclidean; Euclidean✓; _div_)
open import AKS.Nat using (Acc; acc; <-well-founded)

2* : ℕ → ℕ
2* n = n + n

infixl 5 _0ᵇ _1ᵇ
data 𝔹⁺ : Set where
  𝕓1ᵇ : 𝔹⁺
  _0ᵇ _1ᵇ : 𝔹⁺ → 𝔹⁺

infixr 4 +_
data 𝔹 : Set where
  𝕓0ᵇ : 𝔹
  +_ : 𝔹⁺ → 𝔹

⟦_⇓⟧⁺ : 𝔹⁺ → ℕ
⟦ 𝕓1ᵇ  ⇓⟧⁺ = 1
⟦ x 0ᵇ ⇓⟧⁺ = 2* ⟦ x ⇓⟧⁺
⟦ x 1ᵇ ⇓⟧⁺ = 1 + 2* ⟦ x ⇓⟧⁺

⟦_⇓⟧ : 𝔹 → ℕ
⟦ 𝕓0ᵇ ⇓⟧ = 0
⟦ + x ⇓⟧ = ⟦ x ⇓⟧⁺

private
  lemma₁ : ∀ {q} → suc q < suc (q + suc (q + zero))
  lemma₁ {q} = lte q (∀⟨ q ∷ [] ⟩)
  lemma₂ : ∀ {q} → suc q < suc (suc (q + suc (q + zero)))
  lemma₂ {q} = lte (suc q) (∀⟨ q ∷ [] ⟩)

⟦_⇑_⟧ʰ : ∀ n → Acc _<_ n → ∀ {≢0 : False (n ≟ 0)} → 𝔹⁺
⟦ suc n ⇑ acc downward ⟧ʰ with suc n div 2
... | Euclidean✓ (suc q) 0 refl r<m = ⟦ suc q ⇑ downward lemma₁ ⟧ʰ 0ᵇ
... | Euclidean✓ zero 1 refl r<m = 𝕓1ᵇ
... | Euclidean✓ (suc q) 1 refl r<m = ⟦ suc q ⇑ downward lemma₂ ⟧ʰ 1ᵇ

⟦_⇑⟧⁺ : ℕ⁺ → 𝔹⁺
⟦ ℕ+ n ⇑⟧⁺ = ⟦ suc n ⇑ <-well-founded ⟧ʰ

⟦_⇑⟧ : ℕ → 𝔹
⟦ zero ⇑⟧ = 𝕓0ᵇ
⟦ suc n ⇑⟧ = + ⟦ ℕ+ n ⇑⟧⁺

ℕ→𝔹→ℕ : ∀ n → ⟦ ⟦ n ⇑⟧ ⇓⟧ ≡ n
ℕ→𝔹→ℕ zero = refl
ℕ→𝔹→ℕ (suc n) = ℕ⁺→𝔹⁺→ℕ (suc n) <-well-founded
  where
  ℕ⁺→𝔹⁺→ℕ : ∀ (n : ℕ) (rec : Acc _<_ n) {≢0 : False (n ≟ 0)} → ⟦ ⟦ n ⇑ rec ⟧ʰ {≢0} ⇓⟧⁺ ≡ n
  ℕ⁺→𝔹⁺→ℕ (suc n) (acc downward) with suc n div 2
  ... | Euclidean✓ (suc q) 0 refl r<m rewrite ℕ⁺→𝔹⁺→ℕ (suc q) (downward lemma₁) {tt} = ∀⟨ q ∷ [] ⟩
  ... | Euclidean✓ zero 1 refl r<m = refl
  ... | Euclidean✓ (suc q) 1 refl r<m rewrite ℕ⁺→𝔹⁺→ℕ (suc q) (downward lemma₂) {tt} = ∀⟨ q ∷ [] ⟩

⌈log₂_⌉⁺ : 𝔹⁺ → ℕ
⌈log₂ 𝕓1ᵇ ⌉⁺ = 1
⌈log₂ (b 0ᵇ) ⌉⁺ = 1 + ⌈log₂ b ⌉⁺
⌈log₂ (b 1ᵇ) ⌉⁺ = 1 + ⌈log₂ b ⌉⁺

⌈log₂_⌉ : 𝔹 → ℕ
⌈log₂ 𝕓0ᵇ ⌉ = 0
⌈log₂ + b ⌉ = ⌈log₂ b ⌉⁺

⌊_/2⌋⁺ : 𝔹⁺ → 𝔹⁺
⌊ 𝕓1ᵇ /2⌋⁺ = 𝕓1ᵇ
⌊ b 0ᵇ /2⌋⁺ = b
⌊ b 1ᵇ /2⌋⁺ = b

⌊_/2⌋ : 𝔹 → 𝔹
⌊ 𝕓0ᵇ /2⌋ = 𝕓0ᵇ
⌊ + b /2⌋ = + ⌊ b /2⌋⁺

-- _+ᵇ_ : 𝔹 → 𝔹 → 𝔹
-- n +ᵇ m = ⟦ ⟦ n ⇓⟧ + ⟦ m ⇓⟧ ⇑⟧

-- -- data Bit : Set where
-- --   0𝑏 : Bit
-- --   1𝑏 : Bit

-- -- _+ᵇ⁺_ : 𝔹⁺ → 𝔹⁺ → 𝔹⁺
-- -- n +ᵇ⁺ m = ⟦ ⟦ n ⇓⟧⁺ ⇑⟧⁺
--   -- where
--   -- loop : Bit → 𝔹⁺ → 𝔹⁺ → 𝔹⁺
--   -- loop carry x y = ?

-- -- unique⁺ : ∀ x y → ⟦ x ⇓⟧⁺ ≡ ⟦ y ⇓⟧⁺ → x ≡ y
-- -- unique⁺ 1ᵇ 1ᵇ p = refl
-- -- unique⁺ 1ᵇ (y 0ᵇ) p = {!!}
-- -- unique⁺ 1ᵇ (y 1ᵇ) p = {!!}
-- -- unique⁺ (x 0ᵇ) 1ᵇ p = {!!}
-- -- unique⁺ (x 0ᵇ) (y 0ᵇ) p = {!!}
-- -- unique⁺ (x 0ᵇ) (y 1ᵇ) p = {!!}
-- -- unique⁺ (x 1ᵇ) y p = {!!}

-- -- unique : ∀ x y → ⟦ x ⇓⟧ ≡ ⟦ y ⇓⟧ → x ≡ y
-- -- unique 𝕓0ᵇ 𝕓0ᵇ p = refl
-- -- unique 𝕓0ᵇ (𝕓 y) p = {!!}
-- -- unique (𝕓 x) 𝕓0ᵇ p = {!!}
-- -- unique (𝕓 x) (𝕓 y) p = {!!}

module Test where
  eval-unit₁ : ⟦ + 𝕓1ᵇ 0ᵇ 1ᵇ 0ᵇ ⇓⟧ ≡ 10
  eval-unit₁ = refl

  log-unit₁ : ⌈log₂ ⟦ 15 ⇑⟧ ⌉ ≡ 4
  log-unit₁ = refl


{-# OPTIONS --cubical-compatible #-}
open import Common.Prelude
open import Common.Equality

KNat : {x : Nat} (e : x ≡ x) → e ≡ refl
KNat refl = refl

KEqNat : {x : Nat} {e : x ≡ x} (p : e ≡ e) → p ≡ refl
KEqNat refl = refl

KListNat : {x : List Nat} (e : x ≡ x) → e ≡ refl
KListNat refl = refl

data D (A : Set) : Nat → Set where
  c : (x : A)(y : Nat) → D A y

-- Jesper 2015-12-18: this test case doesn't work yet with the new unifier
-- We need generalization of indices when applying the injectivity rule
--test : {A : Set} {x₁ x₂ : A} {y : Nat} → c x₁ y ≡ c x₂ y → Set
--test refl = Nat


{-# OPTIONS --copatterns --sized-types #-}

open import Size
open import Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P
open ≡-Reasoning

open import Algebra.Structures using (IsCommutativeSemiring; IsCommutativeMonoid)

open import Data.Nat
open import Data.Nat.Properties using (isCommutativeSemiring)
open import Stream
open ∼ˢ∞-Reasoning

⟦_⟧ : ℕ → Str ℕ
hd (⟦ n ⟧) = n
tl (⟦ n ⟧) = ⟦ 0 ⟧

_⊕_ : ∀{i} → Str {i} ℕ → Str {i} ℕ → Str {i} ℕ
hd (s ⊕ t) = (hd s) + (hd t)
tl (s ⊕ t) = (tl s) ⊕ (tl t)

_×_ : ∀{i} → Str {i} ℕ → Str {i} ℕ → Str {i} ℕ
hd (s × t) = hd s * hd t
tl (s × t)= ((tl s) × t) ⊕ (⟦ hd s ⟧ × (tl t))

comm-* : ∀ m n → m * n ≡ n * m
comm-* = IsCommutativeMonoid.comm
         (IsCommutativeSemiring.*-isCommutativeMonoid isCommutativeSemiring)

comm-+ : ∀ m n → m + n ≡ n + m
comm-+ = IsCommutativeMonoid.comm
         (IsCommutativeSemiring.+-isCommutativeMonoid isCommutativeSemiring)

Bisim = _∼ˢ_

{-
mutual
  comm-× : ∀{i} →
           (s t : Str {i} ℕ) → Bisim {ℕ} {i} (s × t) (t × s)
  hd≡ (comm-× s t) = comm-* (hd s) (hd t)
  tl∼ (comm-× s t) = lem-comm-× s t

  lem-comm-× : ∀{i} → ∀{j : Size< i} →
               (s t : Str {i} ℕ) →
               Bisim {ℕ} {j}
                 ((tl s × t) ⊕ (⟦ hd s ⟧ × tl t))
                 ((tl t × s) ⊕ (⟦ hd t ⟧ × tl s))
  hd≡ (lem-comm-× {i} {j} s t) =
    begin
      hd s' * hd t + hd s * hd t'
    ≡⟨ comm-+ (hd s' * hd t) (hd s * hd t') ⟩
      hd s * hd t' + hd s' * hd t
    ≡⟨ cong (λ x → x + hd s' * hd t) (comm-* (hd s) (hd t')) ⟩
      hd t' * hd s + hd s' * hd t
    ≡⟨ cong (λ x → hd t' * hd s + x) (comm-* (hd s') (hd t)) ⟩
      hd t' * hd s + hd t * hd s'
    ∎
    where
      s' = tl s {j}
      t' = tl t {j}

  tl∼ (lem-comm-× {i} {j} s t) {k} = lem {k}
    where
      s' = tl s {j}
      t' = tl t {j}

      lem : ∀{k : Size< j} → Bisim {ℕ} {k}
        (((tl s' × t) ⊕ (⟦ hd s' ⟧ × t')) ⊕ ((⟦ 0 ⟧ × t') ⊕ (⟦ hd s ⟧ × tl t')))
        (((tl t' × s) ⊕ (⟦ hd t' ⟧ × s')) ⊕ ((⟦ 0 ⟧ × s') ⊕ (⟦ hd t ⟧ × tl s')))
      lem = {!!}
        where
          s'' = tl s' {k}
          t'' = tl t' {k}
-}

zero-⊕-unit-l : (s : Str ℕ) → (⟦ 0 ⟧ ⊕ s) ∼ˢ∞ s
hd≡∞ (zero-⊕-unit-l s) = refl
tl∼∞ (zero-⊕-unit-l s) = zero-⊕-unit-l (tl s)

zero-⊕-unit-r : (s : Str ℕ) → (s ⊕ ⟦ 0 ⟧) ∼ˢ∞ s
hd≡∞ (zero-⊕-unit-r s) = comm-+ (hd s) 0
tl∼∞ (zero-⊕-unit-r s) = zero-⊕-unit-r (tl s)

zero-×-annihil-l : (s : Str ℕ) → (⟦ 0 ⟧ × s) ∼ˢ∞ ⟦ 0 ⟧
hd≡∞ (zero-×-annihil-l s) = refl
tl∼∞ (zero-×-annihil-l s) =
  beginˢ∞
    tl (⟦ 0 ⟧ × s)
  ∼ˢ∞⟨ s-bisim∞-refl ⟩
    (⟦ 0 ⟧ × s) ⊕ (⟦ 0 ⟧ × tl s)
  ∼ˢ∞⟨ {!!} ⟩
    tl (⟦ 0 ⟧)
  ∎ˢ∞

mutual
  comm-× : (s t : Str ℕ) → (s × t) ∼ˢ∞ (t × s)
  hd≡∞ (comm-× s t) = comm-* (hd s) (hd t)
  tl∼∞ (comm-× s t) = lem-comm-× s t

  lem-comm-× : (s t : Str ℕ) →
               ((tl s × t) ⊕ (⟦ hd s ⟧ × tl t))
               ∼ˢ∞ ((tl t × s) ⊕ (⟦ hd t ⟧ × tl s))
  hd≡∞ (lem-comm-× s t) =
    begin
      hd s' * hd t + hd s * hd t'
    ≡⟨ comm-+ (hd s' * hd t) (hd s * hd t') ⟩
      hd s * hd t' + hd s' * hd t
    ≡⟨ cong (λ x → x + hd s' * hd t) (comm-* (hd s) (hd t')) ⟩
      hd t' * hd s + hd s' * hd t
    ≡⟨ cong (λ x → hd t' * hd s + x) (comm-* (hd s') (hd t)) ⟩
      hd t' * hd s + hd t * hd s'
    ∎
    where
      s' = tl s
      t' = tl t

  tl∼∞ (lem-comm-× s t) = lem
    where
      s' = tl s
      t' = tl t

      lem :
        (((tl s' × t) ⊕ (⟦ hd s' ⟧ × t')) ⊕ ((⟦ 0 ⟧ × t') ⊕ (⟦ hd s ⟧ × tl t')))
        ∼ˢ∞ (((tl t' × s) ⊕ (⟦ hd t' ⟧ × s')) ⊕ ((⟦ 0 ⟧ × s') ⊕ (⟦ hd t ⟧ × tl s')))
      lem = {!!}
        where
          s'' = tl s'
          t'' = tl t'


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

open import LogicalFormulae
open import Orders.Total.Definition
open import Orders.Partial.Definition
open import Setoids.Setoids
open import Functions

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

module Setoids.Orders where

partialOrderToSetoidPartialOrder : {a b : _} {A : Set a} (P : PartialOrder {a} A {b}) → SetoidPartialOrder (reflSetoid A) (PartialOrder._<_ P)
SetoidPartialOrder.<WellDefined (partialOrderToSetoidPartialOrder P) a=b c=d a<c rewrite a=b | c=d = a<c
SetoidPartialOrder.irreflexive (partialOrderToSetoidPartialOrder P) = PartialOrder.irreflexive P
SetoidPartialOrder.<Transitive (partialOrderToSetoidPartialOrder P) = PartialOrder.<Transitive P

totalOrderToSetoidTotalOrder : {a b : _} {A : Set a} (T : TotalOrder {a} A {b}) → SetoidTotalOrder (partialOrderToSetoidPartialOrder (TotalOrder.order T))
SetoidTotalOrder.totality (totalOrderToSetoidTotalOrder T) = TotalOrder.totality T


open import Categories
open import Functors
import RMonads

module RMonads.RKleisli
  {a b c d}
  {C : Cat {a}{b}}
  {D : Cat {c}{d}}
  {J : Fun C D}
  (M : RMonads.RMonad J) where

open import Library
open RMonads.RMonad M
open Cat
open Fun

Kl : Cat
Kl = record{
  Obj  = Obj C;
  Hom  = λ X Y → Hom D (OMap J X) (T Y);
  iden = η;
  comp = λ f g → comp D (bind f) g;
  idl  = λ{X}{Y}{f} →
    proof
    comp D (bind η) f
    ≅⟨ cong (λ g → comp D g f) law1 ⟩
    comp D (iden D) f
    ≅⟨ idl D ⟩
    f
    ∎;
  idr  = law2;
  ass  =  λ{_ _ _ _ f g h} →
    proof
    comp D (bind (comp D (bind f) g)) h
    ≅⟨ cong (λ f → comp D f h) law3 ⟩
    comp D (comp D (bind f) (bind g)) h
    ≅⟨ ass D ⟩
    comp D (bind f) (comp D (bind g) h)
    ∎}


import      Structure.Logic.Classical.NaturalDeduction
-- TODO: Seems like Constructive does not work, but why?

module Structure.Logic.Constructive.Syntax.Algebra {ℓₗ} {Formula} {ℓₘₗ} {Proof} {ℓₒ} {Domain} ⦃ classicalLogic : _ ⦄ where
open Structure.Logic.Classical.NaturalDeduction.ClassicalLogic {ℓₗ} {Formula} {ℓₘₗ} {Proof} {ℓₒ} {Domain} (classicalLogic)

import      Lvl
open import Syntax.Function
open import Type

-- Transitivitity through an operation on proofs
record Transitivable{ℓ}{T : Type{ℓ}}(_▫_ : T → T → Formula) : Type{ℓₘₗ Lvl.⊔ ℓₒ Lvl.⊔ ℓ} where
  field
    _🝖_ : ∀{a b c} → Proof(a ▫ b) → Proof(b ▫ c) → Proof(a ▫ c)
open Transitivable ⦃ ... ⦄ public

Transitivity-to-Transitivable : ∀{_▫_ : Domain → Domain → Formula} → Proof(∀ₗ(a ↦ ∀ₗ(b ↦ ∀ₗ(c ↦ (a ▫ b)∧(b ▫ c) ⟶ (a ▫ c))))) → Transitivable(_▫_)
_🝖_ ⦃ Transitivity-to-Transitivable proof ⦄ {a}{b}{c} ab bc =
  ([→].elim
    ([∀].elim ([∀].elim ([∀].elim proof {a}){b}){c})
    ([∧].intro ab bc)
  )

instance
  [⟶]-transitivable : Transitivable(_⟶_)
  _🝖_ ⦃ [⟶]-transitivable ⦄ = [→].transitivity

instance
  [⟷]-transitivable : Transitivable(_⟷_)
  _🝖_ ⦃ [⟷]-transitivable ⦄ = [↔].transitivity


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

module Container.Fixpoint where

open import Container
open import Prelude

data μ {s p} (C : Container s p) : Type (s ℓ⊔ p) where
  sup : ⟦ C ⟧ (μ C) → μ C

record ν {s p} (C : Container s p) : Type (s ℓ⊔ p) where
  coinductive
  field inf : ⟦ C ⟧ (ν C)
open ν public


------------------------------------------------------------------------
-- The Agda standard library
--
-- Bounded vectors
------------------------------------------------------------------------

-- Vectors of a specified maximum length.

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

module Data.BoundedVec where

open import Data.Nat
open import Data.List.Base as List using (List)
open import Data.Vec as Vec using (Vec)
import Data.BoundedVec.Inefficient as Ineff
open import Relation.Binary.PropositionalEquality
open import Data.Nat.Solver
open +-*-Solver

------------------------------------------------------------------------
-- The type

abstract

  data BoundedVec {a} (A : Set a) : ℕ → Set a where
    bVec : ∀ {m n} (xs : Vec A n) → BoundedVec A (n + m)

  [] : ∀ {a n} {A : Set a} → BoundedVec A n
  [] = bVec Vec.[]

  infixr 5 _∷_

  _∷_ : ∀ {a n} {A : Set a} →
        A → BoundedVec A n → BoundedVec A (suc n)
  x ∷ bVec xs = bVec (Vec._∷_ x xs)

------------------------------------------------------------------------
-- Pattern matching

infixr 5 _∷v_

data View {a} (A : Set a) : ℕ → Set a where
  []v  : ∀ {n} → View A n
  _∷v_ : ∀ {n} (x : A) (xs : BoundedVec A n) → View A (suc n)

abstract

  view : ∀ {a n} {A : Set a} → BoundedVec A n → View A n
  view (bVec Vec.[])         = []v
  view (bVec (Vec._∷_ x xs)) = x ∷v bVec xs

------------------------------------------------------------------------
-- Increasing the bound

abstract

  ↑ : ∀ {a n} {A : Set a} → BoundedVec A n → BoundedVec A (suc n)
  ↑ {A = A} (bVec {m = m} {n = n} xs) =
    subst (BoundedVec A) lemma
            (bVec {m = suc m} xs)
    where
    lemma : n + (1 + m) ≡ 1 + (n + m)
    lemma = solve 2 (λ m n → n :+ (con 1 :+ m)  :=  con 1 :+ (n :+ m))
                    refl m n

------------------------------------------------------------------------
-- Conversions

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

 abstract

  fromList : (xs : List A) → BoundedVec A (List.length xs)
  fromList xs =
    subst (BoundedVec A) lemma
            (bVec {m = zero} (Vec.fromList xs))
    where
    lemma : List.length xs + 0 ≡ List.length xs
    lemma = solve 1 (λ m → m :+ con 0  :=  m) refl _

  toList : ∀ {n} → BoundedVec A n → List A
  toList (bVec xs) = Vec.toList xs

  toInefficient : ∀ {n} → BoundedVec A n → Ineff.BoundedVec A n
  toInefficient xs with view xs
  ... | []v     = Ineff.[]
  ... | y ∷v ys = y Ineff.∷ toInefficient ys

  fromInefficient : ∀ {n} → Ineff.BoundedVec A n → BoundedVec A n
  fromInefficient Ineff.[]       = []
  fromInefficient (x Ineff.∷ xs) = x ∷ fromInefficient xs


{-# OPTIONS --sized-types #-}
open import Relation.Binary.Core

module BBHeap.Height.Log {A : Set}
                  (_≤_ : A → A → Set)
                  (tot≤ : Total _≤_ ) where

open import BBHeap _≤_ hiding (#)
open import BBHeap.Height _≤_
open import BBHeap.Properties _≤_
open import Bound.Lower A
open import Data.Sum renaming (_⊎_ to _∨_)
open import SNat
open import SNat.Log
open import SNat.Order
open import SNat.Order.Properties
open import SNat.Properties
open import SNat.Sum
open import Relation.Binary.PropositionalEquality

lemma-height-≃ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ≃ r → height l ≡ height r
lemma-height-≃ ≃lf = refl
lemma-height-≃ (≃nd _ _ _ _ _ _ l≃l') rewrite lemma-height-≃ l≃l' = refl

lemma-height'-≃ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ≃ r → height' l ≡ height' r
lemma-height'-≃ ≃lf = refl
lemma-height'-≃ (≃nd _ _ _ _ l≃r l'≃r' l≃l') rewrite lemma-height'-≃ (trans≃ (trans≃ (sym≃ l≃r) l≃l') l'≃r') = refl

lemma-height-height'-⋗ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋗ r → height l ≡ succ (height' r)
lemma-height-height'-⋗ (⋗lf _) = refl
lemma-height-height'-⋗ (⋗nd _ _ _ _ _ l'≃r' l⋗l') rewrite lemma-height-height'-⋗ l⋗l' | lemma-height'-≃ l'≃r' = refl

lemma-height-height'-⋘ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋘ r → height l ≡ height' r ∨ height l ≡ succ (height' r)
lemma-height-height'-⋘ lf⋘ = inj₁ refl
lemma-height-height'-⋘ (ll⋘ _ _ l⋘r _ l'≃r' r≃l')
    with lemma-height-height'-⋘ l⋘r
... | inj₁ hl≡h'r rewrite hl≡h'r | lemma-height'-≃ (trans≃ r≃l' l'≃r') = inj₁ refl
... | inj₂ hl≡h'r+1 rewrite hl≡h'r+1 | lemma-height'-≃ (trans≃ r≃l' l'≃r') = inj₂ refl
lemma-height-height'-⋘ (lr⋘ _ _ _  _ l'≃r' l⋗l') rewrite lemma-height-height'-⋗ (lemma⋗≃ l⋗l' l'≃r')= inj₂ refl

lemma-height-height'-⋙ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋙ r → height l ≡ height' r ∨ height l ≡ succ (height' r)
lemma-height-height'-⋙ (⋙lf _) = inj₂ refl
lemma-height-height'-⋙ (⋙rl _ _ _ _ _ l⋗r')  rewrite lemma-height-height'-⋗ l⋗r' = inj₂ refl
lemma-height-height'-⋙ (⋙rr _ _ _ _ l'⋙r' l≃l')
    with lemma-height-height'-⋙ l'⋙r'
... | inj₁ hl'≡h'r' rewrite lemma-height-≃ l≃l' | hl'≡h'r' = inj₁ refl
... | inj₂ hl'≡h'r'+1  rewrite lemma-height-≃ l≃l' | hl'≡h'r'+1 = inj₂ refl

lemma-height-height' : {b : Bound}(h : BBHeap b) → height h ≡ height' h ∨ height h ≡ succ (height' h)
lemma-height-height' leaf = inj₁ refl
lemma-height-height' (left _ l⋘r)
    with lemma-height-height'-⋘ l⋘r
... | inj₁ hl≡h'r rewrite hl≡h'r = inj₁ refl
... | inj₂ hl≡h'r+1 rewrite hl≡h'r+1 = inj₂ refl
lemma-height-height' (right _ l⋙r)
    with lemma-height-height'-⋙ l⋙r
... | inj₁ hl≡h'r rewrite hl≡h'r = inj₁ refl
... | inj₂ hl≡h'r+1 rewrite hl≡h'r+1 = inj₂ refl

lemma-#-≃ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ≃ r → # l ≡ # r
lemma-#-≃ ≃lf = refl
lemma-#-≃ (≃nd _ _ _ _ l≃r l'≃r' l≃l')
                   rewrite lemma-#-≃ (sym≃ l≃r)
                            | lemma-#-≃ l≃l'
                            | lemma-#-≃ l'≃r' = refl

lemma-#-⋗ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋗ r → # l ≡ succ (# r + # r)
lemma-#-⋗ (⋗lf _) = refl
lemma-#-⋗ (⋗nd _ _ _ _ l≃r l'≃r' l⋗l')
                   rewrite  lemma-#-≃ (sym≃ l≃r)
                            | lemma-#-⋗ l⋗l'
                            | lemma-#-≃ l'≃r' = refl

lemma-⋘-# : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋘ r → # r ≤′ # l
lemma-⋘-# lf⋘ = refl≤′
lemma-⋘-# (ll⋘ {r' = r'} _ _ l⋘r _ l'≃r' r≃l')
                   rewrite lemma-#-≃ r≃l'
                             | lemma-#-≃ l'≃r' = lemma-s≤′s (+-right-monotony-≤′ (# r') (lemma-≡-≤′ (lemma-#-≃ (sym≃ (trans≃ r≃l' l'≃r'))) (lemma-⋘-# l⋘r)))
lemma-⋘-# (lr⋘ {r = r} {r' = r'} _ _ _ _ l'≃r' l⋗l')
                   rewrite lemma-#-⋗ l⋗l'
                             | lemma-#-≃ l'≃r' = lemma-s≤′s (≤′-step (lemma-m≤′m+n (# r' + # r') (# r)))

lemma-#-⋙ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋙ r → # l ≤′ succ (# r + # r)
lemma-#-⋙ (⋙lf _) = refl≤′
lemma-#-⋙ (⋙rl {l' = l'}{r' = r'} _ _ _ l≃r l'⋘r' l⋗r')
                   rewrite lemma-#-≃ (sym≃ l≃r)
                             | lemma-#-⋗ l⋗r'
                             | +-assoc-succ (# r' + # r') (# r' + # r')
                             | +-assoc-succ (# l' + # r') (# l' + # r') = lemma-s≤′s (lemma-s≤′s (lemma-s≤′s (lemma-4m≤′n+m+n+m (lemma-⋘-# l'⋘r'))))
lemma-#-⋙ (⋙rr {l' = l'} {r' = r'} _ _ _ l≃r _ l≃l')
                   rewrite lemma-#-≃ (sym≃ l≃r)
                             | lemma-#-≃ l≃l'
                             | +-assoc-succ (# l' + # r') (# l' + # r') = lemma-s≤′s (≤′-step (≤′-step (lemma-2m≤′m+n+m+n (# l') (# r'))))

mutual
  lemma-⋙-# : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋙ r → # r ≤′ # l
  lemma-⋙-# (⋙lf _) = ≤′-step refl≤′
  lemma-⋙-# (⋙rl {r' = r'} _ _ _ l≃r l'⋘r' l⋗r')
                   rewrite lemma-#-≃ (sym≃ l≃r)
                             | lemma-#-⋗ l⋗r' = lemma-s≤′s (trans≤′ (+-right-monotony-≤′ (# r') (lemma-#-⋘ l'⋘r')) (lemma-s≤′s (+-left-monotony-≤′ (# r' + # r') (≤′-step (lemma-n≤′2n (# r'))))))
  lemma-⋙-# (⋙rr {l' = l'} {r' = r'} _ _ _ l≃r l'⋙r' l≃l')
                   rewrite lemma-#-≃ (sym≃ l≃r)
                             | lemma-#-≃ l≃l'
                             | +-comm (# l') (# r') = lemma-s≤′s (+-right-monotony-≤′ (# l') (lemma-⋙-# l'⋙r'))

  lemma-#-⋘ : {b b' : Bound}{l : BBHeap b}{r : BBHeap b'} → l ⋘ r → # l ≤′ succ (# r + # r)
  lemma-#-⋘ lf⋘ = ≤′-step refl≤′
  lemma-#-⋘ (ll⋘ {r = r} _ _ l⋘r _ l'≃r' r≃l')
                   rewrite lemma-#-≃ (sym≃ l'≃r')
                             | lemma-#-≃ (sym≃ r≃l')
                             | +-assoc-succ (# r + # r) (# r + # r)
                             | +-assoc-left (# r + # r) (# r) (# r) = lemma-s≤′s (≤′-step (trans≤′ (+-right-monotony-≤′ (# r) (lemma-#-⋘ l⋘r)) (lemma-s≤′s (lemma-m≤′m+n ((# r + # r) + # r) (# r)))))
  lemma-#-⋘ (lr⋘ {r' = r'} _ _ l⋙r _ l'≃r' l⋗l')
                   rewrite lemma-#-⋗ l⋗l'
                             | lemma-#-≃ l'≃r' = lemma-s≤′s (lemma-s≤′s (+-left-monotony-≤′ (# r' + # r') (trans≤′ (lemma-⋙-# l⋙r) (lemma-≡-≤′ (lemma-#-⋗ (lemma⋗≃ l⋗l' l'≃r')) refl≤′))))

lemma-#-#' : {b : Bound}(h : BBHeap b) → #' h ≤′ # h
lemma-#-#' leaf = refl≤′
lemma-#-#' (left {r = r} _ l⋘r) = lemma-s≤′s (trans≤′ (lemma-2m≤′2n (lemma-#-#' r)) (+-right-monotony-≤′ (# r) (lemma-⋘-# l⋘r)))
lemma-#-#' (right {r = r} _ l⋙r) = lemma-s≤′s (trans≤′ (lemma-2m≤′2n (lemma-#-#' r)) (+-right-monotony-≤′ (# r) (lemma-⋙-# l⋙r)))

lemma-height'-#' : {b : Bound}(h : BBHeap b) → height' h ≤′ log₂ (#' h + #' h)
lemma-height'-#' leaf = refl≤′
lemma-height'-#' (left {r = r} _ _) = trans≤′ (lemma-s≤′s (trans≤′ (lemma-height'-#' r) (lemma-≤′-log (≤′-step (refl≤′ {#' r + #' r}))))) (lemma-1+logn≤′log2n (#' r + #' r))
lemma-height'-#' (right {r = r} _ _) = trans≤′ (lemma-s≤′s (trans≤′ (lemma-height'-#' r) (lemma-≤′-log (≤′-step (refl≤′ {#' r + #' r}))))) (lemma-1+logn≤′log2n (#' r + #' r))

lemma-height'-# : {b : Bound}(h : BBHeap b) → height' h ≤′ succ (log₂ (# h))
lemma-height'-# h = trans≤′ (trans≤′ (lemma-height'-#' h) (lemma-log2n≤′1+logn (#' h))) (lemma-s≤′s (lemma-≤′-log (lemma-#-#' h)))

theorem-height-# : {b : Bound}(h : BBHeap b) → height h ≤′ succ (succ (log₂ (# h)))
theorem-height-# h
    with lemma-height-height' h
... | inj₁ hh≡h'h rewrite hh≡h'h = ≤′-step (lemma-height'-# h)
... | inj₂  hh≡h'h+1 rewrite hh≡h'h+1 = lemma-s≤′s (lemma-height'-# h)


module Spire.Operational where

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

data Level : Set where
  zero : Level
  suc : Level → Level

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

data Context : Set
data Type (Γ : Context) : Set
data Value (Γ : Context) : Type Γ → Set
data Neutral (Γ : Context) : Type Γ → Set

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

data Context where
  ∅ : Context
  _,_ : (Γ : Context) → Type Γ → Context

data Type Γ where
  `⊥ `⊤ `Bool : Type Γ
  `Desc `Type : (ℓ : Level) → Type Γ
  `Π `Σ : (A : Type Γ) (B : Type (Γ , A)) → Type Γ
  `μ : ∀{ℓ} → Value Γ (`Desc ℓ) → Type Γ
  `⟦_⟧ : ∀{ℓ} → Neutral Γ (`Type ℓ) → Type Γ
  `⟦_⟧ᵈ : ∀{ℓ} → Neutral Γ (`Desc ℓ) → Type Γ → Type Γ

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

⟦_⟧ : ∀{Γ ℓ} → Value Γ (`Type ℓ) →  Type Γ
⟦_⟧ᵈ : ∀{Γ ℓ} → Value Γ (`Desc ℓ) → Type Γ →  Type Γ

postulate
  wknT : ∀{Γ A} → Type Γ → Type (Γ , A)
  subT : ∀{Γ A} → Type (Γ , A) → Value Γ A → Type Γ
  subV : ∀{Γ A B} → Value (Γ , A) B → (x : Value Γ A) → Value Γ (subT B x)

data Var : (Γ : Context) (A : Type Γ) → Set where
  here : ∀{Γ A} → Var (Γ , A) (wknT A)
  there : ∀{Γ A B} → Var Γ A → Var (Γ , B) (wknT A)

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

data Value Γ where
  {- Type introduction -}
  `⊥ `⊤ `Bool `Desc `Type : ∀{ℓ} → Value Γ (`Type ℓ)
  `Π `Σ : ∀{ℓ} (A : Value Γ (`Type ℓ)) (B : Value (Γ , ⟦ A ⟧) (`Type ℓ)) → Value Γ (`Type ℓ)
  `μ : ∀{ℓ} → Value Γ (`Desc ℓ) → Value Γ (`Type ℓ)
  `⟦_⟧ : ∀{ℓ} → Value Γ (`Type ℓ) → Value Γ (`Type (suc ℓ))
  `⟦_⟧ᵈ : ∀{ℓ} → Value Γ (`Desc ℓ) → Value Γ (`Type ℓ) → Value Γ (`Type ℓ)

  {- Desc introduction -}
  `⊤ᵈ `Xᵈ : ∀{ℓ} → Value Γ (`Desc ℓ)
  `Πᵈ `Σᵈ : ∀{ℓ}
    (A : Value Γ (`Type ℓ))
    (B : Value (Γ , ⟦ A ⟧) (`Desc (suc ℓ)))
    → Value Γ (`Desc (suc ℓ))

  {- Value introduction -}
  `tt : Value Γ `⊤
  `true `false : Value Γ `Bool
  _`,_ : ∀{A B} (a : Value Γ A) (b : Value Γ (subT B a)) → Value Γ (`Σ A B)
  `λ : ∀{A B} → Value (Γ , A) B → Value Γ (`Π A B)
  `con : ∀{ℓ} {D : Value Γ (`Desc ℓ)} → Value Γ (⟦ D ⟧ᵈ (`μ D)) → Value Γ (`μ D)
  `neut : ∀{A} → Neutral Γ A → Value Γ A

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

data Neutral Γ where
  {- Value elimination -}
  `var : ∀{A} → Var Γ A → Neutral Γ A
  `if_`then_`else_ : ∀{C} (b : Neutral Γ `Bool) (c₁ c₂ : Value Γ C) → Neutral Γ C
  `elim⊥ : ∀{A} → Neutral Γ `⊥ → Neutral Γ A
  `elimBool : ∀{ℓ} (P : Value (Γ , `Bool) (`Type ℓ))
    (pt : Value Γ (subT ⟦ P ⟧ `true))
    (pf : Value Γ (subT ⟦ P ⟧ `false))
    (b : Neutral Γ `Bool) → Neutral Γ (subT ⟦ P ⟧ (`neut b))
  `proj₁ : ∀{A B} → Neutral Γ (`Σ A B) → Neutral Γ A
  `proj₂ : ∀{A B} (ab : Neutral Γ (`Σ A B)) → Neutral Γ (subT B (`neut (`proj₁ ab)))
  _`$_ : ∀{A B} (f : Neutral Γ (`Π A B)) (a : Value Γ A) → Neutral Γ (subT B a)
  `des : ∀{ℓ} {D : Value Γ (`Desc ℓ)} → Neutral Γ (`μ D) → Neutral Γ (⟦ D ⟧ᵈ (`μ D))

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

⟦ `Π A B ⟧ = `Π ⟦ A ⟧ ⟦ B ⟧
⟦ `Σ A B ⟧ = `Σ ⟦ A ⟧ ⟦ B ⟧
⟦ `⊥ ⟧ = `⊥
⟦ `⊤ ⟧ = `⊤
⟦ `Bool ⟧ = `Bool
⟦ `μ D ⟧ = `μ D
⟦ `Type {zero} ⟧ = `⊥
⟦ `Type {suc ℓ} ⟧ = `Type ℓ
⟦ `⟦ A ⟧ ⟧ = ⟦ A ⟧
⟦ `Desc {ℓ} ⟧ = `Desc ℓ
⟦ `⟦ D ⟧ᵈ X ⟧ = ⟦ D ⟧ᵈ ⟦ X ⟧
⟦ `neut A ⟧ = `⟦ A ⟧

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

⟦ `⊤ᵈ ⟧ᵈ X = `⊤
⟦ `Xᵈ ⟧ᵈ X = X
⟦ `Πᵈ A D ⟧ᵈ X = `Π ⟦ A ⟧ (⟦ D ⟧ᵈ (wknT X))
⟦ `Σᵈ A D ⟧ᵈ X = `Σ ⟦ A ⟧ (⟦ D ⟧ᵈ (wknT X))
⟦ `neut D ⟧ᵈ X = `⟦ D ⟧ᵈ X

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

elim⊥ : ∀{Γ A} → Value Γ `⊥ → Value Γ A
elim⊥ (`neut bot) = `neut (`elim⊥ bot)

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

if_then_else_ : ∀{Γ C} (b : Value Γ `Bool) (c₁ c₂ : Value Γ C) → Value Γ C
if `true then c₁ else c₂ = c₁
if `false then c₁ else c₂ = c₂
if `neut b then c₁ else c₂ = `neut (`if b `then c₁ `else c₂)

elimBool : ∀{Γ ℓ} (P : Value (Γ , `Bool) (`Type ℓ))
  (pt : Value Γ (subT ⟦ P ⟧ `true))
  (pf : Value Γ (subT ⟦ P ⟧ `false))
  (b : Value Γ `Bool)
  → Value Γ (subT ⟦ P ⟧ b)
elimBool P pt pf `true = pt
elimBool P pt pf `false = pf
elimBool P pt pf (`neut b) = `neut (`elimBool P pt pf b)

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

proj₁ : ∀{Γ A B} → Value Γ (`Σ A B) → Value Γ A
proj₁ (a `, b) = a
proj₁ (`neut ab) = `neut (`proj₁ ab)

proj₂ : ∀{Γ A B} (ab : Value Γ (`Σ A B)) → Value Γ (subT B (proj₁ ab))
proj₂ (a `, b) = b
proj₂ (`neut ab) = `neut (`proj₂ ab)

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

des : ∀{Γ ℓ} {D : Value Γ (`Desc ℓ)} → Value Γ (`μ D) → Value Γ (⟦ D ⟧ᵈ (`μ D))
des (`con x) = x
des (`neut x) = `neut (`des x)

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

_$_ : ∀{Γ A B} → Value Γ (`Π A B) → (a : Value Γ A) → Value Γ (subT B a)
`λ b $ a = subV b a
`neut f $ a = `neut (f `$ a)

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

data Term (Γ : Context) : Type Γ → Set
eval : ∀{Γ A} → Term Γ A → Value Γ A

data Term Γ where
  {- Type introduction -}
  `⊥ `⊤ `Bool `Type : ∀{ℓ} → Term Γ (`Type ℓ)
  `Π `Σ : ∀{ℓ} (A : Term Γ (`Type ℓ)) (B : Term (Γ , ⟦ eval A ⟧) (`Type ℓ)) → Term Γ (`Type ℓ)
  `μ : ∀{ℓ} → Term Γ (`Desc ℓ) → Term Γ (`Type ℓ)
  `⟦_⟧ : ∀{ℓ} → Term Γ (`Type ℓ) → Term Γ (`Type (suc ℓ))
  `⟦_⟧ᵈ : ∀{ℓ} → Term Γ (`Desc ℓ) → Term Γ (`Type ℓ) → Term Γ (`Type ℓ)

  {- Desc introduction -}
  `⊤ᵈ `Xᵈ : ∀{ℓ} → Term Γ (`Desc ℓ)
  `Πᵈ `Σᵈ : ∀{ℓ}
    (A : Term Γ (`Type ℓ))
    (D : Term (Γ , ⟦ eval A ⟧) (`Desc (suc ℓ)))
    → Term Γ (`Desc (suc ℓ))

  {- Value introduction -}
  `tt : Term Γ `⊤
  `true `false : Term Γ `Bool
  _`,_ : ∀{A B}
    (a : Term Γ A) (b : Term Γ (subT B (eval a)))
    → Term Γ (`Σ A B)
  `λ : ∀{A B}
    (b : Term (Γ , A) B)
    → Term Γ (`Π A B)
  `con : ∀{ℓ} {D : Value Γ (`Desc ℓ)} → Term Γ (⟦ D ⟧ᵈ (`μ D)) → Term Γ (`μ D)

  {- Value elimination -}
  `var : ∀{A} → Var Γ A → Term Γ A
  `if_`then_`else_ : ∀{C}
    (b : Term Γ `Bool)
    (c₁ c₂ : Term Γ C)
    → Term Γ C
  _`$_ : ∀{A B} (f : Term Γ (`Π A B)) (a : Term Γ A) → Term Γ (subT B (eval a))
  `proj₁ : ∀{A B} → Term Γ (`Σ A B) → Term Γ A
  `proj₂ : ∀{A B} (ab : Term Γ (`Σ A B)) → Term Γ (subT B (proj₁ (eval ab)))
  `elim⊥ : ∀{A} → Term Γ `⊥ → Term Γ A
  `elimBool : ∀{ℓ} (P : Term (Γ , `Bool) (`Type ℓ))
    (pt : Term Γ (subT ⟦ eval P ⟧ `true))
    (pf : Term Γ (subT ⟦ eval P ⟧ `false))
    (b : Term Γ `Bool)
    → Term Γ (subT ⟦ eval P ⟧ (eval b))
  `des : ∀{ℓ} {D : Value Γ (`Desc ℓ)} → Term Γ (`μ D) → Term Γ (⟦ D ⟧ᵈ (`μ D))

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

{- Type introduction -}
eval `⊥ = `⊥
eval `⊤ = `⊤
eval `Bool = `Bool
eval `Type = `Type
eval (`Π A B) = `Π (eval A) (eval B)
eval (`Σ A B) = `Σ (eval A) (eval B)
eval (`μ D) = `μ (eval D)
eval `⟦ A ⟧ = `⟦ eval A ⟧
eval (`⟦ D ⟧ᵈ X) = `⟦ eval D ⟧ᵈ (eval X)

{- Desc introduction -}
eval `⊤ᵈ = `⊤ᵈ
eval `Xᵈ = `Xᵈ
eval (`Πᵈ A D) = `Πᵈ (eval A) (eval D)
eval (`Σᵈ A D) = `Σᵈ (eval A) (eval D)

{- Value introduction -}
eval `tt = `tt
eval `true = `true
eval `false = `false
eval (a `, b) = eval a `, eval b
eval (`λ b) = `λ (eval b)
eval (`con x) = `con (eval x)

{- Value elimination -}
eval (`var i) = `neut (`var i)
eval (`if b `then c₁ `else c₂) = if eval b then eval c₁ else eval c₂
eval (f `$ a) = eval f $ eval a
eval (`proj₁ ab) = proj₁ (eval ab)
eval (`proj₂ ab) = proj₂ (eval ab)
eval (`elim⊥ bot) = elim⊥ (eval bot)
eval (`elimBool P pt pf b) = elimBool (eval P) (eval pt) (eval pf) (eval b)
eval (`des x) = des (eval x)

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


{-# OPTIONS --cubical --safe #-}
module Cubical.Relation.Nullary.DecidableEq where

open import Cubical.Core.Everything

open import Cubical.Foundations.Prelude

open import Cubical.Data.Empty

open import Cubical.Relation.Nullary

-- Proof of Hedberg's theorem: a type with decidable equality is an h-set

Dec→Stable : ∀ {ℓ} (A : Type ℓ) → Dec A → Stable A
Dec→Stable A (yes x) = λ _ → x
Dec→Stable A (no x) = λ f → ⊥-elim (f x)

Stable≡→isSet : ∀ {ℓ} {A : Type ℓ} → (st : ∀ (a b : A) → Stable (a ≡ b)) → isSet A
Stable≡→isSet {A = A} st a b p q j i =
  let f : (x : A) → a ≡ x → a ≡ x
      f x p = st a x (λ h → h p)
      fIsConst : (x : A) → (p q : a ≡ x) → f x p ≡ f x q
      fIsConst = λ x p q i → st a x (isProp¬ _ (λ h → h p) (λ h → h q) i)
      rem : (p : a ≡ b) → PathP (λ i → a ≡ p i) (f a refl) (f b p)
      rem p j = f (p j) (λ i → p (i ∧ j))
  in hcomp (λ k → λ { (i = i0) → f a refl k
                    ; (i = i1) → fIsConst b p q j k
                    ; (j = i0) → rem p i k
                    ; (j = i1) → rem q i k }) a

-- Hedberg's theorem
Discrete→isSet : ∀ {ℓ} {A : Type ℓ} → Discrete A → isSet A
Discrete→isSet d = Stable≡→isSet (λ x y → Dec→Stable (x ≡ y) (d x y))


------------------------------------------------------------------------
-- The Agda standard library
--
-- Sizes for Agda's sized types
------------------------------------------------------------------------

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

module Size where

open import Agda.Builtin.Size public
  renaming ( SizeU to SizeUniv ) --  sort SizeUniv
  using    ( Size                --  Size   : SizeUniv
           ; Size<_              --  Size<_ : Size → SizeUniv
           ; ↑_                  --  ↑_     : Size → Size
           ; ∞ )                 --  ∞      : Size


module Abstract where

data Bool : Set where
  true false : Bool

not : Bool → Bool
not true  = false
not false = true

abstract
  Answer : Set
  Answer = Bool

  yes : Answer
  yes = true

  no : Answer
  no = false

  contradict : Answer → Answer
  contradict x = not x

counter-contradict : Answer → Answer
counter-contradict x = contradict (contradict x)

no-way : Answer
no-way = contradict yes

data Answers : Set where
  one-answer   : Answer → Answers
  more-answers : Answer → Answers → Answers

yes-or-no : Answers
yes-or-no = more-answers yes (one-answer no)


open import Nat
open import Prelude
open import contexts
open import dynamics-core

module canonical-value-forms where
  canonical-value-forms-num : ∀{Δ d} →
                              Δ , ∅ ⊢ d :: num →
                              d val →
                              Σ[ n ∈ Nat ] (d == N n)
  canonical-value-forms-num TANum VNum = _ , refl
  canonical-value-forms-num (TAVar x₁) ()
  canonical-value-forms-num (TAAp wt wt₁) ()
  canonical-value-forms-num (TAEHole x x₁) ()
  canonical-value-forms-num (TANEHole x wt x₁) ()
  canonical-value-forms-num (TACast wt x) ()
  canonical-value-forms-num (TAFailedCast wt x x₁ x₂) ()

  canonical-value-forms-arr : ∀{Δ d τ1 τ2} →
                              Δ , ∅ ⊢ d :: (τ1 ==> τ2) →
                              d val →
                              Σ[ x ∈ Nat ] Σ[ d' ∈ ihexp ]
                                ((d == (·λ x ·[ τ1 ] d')) ×
                                 (Δ , ■ (x , τ1) ⊢ d' :: τ2))
  canonical-value-forms-arr (TAVar x₁) ()
  canonical-value-forms-arr {Δ = Δ} {d = ·λ x ·[ τ1 ] d} {τ1 = τ1} {τ2 = τ2} (TALam _ wt) VLam
    = _ , _ , refl , tr (λ Γ → Δ , Γ ⊢ d :: τ2) (extend-empty x τ1) wt
  canonical-value-forms-arr (TAAp wt wt₁) ()
  canonical-value-forms-arr (TAEHole x x₁) ()
  canonical-value-forms-arr (TANEHole x wt x₁) ()
  canonical-value-forms-arr (TACast wt x) ()
  canonical-value-forms-arr (TAFailedCast x x₁ x₂ x₃) ()

  canonical-value-form-sum : ∀{Δ d τ1 τ2} →
                              Δ , ∅ ⊢ d :: (τ1 ⊕ τ2) →
                              d val →
                              (Σ[ d' ∈ ihexp ] ((d == (inl τ2 d')) × (Δ , ∅ ⊢ d' :: τ1))) +
                              (Σ[ d' ∈ ihexp ] ((d == (inr τ1 d')) × (Δ , ∅ ⊢ d' :: τ2)))
  canonical-value-form-sum (TAInl wt) (VInl v) = Inl (_ , refl , wt)
  canonical-value-form-sum (TAInr wt) (VInr v) = Inr (_ , refl , wt)

  canonical-value-form-prod : ∀{Δ d τ1 τ2} →
                              Δ , ∅ ⊢ d :: (τ1 ⊠ τ2) →
                              d val →
                              Σ[ d1 ∈ ihexp ] Σ[ d2 ∈ ihexp ]
                                ((d == ⟨ d1 , d2 ⟩) ×
                                 (Δ , ∅ ⊢ d1 :: τ1) ×
                                 (Δ , ∅ ⊢ d2 :: τ2))
  canonical-value-form-prod (TAVar x) ()
  canonical-value-form-prod (TAAp wt wt₁) ()
  canonical-value-form-prod (TACase wt x wt₁ x₁ wt₂) ()
  canonical-value-form-prod (TAPair wt wt₁) (VPair v v₁) = _ , _ , refl , wt , wt₁
  canonical-value-form-prod (TAFst wt) ()
  canonical-value-form-prod (TASnd wt) ()
  canonical-value-form-prod (TAEHole x x₁) ()
  canonical-value-form-prod (TANEHole x wt x₁) ()
  canonical-value-form-prod (TACast wt x) ()
  canonical-value-form-prod (TAFailedCast wt x x₁ x₂) ()

  -- this argues (somewhat informally, because you still have to inspect
  -- the types of the theorems above and manually verify this property)
  -- that we didn't miss any cases above; this intentionally will make this
  -- file fail to typecheck if we added more types, hopefully forcing us to
  -- remember to add canonical forms lemmas as appropriate
  canonical-value-forms-coverage1 : ∀{Δ d τ} →
                                   Δ , ∅ ⊢ d :: τ →
                                   d val →
                                   τ ≠ num →
                                   ((τ1 : htyp) (τ2 : htyp) → τ ≠ (τ1 ==> τ2)) →
                                   ((τ1 : htyp) (τ2 : htyp) → τ ≠ (τ1 ⊕ τ2)) →
                                   ((τ1 : htyp) (τ2 : htyp) → τ ≠ (τ1 ⊠ τ2)) →
                                   ⊥
  canonical-value-forms-coverage1 TANum val nn na ns np = nn refl
  canonical-value-forms-coverage1 (TALam x wt) val nn na ns np = na _ _ refl
  canonical-value-forms-coverage1 (TAInl wt) val nn na ns np = ns _ _ refl
  canonical-value-forms-coverage1 (TAInr wt) val nn na ns np = ns _ _ refl
  canonical-value-forms-coverage1 (TAPair wt wt₁) val nn na ns np = np _ _ refl

  canonical-value-forms-coverage2 : ∀{Δ d} →
                                   Δ , ∅ ⊢ d :: ⦇-⦈ →
                                   d val →
                                   ⊥
  canonical-value-forms-coverage2 (TAVar x₁) ()
  canonical-value-forms-coverage2 (TAAp wt wt₁) ()
  canonical-value-forms-coverage2 (TAEHole x x₁) ()
  canonical-value-forms-coverage2 (TANEHole x wt x₁) ()
  canonical-value-forms-coverage2 (TACast wt x) ()
  canonical-value-forms-coverage2 (TAFailedCast wt x x₁ x₂) ()


module BasicIS4.Metatheory.DyadicGentzen-BasicKripkeBozicDosen where

open import BasicIS4.Syntax.DyadicGentzen public
open import BasicIS4.Semantics.BasicKripkeBozicDosen public hiding (_⊨_) -- TODO

-- Soundness with respect to all models, or evaluation.

eval : ∀ {A Γ Δ} → Γ ⁏ Δ ⊢ A → Γ ⁏ Δ ⊨ A
eval (var i)           γ δ = lookup i γ
eval (lam t)           γ δ = λ ξ a → eval t (mono⊩⋆ ξ γ , a) (λ ζ →
                               let _ , (ζ′ , ξ′) = ≤⨾R→R⨾≤ (_ , (ξ , ζ))
                               in  mono⊩⋆ ξ′ (δ ζ′))
eval (app {A} {B} t u) γ δ = _⟪$⟫_ {A} {B} (eval t γ δ) (eval u γ δ)
eval (mvar i)          γ δ = lookup i (δ reflR)
eval (box t)           γ δ = λ ζ → eval t ∙ (λ ζ′ → δ (transR ζ ζ′))
eval (unbox t u)       γ δ = eval u γ (λ ζ → δ ζ , (eval t γ δ) ζ)
eval (pair t u)        γ δ = eval t γ δ , eval u γ δ
eval (fst t)           γ δ = π₁ (eval t γ δ)
eval (snd t)           γ δ = π₂ (eval t γ δ)
eval unit              γ δ = ∙

-- TODO: Correctness of evaluation with respect to conversion.


module Structure.Categorical.Properties where

import      Functional.Dependent as Fn
open import Lang.Instance
import      Lvl
open import Logic
open import Logic.Predicate
open import Logic.Propositional
open import Structure.Setoid
import      Structure.Categorical.Names as Names
import      Structure.Operator.Names as Names
import      Structure.Relator.Names as Names
open import Structure.Relator.Properties
open import Syntax.Function
open import Type
open import Type.Properties.Singleton

private variable ℓₒ ℓₘ ℓₑ : Lvl.Level
private variable Obj : Type{ℓₒ}

module Object where
  module _ (Morphism : Obj → Obj → Type{ℓₘ}) where
    open Names.ArrowNotation(Morphism)

    module _ ⦃ morphism-equiv : ∀{x y} → Equiv{ℓₑ}(x ⟶ y) ⦄ where
      -- An initial object is an object in which there is an unique morphism from it to every object.
      Initial : Obj → Stmt
      Initial(x) = (∀{y} → IsUnit(x ⟶ y))

      -- An terminal object is an object in which there is an unique morphism to it from every object.
      Terminal : Obj → Stmt
      Terminal(y) = (∀{x} → IsUnit(x ⟶ y))

module Morphism where
  module _ {Morphism : Obj → Obj → Type{ℓₘ}} ⦃ equiv-morphism : ∀{x y} → Equiv{ℓₑ}(Morphism x y) ⦄ where
    open Names.ArrowNotation(Morphism)

    module OperModule (_▫_ : Names.SwappedTransitivity(_⟶_)) where
      record Associativity : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
        constructor intro
        field proof : Names.Morphism.Associativity{Morphism = Morphism}(_▫_)
      associativity = inst-fn Associativity.proof

      module _ {x : Obj} (f : x ⟶ x) where
        record Idempotent : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
          constructor intro
          field proof : Names.Morphism.Idempotent{Morphism = Morphism}(_▫_)(f)
        idempotent = inst-fn Idempotent.proof

      module IdModule (id : Names.Reflexivity(_⟶_)) where
        record Identityₗ : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
          constructor intro
          field proof : Names.Morphism.Identityₗ(_▫_)(\{a} → id{a})
        identityₗ = inst-fn Identityₗ.proof

        record Identityᵣ : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
          constructor intro
          field proof : Names.Morphism.Identityᵣ(_▫_)(\{a} → id{a})
        identityᵣ = inst-fn Identityᵣ.proof

        Identity = Identityₗ ∧ Identityᵣ
        identity-left  = inst-fn{X = Identity}(Identityₗ.proof Fn.∘ [∧]-elimₗ{Q = Identityᵣ})
        identity-right = inst-fn{X = Identity}(Identityᵣ.proof Fn.∘ [∧]-elimᵣ{P = Identityₗ})

        module _ {x : Obj} (f : x ⟶ x) where
          record Involution : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
            constructor intro
            field proof : Names.Morphism.Involution{Morphism = Morphism}(_▫_)(id)(f)
          involution = inst-fn Involution.proof

        module _ {x y : Obj} (f : x ⟶ y) where
          module _ (f⁻¹ : y ⟶ x) where
            -- A morphism have a right inverse morphism.
            -- Also called: Split monomorphism, retraction
            record Inverseₗ : Stmt{ℓₘ Lvl.⊔ ℓₑ} where
              constructor intro
              field proof : Names.Morphism.Inverseₗ(_▫_)(\{a} → id{a})(f)(f⁻¹)
            inverseₗ = inst-fn Inverseₗ.proof

            -- A morphism have a right inverse morphism.
            -- Also called: Split epimorphism, section
            record Inverseᵣ : Stmt{ℓₘ Lvl.⊔ ℓₑ} where
              constructor intro
              field proof : Names.Morphism.Inverseᵣ(_▫_)(\{a} → id{a})(f)(f⁻¹)
            inverseᵣ = inst-fn Inverseᵣ.proof

            Inverse = Inverseₗ ∧ Inverseᵣ
            module Inverse(inverse : Inverse) where
              instance
                left : Inverseₗ
                left = [∧]-elimₗ inverse

              instance
                right : Inverseᵣ
                right = [∧]-elimᵣ inverse

          Invertibleₗ = ∃(Inverseₗ)
          Invertibleᵣ = ∃(Inverseᵣ)

          -- A morphism is an isomorphism when it is invertible with respect to the operator.
          -- For the set and functions category, it means that f is bijective.
          Isomorphism : Stmt
          Isomorphism = ∃(Inverse)
          module Isomorphism ⦃ iso : Isomorphism ⦄ where
            instance inverse = [∃]-proof iso
            instance inverse-left  = [∧]-elimₗ inverse
            instance inverse-right = [∧]-elimᵣ inverse

          inv : ⦃ Isomorphism ⦄ → (y ⟶ x)
          inv ⦃ p ⦄ = [∃]-witness p

        -- Proposition stating that two objects are isomorphic.
        Isomorphic : Obj → Obj → Stmt
        Isomorphic(x)(y) = ∃(Isomorphism{x}{y})
        _⤖_ = Isomorphic

        module _ {x : Obj} (f : ⟲ x) where
          -- A morphism is an automorphism when it is an endomorphism and an isomorphism.
          Automorphism : Stmt
          Automorphism = Isomorphism(f)

        Automorphic : Obj → Stmt
        Automorphic(x) = ∃(Automorphism{x})

      module _ {x y : Obj} (f : x ⟶ y) where
        -- A morphism is an monomorphism when it is left-cancellable ("injective").
        -- ∀{z}{g₁ g₂ : z ⟶ x} → (f ∘ g₁ ≡ f ∘ g₂) → (g₁ ≡ g₂)
        record Monomorphism : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
          constructor intro
          field
            proof : ∀{z} → Names.CancellationOnₗ {T₂ = z ⟶ x} (_▫_) (f)
        cancellationₗ = inst-fn Monomorphism.proof

        -- A morphism is an epimorphism when it is right-cancellable ("surjective").
        -- ∀{z}{g₁ g₂ : y ⟶ z} → (g₁ ∘ f ≡ g₂ ∘ f) → (g₁ ≡ g₂)
        record Epimorphism : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
          constructor intro
          field
            proof : ∀{z} → Names.CancellationOnᵣ {T₁ = y ⟶ z} (_▫_) (f)
        cancellationᵣ = inst-fn Epimorphism.proof

      -- Proposition stating that two objects are monomorphic.
      Monomorphic : Obj → Obj → Stmt
      Monomorphic(x)(y) = ∃(Monomorphism{x}{y})
      _↣_ = Monomorphic

      -- Proposition stating that two objects are epimorphic.
      Epimorphic : Obj → Obj → Stmt
      Epimorphic(x)(y) = ∃(Epimorphism{x}{y})
      _↠_ = Epimorphic

    open OperModule public
    open IdModule   public

module Polymorphism where
  module _ {Morphism : Obj → Obj → Type{ℓₘ}} ⦃ equiv-morphism : ∀{x y} → Equiv{ℓₑ}(Morphism x y) ⦄ where
    open Names.ArrowNotation(Morphism)

    module OperModule (_▫_ : Names.SwappedTransitivity(_⟶_)) where
      module _ (x y : Obj) (f : ∀{x y} → (x ⟶ y)) where
        record IdempotentOn : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
          constructor intro
          field proof : Names.Polymorphism.IdempotentOn{Morphism = Morphism}(_▫_)(x)(y)(f)
        idempotent-on = inst-fn IdempotentOn.proof

      module IdModule (id : Names.Reflexivity(_⟶_)) where
        module _ (x y : Obj) (f : ∀{x y} → (x ⟶ y)) where
          record InvolutionOn : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
            constructor intro
            field proof : Names.Polymorphism.InvolutionOn{Morphism = Morphism}(_▫_)(id) (x)(y) (f)
          involution-on = inst-fn InvolutionOn.proof

        module _ (f : ∀{x y} → (x ⟶ y)) where
          record Involution : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
            constructor intro
            field proof : Names.Polymorphism.Involution{Morphism = Morphism}(_▫_)(id)(f)
          involution = inst-fn Involution.proof

        module _ (inv : ∀{x y : Obj} → (x ⟶ y) → (y ⟶ x)) where
          -- A morphism have a right inverse morphism.
          -- Also called: Split monomorphism, retraction
          record Inverterₗ : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
            constructor intro
            field proof : ∀{x y : Obj}{f : x ⟶ y} → Names.Morphism.Inverseₗ(_▫_)(\{a} → id{a})(f)(inv f)
            instance
              inverseₗ : ∀{x y : Obj}{f : x ⟶ y} → Morphism.Inverseₗ(_▫_)(\{x} → id{x})(f)(inv f)
              inverseₗ = Morphism.intro proof

          inverterₗ = inst-fn Inverterₗ.proof

          -- A morphism have a right inverse morphism.
          -- Also called: Split epimorphism, section
          record Inverterᵣ : Stmt{Lvl.of(Obj) Lvl.⊔ ℓₘ Lvl.⊔ ℓₑ} where
            constructor intro
            field proof : ∀{x y : Obj}{f : x ⟶ y} → Names.Morphism.Inverseᵣ(_▫_)(\{a} → id{a})(f)(inv f)
            instance
              inverseᵣ : ∀{x y : Obj}{f : x ⟶ y} → Morphism.Inverseᵣ(_▫_)(\{x} → id{x})(f)(inv f)
              inverseᵣ = Morphism.intro proof
          inverterᵣ = inst-fn Inverterᵣ.proof

          Inverter = Inverterₗ ∧ Inverterᵣ
          module Inverter(inverter : Inverter) where
            instance
              left : Inverterₗ
              left = [∧]-elimₗ inverter
            open Inverterₗ(left) public

            instance
              right : Inverterᵣ
              right = [∧]-elimᵣ inverter
            open Inverterᵣ(right) public

            module _ {x y : Obj} {f : x ⟶ y} where
              instance
                inverse : Morphism.Inverse(_▫_)(\{x} → id{x})(f)(inv f)
                inverse = [∧]-intro inverseₗ inverseᵣ
              open Morphism.Inverse(_▫_)(\{x} → id{x})(f)(inv f)(inverse) renaming (left to inverseₗ ; right to inverseᵣ)

            invertibleₗ : ∀{x y : Obj}{f : x ⟶ y} → Morphism.Invertibleₗ(_▫_)(\{x} → id{x})(f)
            invertibleₗ {f = f} = [∃]-intro (inv f) ⦃ inverseₗ ⦄

            invertibleᵣ : ∀{x y : Obj}{f : x ⟶ y} → Morphism.Invertibleᵣ(_▫_)(\{x} → id{x})(f)
            invertibleᵣ {f = f} = [∃]-intro (inv f) ⦃ inverseᵣ ⦄

            isomorphism : ∀{x y : Obj}{f : x ⟶ y} → Morphism.Isomorphism(_▫_)(\{x} → id{x})(f)
            isomorphism {f = f} = [∃]-intro (inv f) ⦃ inverse ⦄

    open OperModule public
    open IdModule   public


module slots.defs where

open import slots.imports

record config
  : Set where

  field
    n : ℕ -- reel count
    m : ℕ -- fruit count

  Win/Bet = ℕ -- win per 1 bet
  Fruit = Fin m
  ReelNo = Fin n
  Reel = List Fruit
  Reels = Vec Reel n
  WinLine = Vec Win/Bet n
  WinTable = Vec WinLine m
  Line = Vec Fruit n

record game (cfg : config) : Set where
  open config cfg

  field
    reels : Reels
    winTable : WinTable


module Interior where

open import Basics
open import Ix
open import All
open import Cutting

module INTERIOR {I}(C : I |> I) where

  open _|>_ C

  data Interior (P : I -> Set)(i : I) : Set where
    tile : P i -> Interior P i
    <_>  : Cutting C (Interior P) i -> Interior P i

  ifold : forall {P Q} ->
          [ P -:> Q ] ->
          [ Cutting C Q -:> Q ] ->
          [ Interior P -:> Q ]
  ifolds : forall {P Q} ->
          [ P -:> Q ] ->
          [ Cutting C Q -:> Q ] ->
          [ All (Interior P) -:> All Q ]
  ifold pq cq i (tile p) = pq i p
  ifold pq cq i < c 8>< ps > = cq i (c 8>< ifolds pq cq _ ps)
  ifolds pq cq [] <> = <>
  ifolds pq cq (i ,- is) (x , xs) = ifold pq cq i x , ifolds pq cq is xs

  -- tile : [ P -:> Interior P ]

  extend : forall {P Q} ->
          [ P -:> Interior Q ] ->
          [ Interior P -:> Interior Q ]
  extend k = ifold k (\ i x -> < x >)

  -- and we have a monad, not in Set, but in I -> Set

open INTERIOR NatCut
{-
foo : Interior (\ n -> n == 3) 12
foo = < ((3 , 9 , refl _)) 8>< (tile (refl _) , {!!} , <>) >
-}


module GGT.Group.Structures
  {a b ℓ}
  where

open import Relation.Unary using (Pred)
open import Relation.Binary
open import Algebra.Bundles using (Group)
open import Level
open import GGT.Group.Definitions

record IsSubGroup (G : Group a ℓ) (P : Pred (Group.Carrier G) b) : Set (a ⊔ b ⊔ ℓ) where
  open Group G
  field
    ε∈ : (P ε)
    ∙-⁻¹-closed : IsOpInvClosed G P
    r : P Respects _≈_

  -- coset relation
  _∼_ : Rel Carrier b
  x ∼ y = P (x - y)

syntax IsSubGroup G P = P ≤ G


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

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Equiv.HalfAdjoint
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.SIP

open import Cubical.Data.Sigma

open import Cubical.Structures.Axioms
open import Cubical.Structures.Auto
open import Cubical.Structures.Macro
open import Cubical.Algebra.Ring      renaming (⟨_⟩ to ⟨_⟩r)
open import Cubical.Algebra.AbGroup   hiding (⟨_⟩)
open import Cubical.Algebra.Group     hiding (⟨_⟩)

open Iso

private
  variable
    ℓ : Level

record IsLeftModule (R : Ring {ℓ}) {M : Type ℓ}
              (0m : M)
              (_+_ : M → M → M)
              (-_ : M → M)
              (_⋆_ : ⟨ R ⟩r → M → M) : Type ℓ where

  constructor ismodule

  open Ring R using (_·_; 1r) renaming (_+_ to _+r_)

  field
    +-isAbGroup : IsAbGroup 0m _+_ -_
    ⋆-assoc : (r s : ⟨ R ⟩r) (x : M) → (r · s) ⋆ x ≡ r ⋆ (s ⋆ x)
    ⋆-ldist : (r s : ⟨ R ⟩r) (x : M) → (r +r s) ⋆ x ≡ (r ⋆ x) + (s ⋆ x)
    ⋆-rdist : (r : ⟨ R ⟩r) (x y : M) → r ⋆ (x + y) ≡ (r ⋆ x) + (r ⋆ y)
    ⋆-lid   : (x : M) → 1r ⋆ x ≡ x

  open IsAbGroup +-isAbGroup public
    renaming
    ( assoc       to +-assoc
    ; identity    to +-identity
    ; lid         to +-lid
    ; rid         to +-rid
    ; inverse     to +-inv
    ; invl        to +-linv
    ; invr        to +-rinv
    ; comm        to +-comm
    ; isSemigroup to +-isSemigroup
    ; isMonoid    to +-isMonoid
    ; isGroup     to +-isGroup
    )

record LeftModule (R : Ring {ℓ}) : Type (ℓ-suc ℓ) where

  constructor leftmodule

  field
    Carrier        : Type ℓ
    0m             : Carrier
    _+_            : Carrier → Carrier → Carrier
    -_             : Carrier → Carrier
    _⋆_            : ⟨ R ⟩r → Carrier → Carrier
    isLeftModule   : IsLeftModule R 0m _+_ -_ _⋆_

  open IsLeftModule isLeftModule public

module _ {R : Ring {ℓ}} where
  ⟨_⟩ : LeftModule R → Type ℓ
  ⟨_⟩ = LeftModule.Carrier

  LeftModule→AbGroup : (M : LeftModule R) → AbGroup {ℓ}
  LeftModule→AbGroup (leftmodule _ _ _ _ _ isLeftModule) =
                     abgroup _ _ _ _ (IsLeftModule.+-isAbGroup isLeftModule)

  isSetLeftModule : (M : LeftModule R) → isSet ⟨ M ⟩
  isSetLeftModule M = isSetAbGroup (LeftModule→AbGroup M)

  open Ring R using (1r) renaming (_+_ to _+r_; _·_ to _·s_)

  makeIsLeftModule : {M : Type ℓ} {0m : M}
                  {_+_ : M → M → M} { -_ : M → M} {_⋆_ : ⟨ R ⟩r → M → M}
                  (isSet-M : isSet M)
                  (+-assoc :  (x y z : M) → x + (y + z) ≡ (x + y) + z)
                  (+-rid : (x : M) → x + 0m ≡ x)
                  (+-rinv : (x : M) → x + (- x) ≡ 0m)
                  (+-comm : (x y : M) → x + y ≡ y + x)
                  (⋆-assoc : (r s : ⟨ R ⟩r) (x : M) → (r ·s s) ⋆ x ≡ r ⋆ (s ⋆ x))
                  (⋆-ldist : (r s : ⟨ R ⟩r) (x : M) → (r +r s) ⋆ x ≡ (r ⋆ x) + (s ⋆ x))
                  (⋆-rdist : (r : ⟨ R ⟩r) (x y : M) → r ⋆ (x + y) ≡ (r ⋆ x) + (r ⋆ y))
                  (⋆-lid   : (x : M) → 1r ⋆ x ≡ x)
                → IsLeftModule R 0m _+_ -_ _⋆_
  makeIsLeftModule isSet-M
                +-assoc +-rid +-rinv +-comm
                ⋆-assoc ⋆-ldist ⋆-rdist ⋆-lid =
                ismodule (makeIsAbGroup isSet-M +-assoc +-rid +-rinv +-comm)
                         ⋆-assoc ⋆-ldist ⋆-rdist ⋆-lid

record LeftModuleEquiv {R : Ring {ℓ}} (M N : LeftModule R) : Type ℓ where

  constructor moduleiso

  private
    instance
      _ : LeftModule R
      _ = M
      _ : LeftModule R
      _ = N

  open LeftModule {{...}}

  field
    e : ⟨ M ⟩ ≃ ⟨ N ⟩
    isHom+ : (x y : ⟨ M ⟩) → equivFun e (x + y) ≡ equivFun e x + equivFun e y
    comm⋆ : (r : ⟨ R ⟩r) (x : ⟨ M ⟩) → equivFun e (r ⋆ x) ≡ r ⋆ equivFun e x

module LeftModuleΣTheory (R : Ring {ℓ}) where

  RawLeftModuleStructure = λ (M : Type ℓ) → (M → M → M) × (⟨ R ⟩r → M → M)

  RawLeftModuleEquivStr = AutoEquivStr RawLeftModuleStructure

  rawLeftModuleUnivalentStr : UnivalentStr _ RawLeftModuleEquivStr
  rawLeftModuleUnivalentStr = autoUnivalentStr RawLeftModuleStructure

  open Ring R using (_·_; 1r) renaming (_+_ to _+r_)

  LeftModuleAxioms : (M : Type ℓ) (s : RawLeftModuleStructure M) → Type ℓ
  LeftModuleAxioms M (_+_ , _⋆_) = AbGroupΣTheory.AbGroupAxioms M _+_
                                    × ((r s : ⟨ R ⟩r) (x : M) → (r · s) ⋆ x ≡ r ⋆ (s ⋆ x))
                                    × ((r s : ⟨ R ⟩r) (x : M) → (r +r s) ⋆ x ≡ (r ⋆ x) + (s ⋆ x))
                                    × ((r : ⟨ R ⟩r) (x y : M) → r ⋆ (x + y) ≡ (r ⋆ x) + (r ⋆ y))
                                    × ((x : M) → 1r ⋆ x ≡ x)

  LeftModuleStructure : Type ℓ → Type ℓ
  LeftModuleStructure = AxiomsStructure RawLeftModuleStructure LeftModuleAxioms

  LeftModuleΣ : Type (ℓ-suc ℓ)
  LeftModuleΣ = TypeWithStr ℓ LeftModuleStructure

  LeftModuleEquivStr : StrEquiv LeftModuleStructure ℓ
  LeftModuleEquivStr = AxiomsEquivStr RawLeftModuleEquivStr LeftModuleAxioms

  open AbGroupΣTheory using (isSetAbGroupΣ)

  isSetLeftModuleΣ : (M : LeftModuleΣ)  → isSet _
  isSetLeftModuleΣ (M , (_+_ , _) , (isAbGroup-M , _)) = isSetAbGroupΣ (M , _+_ , isAbGroup-M)

  isPropLeftModuleAxioms : (M : Type ℓ) (s : RawLeftModuleStructure M)
                             → isProp (LeftModuleAxioms M s)
  isPropLeftModuleAxioms M (_+_ , _⋆_) =
     isPropΣ (AbGroupΣTheory.isPropAbGroupAxioms M _+_)
             λ isAbGroup-M →
             isProp× (isPropΠ3 λ _ _ _ → (isSetAbGroupΣ (M , _+_ , isAbGroup-M)) _ _)
            (isProp× (isPropΠ3 λ _ _ _ → (isSetAbGroupΣ (M , _+_ , isAbGroup-M)) _ _)
            (isProp× (isPropΠ3 λ _ _ _ → (isSetAbGroupΣ (M , _+_ , isAbGroup-M)) _ _)
                     (isPropΠ  λ _     → (isSetAbGroupΣ (M , _+_ , isAbGroup-M)) _ _)))

  LeftModule→LeftModuleΣ : LeftModule R → LeftModuleΣ
  LeftModule→LeftModuleΣ
    (leftmodule M 0m _+_ -_ _⋆_ (ismodule +-isAbGroup ⋆-assoc ⋆-ldist ⋆-rdist ⋆-lid)) =
    M , (_+_ , _⋆_) ,
    AbGroupΣTheory.AbGroup→AbGroupΣ (abgroup _ _ _ _ +-isAbGroup) .snd .snd ,
    ⋆-assoc , ⋆-ldist , ⋆-rdist , ⋆-lid

  LeftModuleΣ→LeftModule : LeftModuleΣ → LeftModule R
  LeftModuleΣ→LeftModule (M , (_+_ , _⋆_) , isAbGroup-M , ⋆-assoc , ⋆-ldist , ⋆-rdist , ⋆-lid) =
    let isAbGroup = AbGroupΣTheory.AbGroupΣ→AbGroup (_ , _ , isAbGroup-M ) .AbGroup.isAbGroup
    in leftmodule M _ _+_ _ _⋆_
       (ismodule isAbGroup ⋆-assoc ⋆-ldist ⋆-rdist ⋆-lid)

  LeftModuleIsoLeftModuleΣ : Iso (LeftModule R) LeftModuleΣ
  LeftModuleIsoLeftModuleΣ = iso LeftModule→LeftModuleΣ LeftModuleΣ→LeftModule
                                 (λ _ → refl) helper
    where
      open AbGroupΣTheory
      abgroup-helper : retract (AbGroup→AbGroupΣ {ℓ}) AbGroupΣ→AbGroup
      abgroup-helper = Iso.leftInv AbGroupIsoAbGroupΣ

      open LeftModule
      open IsLeftModule
      helper : _
      Carrier (helper M i) = Carrier M
      0m (helper M i) = 0m M
      _+_ (helper M i) = _+_ M
      -_ (helper M i) =  -_ M
      _⋆_ (helper M i) = _⋆_ M

      +-isAbGroup (isLeftModule (helper M i)) =
        AbGroup.isAbGroup (abgroup-helper (abgroup _ _ _ _ (+-isAbGroup M)) i)
      ⋆-assoc (isLeftModule (helper M i)) = ⋆-assoc M
      ⋆-ldist (isLeftModule (helper M i)) = ⋆-ldist M
      ⋆-rdist (isLeftModule (helper M i)) = ⋆-rdist M
      ⋆-lid (isLeftModule (helper M i)) = ⋆-lid M

  leftModuleUnivalentStr : UnivalentStr LeftModuleStructure LeftModuleEquivStr
  leftModuleUnivalentStr = axiomsUnivalentStr _ isPropLeftModuleAxioms rawLeftModuleUnivalentStr

  LeftModuleΣPath : (M N : LeftModuleΣ) → (M ≃[ LeftModuleEquivStr ] N) ≃ (M ≡ N)
  LeftModuleΣPath = SIP leftModuleUnivalentStr

  LeftModuleEquivStrΣ : (M N : LeftModule R) → Type ℓ
  LeftModuleEquivStrΣ M N = LeftModule→LeftModuleΣ M ≃[ LeftModuleEquivStr ] LeftModule→LeftModuleΣ N

  LeftModuleEquivStrΣPath : {M N : LeftModule R} → Iso (LeftModuleEquiv M N) (LeftModuleEquivStrΣ M N)
  fun LeftModuleEquivStrΣPath (moduleiso e isHom+ comm⋆) = e , isHom+ , comm⋆
  inv LeftModuleEquivStrΣPath (e , isHom+ , comm⋆) = moduleiso e isHom+ comm⋆
  rightInv LeftModuleEquivStrΣPath _ = refl
  leftInv LeftModuleEquivStrΣPath _ = refl

  LeftModulePath : (M N : LeftModule R) → (LeftModuleEquiv M N) ≃ (M ≡ N)
  LeftModulePath M N =
    LeftModuleEquiv M N                                    ≃⟨ isoToEquiv LeftModuleEquivStrΣPath ⟩
    LeftModuleEquivStrΣ M N                                   ≃⟨ LeftModuleΣPath _ _ ⟩
    LeftModule→LeftModuleΣ M ≡ LeftModule→LeftModuleΣ N  ≃⟨ isoToEquiv
                                                             (invIso
                                                             (congIso
                                                             LeftModuleIsoLeftModuleΣ))
                                                           ⟩
    M ≡ N ■

LeftModulePath : {R : Ring {ℓ}} (M N : LeftModule R) → (LeftModuleEquiv M N) ≃ (M ≡ N)
LeftModulePath {ℓ} {R} = LeftModuleΣTheory.LeftModulePath R


{-

This file contains the classic isomorphism theorems for groups (so far
only the first theorem)

-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.Group.IsomorphismTheorems where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Structure
open import Cubical.Foundations.Powerset
open import Cubical.Foundations.Function
open import Cubical.Data.Sigma
open import Cubical.HITs.SetQuotients renaming (_/_ to _/s_ ; rec to recS ; elim to elimS)
open import Cubical.HITs.PropositionalTruncation

open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Group.Properties
open import Cubical.Algebra.Group.Morphisms
open import Cubical.Algebra.Group.MorphismProperties
open import Cubical.Algebra.Group.Subgroup
open import Cubical.Algebra.Group.QuotientGroup
open import Cubical.Algebra.Group.GroupPath

private
  variable
    ℓ : Level

-- The first isomorphism theorem: im ϕ ≃ G / ker ϕ
module _ {G H : Group ℓ} (ϕ : GroupHom G H) where

  open isSubgroup
  open Iso
  open GroupTheory

  kerNormalSubgroup : NormalSubgroup G
  kerNormalSubgroup = kerSubgroup ϕ , isNormalKer ϕ

  private
    imϕ : Group ℓ
    imϕ = imGroup ϕ

  -- for completeness:
  imNormalSubgroup : ((x y : ⟨ H ⟩)
    → GroupStr._·_ (snd H) x y ≡ GroupStr._·_ (snd H) y x)
    → NormalSubgroup H
  imNormalSubgroup comm = imSubgroup ϕ , isNormalIm ϕ comm

  private
    module G = GroupStr (snd G)
    module H = GroupStr (snd H)
    module imG = GroupStr (snd imϕ)
    module kerG = GroupStr (snd (G / kerNormalSubgroup))
    module ϕ = IsGroupHom (ϕ .snd)

  f1 : ⟨ imϕ ⟩ → ⟨ G / kerNormalSubgroup ⟩
  f1 (x , Hx) = rec→Set ( squash/)
                         (λ { (y , hy) → [ y ]})
                         (λ { (y , hy) (z , hz) → eq/ y z (rem y z hy hz) })
                         Hx
    where
    rem : (y z : ⟨ G ⟩) → ϕ .fst y ≡ x → ϕ .fst z ≡ x → ϕ .fst (y G.· G.inv z) ≡ H.1g
    rem y z hy hz =
      ϕ .fst (y G.· G.inv z)        ≡⟨ ϕ.pres· _ _ ⟩
      ϕ .fst y H.· ϕ .fst (G.inv z) ≡⟨ cong (ϕ .fst y H.·_) (ϕ.presinv _) ⟩
      ϕ .fst y H.· H.inv (ϕ .fst z) ≡⟨ (λ i → hy i H.· H.inv (hz i)) ⟩
      x H.· H.inv x                 ≡⟨ H.·InvR x ⟩
      H.1g                          ∎

  f2 : ⟨ G / kerNormalSubgroup ⟩ → ⟨ imϕ ⟩
  f2 = recS imG.is-set (λ y → ϕ .fst y , ∣ y , refl ∣₁)
                       (λ x y r → Σ≡Prop (λ _ → squash₁)
                       (rem x y r))
    where
    rem : (x y : ⟨ G ⟩) → ϕ .fst (x G.· G.inv y) ≡ H.1g → ϕ .fst x ≡ ϕ .fst y
    rem x y r =
      ϕ .fst x                                      ≡⟨ sym (H.·IdR _) ⟩
      ϕ .fst x H.· H.1g                             ≡⟨ cong (ϕ .fst x H.·_) (sym (H.·InvL _)) ⟩
      ϕ .fst x H.· H.inv (ϕ .fst y) H.· ϕ .fst y    ≡⟨ (λ i → ϕ .fst x H.· ϕ.presinv y (~ i) H.· ϕ .fst y) ⟩
      ϕ .fst x H.· ϕ .fst (G.inv y) H.· ϕ .fst y    ≡⟨ H.·Assoc _ _ _ ⟩
      (ϕ .fst x H.· ϕ .fst (G.inv y)) H.· ϕ .fst y  ≡⟨ cong (H._· _) (sym (ϕ.pres· _ _)) ⟩
      ϕ .fst (x G.· G.inv y) H.· ϕ .fst y           ≡⟨ cong (H._· ϕ .fst y) r ⟩
      H.1g H.· ϕ .fst y                             ≡⟨ H.·IdL _ ⟩
      ϕ .fst y ∎

  f12 : (x : ⟨ G / kerNormalSubgroup ⟩) → f1 (f2 x) ≡ x
  f12 = elimProp (λ _ → squash/ _ _) (λ _ → refl)

  f21 : (x : ⟨ imϕ ⟩) → f2 (f1 x) ≡ x
  f21 (x , hx) = elim {P = λ hx → f2 (f1 (x , hx)) ≡ (x , hx)}
                      (λ _ → imG.is-set _ _)
                      (λ {(x , hx) → Σ≡Prop (λ _ → squash₁) hx})
                      hx

  f1-isHom : (x y : ⟨ imϕ ⟩) → f1 (x imG.· y) ≡ f1 x kerG.· f1 y
  f1-isHom (x , hx) (y , hy) =
    elim2 {P = λ hx hy → f1 ((x , hx) imG.· (y , hy)) ≡ f1 (x , hx) kerG.· f1 (y , hy)}
          (λ _ _ → kerG.is-set _ _) (λ _ _ → refl) hx hy

  -- The first isomorphism theorem for groups
  isoThm1 : GroupIso imϕ (G / kerNormalSubgroup)
  fun (fst isoThm1) = f1
  inv (fst isoThm1) = f2
  rightInv (fst isoThm1) = f12
  leftInv (fst isoThm1) = f21
  snd isoThm1 = makeIsGroupHom f1-isHom

  -- The SIP lets us turn the isomorphism theorem into a path
  pathThm1 : imϕ ≡ G / kerNormalSubgroup
  pathThm1 = uaGroup (GroupIso→GroupEquiv isoThm1)

  surjImIso : isSurjective ϕ → GroupIso imϕ H
  surjImIso surj =
    BijectionIso→GroupIso
      (bijIso indHom
              (uncurry
                (λ h → elim (λ _ → isPropΠ (λ _ → imG.is-set _ _))
                  (uncurry λ g y
                    → λ inker → Σ≡Prop (λ _ → squash₁) inker)))
              λ b → map (λ x → (b , ∣ x ∣₁) , refl) (surj b))
    where
    indHom : GroupHom imϕ H
    fst indHom = fst
    snd indHom = makeIsGroupHom λ _ _ → refl


open import Type

module Structure.Container.IndexedIterable {ℓᵢ} {Index : Type{ℓᵢ}} where

import      Lvl
open import Data
open import Data.Boolean
open import Data.Boolean.Stmt
open import Data.Option
import      Data.Option.Functions as Option
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Functional
open import Logic.Propositional
open import Logic.Predicate
open import Numeral.Natural
open import Numeral.Natural.Relation.Order
open import Relator.Equals

private variable ℓ ℓₑ ℓₑ₁ ℓₑ₂ : Lvl.Level
private variable T : Type{ℓ}
private variable Elem : Type{ℓₑ}
private variable i : Index

module _ (Iter : Index → Type{ℓ}) where
  IsEmptyTypeFn = ∀{i} → Iter(i) → Bool

  IndexStepFn : IsEmptyTypeFn → Type
  IndexStepFn isEmpty = ∀{i} → (iter : Iter(i)) → (if isEmpty(iter) then Unit else Index)

  CurrentFn : Type{ℓₑ} → IsEmptyTypeFn → Type
  CurrentFn Element isEmpty = ∀{i} → (iter : Iter(i)) → (if isEmpty(iter) then Unit else Element)

  StepFn : Type{ℓₑ} → (isEmpty : IsEmptyTypeFn) → IndexStepFn isEmpty → Type
  StepFn Element isEmpty indexStep =  ∀{i} → (iter : Iter(i)) → Out iter where
    Out : Iter(i) → Type
    Out iter with isEmpty iter | indexStep iter
    ... | 𝑇 | <> = Unit
    ... | 𝐹 | is = Iter(is)

-- An iterator type `Iter` is iterable when there may be elements that the iterator can yield in sequence.
-- It should be possible to decide whether the iterator is empty, and when it is not, get the element it points to and advancing to its next state containing the next element in order.
record Iterable (Iter : Index → Type{ℓ}) {ℓₑ} : Type{ℓ Lvl.⊔ ℓᵢ Lvl.⊔ Lvl.𝐒(ℓₑ)} where
  field
    -- The type of the elements in the iterator.
    {Element} : Type{ℓₑ}

    -- Whether there are no elements left in the iterator.
    isEmpty : IsEmptyTypeFn(Iter)

    -- The current/frontmost element in the iterator if it is non-empty.
    current : CurrentFn(Iter) Element isEmpty

    -- The next iterator index. Advances the index if the iterator is non-empty.
    {indexStep} : IndexStepFn(Iter) isEmpty

    -- The next iterator state. Advancing the iterator if it is non-empty.
    step : StepFn(Iter) Element isEmpty indexStep

  -- Whether there are at most the given number of elements in the iterator.
  atMost : ℕ → Iter(i) → Bool
  atMost(𝟎)    iter = isEmpty(iter)
  atMost(𝐒(n)) iter with isEmpty(iter) | indexStep iter | step iter
  ... | 𝑇 | <>  | <> = 𝑇
  ... | 𝐹 | _   | is = atMost(n) is

  -- Skipping the given number of iterator indices. Advances as many steps as possible.
  indexWalk : (n : ℕ) → (iter : Iter(i)) → (if(atMost n iter) then Unit else Index)
  indexWalk {i} 𝟎 iter with isEmpty(iter)
  ... | 𝑇 = <>
  ... | 𝐹 = i
  indexWalk {i} (𝐒(n)) iter with isEmpty(iter) | indexStep iter | step iter
  ... | 𝑇 | <> | <>    = <>
  ... | 𝐹 | _  | iters = indexWalk n iters

  WalkFn : Type
  WalkFn = ∀{i} → (n : ℕ) → (iter : Iter(i)) → Out n iter where
    Out : ℕ → Iter(i) → Type
    Out n iter with atMost n iter | indexWalk n iter
    ... | 𝑇 | <> = Unit
    ... | 𝐹 | is = Iter(is)

    {-
    walk : WalkFn
    walk(𝟎) iter with isEmpty(iter)
    ... | 𝑇 = <>
    ... | 𝐹 = iter
    walk(𝐒(n)) iter with isEmpty(iter) | indexStep iter | step iter | walk n iter
    ... | 𝑇 | <> | <>    | _    = <>
    ... | 𝐹 | _  | iters | iters2 = ? -- walk n iters
    -}

  Foldᵣ : ∀{ℓ} → Type{ℓ} → Type
  Foldᵣ(T) = ∀{i} → (Element → T → T) → T → Iter(i) → T

  FoldᵣCriteria : Foldᵣ(T) → (∀{i} → (Element → T → T) → T → Iter(i) → Type)
  FoldᵣCriteria foldᵣ(_▫_) id iter with isEmpty iter | indexStep iter | current iter | step iter
  ... | 𝑇 | <> | <> | <>    = (foldᵣ(_▫_) id iter ≡ id)
  ... | 𝐹 | _  | x  | iters = (foldᵣ(_▫_) id iter ≡ x ▫ foldᵣ(_▫_) id iters)

  -- An iterator is finite when it is possible to fold it (when a fold function exists).
  -- This works because a fold for an infinite iterator cannot terminate, and only terminating functions exist.
  -- TODO: But it seems to be impossible to define a "foldUntil" function (though it is up to function extensionality).
  Finite = ∀{ℓ}{T : Type{ℓ}} → ∃{Obj = Foldᵣ(T)}(foldᵣ ↦ ∀{i}{_▫_}{id : T}{iter : Iter(i)} → FoldᵣCriteria (\{i}(_▫_) id → foldᵣ{i}(_▫_) id) (_▫_) id iter)
  module _ ⦃ fin : Finite ⦄ where
    foldᵣ : ∀{i} → (Element → T → T) → T → Iter(i) → T
    foldᵣ = [∃]-witness fin

    length : ∀{i} → Iter(i) → ℕ
    length = foldᵣ(const 𝐒) 𝟎

    count : ∀{i} → (Element → Bool) → Iter(i) → ℕ
    count(P) = foldᵣ(x ↦ if P(x) then 𝐒 else id) 𝟎

    foldₗ : (T → Element → T) → T → Iter(i) → T
    foldₗ(_▫_) = swap(foldᵣ(y ↦ f ↦ x ↦ f(x ▫ y)) id)

    last : ∀{i} → Iter(i) → Option(Element)
    last = foldₗ(const Some) None

    -- Note: Below are possibly inefficient implementations of functions because if they were guaranteed to exit early, the number of computations would be reduced.
    first : ∀{i} → Iter(i) → Option(Element)
    first = foldᵣ(const ∘ Some) None

  -- TODO: Complete = Surjective(step)

  record Initialed (i : Index) : Type{ℓᵢ Lvl.⊔ ℓ} where
    constructor initialed
    eta-equality
    field
      iter : Iter(i)
      left : ℕ

  Initialed-iterable : Iterable(Initialed)
  Element   Initialed-iterable = Element
  isEmpty   Initialed-iterable (initialed iter 𝟎)      = 𝑇
  current   Initialed-iterable (initialed iter 𝟎)      = <>
  indexStep Initialed-iterable (initialed iter 𝟎)      = <>
  step      Initialed-iterable (initialed iter 𝟎)      = <>
  isEmpty   Initialed-iterable (initialed iter (𝐒(_))) = isEmpty iter
  current   Initialed-iterable (initialed iter (𝐒(_))) = current iter
  indexStep Initialed-iterable (initialed iter (𝐒(_))) = indexStep iter
  step      Initialed-iterable (initialed iter (𝐒(n))) with isEmpty iter | indexStep iter | step iter
  ... | 𝑇 | _ | _     = <>
  ... | 𝐹 | _ | sIter = initialed sIter n

  {-
  record Skipped (i : Index) : Type{ℓᵢ Lvl.⊔ ℓ} where
    constructor skipped
    eta-equality
    field
      iter  : Iter(i)
      still : ℕ

  Skipped-iterable : Iterable(Skipped)
  Element   Skipped-iterable = Element
  isEmpty   Skipped-iterable (skipped iter 𝟎)      = 𝑇
  current   Skipped-iterable (skipped iter 𝟎)      = <>
  indexStep Skipped-iterable (skipped iter 𝟎)      = <>
  step      Skipped-iterable (skipped iter 𝟎)      = <>
  isEmpty   Skipped-iterable (skipped iter (𝐒(_))) = isEmpty (walk (𝐒(n)) iter)
  current   Skipped-iterable (skipped iter (𝐒(_))) = current (walk (𝐒(n)) iter)
  indexStep Skipped-iterable (skipped iter (𝐒(_))) = indexStep (walk (𝐒(n)) iter)
  step      Skipped-iterable (skipped iter (𝐒(n))) with isEmpty iter | indexStep iter | step iter
  -}

  mapped : (Element → Elem) → Iterable(Iter)
  Element (mapped {Elem = Elem} f) = Elem
  isEmpty (mapped f) = isEmpty
  current (mapped f) iter with isEmpty iter | current iter
  ... | 𝑇 | <> = <>
  ... | 𝐹 | x  = f(x)
  indexStep (mapped f) iter = indexStep iter
  step      (mapped f) iter = step iter

{-record Stored (n : ℕ) {Iter : Index → Type{ℓ₁}} (iterable : Iterable(Iter)) : Type where
  field
    Queue(Iterator.Element(iterable))
-}

  {- TODO: Also needs to store data, so it cannot be the same Iter
  skipped : ℕ → Iterator{ℓₑ} → Iterator
  Iterator.Element (skipped _ iterator) = Iterator.Element iterator
  Iterator.isEmpty (skipped n iterator) = Iterator.atMost n iterator
  Iterator.current (skipped _ iterator) =
  Iterator.indexStep (skipped iterator) =
  Iterator.step      (skipped iterator) =
-}

{-
skipped : ℕ → ∀{iter} → Iterable{ℓₑ}(iter) → Iterable(iter)
skipped 𝟎 iterable = iterable
skipped (𝐒 n) iterable = {!!}
-}

  -- An empty iterator of the iterable.
  EmptyConstruction : ∀{i} → Iter(i) → Type
  EmptyConstruction(empty) = IsTrue(isEmpty empty)

  -- A function prepending an element to an iterator of the iterable.
  PrependConstruction : ∀{indexPrepend : ∀{i} → Element → Iter(i) → Index} → (∀{i} → (x : Element) → (iter : Iter(i)) → Iter(indexPrepend x iter)) → Type
  PrependConstruction{indexPrepend} (prepend) = ∀{i}{x}{iter : Iter(i)} → ∃{Obj = IndexStep x iter}(Out x iter) where
    IndexStep : Element → Iter(i) → Type
    IndexStep{i} x iter with isEmpty(prepend x iter) | indexStep(prepend x iter)
    ... | 𝑇 | _ = Empty
    ... | 𝐹 | p = (p ≡ i)

    Out : (x : Element) → (iter : Iter(i)) → IndexStep x iter → Type
    Out x iter stepProof with isEmpty(prepend x iter) | indexStep(prepend x iter) | current(prepend x iter) | step(prepend x iter)
    ... | 𝐹 | _ | cur | st with [≡]-intro ← stepProof = (x ≡ cur) ∧ (st ≡ iter)

  module _
    {indexEmpty}{empty}
    ⦃ empty-construciton : EmptyConstruction{indexEmpty}(empty) ⦄
    {indexPrepend : ∀{i} → Element → Iter(i) → Index}
    {prepend : ∀{i} → (x : Element) → (iter : Iter(i)) → Iter(indexPrepend x iter)}
    ⦃ prepend-construction : PrependConstruction{indexPrepend}(prepend) ⦄
    where

    singleton : (x : Element) → Iter(indexPrepend x empty)
    singleton x = prepend x empty


{-# OPTIONS --cubical #-}

module Issue2799 where

open import Agda.Primitive.Cubical

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

{-# BUILTIN PATHP        PathP     #-}

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

record Stream (A : Set) : Set where
  coinductive
  constructor _,_
  field
    head : A
    tail : Stream A

open Stream

mapS : ∀ {A B} → (A → B) → Stream A → Stream B
head (mapS f xs) = f (head xs)
tail (mapS f xs) = mapS f (tail xs)

mapS-id : ∀ {A} {xs : Stream A} → mapS (λ x → x) xs ≡ xs
head (mapS-id {xs = xs} i) = head xs
tail (mapS-id {xs = xs} i) = mapS-id {xs = tail xs} i


module Data.ListSized.Proofs where

import      Lvl
open import Data.ListSized
open import Data.ListSized.Functions
open import Functional
open import Function.Equals
open import Numeral.Finite
open import Numeral.Natural
open import Numeral.Natural.Function
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Proofs
open import Relator.Equals
open import Relator.Equals.Proofs.Equiv
open import Structure.Operator
open import Structure.Relator.Properties
open import Syntax.Transitivity
open import Type

private variable ℓ ℓ₁ ℓ₂ : Lvl.Level
private variable T A A₁ A₂ B B₁ B₂ C C₁ C₂ Result : Type{ℓ}
private variable a b n n₁ n₂ : ℕ
private variable f : B → C
private variable g : A → B
private variable l l₁ l₂ : List(T)(n)
private variable x : T

map-id : (map{A = A}{n = n} id ⊜ id)
_⊜_.proof map-id {∅}     = reflexivity(_≡_)
_⊜_.proof map-id {x ⊰ l} = congruence₂ᵣ(_⊰_)(_) (_⊜_.proof map-id {l})

map-[∘] : (map{n = n} (f ∘ g) ⊜ (map f) ∘ (map g))
_⊜_.proof map-[∘] {∅}     = reflexivity(_≡_)
_⊜_.proof map-[∘] {x ⊰ l} = congruence₂ᵣ(_⊰_)(_) (_⊜_.proof map-[∘] {l})

map-[++] : map f(l₁ ++ l₂) ≡ map f(l₁) ++ map f(l₂)
map-[++] {l₁ = ∅}       = reflexivity(_≡_)
map-[++] {l₁ = x₁ ⊰ l₁} = congruence₂ᵣ(_⊰_)(_) (map-[++] {l₁ = l₁})

map-repeat : map f(repeat x n) ≡ repeat (f(x)) n
map-repeat {n = 𝟎}   = reflexivity(_≡_)
map-repeat {n = 𝐒 n} = congruence₂ᵣ(_⊰_)(_) (map-repeat {n = n})

[+][++]-repeat : repeat x (n₁ + n₂) ≡ repeat x n₁ ++ repeat x n₂
[+][++]-repeat {n₁ = 𝟎}    = reflexivity(_≡_)
[+][++]-repeat {n₁ = 𝐒 n₁} = congruence₂ᵣ(_⊰_)(_) ([+][++]-repeat {n₁ = n₁})


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

module Data.Vec.Iterated where

open import Data.Unit.UniversePolymorphic
open import Level
open import Data.Nat.Base
open import Function

private
  variable
    n m : ℕ

mutual
  Vec :  Type a → ℕ → Type a
  Vec A zero     = Vec⁰
  Vec A (suc n)  = Vec⁺ A n

  record Vec⁰ {a} : Type a where
    eta-equality
    constructor []

  infixr 5 _∷_
  record Vec⁺ {a} (A : Type a) (n : ℕ) : Type a where
    eta-equality
    inductive
    constructor _∷_
    field
      head : A
      tail : Vec A n

open Vec⁺ public

foldr : ∀ {p} (P : ℕ → Type p) →
          (∀ {n} → A → P n → P (suc n)) →
          P zero →
          Vec A n → P n
foldr {n = zero} P f b _         = b
foldr {n = suc n} P f b (x ∷ xs) = f x (foldr P f b xs)

foldl : ∀ {p} (P : ℕ → Type p) →
          (∀ {n} → A → P n → P (suc n)) →
          P zero →
          Vec A n → P n
foldl {n = zero } P f b _ = b
foldl {n = suc n} P f b (x ∷ xs) = foldl (P ∘ suc) f (f x b) xs

foldlN : ∀ {p} (P : ℕ → Type p) →
          (∀ {n} → A → P (suc n) → P n) →
          P n →
          Vec A n → P zero
foldlN P f b xs = foldr (λ n → P n → P zero) (λ x k xs → k (f x xs)) id xs b

module _ (f : A → B → B) (e : B) where
  foldr′ : Vec A n → B
  foldr′ {n = zero } xs = e
  foldr′ {n = suc n} (x ∷ xs) = f x (foldr′ xs)

foldl′ : (A → B → B) → B → Vec A n → B
foldl′ {n = zero}  f b xs = b
foldl′ {n = suc n} f b (x ∷ xs) = foldl′ f (f x b) xs

-- vecFromList : (xs : List A) → Vec A (length xs)
-- vecFromList List.[] = []
-- vecFromList (x List.∷ xs) = x ∷ vecFromList xs

-- vecToList : Vec A n → List A
-- vecToList = foldr′ List._∷_ List.[]

open import Data.Fin.Indexed

infixl 4 lookup
lookup : Fin n → Vec A n → A
lookup f0     = head
lookup (fs i) xs = lookup i (tail xs)

syntax lookup i xs = xs [ i ]

infixl 4 replace
replace : Fin n → A → Vec A n → Vec A n
replace f0     x xs .head = x
replace f0     x xs .tail = xs .tail
replace (fs i) x xs .head = xs .head
replace (fs i) x xs .tail = replace i x (xs .tail)

syntax replace i x xs = xs [ i ]≔ x


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

module Data.List.Kleene where

open import Prelude
open import Data.Fin

mutual
  infixr 5 _&_ ∹_
  infixl 5 _⁺ _⋆
  record _⁺ {a} (A : Set a) : Set a where
    inductive
    constructor _&_
    field
      head : A
      tail : A ⋆

  data _⋆ {a} (A : Set a) : Set a where
    [] : A ⋆
    ∹_ : A ⁺ → A ⋆
open _⁺ public

mutual
  foldr⁺ : (A → B → B) → B → A ⁺ → B
  foldr⁺ f b (x & xs) = f x (foldr⋆ f b xs)

  foldr⋆ : (A → B → B) → B → A ⋆ → B
  foldr⋆ f b [] = b
  foldr⋆ f b (∹ xs) = foldr⁺ f b xs

length⋆ : A ⋆ → ℕ
length⋆ = foldr⋆ (const suc) zero

length⁺ : A ⁺ → ℕ
length⁺ = foldr⁺ (const suc) zero

mutual
  _!⁺_ : (xs : A ⁺) → Fin (length⁺ xs) → A
  xs !⁺ f0  = xs .head
  xs !⁺ fs i = xs .tail !⋆ i

  _!⋆_ : (xs : A ⋆) → Fin (length⋆ xs) → A
  (∹ xs) !⋆ i = xs !⁺ i

map⋆ : (A → B) → A ⋆ → B ⋆
map⋆ f = foldr⋆ (λ x xs → ∹ f x & xs) []

map⁺ : (A → B) → A ⁺ → B ⁺
map⁺ f (x & xs) = f x & map⋆ f xs

mutual
  _⋆++⋆_ : A ⋆ → A ⋆ → A ⋆
  [] ⋆++⋆ ys = ys
  (∹ xs) ⋆++⋆ ys = ∹ (xs ⁺++⋆ ys)

  _⁺++⋆_ : A ⁺ → A ⋆ → A ⁺
  head (xs ⁺++⋆ ys) = head xs
  tail (xs ⁺++⋆ ys) = tail xs ⋆++⋆ ys


{-# OPTIONS --without-K --safe #-}
module Cats.Category.Constructions.Thin where

open import Cats.Category.Base

open import Level using (_⊔_)
open import Relation.Binary.PropositionalEquality using (_≡_)

module _ {lo la l≈} (C : Category lo la l≈) where

  open Category C

  Thin : Set (lo ⊔ la ⊔ l≈)
  Thin = ∀ {A B} {f g : A ⇒ B} → f ≈ g

  StronglyThin : Set (lo ⊔ la)
  StronglyThin = ∀ {A B} {f g : A ⇒ B} → f ≡ g

StronglyThin→Thin : ∀ {lo la l≈} {C : Category lo la l≈}
  → StronglyThin C → Thin C
StronglyThin→Thin {C = C} sthin = ≈.reflexive sthin
  where
    open Category C


-- Andreas, 2013-05-16, raised by Andrea 2015-02-10

open import Common.Size
open import Common.Prelude

data Wrap (A : SizeUniv) : SizeUniv where
-- data Wrap (A : Set) : Set where
  wrap : A → Wrap A

module M (f : ∀ i → Wrap (Size< i)) where

  test : ∀ i → Wrap (Size< i) → ⊥
  test i (wrap j) = test j (f j)

module N (pred : ∀ i → Size< i) where

  f = (λ i → wrap (pred i))
  open M f

  loop : Size → ⊥
  loop i = test i (f i)
  -- = test i (wrap (pred i))
  -- = test (pred i) ((λ i → wrap (pred i)) (pred i))
  -- = test (pred i) (wrap (pred (pred i)))
  -- = test (pred (pred i)) (wrap (pred (pred (pred i))))
  -- = ...


-- 2010-09-07 Andreas

module IrrelevantRecordMatching where

record Prod (A B : Set) : Set where
  constructor _,_
  field
    fst : A
    snd : B

wrongElim : {A : Set} -> .(Prod A A) -> A
wrongElim (a , a') = a
-- needs to fail because a is irrelevant


module Formalization.SKICombinatorCalculus where

import      Lvl
import      Function
open import Functional using (_∘_)
open import Type
open import Structure.Relator.Properties
open import Syntax.Transitivity

data Term : Type{Lvl.𝟎} where
  S   : Term               -- Fusion
  K   : Term               -- Constant
  _·_ : Term → Term → Term
infixl 30 _·_

pattern B  = S · (K · S) · K                 -- Composition
pattern C  = S · (S · (K · B) · S) · (K · K) -- Swapped application
pattern I  = S · K · K                       -- Identity of operation
pattern SA = (S · I) · I                     -- Self application
pattern W  = S · S · (S · K)                 --
pattern Ω  = SA · SA                         --
pattern SW = S · (K · (S · I)) · K           -- Swapped operation
T = C
Z = B
-- Z = C · (C · (B · N · (S · I · I)) · Ω) · I

{- TODO: Is this possible?
term-fn-type : ∀{ℓ} → Term → Type{Lvl.𝐒(ℓ)}
term-fn-type {ℓ} S = ∀{X Y Z : Type{ℓ}} → (X → (Y → Z)) → (X → Y) → (X → Z)
term-fn-type {ℓ} K = ∀{X Y : Type{ℓ}} → Y → X → Y
term-fn-type {ℓ} (x · y) = {!term-fn-type {ℓ} x!}
-}

module Derivation where
  -- TODO: But there are no base cases?
  data deriv : Term → Type{Lvl.𝟎} where
    constant : ∀{α β γ ι} → deriv(α · ((K · β) · γ) · ι) → deriv(α · β · ι)
    fuse     : ∀{α β γ δ ι} → deriv(α · (((S · β) · γ) · δ) · ι) → deriv(α · ((β · δ) · (γ · δ)) · ι)

  _⇒_ : Term → Term → Type
  a ⇒ b = ∀{α ι} → deriv(α · a · ι) → deriv(α · b · ι)

  identity : ∀{β} → ((I · β) ⇒ β)
  identity = constant ∘ fuse

  -- composition : ∀{α ι a b c} → deriv(α · (B · a · b · c) · ι) → deriv(α · ((a · (b · c))) · ι)
  -- composition = {!!}

-- TODO: Is this really correct? Should be similar to deriv
data _⟶_ : Term → Term → Type{Lvl.𝟎} where -- TODO: Use reflexive-transitive closure instead
  constant : ∀{c t} → (((K · c) · t) ⟶ c)
  fuse     : ∀{a b c} → ((((S · a) · b) · c) ⟶ ((a · c) · (b · c)))

  comp     : ∀{a₁ a₂ b₁ b₂} → (a₁ ⟶ a₂) → (b₁ ⟶ b₂) → ((a₁ · b₁) ⟶ (a₂ · b₂))
  refl     : ∀{a} → (a ⟶ a)
  trans    : ∀{a b c} → (a ⟶ b) → (b ⟶ c) → (a ⟶ c)
infixl 29 _⟶_

instance
  [⟶]-reflexivity : Reflexivity(_⟶_)
  [⟶]-reflexivity = intro refl

instance
  [⟶]-transitivity : Transitivity(_⟶_)
  [⟶]-transitivity = intro trans

-- identity : ∀{t} → ((I · t) ⟶ t)
pattern identity = trans fuse constant

-- compₗ : ∀{a₁ a₂ b} → (a₁ ⟶ a₂) → ((a₁ · b) ⟶ (a₂ · b))
pattern compₗ p = comp p refl

-- compᵣ : ∀{a b₁ b₂} → (b₁ ⟶ b₂) → ((a · b₁) ⟶ (a · b₂))
pattern compᵣ p = comp refl p

composition : ∀{a b c} → ((B · a · b · c) ⟶ (a · (b · c)))
composition {a}{b}{c} =
  B · a · b · c                     🝖-[ refl ]
  ((S · (K · S) · K · a) · b) · c   🝖-[ compₗ (compₗ fuse) ]
  (((K · S · a) · (K · a)) · b) · c 🝖-[ compₗ (compₗ (compₗ constant)) ]
  ((S · (K · a)) · b) · c           🝖-[ fuse ]
  (K · a · c) · (b · c)             🝖-[ compₗ constant ]
  a · (b · c)                       🝖-end

swapped-application : ∀{a b c} → ((C · a · b · c) ⟶ ((a · c) · b))
swapped-application {a}{b}{c} =
  C · a · b · c                               🝖-[ refl ]
  S · (S · (K · B) · S) · (K · K) · a · b · c 🝖-[ compₗ (compₗ fuse) ]
  (S · (K · B) · S · a) · (K · K · a) · b · c 🝖-[ compₗ (compₗ (comp fuse constant)) ]
  (K · B · a · (S · a)) · K · b · c           🝖-[ compₗ (compₗ (compₗ (compₗ constant))) ]
  (B · (S · a)) · K · b · c                   🝖-[ compₗ composition ]
  (S · a) · (K · b) · c                       🝖-[ fuse ]
  (a · c) · (K · b · c)                       🝖-[ compᵣ constant ]
  (a · c) · b                                 🝖-end

apply-self : ∀{t} → ((SA · t) ⟶ (t · t))
apply-self = trans fuse (comp identity identity)

swapping : ∀{a b} → ((SW · a · b) ⟶ (b · a))
swapping {a}{b} =
  S · (K · (S · I)) · K · a · b   🝖-[ compₗ fuse ]
  (K · (S · I) · a) · (K · a) · b 🝖-[ compₗ (compₗ constant) ]
  (S · I) · (K · a) · b           🝖-[ fuse ]
  I · b · (K · a · b)             🝖-[ comp identity constant ]
  b · a                           🝖-end

module Boolean where
  TRUE  = K             -- True
  FALSE = S · K         -- False
  NOT   = FALSE · TRUE  -- Not (Negation)
  OR    = TRUE          -- Or (Disjunction)
  AND   = FALSE         -- And (Conjunction)

  IsTrue : Term → Type{Lvl.𝟎}
  IsTrue(a) = ∀{t f} → ((a · t · f) ⟶ t)

  IsFalse : Term → Type{Lvl.𝟎}
  IsFalse(a) = ∀{t f} → ((a · t · f) ⟶ f)

  reduce-true-is-true : ∀{t} → (t ⟶ TRUE) → IsTrue(t)
  reduce-true-is-true tT = (compₗ (compₗ tT)) 🝖 constant

  reduce-false-is-false : ∀{t} → (t ⟶ FALSE) → IsFalse(t)
  reduce-false-is-false tT = (compₗ (compₗ tT)) 🝖 identity

  true : IsTrue(TRUE)
  true = constant

  false : IsFalse(FALSE)
  false = identity

  not-true-is-false : ∀{t} → IsTrue(t) → IsFalse(t · NOT)
  not-true-is-false t-true = (compₗ t-true) 🝖 fuse 🝖 constant

  {-not-false-is-true : ∀{t} → IsFalse(t) → IsTrue(t · NOT)
  not-false-is-true {term} t-false {t}{f} =
    term · NOT · t · f         🝖-[ refl ]
    term · (S · K · K) · t · f 🝖-[ {!!} ]
    f · (S · K · K) · t · f 🝖-[ {!!} ]
    t                          🝖-end
  -}

  not-true : IsFalse(TRUE · NOT)
  not-true {t}{f} = not-true-is-false constant
    {-TRUE · NOT · t · f            🝖-[ refl ]
    TRUE · (FALSE · TRUE) · t · f 🝖-[ refl ]
    K · (S · K · K) · t · f       🝖-[ compₗ constant ]
    S · K · K · f                 🝖-[ fuse ]
    K · f · (K · f)               🝖-[ constant ]
    f                             🝖-end-}

  {-
  not-false : IsTrue(FALSE · NOT)
  not-false {t}{f} =
    FALSE · NOT · t · f            🝖-[ refl ]
    FALSE · (FALSE · TRUE) · t · f 🝖-[ refl ]
    S · K · (S · K · K) · t · f    🝖-[ compₗ fuse ]
    K · t · (S · K · K · t) · f    🝖-[ compₗ constant ]
    t · f                          🝖-[ {!!} ] -- TODO: ???
    t                              🝖-end
  -- not-false-is-true identity
  -}

  or-true-true : IsTrue(TRUE · OR · TRUE)
  or-true-true = reduce-true-is-true constant

  or-true-false : IsTrue(TRUE · OR · FALSE)
  or-true-false = reduce-true-is-true constant

  or-false-true : IsTrue(FALSE · OR · TRUE)
  or-false-true = reduce-true-is-true(fuse 🝖 constant)

  or-false-true2 : IsTrue(FALSE · OR · TRUE)
  or-false-true2 = reduce-true-is-true(fuse 🝖 constant)

  or-false-false : IsFalse(FALSE · OR · FALSE)
  or-false-false = reduce-false-is-false(fuse 🝖 constant)

  and-true-true : IsTrue(TRUE · TRUE · AND)
  and-true-true = reduce-true-is-true(constant)

  and-true-false : IsFalse(TRUE · FALSE · AND)
  and-true-false = reduce-false-is-false(constant)

  and-false-true : IsFalse(FALSE · TRUE · AND)
  and-false-true = reduce-false-is-false(identity)

  and-false-false : IsFalse(FALSE · FALSE · AND)
  and-false-false = reduce-false-is-false(fuse 🝖 constant)


-- Andreas and James, 2013-11-19

{-# OPTIONS --copatterns  #-}
-- {-# OPTIONS -v tc.cover.splittree:15 -v tc.cc:15 #-}

open import Common.Level
open import Common.Product

mutual
  data Delay (A : Set) : Set where
    later : ∞Delay A → Delay A

  record ∞Delay (A : Set) : Set where
    coinductive
    constructor delay
    field
      force : Delay A
open ∞Delay public

data Def {A : Set} : Delay A → Set where
  later⇓ : ∀ (x : ∞Delay A) → Def (force x) → Def (later x)

data Ty : Set where
  _⇒_ : (a b : Ty) → Ty

data Tm (Γ : Ty) : (a : Ty) → Set where
  abs : ∀ a b (t : Tm (Γ ⇒ a) b) → Tm Γ (a ⇒ b)

data Val : (a : Ty) → Set where
  lam : ∀ Γ a b (t : Tm (Γ ⇒ a) b) → Val (a ⇒ b)

postulate
  eval : ∀ Γ a → Tm Γ a → Delay (Val a)

∞apply : ∀ a b → Val (a ⇒ b) → ∞Delay (Val b)
force (∞apply .a .b (lam Γ a b t)) = eval (Γ ⇒ a) b t

β-expand : ∀ Γ a b (t : Tm (Γ ⇒ a) b) →
  Def (eval (Γ ⇒ a) b t) → Def (later (∞apply a b (lam Γ a b t)))
β-expand Γ a b t = later⇓ (∞apply a b (lam Γ a b t))

-- This line failed because of a missing reduction (due to wrong split tree).