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

open import Cubical.Foundations.Prelude

open import Cubical.Algebra.CommRing

module _ where
  open import Cubical.HITs.Ints.BiInvInt
    renaming (
      _+_ to _+ℤ_;
      -_ to _-ℤ_;
      +-assoc to +ℤ-assoc;
      +-comm to +ℤ-comm
    )

  BiInvIntAsCommRing : CommRing {ℓ-zero}
  BiInvIntAsCommRing =
    makeCommRing
      zero (suc zero) _+ℤ_ _·_ _-ℤ_
      isSetBiInvInt
      +ℤ-assoc +-zero +-invʳ +ℤ-comm
      ·-assoc ·-identityʳ
      (λ x y z → sym (·-distribˡ x y z))
      ·-comm

-- makeCommRing ? ? ? ? ? ? ? ? ? ? ? ? ? ?

module _ where
  open import Cubical.Data.Int

  IntAsCommRing : CommRing {ℓ-zero}
  IntAsCommRing = makeCommRing {R = Int} 0 1 _+_ _·_ -_ isSetInt
    +-assoc +-identityʳ +-inverseʳ +-comm (λ x y z → sym (·-assoc x y z)) ·-identityʳ
    (λ x y z → sym (·-distribˡ x y z)) ·-comm

module _ where
  open import Cubical.HITs.Ints.QuoInt

  QuoIntAsCommRing : CommRing {ℓ-zero}
  QuoIntAsCommRing = makeCommRing {R = ℤ} 0 1 _+_ _·_ -_ isSetℤ
    +-assoc +-identityʳ +-inverseʳ +-comm ·-assoc ·-identityʳ
    (λ x y z → sym (·-distribˡ x y z)) ·-comm

module _ where
  open import Cubical.Data.DiffInt

  DiffIntAsCommRing : CommRing {ℓ-zero}
  DiffIntAsCommRing = makeCommRing {R = ℤ} 0 1 _+_ _·_ -_ isSetℤ
    +-assoc +-identityʳ +-inverseʳ +-comm ·-assoc ·-identityʳ ·-distribˡ ·-comm

open import Cubical.Algebra.Ring using (ringequiv)
open import Cubical.Foundations.Equiv
open import Cubical.Reflection.Base using (_$_) -- TODO: add this to Foundation.Function
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Univalence
open import Cubical.Foundations.Structure
open import Cubical.HITs.Ints.BiInvInt using (BiInvInt)
open import Cubical.Data.Nat using (suc; zero) renaming (_·_ to _·ⁿ_; _+_ to _+ⁿ_)
open import Cubical.Data.Int as Int using (sucInt; predInt; Int) renaming
  ( _+_ to _+'_
  ; _·_ to _·'_
  ; -_ to -'_
  ; pos to pos'
  ; negsuc to negsuc'
  ; sgn to sgn'
  ; abs to abs'
  ; signed to signed'
  )

module _ where
  open import Cubical.HITs.Ints.BiInvInt renaming
    ( fwd to ⟦_⟧
    ; suc to sucᵇ
    )

  private
    suc-⟦⟧ : ∀ x → sucᵇ ⟦ x ⟧ ≡ ⟦ sucInt x ⟧
    suc-⟦⟧ (pos' n) = refl
    suc-⟦⟧ (negsuc' zero) = suc-pred _
    suc-⟦⟧ (negsuc' (suc n)) = suc-pred _

    pred-⟦⟧ : ∀ x → predl ⟦ x ⟧ ≡ ⟦ predInt x ⟧
    pred-⟦⟧ (pos' zero) = refl
    pred-⟦⟧ (pos' (suc n)) = pred-suc _
    pred-⟦⟧ (negsuc' zero) = refl
    pred-⟦⟧ (negsuc' (suc n)) = refl

    neg-⟦⟧ : ∀ x → - ⟦ x ⟧ ≡ ⟦ -' x ⟧
    neg-⟦⟧ (pos' zero) = refl
    neg-⟦⟧ (pos' (suc n)) = (λ i → predl (neg-⟦⟧ (pos' n) i)) ∙ pred-⟦⟧ (-' pos' n) ∙ cong ⟦_⟧ (Int.predInt-neg (pos' n))
    neg-⟦⟧ (negsuc' zero) = refl
    neg-⟦⟧ (negsuc' (suc n)) = (λ i → sucᵇ (neg-⟦⟧ (negsuc' n) i))

    pres1 : 1 ≡ ⟦ 1 ⟧
    pres1 = refl

    isHom+ : ∀ x y → ⟦ x +' y ⟧ ≡ ⟦ x ⟧ + ⟦ y ⟧
    isHom+ (pos' zero) y i = ⟦ Int.+-comm 0 y i ⟧
    isHom+ (pos' (suc n)) y =
      ⟦ pos' (suc n) +' y ⟧     ≡[ i ]⟨ ⟦ Int.sucInt+ (pos' n) y (~ i) ⟧ ⟩
      ⟦ sucInt (pos' n +' y) ⟧  ≡⟨ sym $ suc-⟦⟧ _ ⟩
      sucᵇ  ⟦ pos' n +' y ⟧     ≡[ i ]⟨ sucᵇ $ isHom+ (pos' n) y i ⟩
      sucᵇ (⟦ pos' n ⟧ + ⟦ y ⟧) ≡⟨ refl ⟩
      sucᵇ  ⟦ pos' n ⟧ + ⟦ y ⟧  ∎
    isHom+ (negsuc' zero) y = pred-suc-inj _ _ (λ i → predl (γ i)) where
      -- γ =   sucᵇ ⟦  negsuc' zero +' y ⟧  ≡⟨ suc-⟦⟧ (negsuc' zero +' y) ⟩
      --     ⟦ sucInt (negsuc' zero +' y)⟧  ≡⟨ cong ⟦_⟧ $ Int.sucInt+ (negsuc' zero) y ∙ Int.+-comm 0 y ⟩
      --                       ⟦       y ⟧  ≡⟨ sym (suc-pred ⟦ y ⟧) ⟩
      --     sucᵇ (pred zero + ⟦       y ⟧) ∎
      γ = suc-⟦⟧ (negsuc' zero +' y) ∙ (λ i → ⟦ (Int.sucInt+ (negsuc' zero) y ∙ Int.+-comm 0 y) i ⟧) ∙ sym (suc-pred ⟦ y ⟧)
    isHom+ (negsuc' (suc n)) y = (λ i → ⟦ Int.predInt+ (negsuc' n) y (~ i) ⟧) ∙ sym (pred-⟦⟧ (negsuc' n +' y))
                               ∙ (λ i → pred $ isHom+ (negsuc' n) y i)

    isHom· : ∀ x y → ⟦ x ·' y ⟧ ≡ ⟦ x ⟧ · ⟦ y ⟧
    isHom· (pos' zero) y i = ⟦ Int.signed-zero (Int.sgn y) i ⟧
    isHom· (pos' (suc n)) y =
      ⟦ pos' (suc n) ·' y ⟧      ≡⟨ cong ⟦_⟧ $ Int.·-pos-suc n y ⟩
      ⟦ y +' pos' n ·' y ⟧       ≡⟨ isHom+ y _ ⟩
      ⟦ y ⟧ + ⟦ pos' n ·' y ⟧    ≡[ i ]⟨ ⟦ y ⟧ + isHom· (pos' n) y i ⟩
      ⟦ y ⟧ + ⟦ pos' n ⟧ · ⟦ y ⟧ ≡⟨ (λ i → ⟦ y ⟧ + ·-comm ⟦ pos' n ⟧ ⟦ y ⟧ i)
                                  ∙ sym (·-suc ⟦ y ⟧ ⟦ pos' n ⟧) ∙ ·-comm ⟦ y ⟧ _ ⟩
      sucᵇ ⟦ pos' n ⟧ · ⟦ y ⟧ ∎
    isHom· (negsuc' zero) y =
      ⟦ -1 ·'  y ⟧ ≡⟨ cong ⟦_⟧ (Int.·-neg1 y) ⟩
      ⟦ -'     y ⟧ ≡⟨ sym (neg-⟦⟧ y) ⟩
        -    ⟦ y ⟧ ≡⟨ sym (·-neg1 ⟦ y ⟧) ⟩
        -1 · ⟦ y ⟧ ∎
    isHom· (negsuc' (suc n)) y =
      ⟦ negsuc' (suc n) ·' y ⟧         ≡⟨ cong ⟦_⟧ $ Int.·-negsuc-suc n y ⟩
      ⟦ -' y   +'  negsuc' n   ·'  y ⟧ ≡⟨ isHom+ (-' y) _ ⟩
      ⟦ -' y ⟧ + ⟦ negsuc' n   ·'  y ⟧ ≡[ i ]⟨ ⟦ -' y ⟧ + isHom· (negsuc' n) y i ⟩
      ⟦ -' y ⟧ + ⟦ negsuc' n ⟧ · ⟦ y ⟧ ≡⟨ cong₂ _+_ (sym (neg-⟦⟧ y)) refl ⟩
      -  ⟦ y ⟧ + ⟦ negsuc' n ⟧ · ⟦ y ⟧ ≡⟨ (λ i → - ⟦ y ⟧ + ·-comm ⟦ negsuc' n ⟧ ⟦ y ⟧ i)
                                        ∙ sym (·-pred ⟦ y ⟧ ⟦ negsuc' n ⟧) ∙ ·-comm ⟦ y ⟧ _ ⟩
      pred ⟦ negsuc' n ⟧ · ⟦ y ⟧       ∎

    ⟦⟧-isEquiv : isEquiv ⟦_⟧
    ⟦⟧-isEquiv = isoToIsEquiv (iso ⟦_⟧ bwd fwd-bwd bwd-fwd)

  Int≃BiInvInt-CommRingEquivΣ : Σ[ e ∈ ⟨ IntAsCommRing ⟩ ≃ ⟨ BiInvIntAsCommRing ⟩ ] CommRingEquiv IntAsCommRing BiInvIntAsCommRing e
  Int≃BiInvInt-CommRingEquivΣ .fst = ⟦_⟧ , ⟦⟧-isEquiv
  Int≃BiInvInt-CommRingEquivΣ .snd = ringequiv pres1 isHom+ isHom·

  Int≡BiInvInt-AsCommRing : IntAsCommRing ≡ BiInvIntAsCommRing
  Int≡BiInvInt-AsCommRing = CommRingPath _ _ .fst Int≃BiInvInt-CommRingEquivΣ

module _ where
  open import Cubical.HITs.Ints.QuoInt as QuoInt renaming
    ( Int→ℤ to ⟦_⟧
    )
  open import Cubical.Data.Bool

  private
    suc-⟦⟧ : ∀ x → sucℤ ⟦ x ⟧ ≡ ⟦ sucInt x ⟧
    suc-⟦⟧ (pos' n) = refl
    suc-⟦⟧ (negsuc' zero) = sym posneg
    suc-⟦⟧ (negsuc' (suc n)) = refl

    pred-⟦⟧ : ∀ x → predℤ ⟦ x ⟧ ≡ ⟦ predInt x ⟧
    pred-⟦⟧ (pos' zero) = refl
    pred-⟦⟧ (pos' (suc n)) = refl
    pred-⟦⟧ (negsuc' n) = refl

    neg-⟦⟧ : ∀ x → - ⟦ x ⟧ ≡ ⟦ -' x ⟧
    neg-⟦⟧ (pos' zero) = sym posneg
    neg-⟦⟧ (pos' (suc n)) = refl
    neg-⟦⟧ (negsuc' n) = refl

    pres1 : 1 ≡ ⟦ 1 ⟧
    pres1 = refl

    isHom+ : ∀ x y → ⟦ x +' y ⟧ ≡ ⟦ x ⟧ + ⟦ y ⟧
    isHom+ (pos' zero) y i = ⟦ Int.+-comm 0 y i ⟧
    isHom+ (pos' (suc n)) y =
      ⟦ pos' (suc n)   +' y  ⟧ ≡[ i ]⟨ ⟦ Int.sucInt+ (pos' n) y (~ i) ⟧ ⟩
      ⟦ sucInt (pos' n +' y) ⟧ ≡⟨ sym $ suc-⟦⟧ _ ⟩
      sucℤ  ⟦ pos' n   +' y  ⟧ ≡[ i ]⟨ sucℤ $ isHom+ (pos' n) y i ⟩
      sucℤ (⟦ pos' n ⟧ + ⟦ y ⟧) ≡⟨ refl ⟩
      sucℤ  ⟦ pos' n ⟧ + ⟦ y ⟧  ∎
    isHom+ (negsuc'  zero  ) y = sucℤ-inj _ _ (suc-⟦⟧ (negsuc' zero +' y)
                               ∙ (cong ⟦_⟧ $ Int.sucInt+ (negsuc' zero) y
                               ∙ Int.+-identityˡ y)
                               ∙ sym (sucPredℤ ⟦ y ⟧))
    isHom+ (negsuc' (suc n)) y = cong ⟦_⟧ (sym (Int.predInt+ (negsuc' n) y))
                               ∙ (sym $ pred-⟦⟧ (negsuc' n +' y))
                               ∙ (λ i → predℤ $ isHom+ (negsuc' n) y i)

    isHom· : ∀ x y → ⟦ x ·' y ⟧ ≡ ⟦ x ⟧ · ⟦ y ⟧
    isHom· (pos' zero) y = (cong ⟦_⟧ $ Int.signed-zero (sgn' y)) ∙ sym (signed-zero (sign ⟦ y ⟧) spos)
    isHom· (pos' (suc n)) y =
      ⟦ pos' (suc n)     ·'  y ⟧ ≡⟨ cong ⟦_⟧ $ Int.·-pos-suc n y ⟩
      ⟦ y   +'  pos' n   ·'  y ⟧ ≡⟨ isHom+ y _ ⟩
      ⟦ y ⟧ + ⟦ pos' n   ·'  y ⟧ ≡[ i ]⟨ ⟦ y ⟧ + isHom· (pos' n) y i ⟩
      ⟦ y ⟧ + ⟦ pos' n ⟧ · ⟦ y ⟧ ≡⟨ sym $ ·-pos-suc n ⟦ y ⟧ ⟩
      sucℤ ⟦ pos' n ⟧ · ⟦ y ⟧ ∎
    isHom· (negsuc' zero) y =
      ⟦ -1 ·'  y ⟧ ≡⟨ cong ⟦_⟧ (Int.·-neg1 y) ⟩
      ⟦ -'     y ⟧ ≡⟨ sym (neg-⟦⟧ y) ⟩
        -    ⟦ y ⟧ ≡⟨ sym (·-neg1 ⟦ y ⟧) ⟩
        -1 · ⟦ y ⟧ ∎
    isHom· (negsuc' (suc n)) y =
      ⟦ negsuc' (suc n) ·' y ⟧         ≡⟨ cong ⟦_⟧ $ Int.·-negsuc-suc n y ⟩
      ⟦ -' y   +'  negsuc' n   ·'  y ⟧ ≡⟨ isHom+ (-' y) _ ⟩
      ⟦ -' y ⟧ + ⟦ negsuc' n   ·'  y ⟧ ≡[ i ]⟨ ⟦ -' y ⟧ + isHom· (negsuc' n) y i ⟩
      ⟦ -' y ⟧ + ⟦ negsuc' n ⟧ · ⟦ y ⟧ ≡⟨ cong₂ _+_ (sym (neg-⟦⟧ y)) refl ⟩
      -  ⟦ y ⟧ + ⟦ negsuc' n ⟧ · ⟦ y ⟧ ≡⟨ sym (·-neg-suc (suc n) ⟦ y ⟧) ⟩
      predℤ ⟦ negsuc' n ⟧ · ⟦ y ⟧      ∎

    ⟦⟧-isEquiv : isEquiv ⟦_⟧
    ⟦⟧-isEquiv = isoToIsEquiv (iso ⟦_⟧ ℤ→Int ℤ→Int→ℤ Int→ℤ→Int)

  Int≃QuoInt-CommRingEquivΣ : Σ[ e ∈ ⟨ IntAsCommRing ⟩ ≃ ⟨ QuoIntAsCommRing ⟩ ] CommRingEquiv IntAsCommRing QuoIntAsCommRing e
  Int≃QuoInt-CommRingEquivΣ .fst = ⟦_⟧ , ⟦⟧-isEquiv
  Int≃QuoInt-CommRingEquivΣ .snd = ringequiv pres1 isHom+ isHom·

  Int≡QuoInt-AsCommRing : IntAsCommRing ≡ QuoIntAsCommRing
  Int≡QuoInt-AsCommRing = CommRingPath _ _ .fst Int≃QuoInt-CommRingEquivΣ

QuoInt≡BiInvInt-AsCommRing : QuoIntAsCommRing ≡ BiInvIntAsCommRing
QuoInt≡BiInvInt-AsCommRing = sym Int≡QuoInt-AsCommRing ∙ Int≡BiInvInt-AsCommRing

open import Cubical.HITs.SetQuotients

module _ where
  open import Cubical.Data.Sigma
  open import Cubical.Data.Bool
  open import Cubical.Data.Nat using (ℕ) renaming (_·_ to _·ⁿ_)
  open import Cubical.HITs.Rationals.QuoQ using (ℚ) renaming (_+_ to _+ʳ_)
  open import Cubical.HITs.Ints.QuoInt using (ℤ; sign; signed; abs) renaming (_+_ to _+ᶻ_)
  open import Cubical.Data.NatPlusOne using (ℕ₊₁; 1+_)

  test1 : ℤ → _
  test1 x = {! x +ᶻ x  !}
  -- Normal form:
  --   x +ᶻ x

  test2 : ℤ × ℕ₊₁  → _
  test2 x = {! [ x ] +ʳ [ x ]  !}
  -- Normal form:
  --   [  signed (sign (fst x) ⊕ false) (abs (fst x) ·ⁿ suc (ℕ₊₁.n (snd x)))
  --   +ᶻ signed (sign (fst x) ⊕ false) (abs (fst x) ·ⁿ suc (ℕ₊₁.n (snd x)))
  --   , (1+ (ℕ₊₁.n (snd x) +ⁿ ℕ₊₁.n (snd x) ·ⁿ suc (ℕ₊₁.n (snd x))))
  --   ]

  test3 : ℚ → ℤ × ℕ₊₁  → _
  test3 x y = {! x +ʳ [ y ]  !}
  -- Normal form:
  --   rec
  --   (λ f g F G i j z →
  --      squash/ (f z) (g z) (λ i₁ → F i₁ z) (λ i₁ → G i₁ z) i j)
  --   (λ a → ...
  --     ...
  --   ... 2000 more lines ...

open import Cubical.Data.DiffInt as DiffInt hiding (_+'_; _·'_)

⟦⟧-isEquiv : isEquiv ⟦_⟧
⟦⟧-isEquiv = isoToIsEquiv (iso ⟦_⟧ bwd fwd-bwd bwd-fwd)

pres1 : 1 ≡ ⟦ 1 ⟧
pres1 = refl

isHom+ : ∀ x y → ⟦ x +' y ⟧ ≡ ⟦ x ⟧ + ⟦ y ⟧
isHom+ (pos' zero) y = {!   !}
isHom+ (pos' (suc n)) y = {!   !} -- ? ∙ λ i → sucℤ (isHom+ (pos' n) y i)
isHom+ (negsuc' zero) y = {! [ 0 , 1 ] + ⟦ y ⟧  !}
isHom+ (negsuc' (suc n)) y = {!   !}

isHom· : ∀ x y → ⟦ x ·' y ⟧ ≡ ⟦ x ⟧ · ⟦ y ⟧
isHom· = {!   !}

Int≃DiffInt-CommRingEquivΣ : Σ[ e ∈ ⟨ IntAsCommRing ⟩ ≃ ⟨ DiffIntAsCommRing ⟩ ] CommRingEquiv IntAsCommRing DiffIntAsCommRing e
Int≃DiffInt-CommRingEquivΣ .fst = ⟦_⟧ , ⟦⟧-isEquiv
Int≃DiffInt-CommRingEquivΣ .snd = ringequiv pres1 isHom+ isHom·

Int≡DiffInt-AsCommRing : IntAsCommRing ≡ DiffIntAsCommRing
Int≡DiffInt-AsCommRing = CommRingPath _ _ .fst Int≃DiffInt-CommRingEquivΣ

DiffInt≡BiInvInt-AsCommRing : DiffIntAsCommRing ≡ BiInvIntAsCommRing
DiffInt≡BiInvInt-AsCommRing = sym Int≡DiffInt-AsCommRing ∙ Int≡BiInvInt-AsCommRing


-- Andreas, 2016-06-01, issue 1997 reported by Andres

{-# OPTIONS --rewriting #-}

infix  4 _≡_
infixl 6 _+_

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

{-# BUILTIN REWRITE _≡_ #-}

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

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

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

plus0 : (x : ℕ) → x + zero ≡ x
plus0 zero    = refl
plus0 (suc x) = cong suc (plus0 x)

{-# REWRITE plus0 #-}
{-# REWRITE plus0 #-}

-- Should complain about duplicate rewrite rule


module Data.Lens.Proofs.LensLaws where

open import Haskell.Prelude renaming (zero to Z; suc to S)
open import Data.Lens.Lens
open import Data.Logic
open import Agda.Primitive

-- First, define the lens laws

ViewSet : {a b : Set} -> (l : Lens a b) -> Set
ViewSet {a} {b} l = (v : b) (s : a) -> view l (set l v s) ≡ v

SetView : {a b : Set} -> (l : Lens a b) -> Set
SetView {a} {b} l = (s : a) -> set l (view l s) s ≡ s

SetSet : {a b : Set} -> (l : Lens a b) -> Set
SetSet {a} {b} l = (v1 v2 : b) (s : a) -> set l v2 (set l v1 s) ≡ set l v2 s

-- Define ValidLens as a lens for which the laws hold

data ValidLens (a b : Set) : Set₁ where
  CValidLens : (l : Lens a b) -> ViewSet l -> SetView l -> SetSet l -> ValidLens a b

toLens : ValidLens a b -> Lens a b
toLens (CValidLens l _ _ _) = l


{-# OPTIONS --rewriting #-}

open import Agda.Primitive

postulate
  _↦_ : ∀{i j}{A : Set i}{B : Set j} → A → B → Set (i ⊔ j)

{-# BUILTIN REWRITE _↦_ #-}  -- currently fails a sanity check

postulate
  resize : ∀{i j} → Set i → Set j
  resize-id : ∀{i} {j} {A : Set i} → resize {i} {j} A ↦ A

{-# REWRITE resize-id #-}

-- Impredicative quantification

Forall : ∀{i} (F : Set i → Set) → Set
Forall {i} F = resize ((X : Set i) → F X)

-- Example: Impredicative encoding of natural numbers

Nat = Forall λ X → (X → X) → X → X

zero : Nat
zero X s z = z

suc : Nat → Nat
suc n X s z = s (n X s z)

-- requires impredicativity:

id : Nat → Nat
id n = n Nat suc zero


module Miscellaneous.TFlipFlop where

open import Data.Boolean
import      Data.Boolean.Operators
open        Data.Boolean.Operators.Logic
open import Data.Boolean.Numeral
open import Numeral.Natural
open import Syntax.Number

tFlipFlop : Bool → (ℕ → Bool) → (ℕ → Bool)
tFlipFlop init T(𝟎)    = init
tFlipFlop init T(𝐒(n)) = T(n) ⊕ tFlipFlop init T(n)

open import Data
open import Relator.Equals

module _ where
  postulate Q₀ : ℕ → Bool
  postulate Q₁ : ℕ → Bool

  postulate f : Bool → Bool
  postulate g : Bool → Bool

  postulate q₀0 : Q₀(0) ≡ 1
  postulate q₁0 : Q₁(0) ≡ 1

  postulate q₀1 : Q₀(1) ≡ 0
  postulate q₁1 : Q₁(1) ≡ 1

  postulate q₀2 : Q₀(2) ≡ 1
  postulate q₁2 : Q₁(2) ≡ 0

  postulate q₀3 : Q₀(3) ≡ 0
  postulate q₁3 : Q₁(3) ≡ 0

  postulate q₀4 : Q₀(4) ≡ Q₀(0)
  postulate q₁4 : Q₁(4) ≡ Q₁(0)

  {-# REWRITE q₀0 q₁0 q₀1 q₁1 q₀2 q₁2 q₀3 q₁3 q₀4 q₁4 #-}

  private variable n : ℕ

  postulate q₀step : Q₀(𝐒 n) ≡ f(Q₁(n)) ⊕ Q₀(n)
  postulate q₁step : Q₁(𝐒 n) ≡ g(Q₀(n)) ⊕ Q₁(n)

  open import Numeral.Natural.Oper
  open import Relator.Equals.Proofs
  open import Structure.Function
  open import Structure.Operator
  open import Syntax.Transitivity

  q₀cyclic : Q₀(n + 4) ≡ Q₀(n)
  q₁cyclic : Q₁(n + 4) ≡ Q₁(n)

  q₀cyclic {𝟎} = [≡]-intro
  q₀cyclic {𝐒 n} =
    Q₀ (𝐒 n + 4)                🝖[ _≡_ ]-[]
    Q₀ (𝐒(n + 4))               🝖[ _≡_ ]-[ q₀step{n + 4} ]
    f(Q₁(n + 4)) ⊕ Q₀(n + 4)    🝖[ _≡_ ]-[ congruence₂(_⊕_) (congruence₁(f) (q₁cyclic{n})) (q₀cyclic{n}) ]
    f(Q₁(n)) ⊕ Q₀(n)            🝖[ _≡_ ]-[ q₀step{n} ]-sym
    Q₀ (𝐒 n)                    🝖-end

  q₁cyclic {𝟎} = [≡]-intro
  q₁cyclic {𝐒 n} =
    Q₁ (𝐒 n + 4)                🝖[ _≡_ ]-[]
    Q₁ (𝐒(n + 4))               🝖[ _≡_ ]-[ q₁step{n + 4} ]
    g(Q₀(n + 4)) ⊕ Q₁(n + 4)    🝖[ _≡_ ]-[ congruence₂(_⊕_) (congruence₁(g) (q₀cyclic{n})) (q₁cyclic{n}) ]
    g(Q₀(n)) ⊕ Q₁(n)            🝖[ _≡_ ]-[ q₁step{n} ]-sym
    Q₁ (𝐒 n)                    🝖-end

  f0 : f(0) ≡ 1
  f0 with f(0) | q₀step{2}
  ... | 𝑇 | q = [≡]-intro

  f1 : f(1) ≡ 1
  f1 with f(1) | q₀step{0}
  ... | 𝑇 | q = [≡]-intro

  f1' : f(1) ≡ 1
  f1' with f(1) | q₀step{1}
  ... | 𝑇 | q = [≡]-intro

  f1'' : f(1) ≡ 1
  f1'' with f(1) | q₀step{0}
  ... | 𝑇 | q = [≡]-intro

  g1 : g(1) ≡ 0
  g1 with g(1) | q₁step{0}
  ... | 𝐹 | q = [≡]-intro

  g0 : g(0) ≡ 1
  g0 with g(0) | q₁step{1}
  ... | 𝑇 | q = [≡]-intro

  g1' : g(1) ≡ 0
  g1' with g(1) | q₁step{2}
  ... | 𝐹 | q = [≡]-intro

  g1'' : g(0) ≡ 1
  g1'' with g(0) | q₁step{3}
  ... | 𝑇 | q = [≡]-intro


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

open import Algebra.Structures.Bundles.Field

module Algebra.Linear.Morphism.Bundles
  {k ℓᵏ} (K : Field k ℓᵏ)
  where

open import Algebra.FunctionProperties as FP
open import Relation.Binary using (Rel; Setoid)
open import Level

import Algebra.Linear.Structures.Bundles as VS

open import Algebra.Linear.Morphism.VectorSpace K

open import Function.Equality as FunEq using (_⟶_; _⟨$⟩_; setoid)

module _
  {a₁ ℓ₁} (From : VS.VectorSpace K a₁ ℓ₁)
  {a₂ ℓ₂} (To   : VS.VectorSpace K a₂ ℓ₂)
  where

  private
    module F = VS.VectorSpace From
    module T = VS.VectorSpace To

    K' : Set k
    K' = Field.Carrier K

    open F using ()
      renaming
        ( Carrier to A
        ; _≈_     to _≈₁_
        ; refl    to ≈₁-refl
        ; sym     to ≈₁-sym
        ; setoid  to A-setoid
        ; _+_     to +₁
        ; _∙_     to ∙₁
        )

    open T using ()
      renaming
        ( Carrier to B
        ; _≈_     to _≈₂_
        ; refl    to ≈₂-refl
        ; sym     to ≈₂-sym
        ; trans   to ≈₂-trans
        ; setoid  to B-setoid
        ; _+_     to +₂
        ; _∙_     to ∙₂
        )

    hom-setoid : ∀ {Carrier} -> (Carrier -> (A-setoid ⟶ B-setoid))
                     -> Setoid (suc (k ⊔ a₁ ⊔ a₂ ⊔ ℓ₁ ⊔ ℓ₂)) (a₁ ⊔ ℓ₁ ⊔ ℓ₂)
    hom-setoid {Carrier} app = record
      { Carrier       = Carrier
      ; _≈_           = λ f g → ∀ {x y} (r : x ≈₁ y) -> (app f ⟨$⟩ x) ≈₂ (app g ⟨$⟩ y)
      ; isEquivalence = record
        { refl  = λ {f} -> FunEq.cong (app f)
        ; sym   = λ r rₓ → ≈₂-sym (r (≈₁-sym rₓ))
        ; trans = λ r₁ r₂ rₓ → ≈₂-trans (r₁ ≈₁-refl) (r₂ rₓ)
        }
      }

  open LinearDefinitions A B _≈₂_

  record LinearMap : Set (suc (k ⊔ a₁ ⊔ a₂ ⊔ ℓ₁ ⊔ ℓ₂)) where
    field
      ⟦_⟧         : Morphism
      isLinearMap : IsLinearMap From To ⟦_⟧

    infixr 25 _⟪$⟫_
    _⟪$⟫_ : A -> B
    _⟪$⟫_ = ⟦_⟧

    open IsLinearMap isLinearMap public

  linearMap-setoid : Setoid (suc (k ⊔ a₁ ⊔ a₂ ⊔ ℓ₁ ⊔ ℓ₂)) (a₁ ⊔ ℓ₁ ⊔ ℓ₂)
  linearMap-setoid = hom-setoid {LinearMap} λ f → record
    { _⟨$⟩_ = λ x → f LinearMap.⟪$⟫ x
    ; cong = LinearMap.⟦⟧-cong f
    }

  record LinearIsomorphism : Set (suc (k ⊔ a₁ ⊔ a₂ ⊔ ℓ₁ ⊔ ℓ₂)) where
    field
      ⟦_⟧                 : Morphism
      isLinearIsomorphism : IsLinearIsomorphism From To ⟦_⟧

    open IsLinearIsomorphism isLinearIsomorphism public

    linearMap : LinearMap
    linearMap = record { ⟦_⟧ = ⟦_⟧ ; isLinearMap = isLinearMap }

    open LinearMap linearMap public
      using (_⟪$⟫_)

  linearIsomorphism-setoid : Setoid (suc (k ⊔ a₁ ⊔ a₂ ⊔ ℓ₁ ⊔ ℓ₂)) (a₁ ⊔ ℓ₁ ⊔ ℓ₂)
  linearIsomorphism-setoid = hom-setoid {LinearIsomorphism} λ f → record
    { _⟨$⟩_ = λ x -> f LinearIsomorphism.⟪$⟫ x
    ; cong = LinearIsomorphism.⟦⟧-cong f
    }

module _ {a ℓ} (V : VS.VectorSpace K a ℓ) where
  LinearEndomorphism : Set (suc (k ⊔ a ⊔ ℓ))
  LinearEndomorphism = LinearMap V V

  LinearAutomorphism : Set (suc (k ⊔ a ⊔ ℓ))
  LinearAutomorphism = LinearIsomorphism V V


open import FRP.LTL.RSet.Core using ( RSet ; ⟦_⟧ )
open import FRP.LTL.RSet.Stateless using ( _⇒_ )
open import FRP.LTL.Time using ( _≤_ ; ≤-refl ; _≤-trans_ )

module FRP.LTL.RSet.Globally where

-- □ A is "A holds globally in the future"

□ : RSet → RSet
□ A t = ∀ {u} → (t ≤ u) → A u

-- Comonad structure of □

extend : ∀ {A B} → ⟦ A ⇒ B ⟧ → ⟦ □ A ⇒ □ B ⟧
extend f a s≤t = f (a s≤t)

extract : ∀ {A} → ⟦ □ A ⇒ A ⟧
extract a = a ≤-refl

duplicate : ∀ {A} → ⟦ □ A ⇒ □ (□ A) ⟧
duplicate a s≤t t≤u = a (s≤t ≤-trans t≤u)

-- Applicative structure of □

[_] : ∀ {A} → ⟦ A ⟧ → ⟦ □ A ⟧
[ a ] s≤t = a

_⟨*⟩_ : ∀ {A B} → ⟦ □ (A ⇒ B) ⇒ □ A ⇒ □ B ⟧
(f ⟨*⟩ a) s≤t = f s≤t (a s≤t)


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

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

open VectorSpace(vectorSpace)

open import Data.Tuple as Tuple using (_,_)
open import Logic.Propositional
open import Logic.Predicate
import      Lvl
open import Sets.ExtensionalPredicateSet as PredSet using (PredSet ; _∈_ ; [∋]-binaryRelator)
open import Structure.Container.SetLike using (SetElement)
private open module SetLikeFunctionProperties{ℓ} = Structure.Container.SetLike.FunctionProperties{C = PredSet{ℓ}(V)}{E = V}(_∈_)
open import Structure.Operator
open import Structure.Operator.Proofs.Util
open import Structure.Operator.Properties
open import Structure.Operator.Vector
open import Structure.Operator.Vector.Subspace ⦃ vectorSpace = vectorSpace ⦄
open import Syntax.Transitivity

private variable ℓ ℓ₁ ℓ₂ ℓₗ : Lvl.Level

module _ where
  module _ where
    -- TODO: This operator can also be constructed for vector spaces, not just subspaces
    _+ˢᵘᵇ_ : SubspaceObject{ℓ₁} → SubspaceObject{ℓ₂} → SubspaceObject
    ([∃]-intro V₁ ⦃ p₁ ⦄) +ˢᵘᵇ ([∃]-intro V₂ ⦃ p₂ ⦄) = [∃]-intro (PredSet.map₂(_+ᵥ_) V₁ V₂) ⦃ p ⦄ where
      p : Subspace(PredSet.map₂(_+ᵥ_) V₁ V₂)
      ∃.witness (Structure.Container.SetLike.FunctionProperties._closed-under₂_.proof (Subspace.add-closure p) ([∃]-intro(a₁ , a₂)) ([∃]-intro(b₁ , b₂))) = ((a₁ +ᵥ b₁) , (a₂ +ᵥ b₂))
      ∃.proof (Structure.Container.SetLike.FunctionProperties._closed-under₂_.proof (Subspace.add-closure p) {a}{b} ([∃]-intro ([∧]-intro a₁ a₂) ⦃ [∧]-intro ([∧]-intro a₁V₁ a₂V₂) a₁a₂a ⦄) ([∃]-intro (b₁ , b₂) ⦃ [∧]-intro ([∧]-intro b₁V₁ b₂V₂) b₁b₂b ⦄)) = [∧]-intro ([∧]-intro l₁ l₂) r where
        l₁ : (a₁ +ᵥ b₁) ∈ V₁
        l₁ = (V₁ closureUnder₂(_+ᵥ_)) a₁V₁ b₁V₁
        l₂ : (a₂ +ᵥ b₂) ∈ V₂
        l₂ = (V₂ closureUnder₂(_+ᵥ_)) a₂V₂ b₂V₂
        r : (a₁ +ᵥ b₁) +ᵥ (a₂ +ᵥ b₂) ≡ a +ᵥ b
        r =
          (a₁ +ᵥ b₁) +ᵥ (a₂ +ᵥ b₂) 🝖[ _≡_ ]-[ One.associate-commute4-c {_▫_ = _+ᵥ_} ⦃ op = [+ᵥ]-binary-operator ⦄ ⦃ assoc = [+ᵥ]-associativity ⦄ ⦃ comm = [+ᵥ]-commutativity ⦄ ] -- TODO: Why are the instances not inferred?
          (a₁ +ᵥ a₂) +ᵥ (b₁ +ᵥ b₂) 🝖[ _≡_ ]-[ congruence₂(_+ᵥ_) ⦃ [+ᵥ]-binary-operator ⦄ a₁a₂a b₁b₂b ]
          a +ᵥ b                   🝖-end
      ∃.witness (Structure.Container.SetLike.FunctionProperties._closed-under₁_.proof (Subspace.mul-closure p {s}) ([∃]-intro(v₁ , v₂))) = ((s ⋅ₛᵥ v₁) , (s ⋅ₛᵥ v₂))
      ∃.proof (Structure.Container.SetLike.FunctionProperties._closed-under₁_.proof (Subspace.mul-closure p {s}) {v} ([∃]-intro(v₁ , v₂) ⦃ [∧]-intro ([∧]-intro v₁V₁ v₂V₂) v₁v₂v ⦄)) = [∧]-intro ([∧]-intro l₁ l₂) r where
        l₁ : (s ⋅ₛᵥ v₁) ∈ V₁
        l₁ = (V₁ closureUnder₁(s ⋅ₛᵥ_)) v₁V₁
        l₂ : (s ⋅ₛᵥ v₂) ∈ V₂
        l₂ = (V₂ closureUnder₁(s ⋅ₛᵥ_)) v₂V₂
        r : (s ⋅ₛᵥ v₁) +ᵥ (s ⋅ₛᵥ v₂) ≡ (s ⋅ₛᵥ v)
        r =
          (s ⋅ₛᵥ v₁) +ᵥ (s ⋅ₛᵥ v₂) 🝖[ _≡_ ]-[ distributivityₗ(_⋅ₛᵥ_)(_+ᵥ_) ]-sym
          s ⋅ₛᵥ (v₁ +ᵥ v₂)         🝖[ _≡_ ]-[ congruence₂ᵣ(_⋅ₛᵥ_)(s) v₁v₂v ]
          s ⋅ₛᵥ v                  🝖-end

  -- TODO: Formulate
  -- [⊕ˢᵘᵇ]-span-vectorSpace : (V₁ ⊕ V₂ ⊕ … ≡ₛ 𝐔) ↔ (∀{v₁}{v₂}{…} → (v₁ ∈ V₁) → (v₂ ∈ V₂) → … → (v₁ + v₂ + … ≡ 𝟎ᵥ) → ((v₁ ≡ 𝟎ᵥ) ∧ (v₂ ≡ 𝟎ᵥ) ∧ …))
  -- [⊕ˢᵘᵇ]-span-existence-finite-space : Finite → ∃(\{(V₁ , V₂ , …) → V₁ ⊕ V₂ ⊕ … ≡ₛ 𝐔}) -- TODO: Just take the "standard" "axis aligned" subspaces


module Issue442 where

postulate
  A : Set
  f : (P : A → A → Set) → (∀ {x} → P x x) →
      (∀ {x y z} → P y z → P x y → A) → A
  P : A → A → Set
  reflP : ∀ {x} → P x x
  g : ∀ {x y z} → P y z → P x y → A

a : A
a = f _ (λ {x} → reflP {x}) g

-- Test case was:
-- {-# OPTIONS --allow-unsolved-metas #-}
-- a = f _ reflP g


{-# OPTIONS --cubical #-}

module Type.Cubical.InductivePath where

open import Functional
import      Lvl
open import Type
import      Type.Cubical as Cubical
open import Type.Cubical.InductiveInterval

private variable ℓ : Lvl.Level
private variable A B P : Type{ℓ}
private variable x y z : A

data Path {P : Type{ℓ}} : P → P → Type{ℓ} where
  intro : (p : Interval → P) → Path(p(𝟎)) (p(𝟏))

point : (x : P) → Path x x
point x = intro(const x)

pointOn : ∀{x y : A} → Path x y → (Interval → A)
pointOn (intro p) = p

reverse : Path x y → Path y x
reverse(intro f) = intro(f ∘ flip)

spaceMap : Path A B → (A → B)
spaceMap (intro p) = transp p

{-
concat : Path x y → Path y z → Path x z
concat xy yz = {!xy yz!}
-}

module _ where
  private variable X : Type{ℓ}
  private variable Y : X → Type{ℓ}

  {- TODO: Define an eliminator for Path and use it to prove this?
  mapping : ∀{f g : (x : X) → Y(x)} → (∀{x} → Path(f(x)) (g(x))) → Path f g
  mapping {X = X}{Y = Y}{f = f}{g = g} ppt = intro(i ↦ x ↦ {!pointOn(ppt{x}) i!}) where
    p : (∀{x} → Path(f(x)) (g(x))) → Interval → (x : X) → Y(x)
    p ppt i x with ppt{x}
    ... | q = {!q!}
  -}

  mappingPoint : ∀{f g : (x : X) → Y(x)} → Path f g → (∀{x} → Path(f(x)) (g(x)))
  mappingPoint (intro pfg) {x} = intro (i ↦ pfg i x)

module _ where
  private variable X X₁ X₂ Y Y₁ Y₂ : Type{ℓ}

  map : (f : X → Y) → ∀{a b} → Path a b → Path (f(a)) (f(b))
  map f (intro ab) = intro(f ∘ ab)

  liftedSpaceMap : (S : X → Type{ℓ}) → ∀{a b} → Path a b → S(a) → S(b)
  liftedSpaceMap S p = spaceMap(map S p)


------------------------------------------------------------------------
-- A virtual machine
------------------------------------------------------------------------

module Lambda.VirtualMachine where

open import Category.Monad
open import Category.Monad.Partiality as P
  using (_⊥; never); open P._⊥
open import Codata.Musical.Notation
open import Data.Empty using (⊥-elim)
open import Data.Fin
open import Data.List hiding (lookup)
open import Data.Maybe
open import Data.Nat
open import Data.Product as Prod
open import Data.Vec using (Vec; []; _∷_; lookup)
open import Function.Base
import Level
open import Relation.Binary.Construct.Closure.ReflexiveTransitive
  hiding (return)
open import Relation.Binary.PropositionalEquality as PE using (_≡_)
open import Relation.Nullary

open RawMonad (P.monad {f = Level.zero})

open import Lambda.Syntax
private module C = Closure Tm

------------------------------------------------------------------------
-- Instruction set

mutual

  -- Instructions.

  data Instr (n : ℕ) : Set where
    var : (x : Fin n) → Instr n
    con : (i : ℕ) → Instr n
    clo : (c : Code (suc n)) → Instr n
    app : Instr n
    ret : Instr n

  -- Code.

  Code : ℕ → Set
  Code n = List (Instr n)

-- Environments and values.

open Closure Code

------------------------------------------------------------------------
-- Compiler

-- The compiler takes a code continuation.

comp : ∀ {n} → Tm n → Code n → Code n
comp (con i)   c = con i ∷ c
comp (var x)   c = var x ∷ c
comp (ƛ t)     c = clo (comp t [ ret ]) ∷ c
comp (t₁ · t₂) c = comp t₁ (comp t₂ (app ∷ c))

-- Environments and values can also be compiled.

mutual

  comp-env : ∀ {n} → C.Env n → Env n
  comp-env []      = []
  comp-env (v ∷ ρ) = comp-val v ∷ comp-env ρ

  comp-val : C.Value → Value
  comp-val (C.con i) = con i
  comp-val (C.ƛ t ρ) = ƛ (comp t [ ret ]) (comp-env ρ)

-- lookup x is homomorphic with respect to comp-env/comp-val.

lookup-hom : ∀ {n} (x : Fin n) ρ →
             lookup (comp-env ρ) x ≡ comp-val (lookup ρ x)
lookup-hom zero    (v ∷ ρ) = PE.refl
lookup-hom (suc x) (v ∷ ρ) = lookup-hom x ρ

------------------------------------------------------------------------
-- Stacks and states

-- Stacks.

data StackElement : Set where
  val : (v : Value) → StackElement
  ret : ∀ {n} (c : Code n) (ρ : Env n) → StackElement

Stack : Set
Stack = List StackElement

-- States.

data State : Set where
  ⟨_,_,_⟩ : ∀ {n} (c : Code n) (s : Stack) (ρ : Env n) → State

------------------------------------------------------------------------
-- Relational semantics of the VM

module Relational where

  infix 4 _⟶_

  data _⟶_ : State → State → Set where
    var : ∀ {n} {x : Fin n} {c s ρ} →
          ⟨ var x ∷ c , s , ρ ⟩ ⟶ ⟨ c , val (lookup ρ x) ∷ s , ρ ⟩
    con : ∀ {n i} {c : Code n} {s ρ} →
          ⟨ con i ∷ c , s , ρ ⟩ ⟶ ⟨ c , val (con i) ∷ s , ρ ⟩
    clo : ∀ {n} {c : Code n} {c′ s ρ} →
          ⟨ clo c′ ∷ c , s , ρ ⟩ ⟶ ⟨ c , val (ƛ c′ ρ) ∷ s , ρ ⟩
    app : ∀ {n} {c : Code n} {v n′} {c′ : Code (suc n′)} {ρ′ s ρ} →
          ⟨ app ∷ c , val v ∷ val (ƛ c′ ρ′) ∷ s , ρ ⟩ ⟶ ⟨ c′ , ret c ρ ∷ s , v ∷ ρ′ ⟩
    ret : ∀ {n} {c : Code n} {v n′} {c′ : Code n′} {ρ′ s ρ} →
          ⟨ ret ∷ c , val v ∷ ret c′ ρ′ ∷ s , ρ ⟩ ⟶ ⟨ c′ , val v ∷ s , ρ′ ⟩

  -- Final (stuck) states.

  Final : State → Set
  Final s = ∄ λ s′ → s ⟶ s′

  -- s ⇓ v means that s is a successful final state, and that the
  -- corresponding value is v.

  infix 4 _⇓_

  data _⇓_ : State → Value → Set where
    final : ∀ {v} → ⟨ [] , val v ∷ [] , [] ⟩ ⇓ v

  -- Sanity check.

  ⇓-final : ∀ {s v} → s ⇓ v → Final s
  ⇓-final final (_ , ())

  -- Crashing stuck states.

  Stuck : State → Set
  Stuck s = Final s × ∄ (λ v → s ⇓ v)

  -- Reflexive transitive closure.

  infix 4 _⟶⋆_

  _⟶⋆_ : State → State → Set
  _⟶⋆_ = Star _⟶_

  -- Infinite sequences of steps.

  infixr 5 _◅_
  infix  4 _⟶∞

  data _⟶∞ : State → Set where
    _◅_ : ∀ {s₁ s₂} (s₁⟶s₂ : s₁ ⟶ s₂) (s₂⟶∞ : ∞ (s₂ ⟶∞)) → s₁ ⟶∞

  -- A variant of _⟶∞ which is easier to use.

  module InfiniteSequence where

    infix  4 _⟶∞′
    infix  3 _⟶∞⟨_⟩
    infixr 2 _⟶⟨_⟩′_ _⟶⋆⟨_⟩′_

    data _⟶∞′ : State → Set where
      _⟶⟨_⟩′_  : ∀ s₁ {s₂} (s₁⟶s₂ : s₁ ⟶ s₂) (s₂⟶∞ : ∞ (s₂ ⟶∞′)) → s₁ ⟶∞′
      _⟶⋆⟨_⟩′_ : ∀ s₁ {s₂} (s₁⟶⋆s₂ : s₁ ⟶⋆ s₂) (s₂⟶∞ : s₂ ⟶∞′) → s₁ ⟶∞′
      _⟶∞⟨_⟩   : ∀ s (s⟶∞ : s ⟶∞′) → s ⟶∞′

    sound : ∀ {s} → s ⟶∞′ → s ⟶∞
    sound (s₁ ⟶⟨ s₁⟶s₂ ⟩′ s₂⟶∞)           = s₁⟶s₂ ◅ ♯ (sound (♭ s₂⟶∞))
    sound (s  ⟶⋆⟨ ε ⟩′ s⟶∞)               = sound s⟶∞
    sound (s₁ ⟶⋆⟨ s₁⟶s₂ ◅ s₂⟶⋆s₃ ⟩′ s₃⟶∞) = s₁⟶s₂ ◅ ♯ (sound (_ ⟶⋆⟨ s₂⟶⋆s₃ ⟩′ s₃⟶∞))
    sound (s  ⟶∞⟨ s⟶∞ ⟩)                  = sound s⟶∞

    complete : ∀ {s} → s ⟶∞ → s ⟶∞′
    complete (s₁⟶s₂ ◅ s₂⟶∞) = _ ⟶⟨ s₁⟶s₂ ⟩′ ♯ complete (♭ s₂⟶∞)

------------------------------------------------------------------------
-- Functional semantics of the VM

module Functional where

  -- The result of running the VM one step.

  data Result : Set where
    continue : (s : State) → Result
    done     : (v : Value) → Result
    crash    : Result

  -- A single step of the computation.

  step : State → Result
  step ⟨ []         ,                 val v ∷ [] , [] ⟩ = done v
  step ⟨ var x  ∷ c ,                          s , ρ  ⟩ = continue ⟨ c  , val (lookup ρ x) ∷ s ,     ρ  ⟩
  step ⟨ con i  ∷ c ,                          s , ρ  ⟩ = continue ⟨ c  , val (con i)      ∷ s ,     ρ  ⟩
  step ⟨ clo c′ ∷ c ,                          s , ρ  ⟩ = continue ⟨ c  , val (ƛ c′ ρ)     ∷ s ,     ρ  ⟩
  step ⟨ app    ∷ c , val v ∷ val (ƛ c′ ρ′) ∷  s , ρ  ⟩ = continue ⟨ c′ , ret c ρ          ∷ s , v ∷ ρ′ ⟩
  step ⟨ ret    ∷ c , val v ∷ ret c′ ρ′     ∷  s , ρ  ⟩ = continue ⟨ c′ , val v            ∷ s ,     ρ′ ⟩
  step _                                                = crash

  -- The VM.

  exec : State → Maybe Value ⊥
  exec s with step s
  ... | continue s′ = later (♯ exec s′)
  ... | done v      = return (just v)
  ... | crash       = return nothing

  -- Equality for partial computations returning Maybe Value.
  --
  -- Note that propositional equality is used for the underlying
  -- values, which can include code components. In other words, if
  -- v₁ ≈ v₂, then any code components in these values have to be
  -- /syntactically/ equal.

  module Equality where

    private
      open module PEq {A : Set} = P.Equality {A = A} _≡_ public
        using (_≈_; now; later; laterˡ)

    open P public using (later⁻¹; now≉never)

    module EqReasoning {A : Set} = P.Reasoning {A = A} PE.isEquivalence

------------------------------------------------------------------------
-- Equivalence proof

module Equivalence where

  open Relational
  open Functional
  open Functional.Equality

  ----------------------------------------------------------------------
  -- Classification of states

  -- Inductive characterisation of states which are stuck and not
  -- final.

  data Crashing : State → Set where
    crash₁  : ∀ {n ρ}                → Crashing (⟨_,_,_⟩ {    n}        []                            []        ρ )
    crash₂  : ∀ {n n′ c ρ′ s ρ}      → Crashing (⟨_,_,_⟩ {    n}        [] (         ret {n′} c ρ′  ∷ s )       ρ )
    crash₃  : ∀ {n v e s ρ}          → Crashing (⟨_,_,_⟩ {    n}        [] (val v  ∷ e              ∷ s )       ρ )
    crash₄  : ∀ {n v₁ v₂ ρ}          → Crashing (⟨_,_,_⟩ {suc n}        [] (         val v₁         ∷ []) (v₂ ∷ ρ))
    crash₅  : ∀ {n c ρ}              → Crashing (⟨_,_,_⟩ {    n} (app ∷ c)                            []        ρ )
    crash₆  : ∀ {n c v ρ}            → Crashing (⟨_,_,_⟩ {    n} (app ∷ c) (         val v          ∷ [])       ρ )
    crash₇  : ∀ {n c n′ c′ ρ′ s ρ}   → Crashing (⟨_,_,_⟩ {    n} (app ∷ c) (         ret {n′} c′ ρ′ ∷ s )       ρ )
    crash₈  : ∀ {n c v i s ρ}        → Crashing (⟨_,_,_⟩ {    n} (app ∷ c) (val v  ∷ val (con i)    ∷ s )       ρ )
    crash₉  : ∀ {n c v n′ c′ ρ′ s ρ} → Crashing (⟨_,_,_⟩ {    n} (app ∷ c) (val v  ∷ ret {n′} c′ ρ′ ∷ s )       ρ )
    crash₁₀ : ∀ {n c ρ}              → Crashing (⟨_,_,_⟩ {    n} (ret ∷ c)                            []        ρ )
    crash₁₁ : ∀ {n c v ρ}            → Crashing (⟨_,_,_⟩ {    n} (ret ∷ c) (         val v          ∷ [])       ρ )
    crash₁₂ : ∀ {n c n′ c′ ρ′ s ρ}   → Crashing (⟨_,_,_⟩ {    n} (ret ∷ c) (         ret {n′} c′ ρ′ ∷ s )       ρ )
    crash₁₃ : ∀ {n c v₁ v₂ s ρ}      → Crashing (⟨_,_,_⟩ {    n} (ret ∷ c) (val v₁ ∷ val v₂         ∷ s )       ρ )

  -- There are three kinds of states.

  data Kind (s : State) : Set where
    done     : ∀ {v} (s⇓v : s ⇓ v)    → Kind s
    continue : ∀ {s′} (s⟶s′ : s ⟶ s′) → Kind s
    crash    : (s↯ : Crashing s)      → Kind s

  -- We can assign (at least) one kind to every state.

  kind : ∀ s → Kind s
  kind ⟨ []         ,                 val v ∷ [] , [] ⟩ = done final
  kind ⟨ var x  ∷ c ,                          s , ρ  ⟩ = continue var
  kind ⟨ con i  ∷ c ,                          s , ρ  ⟩ = continue con
  kind ⟨ clo c′ ∷ c ,                          s , ρ  ⟩ = continue clo
  kind ⟨ app    ∷ c , val v ∷ val (ƛ c′ ρ′) ∷  s , ρ  ⟩ = continue app
  kind ⟨ ret    ∷ c , val v ∷ ret c′ ρ′     ∷  s , ρ  ⟩ = continue ret

  kind ⟨ []      ,                       [] , _     ⟩ = crash crash₁
  kind ⟨ []      ,         ret _ _     ∷ _  , _     ⟩ = crash crash₂
  kind ⟨ []      , val _ ∷ _           ∷ _  , _     ⟩ = crash crash₃
  kind ⟨ []      ,         val _       ∷ [] , _ ∷ _ ⟩ = crash crash₄
  kind ⟨ app ∷ _ ,                       [] , _     ⟩ = crash crash₅
  kind ⟨ app ∷ _ ,         val _       ∷ [] , _     ⟩ = crash crash₆
  kind ⟨ app ∷ _ ,         ret _ _     ∷ _  , _     ⟩ = crash crash₇
  kind ⟨ app ∷ _ , val _ ∷ val (con _) ∷ _  , _     ⟩ = crash crash₈
  kind ⟨ app ∷ _ , val _ ∷ ret _ _     ∷ _  , _     ⟩ = crash crash₉
  kind ⟨ ret ∷ _ ,                       [] , _     ⟩ = crash crash₁₀
  kind ⟨ ret ∷ _ ,         val _       ∷ [] , _     ⟩ = crash crash₁₁
  kind ⟨ ret ∷ _ ,         ret _ _     ∷ _  , _     ⟩ = crash crash₁₂
  kind ⟨ ret ∷ _ , val _ ∷ val _       ∷ _  , _     ⟩ = crash crash₁₃

  -- The functional semantics crashes for crashing states.

  exec-crashes : ∀ {s} → Crashing s → exec s ≈ return nothing
  exec-crashes crash₁  = now PE.refl
  exec-crashes crash₂  = now PE.refl
  exec-crashes crash₃  = now PE.refl
  exec-crashes crash₄  = now PE.refl
  exec-crashes crash₅  = now PE.refl
  exec-crashes crash₆  = now PE.refl
  exec-crashes crash₇  = now PE.refl
  exec-crashes crash₈  = now PE.refl
  exec-crashes crash₉  = now PE.refl
  exec-crashes crash₁₀ = now PE.refl
  exec-crashes crash₁₁ = now PE.refl
  exec-crashes crash₁₂ = now PE.refl
  exec-crashes crash₁₃ = now PE.refl

  -- The relational semantics also crashes for crashing states.

  ⟶-crashes : ∀ {s} → Crashing s → Stuck s
  ⟶-crashes s↯ = (helper₁ s↯ , helper₂ s↯)
    where
    helper₁ : ∀ {s} → Crashing s → Final s
    helper₁ crash₁  (_ , ())
    helper₁ crash₂  (_ , ())
    helper₁ crash₃  (_ , ())
    helper₁ crash₄  (_ , ())
    helper₁ crash₅  (_ , ())
    helper₁ crash₆  (_ , ())
    helper₁ crash₇  (_ , ())
    helper₁ crash₈  (_ , ())
    helper₁ crash₉  (_ , ())
    helper₁ crash₁₀ (_ , ())
    helper₁ crash₁₁ (_ , ())
    helper₁ crash₁₂ (_ , ())
    helper₁ crash₁₃ (_ , ())

    helper₂ : ∀ {s} → Crashing s → ∄ λ v → s ⇓ v
    helper₂ crash₁  (_ , ())
    helper₂ crash₂  (_ , ())
    helper₂ crash₃  (_ , ())
    helper₂ crash₄  (_ , ())
    helper₂ crash₅  (_ , ())
    helper₂ crash₆  (_ , ())
    helper₂ crash₇  (_ , ())
    helper₂ crash₈  (_ , ())
    helper₂ crash₉  (_ , ())
    helper₂ crash₁₀ (_ , ())
    helper₂ crash₁₁ (_ , ())
    helper₂ crash₁₂ (_ , ())
    helper₂ crash₁₃ (_ , ())

  ----------------------------------------------------------------------
  -- The relational semantics is sound with respect to the functional
  -- one

  -- Note that these proofs implicitly establish that the relational
  -- semantics is deterministic.

  ⇒⇓ : ∀ {s s′ v} → s ⟶⋆ s′ → s′ ⇓ v → exec s ≈ return (just v)
  ⇒⇓ ε           final = now PE.refl
  ⇒⇓ (var ◅ s⟶⋆) ⇓     = laterˡ (⇒⇓ s⟶⋆ ⇓)
  ⇒⇓ (con ◅ s⟶⋆) ⇓     = laterˡ (⇒⇓ s⟶⋆ ⇓)
  ⇒⇓ (clo ◅ s⟶⋆) ⇓     = laterˡ (⇒⇓ s⟶⋆ ⇓)
  ⇒⇓ (app ◅ s⟶⋆) ⇓     = laterˡ (⇒⇓ s⟶⋆ ⇓)
  ⇒⇓ (ret ◅ s⟶⋆) ⇓     = laterˡ (⇒⇓ s⟶⋆ ⇓)

  ⇒⇑ : ∀ {s} → s ⟶∞ → exec s ≈ never
  ⇒⇑ (var ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
  ⇒⇑ (con ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
  ⇒⇑ (clo ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
  ⇒⇑ (app ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))
  ⇒⇑ (ret ◅ s⟶∞) = later (♯ (⇒⇑ (♭ s⟶∞)))

  ⇒↯ : ∀ {s} → ∃ (λ s′ → s ⟶⋆ s′ × Stuck s′) → exec s ≈ return nothing
  ⇒↯ (_ , var ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
  ⇒↯ (_ , con ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
  ⇒↯ (_ , clo ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
  ⇒↯ (_ , app ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
  ⇒↯ (_ , ret ◅ s⟶⋆ , ↯) = laterˡ (⇒↯ (_ , s⟶⋆ , ↯))
  ⇒↯ (s , ε          , ↯) with kind s
  ... | done s⇓v       = ⊥-elim (proj₂ ↯ (-, s⇓v))
  ... | continue s₁⟶s₂ = ⊥-elim (proj₁ ↯ (-, s₁⟶s₂))
  ... | crash s↯       = exec-crashes s↯

  ----------------------------------------------------------------------
  -- The relational semantics is complete with respect to the
  -- functional one

  ⇐⇓ : ∀ {s v} → exec s ≈ return (just v) → ∃ λ s′ → s ⟶⋆ s′ × s′ ⇓ v
  ⇐⇓ {s = s} ⇓ with kind s
  ⇐⇓ (now PE.refl) | done final   = (_ , ε , final)
  ⇐⇓ (laterˡ ⇓)    | continue var = Prod.map id (Prod.map (_◅_ var) id) (⇐⇓ ⇓)
  ⇐⇓ (laterˡ ⇓)    | continue con = Prod.map id (Prod.map (_◅_ con) id) (⇐⇓ ⇓)
  ⇐⇓ (laterˡ ⇓)    | continue clo = Prod.map id (Prod.map (_◅_ clo) id) (⇐⇓ ⇓)
  ⇐⇓ (laterˡ ⇓)    | continue app = Prod.map id (Prod.map (_◅_ app) id) (⇐⇓ ⇓)
  ⇐⇓ (laterˡ ⇓)    | continue ret = Prod.map id (Prod.map (_◅_ ret) id) (⇐⇓ ⇓)
  ⇐⇓ {s} {v} ⇓     | crash s↯      with
    return (just v)  ≈⟨ sym ⇓ ⟩
    exec s           ≈⟨ exec-crashes s↯ ⟩
    return nothing   ∎
    where open EqReasoning
  ... | now ()

  ⇐⇑ : ∀ {s} → exec s ≈ never → s ⟶∞
  ⇐⇑ {s = s} ⇑ with kind s
  ⇐⇑         ⇑ | done final   = ⊥-elim (now≉never ⇑)
  ⇐⇑         ⇑ | continue var = var ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
  ⇐⇑         ⇑ | continue con = con ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
  ⇐⇑         ⇑ | continue clo = clo ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
  ⇐⇑         ⇑ | continue app = app ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
  ⇐⇑         ⇑ | continue ret = ret ◅ ♯ ⇐⇑ (later⁻¹ ⇑)
  ⇐⇑ {s}     ⇑ | crash s↯     = ⊥-elim (now≉never (
    return nothing  ≈⟨ sym $ exec-crashes s↯ ⟩
    exec s          ≈⟨ ⇑ ⟩
    never           ∎))
    where open EqReasoning

  ⇐↯ : ∀ {s} → exec s ≈ return nothing → ∃ λ s′ → s ⟶⋆ s′ × Stuck s′
  ⇐↯ {s = s} ↯ with kind s
  ⇐↯ (now ())   | done final
  ⇐↯ (laterˡ ↯) | continue var = Prod.map id (Prod.map (_◅_ var) id) $ ⇐↯ ↯
  ⇐↯ (laterˡ ↯) | continue con = Prod.map id (Prod.map (_◅_ con) id) $ ⇐↯ ↯
  ⇐↯ (laterˡ ↯) | continue clo = Prod.map id (Prod.map (_◅_ clo) id) $ ⇐↯ ↯
  ⇐↯ (laterˡ ↯) | continue app = Prod.map id (Prod.map (_◅_ app) id) $ ⇐↯ ↯
  ⇐↯ (laterˡ ↯) | continue ret = Prod.map id (Prod.map (_◅_ ret) id) $ ⇐↯ ↯
  ⇐↯         ↯  | crash s↯     = (_ , ε , ⟶-crashes s↯)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Lexicographic induction
------------------------------------------------------------------------

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

module Induction.Lexicographic where

open import Data.Product
open import Induction
open import Level

-- The structure of lexicographic induction.

Σ-Rec : ∀ {a b ℓ₁ ℓ₂ ℓ₃} {A : Set a} {B : A → Set b} →
        RecStruct A (ℓ₁ ⊔ b) ℓ₂ → (∀ x → RecStruct (B x) ℓ₁ ℓ₃) →
        RecStruct (Σ A B) _ _
Σ-Rec RecA RecB P (x , y) =
  -- Either x is constant and y is "smaller", ...
  RecB x (λ y' → P (x , y')) y
    ×
  -- ...or x is "smaller" and y is arbitrary.
  RecA (λ x' → ∀ y' → P (x' , y')) x

_⊗_ : ∀ {a b ℓ₁ ℓ₂ ℓ₃} {A : Set a} {B : Set b} →
      RecStruct A (ℓ₁ ⊔ b) ℓ₂ → RecStruct B ℓ₁ ℓ₃ →
      RecStruct (A × B) _ _
RecA ⊗ RecB = Σ-Rec RecA (λ _ → RecB)

-- Constructs a recursor builder for lexicographic induction.

Σ-rec-builder :
  ∀ {a b ℓ₁ ℓ₂ ℓ₃} {A : Set a} {B : A → Set b}
    {RecA : RecStruct A (ℓ₁ ⊔ b) ℓ₂}
    {RecB : ∀ x → RecStruct (B x) ℓ₁ ℓ₃} →
  RecursorBuilder RecA → (∀ x → RecursorBuilder (RecB x)) →
  RecursorBuilder (Σ-Rec RecA RecB)
Σ-rec-builder {RecA = RecA} {RecB = RecB} recA recB P f (x , y) =
  (p₁ x y p₂x , p₂x)
  where
  p₁ : ∀ x y →
       RecA (λ x' → ∀ y' → P (x' , y')) x →
       RecB x (λ y' → P (x , y')) y
  p₁ x y x-rec = recB x
                      (λ y' → P (x , y'))
                      (λ y y-rec → f (x , y) (y-rec , x-rec))
                      y

  p₂ : ∀ x → RecA (λ x' → ∀ y' → P (x' , y')) x
  p₂ = recA (λ x → ∀ y → P (x , y))
            (λ x x-rec y → f (x , y) (p₁ x y x-rec , x-rec))

  p₂x = p₂ x

[_⊗_] : ∀ {a b ℓ₁ ℓ₂ ℓ₃} {A : Set a} {B : Set b}
          {RecA : RecStruct A (ℓ₁ ⊔ b) ℓ₂} {RecB : RecStruct B ℓ₁ ℓ₃} →
        RecursorBuilder RecA → RecursorBuilder RecB →
        RecursorBuilder (RecA ⊗ RecB)
[ recA ⊗ recB ] = Σ-rec-builder recA (λ _ → recB)

------------------------------------------------------------------------
-- Example

private

  open import Data.Nat
  open import Induction.Nat as N

  -- The Ackermann function à la Rózsa Péter.

  ackermann : ℕ → ℕ → ℕ
  ackermann m n =
    build [ N.recBuilder ⊗ N.recBuilder ]
          (λ _ → ℕ)
          (λ { (zero  , n)     _                   → 1 + n
             ; (suc m , zero)  (_         , ackm•) → ackm• 1
             ; (suc m , suc n) (ack[1+m]n , ackm•) → ackm• ack[1+m]n
             })
          (m , n)


{-# OPTIONS --without-K --safe #-}
module Source.Type where

open import Source.Size as S using
  ( Size ; Δ ; Δ′ ; Δ″ ; Ω ; Ω′ ; Ω″ ; n ; m ; o ; p ; b )
open import Source.Size.Substitution.Canonical as SC using
  ( Sub⊢ )
open import Source.Size.Substitution.Theory
open import Source.Size.Substitution.Universe as SU using
  ( σ ; τ ; ι ; ⟨_⟩ )
open import Util.Prelude

open S.Ctx

infixr 3 Π_,_
infixr 4 _⇒_
infixl 4 _∙_

data Type (Δ : S.Ctx) : Set where
  Nat : (n : Size Δ) → Type Δ
  Stream : (n : Size Δ) → Type Δ
  _⇒_ : (T U : Type Δ) → Type Δ
  Π_,_ : (n : Size Δ) (T : Type (Δ ∙ n)) → Type Δ

variable T U V W T′ U′ V′ W′ : Type Δ

Π-≡⁺ : ∀ {n m} {T : Type (Δ ∙ n)} {U : Type (Δ ∙ m)}
  → (n≡m : n ≡ m)
  → subst (λ n → Type (Δ ∙ n)) n≡m T ≡ U
  → (Π n , T) ≡ (Π m , U)
Π-≡⁺ refl refl = refl

data Ctx (Δ : S.Ctx) : Set where
  [] : Ctx Δ
  _∙_ : (Γ : Ctx Δ) (T : Type Δ) → Ctx Δ

variable Γ Γ′ Γ″ Ψ Ψ′ Ψ″ : Ctx Δ

sub : SC.Sub Δ Ω → Type Ω → Type Δ
sub σ (Nat n) = Nat (SC.sub σ n)
sub σ (Stream n) = Stream (SC.sub σ n)
sub σ (T ⇒ U) = sub σ T ⇒ sub σ U
sub σ (Π n , T) = Π SC.sub σ n , sub (SC.Lift σ) T

abstract
  sub->> : ∀ {Δ Δ′ Δ″} (σ : SC.Sub Δ Δ′) (τ : SC.Sub Δ′ Δ″) T
    → sub (σ SC.>> τ) T ≡ sub σ (sub τ T)
  sub->> σ τ (Nat n) = cong Nat (SC.sub->> n refl)
  sub->> σ τ (Stream n) = cong Stream (SC.sub->> n refl)
  sub->> σ τ (T ⇒ U) = cong₂ _⇒_ (sub->> σ τ T) (sub->> σ τ U)
  sub->> σ τ (Π n , T)
    rewrite SC.sub->> {σ = σ} {τ} n refl
    = cong (λ T → Π SC.sub σ (SC.sub τ n) , T)
        (trans (cong (λ σ → sub σ T) (sym SC.Lift>>Lift))
          (sub->> (SC.Lift σ) (SC.Lift τ) T))

  sub-Id : (T : Type Δ) → sub SC.Id T ≡ T
  sub-Id (Nat n) = cong Nat (SC.sub-Id n refl)
  sub-Id (Stream n) = cong Stream (SC.sub-Id n refl)
  sub-Id (T ⇒ U) = cong₂ _⇒_ (sub-Id T) (sub-Id U)
  sub-Id (Π n , T)
    rewrite SC.sub-Id n refl
    = cong (λ T → Π n , T) (sub-Id T)

instance
  SubTheory-Type : SubTheory Type
  SubTheory-Type = record
    { _[_] = λ T σ → sub σ T
    ; [Id] = sub-Id
    ; [>>] = sub->>
    }

subΓ : SC.Sub Δ Ω → Ctx Ω → Ctx Δ
subΓ σ [] = []
subΓ σ (Γ ∙ T) = subΓ σ Γ ∙ sub σ T

abstract
  subΓ->> : ∀ (σ : SC.Sub Δ Δ′) (τ : SC.Sub Δ′ Δ″) Γ
    → subΓ (σ SC.>> τ) Γ ≡ subΓ σ (subΓ τ Γ)
  subΓ->> σ τ [] = refl
  subΓ->> σ τ (Γ ∙ T) = cong₂ _∙_ (subΓ->> σ τ Γ) (sub->> σ τ T)

  subΓ-Id : (Γ : Ctx Δ) → subΓ SC.Id Γ ≡ Γ
  subΓ-Id [] = refl
  subΓ-Id (Γ ∙ T) = cong₂ _∙_ (subΓ-Id Γ) (sub-Id T)

instance
  SubTheory-Ctx : SubTheory Ctx
  SubTheory-Ctx = record
    { _[_] = λ Γ σ → subΓ σ Γ
    ; [Id] = subΓ-Id
    ; [>>] = subΓ->>
    }


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

open import Cubical.Foundations.Everything renaming (_⁻¹ to _⁻¹ᵖ; assoc to ∙-assoc)
open import Function.Base using (_∋_; _$_)
import Cubical.Algebra.Monoid as Std
open import MorePropAlgebra.Bundles

module MorePropAlgebra.Properties.Monoid {ℓ} (assumptions : Monoid {ℓ}) where
open Monoid assumptions renaming (Carrier to F)

import MorePropAlgebra.Properties.Semigroup
module Semigroup'Properties = MorePropAlgebra.Properties.Semigroup   (record { Monoid assumptions })
module Semigroup'           =                            Semigroup   (record { Monoid assumptions })
(      Semigroup')          =                            Semigroup ∋ (record { Monoid assumptions })

stdIsMonoid : Std.IsMonoid ε _·_
stdIsMonoid  .Std.IsMonoid.isSemigroup = Semigroup'Properties.stdIsSemigroup
stdIsMonoid  .Std.IsMonoid.identity    = is-identity

stdMonoid : Std.Monoid {ℓ}
stdMonoid = record { Monoid assumptions ; isMonoid = stdIsMonoid }


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.Group.Construct.Unit where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Algebra.Group
open import Cubical.Data.Prod using (_,_)

open import Cubical.Data.Unit

import Cubical.Algebra.Monoid.Construct.Unit as ⊤Monoid
open ⊤Monoid public hiding (⊤-isMonoid; ⊤-Monoid)

inv : Op₁ ⊤
inv _ = tt

⊤-inverseˡ : LeftInverse tt inv _◯_
⊤-inverseˡ _ = refl

⊤-inverseʳ : RightInverse tt inv _◯_
⊤-inverseʳ _ = refl

⊤-inverse : Inverse tt inv _◯_
⊤-inverse = ⊤-inverseˡ , ⊤-inverseʳ

⊤-isGroup : IsGroup ⊤ _◯_ tt inv
⊤-isGroup = record
  { isMonoid = ⊤Monoid.⊤-isMonoid
  ; inverse  = ⊤-inverse
  }

⊤-Group : Group ℓ-zero
⊤-Group = record { isGroup = ⊤-isGroup }


open import Mockingbird.Forest using (Forest)

module Mockingbird.Forest.Combination.Base {b ℓ} (forest : Forest {b} {ℓ}) where

open import Level using (Level; _⊔_)
open import Relation.Unary using (Pred; _∈_)

open Forest forest

private
  variable
    p : Level
    x y z : Bird
    P : Pred Bird p

-- If P is a set of birds, we can think of ⟨ P ⟩ as the set of birds ‘generated
-- by’ P.
data ⟨_⟩ (P : Pred Bird p) : Pred Bird (p ⊔ b ⊔ ℓ) where
  [_] : (x∈P : x ∈ P) → x ∈ ⟨ P ⟩

  _⟨∙⟩_∣_ :
       (x∈⟨P⟩ : x ∈ ⟨ P ⟩)
    → (y∈⟨P⟩ : y ∈ ⟨ P ⟩)
    → (xy≈z : x ∙ y ≈ z)
    → z ∈ ⟨ P ⟩

infixl 6 _⟨∙⟩_
_⟨∙⟩_ : x ∈ ⟨ P ⟩ → y ∈ ⟨ P ⟩ → x ∙ y ∈ ⟨ P ⟩
_⟨∙⟩_ = _⟨∙⟩_∣ refl


-- This is a selection of useful function
-- from the standard library that we tend to use a lot.
module Prelude where

  open import Data.Nat
    hiding (_⊔_)
    public

  open import Level
    renaming (suc to lsuc; zero to ℓ0)
    public

  open import Relation.Binary.PropositionalEquality
    renaming ([_] to Reveal[_] )
    public

  open import Relation.Unary
    public

  open import Data.Unit
    using (⊤; tt)
    public

  open import Data.Sum
    public

  open import Data.Nat.Properties
    public

  open import Relation.Nullary
    hiding (Irrelevant)
    public

  open import Data.Product
    using (_×_; proj₁; proj₂; Σ; _,_; ∃; Σ-syntax; ∃-syntax)
    public

  open import Data.Empty
    using (⊥; ⊥-elim)
    public

  open import Function
    using (_∘_)
    public

  open import Data.List.Relation.Unary.Any
    using (Any; here; there)
    public


------------------------------------------------------------------------------
-- Natural numbers (added for the Collatz function example)
------------------------------------------------------------------------------

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

-- We don't want populate the FOTC library with more first-order logic
-- axioms.

module FOTC.Program.Collatz.Data.Nat where

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

infixr 8 _^_

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

postulate
  div     : D → D → D
  div-x<y : ∀ {m n} → n ≢ 0' → m < n → div m n ≡ zero
  div-x≥y : ∀ {m n} → n ≢ 0' → m ≥ n → div m n ≡ succ₁ (div (m ∸ n) n)
{-# ATP axioms div-x<y div-x≥y #-}

postulate
  _^_ : D → D → D
  ^-0 : ∀ n → n ^ zero      ≡ 1'
  ^-S : ∀ m n → m ^ succ₁ n ≡ m * m ^ n
{-# ATP axioms ^-0 ^-S #-}

postulate
  even : D → D
  odd  : D → D

  even-0 : even zero            ≡ true
  even-S : ∀ n → even (succ₁ n) ≡ odd n

  odd-0 : odd zero            ≡ false
  odd-S : ∀ n → odd (succ₁ n) ≡ even n
{-# ATP axioms even-0 even-S odd-0 odd-S #-}

Even : D → Set
Even n = even n ≡ true
{-# ATP definition Even #-}

NotEven : D → Set
NotEven n = even n ≡ false
{-# ATP definition NotEven #-}

Odd : D → Set
Odd n = odd n ≡ true
{-# ATP definition Odd #-}


-- A binding to a Haskell natural numbers type

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

module Data.Natural where

open import Data.Natural.Primitive public
  using ( Natural ; zero ; suc ; _+_ ; toString ; foldl ; foldl' ; foldr )
  renaming ( fromℕ to # )

% : Natural → ℕ
% = foldr suc' zero'


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

open import Types
open import Paths

{- Stuff about truncation levels (aka h-levers) that do not require the notion
   of equivalence or function extensionality -}

module HLevel {i} where

-- Definition of truncation levels

is-contr : Set i → Set i
is-contr A = Σ A (λ x → ((y : A) → y ≡ x))

is-truncated : ℕ₋₂ → (Set i → Set i)
is-truncated ⟨-2⟩ A = is-contr A
is-truncated (S n) A = (x y : A) → is-truncated n (x ≡ y)

is-prop = is-truncated ⟨-1⟩
is-set  = is-truncated ⟨0⟩
is-gpd  = is-truncated ⟨1⟩

-- The original notion of h-level can be defined in the following way.
-- We won’t use this definition though.
is-hlevel : ℕ → (Set i → Set i)
is-hlevel n A = is-truncated (n -2) A where
  _-2 : ℕ → ℕ₋₂
  O -2 = ⟨-2⟩
  (S n) -2 = S (n -2)

-- The following property is equivalent to being a proposition
has-all-paths : Set i → Set i
has-all-paths A = (x y : A) → x ≡ y

-- Having decidable equality is stronger that being a set
has-dec-eq : Set i → Set i
has-dec-eq A = (x y : A) → (x ≡ y) ⊔ (x ≢ y)

abstract
  all-paths-is-prop : {A : Set i} → (has-all-paths A → is-prop A)
  all-paths-is-prop {A} c x y = (c x y , canon-path) where
    lemma : {x y : A} (p : x ≡ y) → c x y ≡ p ∘ c y y
    lemma refl = refl

    canon-path : {x y : A} (p : x ≡ y) → p ≡ c x y
    canon-path {.y} {y} refl = anti-whisker-right (c y y) (lemma (c y y))

  -- Truncation levels are cumulative
  truncated-is-truncated-S : {A : Set i} (n : ℕ₋₂)
    → (is-truncated n A → is-truncated (S n) A)
  truncated-is-truncated-S ⟨-2⟩ q =
    all-paths-is-prop (λ x y → π₂ q x ∘ ! (π₂ q y))
  truncated-is-truncated-S (S n) q =
    λ x y → truncated-is-truncated-S n (q x y)

  -- A type with a decidable equality is a set
  dec-eq-is-set : {A : Set i} → (has-dec-eq A → is-set A)
  dec-eq-is-set dec x y with dec x y
  dec-eq-is-set dec x y | inr p⊥ = λ p → abort-nondep (p⊥ p)
  dec-eq-is-set {A} dec x y | inl q = paths-A-is-prop q where

    -- The fact that equality is decidable on A gives a canonical path parallel
    -- to every path [p], depending only on the endpoints
    get-path : {u v : A} (r : u ≡ v) → u ≡ v
    get-path {u} {v} r with dec u v
    get-path r | inl q = q
    get-path r | inr r⊥ = abort-nondep (r⊥ r)

    get-path-eq : {u : A} (r : u ≡ u) → get-path r ≡ get-path refl
    get-path-eq {u} r with dec u u
    get-path-eq r | inl q = refl
    get-path-eq r | inr r⊥ = abort-nondep (r⊥ refl)

    lemma : {u v : A} (r : u ≡ v) → r ∘ get-path refl ≡ get-path r
    lemma refl = refl

    paths-A-is-prop : {u v : A} (q : u ≡ v) → is-prop (u ≡ v)
    paths-A-is-prop {u} {.u} refl =
      truncated-is-truncated-S ⟨-2⟩
        (refl , λ r → anti-whisker-right (get-path refl)
                                         (lemma r ∘ get-path-eq r))

module _ {A : Set i} where
  abstract
    contr-has-all-paths : is-contr A → has-all-paths A
    contr-has-all-paths c x y = π₂ c x ∘ ! (π₂ c y)

    prop-has-all-paths : is-prop A → has-all-paths A
    prop-has-all-paths c x y = π₁ (c x y)

    inhab-prop-is-contr : A → is-prop A → is-contr A
    inhab-prop-is-contr x₀ p = (x₀ , λ y → π₁ (p y x₀))

    contr-is-truncated : (n : ℕ₋₂) → (is-contr A → is-truncated n A)
    contr-is-truncated ⟨-2⟩ p = p
    contr-is-truncated (S n) p =
      truncated-is-truncated-S n (contr-is-truncated n p)

    prop-is-truncated-S : (n : ℕ₋₂) → (is-prop A → is-truncated (S n) A)
    prop-is-truncated-S ⟨-2⟩ p = p
    prop-is-truncated-S (S n) p =
      truncated-is-truncated-S (S n) (prop-is-truncated-S n p)

    set-is-truncated-SS : (n : ℕ₋₂) → (is-set A → is-truncated (S (S n)) A)
    set-is-truncated-SS ⟨-2⟩ p = p
    set-is-truncated-SS (S n) p = truncated-is-truncated-S (S (S n))
                                                  (set-is-truncated-SS n p)

    contr-is-prop : is-contr A → is-prop A
    contr-is-prop = contr-is-truncated ⟨-1⟩

    contr-is-set : is-contr A → is-set A
    contr-is-set = contr-is-truncated ⟨0⟩

    contr-is-gpd : is-contr A → is-gpd A
    contr-is-gpd = contr-is-truncated ⟨1⟩

    prop-is-set : is-prop A → is-set A
    prop-is-set = prop-is-truncated-S ⟨-1⟩

    prop-is-gpd : is-prop A → is-gpd A
    prop-is-gpd = prop-is-truncated-S ⟨0⟩

    set-is-gpd : is-set A → is-gpd A
    set-is-gpd = set-is-truncated-SS ⟨-1⟩

    -- If [A] is n-truncated, then so does [x ≡ y] for [x y : A]
    ≡-is-truncated : (n : ℕ₋₂) {x y : A}
      → (is-truncated n A → is-truncated n (x ≡ y))
    ≡-is-truncated ⟨-2⟩ p = (contr-has-all-paths p _ _ , unique-path) where
      unique-path : {u v : A} (q : u ≡ v)
        → q ≡ contr-has-all-paths p u v
      unique-path refl = ! (opposite-right-inverse (π₂ p _))
    ≡-is-truncated (S n) {x} {y} p = truncated-is-truncated-S n (p x y)

  -- The type of paths to a fixed point is contractible
  pathto-is-contr : (x : A) → is-contr (Σ A (λ t → t ≡ x))
  pathto-is-contr x = ((x , refl) , pathto-unique-path) where
    pathto-unique-path : {u : A} (pp : Σ A (λ t → t ≡ u)) → pp ≡ (u , refl)
    pathto-unique-path (u , refl) = refl

  -- Specilization
  module _ where
    ≡-is-set : {x y : A} → (is-set A → is-set (x ≡ y))
    ≡-is-set = ≡-is-truncated ⟨0⟩

    ≡-is-prop : {x y : A} → (is-prop A → is-prop (x ≡ y))
    ≡-is-prop = ≡-is-truncated ⟨-1⟩

abstract
  -- Unit is contractible
  -- I do not need to specify the universe level because in this file [is-contr]
  -- is not yet universe polymorphic ([i] is a global argument)
  unit-is-contr : is-contr unit
  unit-is-contr = (tt , λ y → refl)

  unit-is-truncated : (n : ℕ₋₂) → is-truncated n unit
  unit-is-truncated n = contr-is-truncated n unit-is-contr

  -- [unit-is-truncated#instance] produces unsolved metas
  unit-is-truncated-S#instance : {n : ℕ₋₂} → is-truncated (S n) unit
  unit-is-truncated-S#instance = contr-is-truncated _ unit-is-contr

  unit-is-prop : is-prop unit
  unit-is-prop = unit-is-truncated ⟨-1⟩

  unit-is-set : is-set unit
  unit-is-set = unit-is-truncated ⟨0⟩

  contr-has-section : ∀ {j} {A : Set i} {P : A → Set j}
    → (is-contr A → (x : A) → (u : P x) → Π A P)
  contr-has-section (x , p) x₀ y₀ t = transport _ (p x₀ ∘ ! (p t)) y₀

private
  bool-true≢false-type : bool {i} → Set
  bool-true≢false-type true  = ⊤
  bool-true≢false-type false = ⊥

abstract
  bool-true≢false : true {i} ≢ false
  bool-true≢false p = transport bool-true≢false-type p tt

  bool-false≢true : false {i} ≢ true
  bool-false≢true p = transport bool-true≢false-type (! p) tt

  bool-has-dec-eq : has-dec-eq bool
  bool-has-dec-eq true true = inl refl
  bool-has-dec-eq true false = inr bool-true≢false
  bool-has-dec-eq false true = inr bool-false≢true
  bool-has-dec-eq false false = inl refl

  bool-is-set : is-set bool
  bool-is-set = dec-eq-is-set bool-has-dec-eq

  ⊥-is-prop : is-prop ⊥
  ⊥-is-prop ()


-- Andreas Abel, 2022-06-06, issue #5944 reported by Mike Shulman
-- Support rewriting with 2ltt (match SSet).

{-# OPTIONS --type-in-type --rewriting --two-level #-}

open import Agda.Primitive public

postulate
  Tel   : SSet
  ε     : Tel
  _≡_   : {A : SSet} (a : A) → A → SSet
  cong  : (A B : SSet) (f : A → B) {x y : A} (p : x ≡ y) → f x ≡ f y
  coe←  : (A B : SSet) → (A ≡ B) → B → A
  el    : Tel → SSet
  []    : el ε
  ID    : (Δ : Tel) → Tel
  ID′   : (Δ : Tel) (Θ : el Δ → Tel) → Tel
  ID′ε  : (Δ : Tel) → ID′ Δ (λ _ → ε) ≡ ε

{-# BUILTIN REWRITE _≡_ #-}
{-# REWRITE ID′ε #-}

postulate
  ID′-CONST   : (Θ : Tel) (Δ : Tel)

              → ID′ Θ (λ _ → Δ) ≡ ID Δ

  ID′-CONST-ε : (Θ : Tel) (δ₂ : el (ID ε))

              → coe← (el (ID′ Θ (λ _ → ε))) (el (ID ε)) (cong Tel (SSet lzero) el (ID′-CONST Θ ε)) δ₂ ≡ []

{-# REWRITE ID′-CONST-ε #-}

-- WAS: internal error when trying to make a pattern from SSet

-- Should succeed now


{-# 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.Definition

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

module Setoids.Orders.Total.Definition where

open import Setoids.Orders.Partial.Definition

record SetoidTotalOrder {a b c : _} {A : Set a} {S : Setoid {a} {b} A} {_<_ : Rel {a} {c} A} (P : SetoidPartialOrder S _<_) : Set (a ⊔ b ⊔ c) where
  open Setoid S
  field
    totality : (a b : A) → ((a < b) || (b < a)) || (a ∼ b)
  partial : SetoidPartialOrder S _<_
  partial = P
  min : A → A → A
  min a b with totality a b
  min a b | inl (inl a<b) = a
  min a b | inl (inr b<a) = b
  min a b | inr a=b = a
  max : A → A → A
  max a b with totality a b
  max a b | inl (inl a<b) = b
  max a b | inl (inr b<a) = a
  max a b | inr a=b = b

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


module Categories.Ran where

open import Level
open import Categories.Category
open import Categories.Functor hiding (_≡_)
open import Categories.NaturalTransformation

record Ran {o₀ ℓ₀ e₀} {o₁ ℓ₁ e₁} {o₂ ℓ₂ e₂}
           {A : Category o₀ ℓ₀ e₀} {B : Category o₁ ℓ₁ e₁} {C : Category o₂ ℓ₂ e₂}
           (F : Functor A B) (X : Functor A C) : Set (o₀ ⊔ ℓ₀ ⊔ e₀ ⊔ o₁ ⊔ ℓ₁ ⊔ e₁ ⊔ o₂ ⊔ ℓ₂ ⊔ e₂) where
  field
    R : Functor B C
    η : NaturalTransformation (R ∘ F) X

    δ : (M : Functor B C) → (α : NaturalTransformation (M ∘ F) X) → NaturalTransformation M R

    .δ-unique : {M : Functor B C} → {α : NaturalTransformation (M ∘ F) X} →
                (δ′ : NaturalTransformation M R) → α ≡ η ∘₁ (δ′ ∘ʳ F) → δ′ ≡ δ M α
    .commutes : (M : Functor B C) → (α : NaturalTransformation (M ∘ F) X) → α ≡ η ∘₁ (δ M α ∘ʳ F)


module AgdaCheatSheet where

open import Level using (Level)
open import Data.Nat
open import Data.Bool hiding (_<?_)
open import Data.List using (List; []; _∷_; length)

-- https://alhassy.github.io/AgdaCheatSheet/CheatSheet.pdf

{-
------------------------------------------------------------------------------
-- dependent function

A function whose RESULT type depends on the VALUE of the argument.
  -- given  value  of type A
  -- return result of type B a
  (a : A) → B a

E.g., generic identity
-- input
--  the type of X
--  value of type X
-- output a function X → X
-}
id0 : (X : Set) → X → X
id0 X x = x

id1 id2 id3 : (X : Set) → X → X
id1 X = λ x → x

id2 = λ X x → x
id3 = λ (X : Set) (x : X) → x

-- call it
sad : ℕ
sad = id0 ℕ 3

{-
------------------------------------------------------------------------------
-- implicits

In above, type arg can be inferred.
Use curly braces to mark arg as implicit.
-}

id : {X : Set} → X → X
id x = x

-- call it
nice : ℕ
nice = id 3

-- call with explicit implicit
explicit : ℕ
explicit = id {ℕ} 3

-- call with explicit inferred implicit
explicit’ : ℕ
explicit’ = id0 _ 3

{-
------------------------------------------------------------------------------
-- specifying arguments

{x : _} {y : _} (z : _) → · · ·        ≈ ∀ {x y} z → · · ·

(a1 : A) → (a2 : A) → (b : B) → · · ·  ≈ (a1 a2 : A) (b : B) → · · ·

------------------------------------------------------------------------------
-- dependent datatypes

-- data
-- name
-- arguments
-- type of the datatype
-- constructors and their types
-}

data Vec {ℓ : Level} (A : Set ℓ) : ℕ → Set ℓ where
  []   :                         Vec A  0
  _::_ : {n : ℕ} → A → Vec A n → Vec A (1 + n)

{-
For a given A, type of Vec A is N → Set.
Means Vec A is a FAMILY of types indexed by natural numbers:
- For each n, there is a TYPE Vec A n.

Vec is
- parametrised by A (and ℓ)
- indexed by n

A is type of elements
n is length

only way to Vec A 0 is via []
only way to Vec A (1 + n) is via _::_

enables safe head (since empty impossible)
-}

head : {A : Set} {n : ℕ} → Vec A (1 + n) → A
head (x :: xs) = x

{-
------------------------------------------------------------------------------
-- universes

ℓ arg says Vec is universe polymorphic
- can vectors of numbers and also vectors of types

Levels are essentially natural numbers:
- constructurs
  - lzero
  - lsuc
- _t_ : max of two levels

NO UNIVERSE OF ALL UNIVERSES:
- Set n has type Set n+1 for any n
- the type (n : Level) → Set n
  - is not itself typeable
  — i.e., is not in Set ℓ for any ℓ
  — Agda errors saying it is a value of Set ω

------------------------------------------------------------------------------
-- functions defined by pattern matching ALL cases

must terminate : so recursive calls must be made on structurally smaller arg
-}

infixr 40 _++_

_++_ : {A : Set} {n m : ℕ} → Vec A n → Vec A m → Vec A (n + m)
[]        ++ ys =             ys
(x :: xs) ++ ys = x :: (xs ++ ys)
{-
Append type encodes property : length of catenation is sum of args lengths

- Different types can have the same constructor names.
- Mixifx operators can be written prefix by having all underscores mentioned; e.g.,
- In def, if an arg is not needed, use _ (wildcard pattern)

------------------------------------------------------------------------------
-- Curry-Howard Correspondence — Propositions as Types

Logic                     Programming                 Example Use in Programming
================================================================================
proof / proposition       element / type              “p is a proof of P” ≈ “p is of type P”

true                      singleton type              return type of side-effect only methods
false                     empty type                  return type for non-terminating methods

⇒                         function type           →   methods with an input and output type
∧                         product type            ×   simple records of data and methods
∨                         sum type                +   enumerations or tagged unions

∀                         dependent function type Π   return type varies according to input value
∃                         dependent product  type Σ   record fields depend on each other’s values

natural deduction         type system                 ensuring only “meaningful” programs
hypothesis                free variable               global variables, closures

modus ponens              function application        executing methods on arguments
⇒ -introduction           λ-abstraction               parameters acting as local variables
                                                    to method definitions

induction;
elimination rules         Structural recursion        for-loops are precisely N-induction

Signature, term           Syntax; interface, record type, class
Algebra, Interpretation   Semantics; implementation, instance, object
Free Theory               Data structure
Inference rule            Algebraic datatype constructor
Monoid                    Untyped programming / composition
Category                  Typed programming / composition

------------------------------------------------------------------------------
-- equality

example of propositions-as-types : definition of identity relation (the least reflexive relation)
-}
data _≡_ {A : Set} : A → A → Set where
  refl : {x : A} → x ≡ x
  {-

states that refl {x}
- is a proof of l ≡ r
- whenever l and r simplify to x
  - by definition chasing only

Use it to prove Leibniz’s substitutivity rule, “equals for equals”:
-}
subst : {A : Set} {P : A → Set} {l r : A}
      → l ≡ r  -- must be of the form refl {x} for some canonical form x
      → P l    -- if l and r are both x, then P l and P r are the same type
      → P r    -- matching on proof l ≡ r gave infor about the rest of the program’s type
subst refl it = it

------------------------------------------------------------------------------
-- modules - namespace management

--------------------------------------------------
-- SIMPLE MODULES
module M where
  N : Set
  N = ℕ
  private
    x : ℕ
    x = 3
  y : N
  y = x + 1

-- using it - public names accessible by qualification or by opening them locally or globally
use0 : M.N
use0 = M.y

use1 : ℕ
use1 = y where open M
{- if open, then causes y in M' to duplicate
open M
use2 : ℕ
use2 = y
-}

--------------------------------------------------
-- PARAMETERISED MODULES : by arbitrarily many values and types (but not by other modules)
module M’ (x : ℕ) where
  y : ℕ
  y = x + 1

  -- names are functions
  --exposed : (x : ℕ) → ℕ
  --exposed = M’.y -- TODO compile error

-- using it
use’0 : ℕ
use’0 = M’.y 3

module M” = M’ 3
use” : ℕ
use” = M”.y

use’1 : ℕ
use’1 = y where open M’ 3

{-

“Using Them”:
- names in parameterised modules are are treated as functions
- can instantiate some parameters and name the resulting module
- can still open them as usual

--------------------------------------------------
-- ANONYMOUS MODULES
-- named-then-immediately-opened modules

module _ {A : Set} {a : A} · · ·
  ≈
module T {A : Set} {a : A} · · ·
open T

-- use-case : to  approximate the informal phrase
--   “for any A : Set and a : A, we have · · · ”

-- so common that variable keyword was introduced
--  Names in · · · are functions of only those variable-s they actually mention.

variable
  A : Set
  a : A

--------------------------------------------------
-- opening, using, hiding, renaming

open M hiding (n0; ...; nk)               : treat ni as private

open M using  (n0; ...; nk)               : treat only ni as public

open M renaming (n0 to m0; ...; nk to mk) : use names mi instead of ni

import X.Y.Z       : Use the definitions of module Z which lives in file ./X/Y/Z.agda.
open M public      : Treat the contents of M as if it is the public contents of the current module

Splitting a program over several files improves type checking performance,
since only need to type check files influenced by the change.

------------------------------------------------------------------------------
-- records : record ≈ module + data with one constructor
-}

record PointedSet : Set1 where
  constructor MkIt {- optional -}
  field
    Carrier : Set
    point   : Carrier

  {- like a module, so can add derived definitions -}
  blind : {A : Set} → A → Carrier
  blind = λ a → point

-- construct without named constructor
ex0 : PointedSet
ex0 = record {Carrier = ℕ; point = 3}

-- construct with named constructor
ex1 : PointedSet
ex1 = MkIt ℕ 3

open PointedSet
ex2 : PointedSet
Carrier ex2 = ℕ
point ex2 = 3

{-
Start with ex2 = ?, then in the hole enter C-c C-c RET to obtain the co-pattern setup.

Two tuples are the same when they have the same components.
Likewise a record is defined by its projections, whence co-patterns.
If you’re using many local definitions, you likely want to use co-patterns.

To enable projection of the fields from a record,
each record type comes with a module of the same name.
This module is parameterised by an element of the record type and
contains projection functions for the fields.
-}

useR0 : ℕ
useR0 = PointedSet.point ex0
{-
use¹ : ℕ
use¹ = point where open PointedSet ex0 -- TODO compile error
-}
open PointedSet
use² : ℕ
use² = blind ex0 true

-- pattern match on records

use³ : (P : PointedSet) → Carrier P
use³ record {Carrier = C; point = x} = x

use4 : (P : PointedSet) → Carrier P
use4 (MkIt C x) = x

{-
------------------------------------------------------------------------------
-- TODO Interacting with the real world —Compilation, Haskell, and IO

------------------------------------------------------------------------------
-- absurd patterns

When no constructor are matchable
- match the pattern ()
- provide no right hand side (since no way to could provide an arg to the function)

E.g., numbers smaller than a given natural number
-}

{- Fin n ∼= numbers i with i < n -}
data Fin : ℕ → Set where
  fzero : {n : ℕ} →         Fin (suc n) -- smaller than suc n for any n
  fsuc  : {n : ℕ} → Fin n → Fin (suc n) -- if i smaller than n then fsuc i is smaller than suc n.

{-
for each n, the type Fin n contains n elements
- Fin 2 has elements fsuc fzero and fzero
- Fin 0 has no elements

safe indexing function
-}
_!!_ : {A : Set} {n : ℕ} → Vec A n → Fin n → A
[]        !! ()               -- n is necessarily 0, but no way to make an element of type Fin 0
                              -- so use absurd pattern
(x :: xs) !! fzero  = x
(x :: xs) !! fsuc i = xs !! i

-- Logically “anything follows from false” becomes the following program:

data False : Set where

magic : {Anything-you-want : Set} → False → Anything-you-want
magic ()

{-
do
  magic x = ?
then case split on x
yields the program

------------------------------------------------------------------------------
-- isTrue pattern : passing around explicit proof objects
-- when not possible/easy to capture a desired precondition in types
-}

-- An empty record has only one value: record {} -}
record True : Set where

isTrue : Bool → Set
isTrue true  = True
isTrue false = False

_<0_ : ℕ → ℕ → Bool
_     <0  zero = false
zero  <0 suc y = true
suc x <0 suc y = x <0 y

find : {A : Set} (xs : List A) (i : ℕ) → isTrue (i <0 length xs) → A
find       []       i  ()
find (x ∷ xs)   zero  pf = x
find (x ∷ xs) (suc i) pf = find xs i pf

head’ : {A : Set} (xs : List A) → isTrue (0 <0 length xs) → A
head’       []  ()
head’ (x ∷ xs) _ = x

-- Unlike the _!!_ definition
-- rather than there being no index into the empty list
-- there is no proof that a natural number i is smaller than 0

{-
------------------------------------------------------------------------------
Mechanically Moving from Bool to Set —Avoiding “Boolean Blindness”

proposition represented as type whose elements denote proofs

Why use?
- awkward to request an index be “in bounds” in the find method,
- easier to encode this using Fin
- likewise, head’ is more elegant type when the non-empty precondition
  is part of the datatype definition, as in head.

recipe : from Boolean functions to inductive datatype families

1. Write the Boolean function.
2. Throw away all the cases with right side false.
3. Every case that has right side true corresponds to a new nullary constructor.
4. Every case that has n recursive calls corresponds to an n-ary constructor.

following these steps for _<0_:
-}

data _<1_ : ℕ → ℕ → Set where
  z< :   {y : ℕ} →          zero  <1     y
  s< : {x y : ℕ} → x <1 y → suc x <1 suc y

{-
then prove
- soundness    : constructed values correspond to Boolean-true statements
                 ensured by the second step in recipe
- completeness : true things correspond to terms formed from constructors.
-}

completeness : {x y : ℕ} → isTrue (x <0 y) → x <1 y
completeness     {x}  {zero} ()
completeness  {zero} {suc y} p = z<
completeness {suc x} {suc y} p = s< (completeness p)

{-
begin with
  completeness {x} {y} p = ?
then want case on p
but that requires evaluating x <0 y
which requires we know the shapes of x and y.

shape of proofs usually mimics the shape of definitions they use

------------------------------------------------------------------------------
record Payload (A : Set) : Set
  field
   pPayload  : [a]

record BlockType (A : Set) : Set
  = Proposal (Payload a) Author
  | NilBlock
  | Genesis

record LastVoteInfo
  fields
    lviLiDigest  :: HashValue
    lviRound     :: Round
    lviIsTimeout :: Bool
-}


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

module Data.Binary.Skew where

open import Prelude
open import Data.Nat
open import Data.List

𝔹 : Type
𝔹 = List ℕ

inc : 𝔹 → 𝔹
inc [] = zero ∷ []
inc (x ∷ []) = zero ∷ x ∷ []
inc (x₁ ∷ zero   ∷ xs) = suc x₁ ∷ xs
inc (x₁ ∷ suc x₂ ∷ xs) = zero ∷ x₁ ∷ x₂ ∷ xs

⟦_⇑⟧ : ℕ → 𝔹
⟦ zero ⇑⟧ = []
⟦ suc n ⇑⟧ = inc ⟦ n ⇑⟧

skew : ℕ → ℕ
skew n = suc (n + n)

w : ℕ → ℕ → ℕ
w zero    a = a
w (suc n) a = skew (w n a)

⟦_∷_⇓⟧^ : ℕ → (ℕ → ℕ) → ℕ → ℕ
⟦ x ∷ xs ⇓⟧^ a = let a′ = w x a in a′ + xs (skew a′)

⟦_⇓⟧ : 𝔹 → ℕ
⟦ [] ⇓⟧ = zero
⟦ x ∷ xs ⇓⟧ = let a = w x 1 in a + foldr ⟦_∷_⇓⟧^ (const zero) xs a

-- open import Path.Reasoning
-- import Data.Nat.Properties as ℕ

-- inc-suc : ∀ x → ⟦ inc x ⇓⟧ ≡ suc ⟦ x ⇓⟧
-- inc-suc [] = refl
-- inc-suc (x  ∷ []) = refl
-- inc-suc (x  ∷ zero   ∷ xs) = cong suc (ℕ.+-assoc (w x 1) (w x 1) _)
-- inc-suc (x₁ ∷ suc x₂ ∷ xs) = cong suc (cong (w x₁ 1 +_) {!!})

-- 𝔹-rightInv : ∀ x → ⟦ ⟦ x ⇑⟧ ⇓⟧ ≡ x
-- 𝔹-rightInv zero = refl
-- 𝔹-rightInv (suc x) = {!!}

-- 𝔹-leftInv : ∀ x → ⟦ ⟦ x ⇓⟧ ⇑⟧ ≡ x
-- 𝔹-leftInv [] = refl
-- 𝔹-leftInv (x ∷ xs) = {!!}

-- 𝔹⇔ℕ : 𝔹 ⇔ ℕ
-- 𝔹⇔ℕ .fun = ⟦_⇓⟧
-- 𝔹⇔ℕ .inv = ⟦_⇑⟧
-- 𝔹⇔ℕ .rightInv x = {!!}
-- 𝔹⇔ℕ .leftInv = {!!}


-- The natural numbers.

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

module Tools.Nat where

open import Tools.PropositionalEquality
open import Tools.Nullary

-- We reexport Agda's built-in type of natural numbers.

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

pattern 1+ n = suc n

infix 4 _≟_

-- Predecessor, cutting off at 0.

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

-- Decision of number equality.

_≟_ : (m n : Nat) → Dec (m ≡ n)
zero  ≟ zero   = yes refl
suc m ≟ suc n  with m ≟ n
suc m ≟ suc .m | yes refl = yes refl
suc m ≟ suc n  | no prf   = no (λ x → prf (subst (λ y → m ≡ pred y) x refl))
zero  ≟ suc n  = no λ()
suc m ≟ zero   = no λ()


------------------------------------------------------------------------
-- The Agda standard library
--
-- Polynomial reasoning
------------------------------------------------------------------------

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

open import Tactic.RingSolver.Core.AlmostCommutativeRing

-- Some specialised tools for equational reasoning.
module Tactic.RingSolver.Core.Polynomial.Reasoning
  {a ℓ} (ring : AlmostCommutativeRing a ℓ)
  where

open AlmostCommutativeRing ring
open import Relation.Binary.Reasoning.Setoid setoid public

infixr 1 ≪+_ +≫_ ≪*_ *≫_
infixr 0 _⊙_

≪+_ : ∀ {x₁ x₂ y} → x₁ ≈ x₂ → x₁ + y ≈ x₂ + y
≪+ prf = +-cong prf refl
{-# INLINE ≪+_ #-}

+≫_ : ∀ {x y₁ y₂} → y₁ ≈ y₂ → x + y₁ ≈ x + y₂
+≫_ = +-cong refl
{-# INLINE +≫_ #-}

≪*_ : ∀ {x₁ x₂ y} → x₁ ≈ x₂ → x₁ * y ≈ x₂ * y
≪* prf = *-cong prf refl
{-# INLINE ≪*_ #-}

*≫_ : ∀ {x y₁ y₂} → y₁ ≈ y₂ → x * y₁ ≈ x * y₂
*≫_ = *-cong refl
{-# INLINE *≫_ #-}

-- transitivity as an operator
_⊙_ : ∀ {x y z} → x ≈ y → y ≈ z → x ≈ z
_⊙_ = trans
{-# INLINE _⊙_ #-}


module LC.Subst.Var where

open import Data.Nat
open import Data.Nat.Properties
open import Relation.Nullary

--------------------------------------------------------------------------------
-- variable binding

data Binding : ℕ → ℕ → Set where
  Free  : ∀ {n x} → (n≤x : n ≤ x) → Binding n x
  Bound : ∀ {n x} → (n>x : n > x) → Binding n x

inspectBinding : ∀ n x → Binding n x
inspectBinding n x with n ≤? x
... | yes p = Free p
... | no ¬p = Bound (≰⇒> ¬p)

--------------------------------------------------------------------------------
-- lifiting variables

lift-var : (n i x : ℕ) → ℕ
lift-var n i x with inspectBinding n x
... | Free  _ = i + x      -- free
... | Bound _ =     x      -- bound

--------------------------------------------------------------------------------
-- properties of lift-var

open import Relation.Binary.PropositionalEquality hiding ([_])

module EQ where
    open ≡-Reasoning

    twist : ∀ l m n → l + (m + n) ≡ m + (l + n)
    twist l m n =
        begin
            l + (m + n)
        ≡⟨ sym (+-assoc l m n) ⟩
            l + m + n
        ≡⟨ cong (_+ n) (+-comm l m) ⟩
            m + l + n
        ≡⟨ +-assoc m l n ⟩
            m + (l + n)
        ∎

    l+m+n≡m+x : ∀ l m n x → l + n ≡ x → l + m + n ≡ m + x
    l+m+n≡m+x l m n x l+n≡x =
        begin
            l + m + n
        ≡⟨ +-assoc l m n ⟩
            l + (m + n)
        ≡⟨ twist l m n ⟩
            m + (l + n)
        ≡⟨ cong (m +_) l+n≡x ⟩
            m + x
        ∎

module INEQ where
    open ≤-Reasoning

    m+n≰x+m : ∀ {m n x} → n ≰ x → m + n > x + m
    m+n≰x+m {m} {n} {x} n≰x = begin
            suc x + m
        ≡⟨ +-comm (suc x) m ⟩
            m + suc x
        ≤⟨ +-monoʳ-≤ m (≰⇒> n≰x) ⟩
            m + n
        ∎

    m+n≤x+m : ∀ {m n x} → n ≤ x → m + n ≤ x + m
    m+n≤x+m {m} {n} {x} n≤x = begin
            m + n
        ≤⟨ +-monoʳ-≤ m n≤x ⟩
            m + x
        ≡⟨ +-comm m x ⟩
            x + m
        ∎
    l+n≤n+i+x : ∀ l n i x → l ≤ x → l + n ≤ n + i + x
    l+n≤n+i+x l n i x l≤x =
        begin
            l + n
        ≤⟨ +-monoˡ-≤ n l≤x ⟩
            x + n
        ≤⟨ m≤n+m (x + n) i ⟩
            i + (x + n)
        ≡⟨ cong (i +_) (+-comm x n) ⟩
            i + (n + x)
        ≡⟨ sym (+-assoc i n x) ⟩
            i + n + x
        ≡⟨ cong (_+ x) (+-comm i n) ⟩
            n + i + x
        ∎

    l+m+n≤m+x : ∀ l m n x → l + n ≤ x → l + m + n ≤ m + x
    l+m+n≤m+x l m n x l+n≤x =
        begin
            l + m + n
        ≡⟨ +-assoc l m n ⟩
            l + (m + n)
        ≡⟨ EQ.twist l m n ⟩
            m + (l + n)
        ≤⟨ +-monoʳ-≤ m l+n≤x ⟩
            m + x
        ∎

    l+m+n>m+x : ∀ l m n x → l + n > x → l + m + n > m + x
    l+m+n>m+x l m n x l+n>x =
        begin
            suc m + x
        ≡⟨ sym (+-suc m x) ⟩
            m + suc x
        ≤⟨ +-monoʳ-≤ m l+n>x ⟩
            m + (l + n)
        ≡⟨ EQ.twist m l n ⟩
            l + (m + n)
        ≡⟨ sym (+-assoc l m n) ⟩
            l + m + n
        ∎

    l+m+n>x : ∀ l m n x → l > x → l + m + n > x
    l+m+n>x l m n x l>x =
        begin
            suc x
        ≤⟨ l>x ⟩
            l
        ≤⟨ m≤m+n l m ⟩
            l + m
        ≤⟨ m≤m+n (l + m) n ⟩
            l + m + n
        ∎

open import Relation.Nullary.Negation using (contradiction)
open ≡-Reasoning

lift-var-≤ : ∀ {n i x} → n ≤ x → lift-var n i x ≡ i + x
lift-var-≤ {n} {i} {x} n≤x with inspectBinding n x
... | Free  ≤x = refl
... | Bound >x = contradiction n≤x (<⇒≱ >x)

lift-var-> : ∀ {n i x} → n > x → lift-var n i x ≡ x
lift-var-> {n} {i} {x} n>x with inspectBinding n x
... | Free  ≤x = contradiction n>x (≤⇒≯ ≤x)
... | Bound >x = refl

-- lift-var-+ : ∀ n i x m → lift-var (m + n) i (x + m) ≡ lift-var n i x + m
-- lift-var-+ n i x m with inspectBinding n x
-- ... | Bound >x  =
--         lift-var (m + n) i (x + m)
--     ≡⟨ lift-var-> (INEQ.m+n≰x+m (<⇒≱ >x)) ⟩
--         x + m
--     ∎
-- ... | Free  ≤x  =
--         lift-var (m + n) i (x + m)
--     ≡⟨ lift-var-≤ {m + n} {i} {x + m} (INEQ.m+n≤x+m ≤x)  ⟩
--         i + (x + m)
--     ≡⟨ sym (+-assoc i x m) ⟩
--         i + x + m
--     ∎

--             lift-var (l + n) i
--        ∙ --------------------------> ∙
--        |                             |
--        |                             |
--   lift-var l m                  lift-var l m
--        |                             |
--        ∨                             ∨
--        ∙ --------------------------> ∙
--            lift-var (l + m + n) i

lift-var-lift-var : ∀ l m n i x → lift-var l m (lift-var (l + n) i x) ≡ lift-var (l + m + n) i (lift-var l m x)
lift-var-lift-var l m n i x with inspectBinding l x | inspectBinding (l + n) x
... | Free l≤x | Free l+n≤x =
        lift-var l m (i + x)
    ≡⟨ lift-var-≤ (≤-trans l≤x (m≤n+m x i)) ⟩
        m + (i + x)
    ≡⟨ EQ.twist m i x ⟩
        i + (m + x)
    ≡⟨ sym (lift-var-≤ (INEQ.l+m+n≤m+x l m n x l+n≤x)) ⟩
        lift-var (l + m + n) i (m + x)
    ∎
... | Free l≤x | Bound l+n>x =
        lift-var l m x
    ≡⟨ lift-var-≤ l≤x ⟩
        m + x
    ≡⟨ sym (lift-var-> (INEQ.l+m+n>m+x l m n x l+n>x)) ⟩
        lift-var (l + m + n) i (m + x)
    ∎
... | Bound l>x | Free l+n≤x = contradiction (≤-trans (m≤m+n l n) l+n≤x) (<⇒≱ l>x)
... | Bound l>x | Bound l+n>x =
        lift-var l m x
    ≡⟨ lift-var-> l>x ⟩
        x
    ≡⟨ sym (lift-var-> (INEQ.l+m+n>x l m n x l>x)) ⟩
        lift-var (l + m + n) i x
    ∎

--             lift-var l (n + i)
--        ∙ --------------------------> ∙
--        |                             |
--        |                             |
--   lift-var l (n + m + i)      lift-var (l + n) m
--        |                             |
--        ∨                             ∨
--        ∙ --------------------------> ∙
--

lift-var-lemma : ∀ l m n i x → lift-var l (n + m + i) x ≡ lift-var (l + n) m (lift-var l (n + i) x)
lift-var-lemma l m n i x with inspectBinding l x
... | Free n≤x =
  begin
      n + m + i + x
  ≡⟨ cong (λ w → w + i + x) (+-comm n m) ⟩
      m + n + i + x
  ≡⟨ +-assoc (m + n) i x ⟩
      m + n + (i + x)
  ≡⟨ +-assoc m n (i + x) ⟩
    m + (n + (i + x))
  ≡⟨ cong (m +_) (sym (+-assoc n i x)) ⟩
      m + (n + i + x)
  ≡⟨ sym (lift-var-≤ {l + n} {m} {n + i + x} (INEQ.l+n≤n+i+x l n i x n≤x)) ⟩
      lift-var (l + n) m (n + i + x)
  ∎
... | Bound n>x =
  begin
      x
  ≡⟨ sym (lift-var-> {l + n} {m} {x} (≤-trans n>x (m≤m+n l n))) ⟩
      lift-var (l + n) m x
  ∎


-- Andreas, 2016-09-28
-- Level constraints X <= a and a <= X should solve X = a.

-- {-# OPTIONS -v tc.constr.add:40 #-}

open import Common.Level

module _ (a : Level) where
 mutual
  X : Level
  X = _

  data C : Set (lsuc X) where
    c : Set a → C  -- constrains X by a <= X

  data D : Set (lsuc a) where
    c : Set X → D  -- constrains X by X <= a

-- should succeed


module Types4Crib where

open import Basics public

_<=_ : Nat -> Nat -> Set
ze <= y = One
su x <= ze = Zero
su x <= su y = x <= y

cmp : (x y : Nat) -> (x <= y) + (y <= x)
cmp ze y = inl <>
cmp (su x) ze = inr <>
cmp (su x) (su y) = cmp x y

data Bnd : Set where
  bot : Bnd
  # : Nat -> Bnd
  top : Bnd

_<B=_ : Bnd -> Bnd -> Set
bot <B= _ = One
# x <B= # y = x <= y
_ <B= top = One
_ <B= _ = Zero

data T23 (l u : Bnd) : Nat -> Set where
  leaf : (lu : l <B= u) -> T23 l u ze
  node2 : forall {h} x
    (tlx : T23 l (# x) h)(txu : T23 (# x) u h) ->
    T23 l u (su h)
  node3 : forall {h} x y
    (tlx : T23 l (# x) h)(txy : T23 (# x) (# y) h)(tyu : T23 (# y) u h) ->
    T23 l u (su h)

data Intv (l u : Bnd) : Set where
  intv : (x : Nat)(lx : l <B= # x)(xu : # x <B= u) -> Intv l u

TooBig : Bnd -> Bnd -> Nat -> Set
TooBig l u h = Sg Nat \ x -> T23 l (# x) h * T23 (# x) u h

insert : forall {h l u} -> Intv l u -> T23 l u h ->
          TooBig l u h + T23 l u h
insert (intv x lx xu) (leaf lu) = inl (x , (leaf lx , leaf xu))
insert (intv x lx xu) (node2 y tly tyu) with cmp x y
insert (intv x lx xu) (node2 y tly tyu) | inl xy with insert (intv x lx xy) tly
insert (intv x lx xu) (node2 y tly tyu) | inl xy | inl (z , tlz , tzu)
  = inr (node3 z y tlz tzu tyu)
insert (intv x lx xu) (node2 y tly tyu) | inl xy | inr tly'
  = inr (node2 y tly' tyu)
insert (intv x lx xu) (node2 y tly tyu) | inr yx with insert (intv x yx xu) tyu
insert (intv x lx xu) (node2 y tly tyu) | inr yx | inl (v , tyv , tvu) = inr (node3 y v tly tyv tvu)
insert (intv x lx xu) (node2 y tly tyu) | inr yx | inr tyv' = inr (node2 y tly tyv')
insert (intv x lx xu) (node3 y z tly tyz tzu) with cmp x y
insert (intv x lx xu) (node3 y z tly tyz tzu) | inl xy with insert (intv x lx xy) tly
insert (intv x lx xu) (node3 y z tly tyz tzu) | inl xy | inl (v , tlv , tvy) = inl (y , node2 v tlv tvy , node2 z tyz tzu)
insert (intv x lx xu) (node3 y z tly tyz tzu) | inl xy | inr tly' = inr (node3 y z tly' tyz tzu)
insert (intv x lx xu) (node3 y z tly tyz tzu) | inr yx with cmp x z
insert (intv x lx xu) (node3 y z tly tyz tzu) | inr yx | inl xz with insert (intv x yx xz) tyz
insert (intv x lx xu) (node3 y z tly tyz tzu) | inr yx | inl xz | inl (v , tyv , tvz)
  = inl (v , node2 y tly tyv , node2 z tvz tzu)
insert (intv x lx xu) (node3 y z tly tyz tzu) | inr yx | inl xz | inr tyz'
  = inr (node3 y z tly tyz' tzu)
insert (intv x lx xu) (node3 y z tly tyz tzu) | inr yx | inr zx with insert (intv x zx xu) tzu
insert (intv x lx xu) (node3 y z tly tyz tzu) | inr yx | inr zx | inl (v , tzv , tvu) = inl (z , node2 y tly tyz , node2 v tzv tvu)
insert (intv x lx xu) (node3 y z tly tyz tzu) | inr yx | inr zx | inr tzu' = inr (node3 y z tly tyz tzu')


{-# OPTIONS --without-K --safe #-}
open import Axiom.Extensionality.Propositional using (Extensionality)

module Cats.Category.Sets.Facts.Exponential
  (funext : ∀ {a b} → Extensionality a b)
  where

open import Data.Product using (_×_ ; _,_ ; proj₁ ; proj₂)
open import Relation.Binary.PropositionalEquality using (_≡_ ; refl ; sym)

open import Cats.Category
open import Cats.Category.Sets using (Sets)
open import Cats.Category.Sets.Facts.Product using (hasBinaryProducts)

instance
  hasExponentials : ∀ {l} → HasExponentials (Sets l)
  hasExponentials .HasExponentials.hasBinaryProducts = hasBinaryProducts
  hasExponentials .HasExponentials._↝′_ B C = record
    { Cᴮ = B → C
    ; eval = λ { (f , x) → f x }
    ; curry′ = λ f → record
      { arr = λ a b → f (a , b)
      ; prop = λ x → refl
      ; unique = λ eq a → funext λ b → sym (eq _)
      }
    }


module Computability.Enumeration.Diagonal where

open import Computability.Prelude
open import Computability.Function
open import Computability.Data.Fin.Opposite
open import Computability.Data.Nat.Iteration
open import Computability.Enumeration.Base
open import Data.Nat using (_∸_; pred; ⌊_/2⌋; _≤_; _<_; s≤s; z≤n)
open import Data.Nat.Properties using (+-suc; +-assoc; +-comm; +-identityʳ)
open import Data.Nat.Properties using (*-suc; *-assoc; *-comm; *-zeroʳ)
open import Data.Nat.Properties using (≤-step)
open import Data.Fin using (Fin; zero; suc; inject₁; fromℕ; fromℕ<; toℕ; opposite)
open import Data.Fin.Properties using (toℕ<n; toℕ-fromℕ; toℕ-inject₁; fromℕ<-toℕ)
open import Relation.Binary.PropositionalEquality using (_≢_; cong; sym)
open Relation.Binary.PropositionalEquality.≡-Reasoning

Diagonal : Set
Diagonal = Σ[ k ∈ ℕ ] Fin (suc k)

step-Diag : Diagonal → Diagonal
step-Diag (k , zero) = suc k , fromℕ (suc k)
step-Diag (k , suc i) = k , inject₁ i

triangle : ℕ → ℕ
triangle k = ⌊ suc k * k /2⌋

enum-Diag : ℕ → Diagonal
enum-Diag n = iterate step-Diag n (zero , zero)

code-Diag : Diagonal → ℕ
code-Diag (k , i) = toℕ (opposite i) + triangle k

module TriangleProperties where
  elim-⌊/2⌋ : ∀ k i → ⌊ i * 2 + k /2⌋ ≡ i + ⌊ k /2⌋
  elim-⌊/2⌋ k zero = refl
  elim-⌊/2⌋ k (suc i) rewrite elim-⌊/2⌋ k i = refl

  rewrite-triangle : (k : ℕ) → suc (k + suc (k + k * suc k)) ≡ suc k * 2 + (k + k * k)
  rewrite-triangle k
    rewrite *-comm k (suc k)
          | +-suc k (k + (k + k * k))
          | *-comm k 2
          | +-identityʳ k
          | +-assoc k k (k + k * k) = refl

  triangle-relation : ∀ k → triangle (suc k) ≡ suc k + triangle k
  triangle-relation k =
    begin
      ⌊ suc (suc k) * suc k /2⌋
    ≡⟨ cong ⌊_/2⌋ (rewrite-triangle k) ⟩
      ⌊ suc k * 2 + suc k * k /2⌋
    ≡⟨ elim-⌊/2⌋ (suc k * k) (suc k) ⟩
      suc k + ⌊ suc k * k /2⌋
    ∎

open TriangleProperties

step-Diag-suc : ∀ d → code-Diag (step-Diag d) ≡ suc (code-Diag d)
step-Diag-suc (k , zero)
  rewrite opposite-fromℕ k
        | toℕ-fromℕ k
        | triangle-relation k = refl
step-Diag-suc (k , suc i)
  rewrite opposite-inject₁-suc i
        | toℕ-inject₁ (opposite i) = refl

code-Diag-LInv : ∀ n → code-Diag (enum-Diag n) ≡ n
code-Diag-LInv zero = refl
code-Diag-LInv (suc n) =
  begin
    code-Diag (step-Diag (enum-Diag n))
  ≡⟨ step-Diag-suc (enum-Diag n) ⟩
    suc (code-Diag (enum-Diag n))
  ≡⟨ cong suc (code-Diag-LInv n) ⟩
    suc n
  ∎

enum-Diag-Fin-Order : ∀ k i → (lt : i < suc k) → iterate step-Diag i (k , fromℕ k) ≡ (k , opposite (fromℕ< lt))
enum-Diag-Fin-Order k zero lt = refl
enum-Diag-Fin-Order k (suc i) (s≤s lt)
  rewrite enum-Diag-Fin-Order k i (≤-step lt)
        | opposite-fromℕ< i k lt = refl

enum-Diag-Fin : ∀ k (i : Fin (suc k)) → iterate step-Diag (toℕ i) (k , fromℕ k) ≡ (k , opposite i)
enum-Diag-Fin k i =
  begin
    iterate step-Diag (toℕ i) (k , fromℕ k)
  ≡⟨ enum-Diag-Fin-Order k (toℕ i) (toℕ<n i)⟩
    (k , opposite (fromℕ< (toℕ<n i)))
  ≡⟨ cong (λ e → k , opposite e) (fromℕ<-toℕ i (toℕ<n i)) ⟩
    (k , opposite i)
  ∎

enum-Diag-triangle : ∀ k → enum-Diag (triangle k) ≡ (k , fromℕ k)
enum-Diag-triangle zero = refl
enum-Diag-triangle (suc k) =
  begin
    enum-Diag (triangle (suc k))
  ≡⟨ cong enum-Diag (triangle-relation k) ⟩
    enum-Diag (suc k + triangle k)
  ≡⟨ split-iterate step-Diag (zero , zero) (suc k) (triangle k) ⟩
    iterate step-Diag (suc k) (enum-Diag (triangle k))
  ≡⟨ cong (iterate step-Diag (suc k)) (enum-Diag-triangle k) ⟩
    iterate step-Diag (suc k) (k , fromℕ k)
  ≡⟨ sym (cong (λ e → iterate step-Diag (suc e) (k , fromℕ k)) (toℕ-fromℕ k)) ⟩
    iterate step-Diag (suc (toℕ (fromℕ k))) (k , fromℕ k)
  ≡⟨ cong step-Diag (enum-Diag-Fin k (fromℕ k)) ⟩
    step-Diag (k , opposite (fromℕ k))
  ≡⟨ cong (λ e → step-Diag (k , e)) (opposite-fromℕ k) ⟩
    step-Diag (k , zero)
  ∎

code-Diag-RInv : ∀ d → enum-Diag (code-Diag d) ≡ d
code-Diag-RInv (k , i) =
  begin
    enum-Diag (toℕ (opposite i) + triangle k)
  ≡⟨ split-iterate step-Diag (zero , zero) (toℕ (opposite i)) (triangle k) ⟩
    iterate step-Diag (toℕ (opposite i)) (enum-Diag (triangle k))
  ≡⟨ cong (iterate step-Diag (toℕ (opposite i))) (enum-Diag-triangle k) ⟩
    iterate step-Diag (toℕ (opposite i)) (k , fromℕ k)
  ≡⟨ enum-Diag-Fin k (opposite i) ⟩
    k , opposite (opposite i)
  ≡⟨ cong (λ e → k , e) (opposite-opposite i) ⟩
    k , i
  ∎

open Enumerable

Diag-Enumerable : Enumerable Diagonal
enum Diag-Enumerable = enum-Diag
proj₁ (bijective Diag-Enumerable) {x = n₀} {y = n₁} eq =
  begin
    n₀
  ≡⟨ sym (code-Diag-LInv n₀) ⟩
    code-Diag (enum-Diag n₀)
  ≡⟨ cong code-Diag eq ⟩
    code-Diag (enum-Diag n₁)
  ≡⟨ code-Diag-LInv n₁ ⟩
    n₁
  ∎
proj₁ (proj₂ (bijective Diag-Enumerable) d) = code-Diag d
proj₂ (proj₂ (bijective Diag-Enumerable) d) = code-Diag-RInv d


postulate Ty : Set

data Cxt : Set where
  ε : Cxt
  sg : (A : Ty) → Cxt
  _∙_ : (Γ₁ Γ₂ : Cxt) → Cxt

variable Γ Γ₁ Γ₂ Δ : Cxt

postulate Ren : (Δ Γ : Cxt) → Set

<_,_> : (f₁ : Ren Δ Γ₁) (f₂ : Ren Δ Γ₂) → Ren Δ (Γ₁ ∙ Γ₂)
<_,_> = {!!}

<_,_>₁ : (f₁ : Ren Δ Γ₁) (f₂ : Ren Δ Γ₂) → Cxt → Ren Δ (Γ₁ ∙ Γ₂)
< f₁ , f₂ >₁ x = {!!}


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

open import Agda.Primitive
open import Prelude
import GSeTT.Typed-Syntax
import Globular-TT.Syntax

{- Type theory for globular sets -}
module Globular-TT.Typed-Syntax {l}
  (index : Set l) (rule : index → GSeTT.Typed-Syntax.Ctx × (Globular-TT.Syntax.Pre-Ty index)) (eqdec-index : eqdec index)  where

  open import Globular-TT.Syntax index
  open import Globular-TT.Rules index rule
  open import Globular-TT.Eqdec-syntax index eqdec-index
  open import Globular-TT.Uniqueness-Derivations index rule eqdec-index

  Ctx : Set (lsuc l)
  Ctx = Σ Pre-Ctx (λ Γ → Γ ⊢C)

  Ty : Ctx → Set (lsuc l)
  Ty (Γ , _) = Σ Pre-Ty (λ A → Γ ⊢T A)

  Tm : ∀ (Γ : Ctx) → Ty Γ → Set (lsuc l)
  Tm (Γ , _) (A , _) = Σ Pre-Tm (λ t → Γ ⊢t t # A)

  Sub : ∀ (Δ : Ctx) (Γ : Ctx) → Set (lsuc l)
  Sub (Δ , _) (Γ , _) = Σ Pre-Sub (λ γ → Δ ⊢S γ > Γ)

  eqC : ∀ (Γ Δ : Ctx) → fst Γ == fst Δ → Γ == Δ
  eqC (Γ , Γ⊢) (.Γ , Γ⊢') idp = Σ= idp (has-all-paths-⊢C _ _)

  eqT : ∀ {Γ} (A B : Ty Γ) → fst A == fst B → A == B
  eqT (A , Γ⊢A) (.A , Γ⊢'A) idp = Σ= idp (has-all-paths-⊢T _ _)

  eqt : ∀ {Γ A} (t u : Tm Γ A) → fst t == fst u → t == u
  eqt (t , Γ⊢t:A) (.t , Γ⊢':A) idp = Σ= idp (has-all-paths-⊢t _ _)

  eqS : ∀ {Γ Δ} (γ δ : Sub Γ Δ) → fst γ == fst δ → γ == δ
  eqS (γ , Γ⊢γ:Δ) (.γ , Γ⊢'γ:Δ) idp = Σ= idp (has-all-paths-⊢S _ _)

  trS : ∀ {Γ Δ Θ : Ctx} → (p : Δ == Θ) → {γ : Sub Γ Δ} → {δ : Sub Γ Θ} → fst γ == fst δ → transport p γ == δ
  trS {Γ} {Δ} {Θ} idp {γ} {δ} x = eqS {Γ} {Θ} γ δ x

  private
    eqdec-typedTy : ∀ Γ → eqdec (Ty Γ)
    eqdec-typedTy Γ (A , Γ⊢A) (B , Γ⊢B) with eqdec-Ty A B
    ... | inl idp = inl (eqT {Γ} (A , Γ⊢A) (B , Γ⊢B) idp)
    ... | inr A≠B = inr λ p → A≠B (fst-is-inj p)

  is-set-Ty : ∀ Γ → is-set (Ty Γ)
  is-set-Ty Γ = eqdec-is-set (eqdec-typedTy Γ)