{-# OPTIONS --safe --experimental-lossy-unification #-}
module Cubical.Algebra.GradedRing.Instances.PolynomialsFun where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Empty as ⊥
open import Cubical.Data.Nat hiding (_·_) renaming (_+_ to _+n_)
open import Cubical.Data.Nat.Order
open import Cubical.Data.Sigma

open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Ring
open import Cubical.Algebra.GradedRing.Base
open import Cubical.Algebra.GradedRing.DirectSumFun

private variable
  ℓ : Level

module _
  (ARing@(A , Astr) : Ring ℓ)
  (n : ℕ)
  where

  open RingStr Astr
  open RingTheory ARing

  PolyGradedRing : GradedRing ℓ-zero ℓ
  PolyGradedRing = ⊕Fun-GradedRing
                   _+n_ (makeIsMonoid isSetℕ +-assoc +-zero λ _ → refl) (λ _ _ → refl)
                   (λ _ → A)
                   (λ _ → snd (Ring→AbGroup ARing))
                   1r _·_ 0LeftAnnihilates 0RightAnnihilates
                   (λ a b c → ΣPathP ((+-assoc _ _ _) , (·Assoc _ _ _)))
                   (λ a → ΣPathP ((+-zero _) , (·IdR _)))
                   (λ a → ΣPathP (refl , (·IdL _)))
                   ·DistR+
                   ·DistL+


module lambda.vec where

open import Data.Nat
open import Data.Fin hiding (_+_)

infixr 40 _▸_

data vec (T : Set) : ℕ → Set where
  ε : vec T 0
  _▸_ : ∀ {n} → vec T n → T → vec T (suc n)

lookup : ∀ {n} → {T : Set} → Fin n → vec T n → T
lookup zero (Γ ▸ x) = x
lookup (suc i) (Γ ▸ x) = lookup i Γ


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

open import Algebra
open import Prelude
open import HITs.PropositionalTruncation
open import HITs.PropositionalTruncation.Sugar

module Algebra.Construct.Cayley {a} (mon : Monoid a) where

open Monoid mon

𝒞 : Type a
𝒞 = Σ[ f ⦂ (𝑆 → 𝑆) ] × ∀ x → ∥ f ε ∙ x ≡ f x ∥

⟦_⇓⟧ : 𝒞 → 𝑆
⟦ x ⇓⟧ = x .fst ε

⟦_⇑⟧ : 𝑆 → 𝒞
⟦ x ⇑⟧ .fst y = x ∙ y
⟦ x ⇑⟧ .snd y = ∣ cong (_∙ y) (∙ε x) ∣

ⓔ : 𝒞
ⓔ .fst x = x
ⓔ .snd x = ∣ ε∙ x ∣

open import Relation.Binary
open import HITs.PropositionalTruncation.Equivalence
open import Relation.Binary.Equivalence.Reasoning (trunc-equivalence (≡-equivalence {A = 𝑆}))

_⊙_ : 𝒞 → 𝒞 → 𝒞
(x ⊙ y) .fst z = x .fst (y .fst z)
(x ⊙ y) .snd z =
  x .fst (y .fst ε) ∙ z     ≋˘⟨ cong (_∙ z) ∥$∥ (x .snd (y .fst ε)) ⟩
  x .fst ε ∙ y .fst ε ∙ z   ≡⟨ assoc (x .fst ε) (y .fst ε) z ⟩
  x .fst ε ∙ (y .fst ε ∙ z) ≋⟨ cong (x .fst ε ∙_) ∥$∥ (y .snd z)  ⟩
  x .fst ε ∙ y .fst z       ≋⟨ x .snd (y .fst z) ⟩
  x .fst (y .fst z) ∎

⊙-assoc : Associative _⊙_
⊙-assoc x y z i .fst k = x .fst (y .fst (z .fst k))
⊙-assoc x y z i .snd k = squash (((x ⊙ y) ⊙ z) .snd k) ((x ⊙ (y ⊙ z)) .snd k) i

ⓔ⊙ : ∀ x → ⓔ ⊙ x ≡ x
ⓔ⊙ x i .fst y = x .fst y
ⓔ⊙ x i .snd y = squash ((ⓔ ⊙ x) .snd y) (x .snd y) i

⊙ⓔ : ∀ x → x ⊙ ⓔ ≡ x
⊙ⓔ x i .fst y = x .fst y
⊙ⓔ x i .snd y = squash ((x ⊙ ⓔ) .snd y) (x .snd y) i

cayleyMonoid : Monoid a
Monoid.𝑆 cayleyMonoid = 𝒞
Monoid._∙_ cayleyMonoid = _⊙_
Monoid.ε cayleyMonoid = ⓔ
Monoid.assoc cayleyMonoid = ⊙-assoc
Monoid.ε∙ cayleyMonoid = ⓔ⊙
Monoid.∙ε cayleyMonoid = ⊙ⓔ

open import Data.Sigma.Properties

module _ (sIsSet : isSet 𝑆) where
  𝒞-leftInv-fst : ∀ x y → ⟦ ⟦ x ⇓⟧ ⇑⟧ .fst y ≡ x .fst y
  𝒞-leftInv-fst x y = rec (sIsSet (x .fst ε ∙ y) (x .fst y)) id (x .snd y)

  𝒞-leftInv : ∀ x → ⟦ ⟦ x ⇓⟧ ⇑⟧ ≡ x
  𝒞-leftInv x = Σ≡Prop (λ f xs ys → funExt λ x → squash (xs x) (ys x)) (funExt (𝒞-leftInv-fst x))

  𝒞-iso : 𝒞 ⇔ 𝑆
  fun 𝒞-iso = ⟦_⇓⟧
  inv 𝒞-iso = ⟦_⇑⟧
  rightInv 𝒞-iso = ∙ε
  leftInv 𝒞-iso = 𝒞-leftInv


-- Path induction

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

module Experiment.PropositionalEq where

open import Level renaming (zero to lzero; suc to lsuc)
open import Relation.Binary.PropositionalEquality
import Relation.Binary.Reasoning.Setoid as SetoidReasoning
open import Relation.Binary

private
  variable
    a c : Level
    A : Set a

-- HoTT 1.12.1
-- Path induction
PathInd : (C : (x y : A) → x ≡ y → Set c) →
          (∀ x → C x x refl) → ∀ x y (p : x ≡ y) → C x y p
PathInd C c x .x refl = c x

PathInd-refl : ∀ (C : (x y : A) → x ≡ y → Set c) (c : ∀ x → C x x refl) x →
               PathInd C c x x refl ≡ c x
PathInd-refl C c x = refl

-- Based path induction
BasedPathInd : (a : A) (C : ∀ x → a ≡ x → Set c) → C a refl →
               ∀ x (p : a ≡ x) → C x p
BasedPathInd a C c .a refl = c

BasedPathInd-refl : ∀ (a : A) (C : ∀ x → a ≡ x → Set c) (c : C a refl) →
                    BasedPathInd a C c a refl ≡ c
BasedPathInd-refl _ _ _ = refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Indexed containers core
------------------------------------------------------------------------

module Data.Container.Indexed.Core where

open import Level
open import Data.Product
open import Relation.Unary

infix 5 _◃_/_

record Container {i o} (I : Set i) (O : Set o) (c r : Level) :
                 Set (i ⊔ o ⊔ suc c ⊔ suc r) where
  constructor _◃_/_
  field
    Command  : (o : O) → Set c
    Response : ∀ {o} → Command o → Set r
    next     : ∀ {o} (c : Command o) → Response c → I

-- The semantics ("extension") of an indexed container.

⟦_⟧ : ∀ {i o c r ℓ} {I : Set i} {O : Set o} → Container I O c r →
      Pred I ℓ → Pred O _
⟦ C ◃ R / n ⟧ X o = Σ[ c ∈ C o ] ((r : R c) → X (n c r))

------------------------------------------------------------------------
-- All and any

module _ {i o c r ℓ} {I : Set i} {O : Set o}
         (C : Container I O c r) {X : Pred I ℓ} where

  -- All.

  □ : ∀ {ℓ′} → Pred (Σ I X) ℓ′ → Pred (Σ O (⟦ C ⟧ X)) _
  □ P (_ , _ , k) = ∀ r → P (_ , k r)

  -- Any.

  ◇ : ∀ {ℓ′} → Pred (Σ I X) ℓ′ → Pred (Σ O (⟦ C ⟧ X)) _
  ◇ P (_ , _ , k) = ∃ λ r → P (_ , k r)


{-# OPTIONS --guardedness #-}
module induction-ex where

open import Relation.Binary.PropositionalEquality
open import Size
open import Data.Bool

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

data Nat : Set where
     zero : Nat
     suc  : Nat → Nat

add : Nat → Nat → Nat
add zero x = x
add (suc x) y = suc ( add x y )

_++_ : {A : Set} → List A → List A → List A
[] ++ y = y
(x ∷ t) ++ y = x ∷ ( t ++ y )

test1 = (zero ∷ []) ++ (zero ∷ [])

length : {A : Set } → List A → Nat
length [] = zero
length (_ ∷ t)  = suc ( length t )

lemma1 : {A : Set} → (x y : List A ) → length ( x ++ y ) ≡ add (length x) (length y)
lemma1 [] y = refl
lemma1 (x ∷ t) y = cong ( λ k → suc k ) lemma2  where
   lemma2 : length (t ++ y) ≡ add (length t) (length y)
   lemma2 = lemma1 t y

-- record List1 ( A : Set  ) : Set where
--    inductive
--    field
--       nil : List1 A
--       cons : A → List1 A → List1 A
--
-- record List2 ( A : Set  ) : Set where
--    coinductive
--    field
--       nil : List2 A
--       cons : A → List2 A → List2 A

data SList (i : Size) (A : Set) : Set where
  []' : SList i A
  _∷'_ : {j : Size< i} (x : A) (xs : SList j A) → SList i A

map : ∀{i A B} → (A → B) → SList i A → SList i B
map f []' = []'
map f ( x ∷' xs)= f x ∷' map f xs

foldr : ∀{i} {A B : Set} → (A → B → B) → B → SList i A → B
foldr c n []' = n
foldr c n (x ∷' xs) = c x (foldr c n xs)

any : ∀{i A} → (A → Bool) → SList i A → Bool
any p xs = foldr _∨_ false (map p xs)

-- Sappend : {A : Set } {i j : Size } → SList i A → SList j A → SList {!!} A
-- Sappend []' y = y
-- Sappend (x ∷' x₁) y =  _∷'_  {?}  x (Sappend x₁ y)

language : { Σ : Set } → Set
language {Σ} = List Σ → Bool

record Lang (i : Size) (A : Set) : Set where
  coinductive
  field
    ν : Bool
    δ : ∀{j : Size< i} → A → Lang j A

open Lang

∅ : ∀ {i A}  → Lang i A
ν ∅   = false
δ ∅ _ = ∅

∅' :  {i : Size } { A : Set }  → Lang i A
∅' {i} {A}  = record { ν = false ; δ = lemma3 } where
    lemma3 : {j : Size< i} → A → Lang j A
    lemma3 {j} _ = {!!}

∅l : {A : Set } → language {A}
∅l _ = false

ε : ∀ {i A} → Lang i A
ν ε   = true
δ ε _ = ∅

εl : {A : Set } → language {A}
εl [] = true
εl (_ ∷ _)  = false

_+_ : ∀ {i A} → Lang i A → Lang i A → Lang i A
ν (a + b)   = ν a   ∨  ν b
δ (a + b) x = δ a x + δ b x

Union : {Σ : Set} → ( A B : language {Σ} ) → language {Σ}
Union {Σ} A B x = (A x ) ∨ (B x)

_·_ : ∀ {i A} → Lang i A → Lang i A → Lang i A
ν (a · b)   = ν a ∧ ν b
δ (a · b) x = if (ν a) then ((δ a x · b ) + (δ b x )) else ( δ a x · b )

split : {Σ : Set} → (List Σ → Bool)
      → ( List Σ → Bool) → List Σ → Bool
split x y  [] = x [] ∨ y []
split x y (h  ∷ t) = (x [] ∧ y (h  ∷ t)) ∨
  split (λ t1 → x (  h ∷ t1 ))  (λ t2 → y t2 ) t

Concat : {Σ : Set} → ( A B : language {Σ} ) → language {Σ}
Concat {Σ} A B = split A B


------------------------------------------------------------------------
-- The Agda standard library
--
-- Vector equality over propositional equality
------------------------------------------------------------------------

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

open import Relation.Binary

module Data.Vec.Relation.Binary.Equality.Propositional {a} {A : Set a} where

open import Data.Nat.Base using (ℕ; zero; suc; _+_)
open import Data.Vec
open import Data.Vec.Relation.Binary.Pointwise.Inductive
  using (Pointwise-≡⇒≡; ≡⇒Pointwise-≡)
import Data.Vec.Relation.Binary.Equality.Setoid as SEq
open import Relation.Binary.PropositionalEquality

------------------------------------------------------------------------
-- Publically re-export everything from setoid equality

open SEq (setoid A) public

------------------------------------------------------------------------
-- ≋ is propositional

≋⇒≡ : ∀ {n} {xs ys : Vec A n} → xs ≋ ys → xs ≡ ys
≋⇒≡ = Pointwise-≡⇒≡

≡⇒≋ : ∀ {n} {xs ys : Vec A n} → xs ≡ ys → xs ≋ ys
≡⇒≋ = ≡⇒Pointwise-≡

-- See also Data.Vec.Relation.Binary.Equality.Propositional.WithK.≋⇒≅.


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

module Dodo.Binary.Acyclic where

-- Stdlib imports
open import Level using (Level; _⊔_)
open import Function using (flip)
open import Data.Product using (_×_; _,_; proj₁; proj₂)
open import Relation.Binary using (Rel; REL)
open import Relation.Binary using (Irreflexive; Transitive; Symmetric)
open import Relation.Binary.Construct.Closure.Transitive using (TransClosure; [_]; _∷_; _++_)
-- Local imports
open import Dodo.Binary.Equality
open import Dodo.Binary.Transitive

-- # Definitions

-- | Acyclicity of a binary relation R: x R⁺ y → x ≠ y
--
-- Defined with an underlying equality (≈)
Acyclic : {a ℓ₁ ℓ₂ : Level} → {A : Set a} → Rel A ℓ₁ → Rel A ℓ₂ → Set _
Acyclic _≈_ _<_ = Irreflexive _≈_ (TransClosure _<_)

-- # Operations

module _ {a ℓ₁ ℓ₂ : Level} {A : Set a}
    {_≈_ : Rel A ℓ₁} {R : Rel A ℓ₂} where

  -- | Any acyclic relation is also irreflexive
  Acyclic⇒Irreflexive : Acyclic _≈_ R → Irreflexive _≈_ R
  Acyclic⇒Irreflexive acyclicR x≈y Rxy = acyclicR x≈y [ Rxy ]

module _ {a ℓ₁ ℓ₂ ℓ₃ : Level} {A : Set a}
    {_≈_ : Rel A ℓ₁} {P : Rel A ℓ₂} {Q : Rel A ℓ₃} where

  -- | If a relation is acyclic, then any subset of that relation is also acyclic
  acyclic-⊆₂ : Acyclic _≈_ Q → P ⊆₂ Q → Acyclic _≈_ P
  acyclic-⊆₂ acyclicQ P⊆Q x≈y P⁺ = acyclicQ x≈y (⊆₂-apply (⁺-preserves-⊆₂ P⊆Q) P⁺)

module _ {a ℓ₁ ℓ₂ ℓ₃ : Level} {A : Set a}
    {_≈_ : Rel A ℓ₁} {R : Rel A ℓ₂} where

  -- | If a relation is acyclic, then its transitive closure is also acyclic
  ⁺-preserves-acyclic : Acyclic _≈_ R → Acyclic _≈_ (TransClosure R)
  ⁺-preserves-acyclic acR x≈y R⁺⁺xy = acR x≈y (⇔₂-apply-⊇₂ ⁺-idem R⁺⁺xy)


module Automata.Nondeterministic where

-- Standard libraries imports ----------------------------------------
open import Level using ()
  renaming (zero to ℓ₀)

open import Data.Nat using (ℕ)
open import Data.Product using (_×_)
open import Data.Vec using (Vec ; [] ; _∷_)

open import Relation.Unary using (Pred)
open import Relation.Binary.PropositionalEquality using (_≡_)
----------------------------------------------------------------------

-- Thesis imports ----------------------------------------------------
open import Utilities.ExistsSyntax using (∃-syntax)
----------------------------------------------------------------------

record NDA (Σ : Set) : Set₁ where
  constructor ⟨_,_,_,_⟩

  field
    Q : Set
    S : Pred Q ℓ₀
    F : Pred Q ℓ₀
    Δ : Q → Σ → Pred Q ℓ₀

  Δ* : Q → {n : ℕ} → Vec Σ n → Pred Q ℓ₀
  Δ* q [] = q ≡_
  Δ* q (x ∷ xs) q′ = ∃ q₀ ∶ Q • ((Δ q x q₀) × (Δ* q₀ xs q′))

  Accepts : {n : ℕ} → Pred (Vec Σ n) ℓ₀
  Accepts xs = ∃ q ∶ Q • (S q
                       × ∃ q′ ∶ Q • ((F q′)
                                  × (Δ* q xs q′)))

  -- :TODO: are these useful?
  _-Reachable : ℕ → Q → Pred Q ℓ₀
  _-Reachable n q q′ = ∃ xs ∶ Vec Σ n • (Δ* q xs q′)

  Reachable : Q → Pred Q ℓ₀
  Reachable q q′ = ∃ n ∶ ℕ • (n -Reachable) q q′


module Eq.KleeneTheory where

open import Prelude
open import T
open import Eq.Defs
open import Eq.LogicalTheory
open import Eq.KleeneTheoryEarly public

-- Harper says that Kleene equality is "evidently reflexive",
-- but this requires/implies termination!
-- We pick it directly from the consistency and reflexivity of
-- logical equivalence.
-- We could also prove it using halting, which we could prove from
-- either our HT result or from reflexivity of logical equivalence.
-- This is a bit simpler.
kleene-refl : Reflexive KleeneEq
kleene-refl {e} = ological-consistent (ological-refl e)

-- For kicks, we'll prove halting for closed nats.
nats-halt : (n : TNat) → THalts n
nats-halt n with kleene-refl {n}
... | kleeneq _ val E1 _ = halts E1 val

kleene-is-equivalence : IsEquivalence KleeneEq
kleene-is-equivalence = record { refl_ = kleene-refl
                               ; sym_ = kleene-sym
                               ; trans_ = kleene-trans }


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

-- Some properties of Restriction Categories

-- The first few lemmas are from Cocket & Lack, Lemma 2.1 and 2.2
module Categories.Category.Restriction.Properties where

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

open import Categories.Category.Core using (Category)
open import Categories.Category.Restriction using (Restriction)
open import Categories.Category.SubCategory
open import Categories.Morphism using (Mono)
open import Categories.Morphism.Idempotent using (Idempotent)
open import Categories.Morphism.Properties using (Mono-id)
import Categories.Morphism.Reasoning as MR

module _ {o ℓ e : Level} {𝒞 : Category o ℓ e} (R : Restriction 𝒞) where
  open Category 𝒞
  open Restriction R
  open HomReasoning
  open MR 𝒞 using (elimˡ; introʳ)

  private
    variable
      A B C : Obj
      f : A ⇒ B
      g : B ⇒ C

  ↓f-idempotent : (A ⇒ B) → Idempotent 𝒞 A
  ↓f-idempotent f = record { idem = f ↓ ; idempotent = ⟺ ↓-denestʳ ○ ↓-cong pidʳ }

  -- a special version of ↓ being a partial left identity
  ↓-pidˡ-gf : f ↓ ∘ (g ∘ f) ↓ ≈ (g ∘ f) ↓
  ↓-pidˡ-gf {f = f} {g = g} = begin
    f ↓ ∘ (g ∘ f) ↓   ≈⟨ ↓-comm ⟩
    (g ∘ f) ↓ ∘ f ↓   ≈˘⟨ ↓-denestʳ ⟩
    ((g ∘ f) ∘ f ↓) ↓ ≈⟨ ↓-cong assoc ⟩
    (g ∘ (f ∘ f ↓)) ↓ ≈⟨ ↓-cong (∘-resp-≈ʳ pidʳ) ⟩
    (g ∘ f) ↓ ∎

  -- left denesting looks different in its conclusion
  ↓-denestˡ : (g ↓ ∘ f) ↓ ≈ (g ∘ f) ↓
  ↓-denestˡ {g = g} {f = f} = begin
    (g ↓ ∘ f) ↓       ≈⟨ ↓-cong ↓-skew-comm ⟩
    (f ∘ (g ∘ f) ↓) ↓ ≈⟨ ↓-denestʳ ⟩
    f ↓ ∘ (g ∘ f) ↓   ≈⟨ ↓-pidˡ-gf ⟩
    (g ∘ f) ↓         ∎

  ↓-idempotent : f ↓ ↓ ≈ f ↓
  ↓-idempotent {f = f} = begin
    f ↓ ↓        ≈˘⟨ ↓-cong identityʳ ⟩
    (f ↓ ∘ id) ↓ ≈⟨ ↓-denestˡ ⟩
    (f ∘ id) ↓   ≈⟨ ↓-cong identityʳ ⟩
    f ↓ ∎

  ↓↓denest : (g ↓ ∘ f ↓) ↓ ≈ g ↓ ∘ f ↓
  ↓↓denest {g = g} {f = f} = begin
    (g ↓ ∘ f ↓) ↓ ≈⟨ ↓-denestʳ ⟩
    g ↓ ↓ ∘ f ↓   ≈⟨ (↓-idempotent ⟩∘⟨refl) ⟩
    g ↓ ∘ f ↓ ∎

  Mono⇒f↓≈id : Mono 𝒞 f → f ↓ ≈ id
  Mono⇒f↓≈id {f = f} mono = mono (f ↓) id (pidʳ ○ ⟺ identityʳ)

  -- if the domain of g is at least that of f, then the restriction coincides
  ↓⊃⇒≈ : f ∘ g ↓ ≈ f → f ↓ ≈ f ↓ ∘ g ↓
  ↓⊃⇒≈ {f = f} {g = g} fg↓≈f = ⟺ (↓-cong fg↓≈f) ○ ↓-denestʳ

  Mono⇒Total : Mono 𝒞 f → total f
  Mono⇒Total = Mono⇒f↓≈id

  ∘-pres-total : {A B C : Obj} {f : B ⇒ C} {g : A ⇒ B} → total f → total g → total (f ∘ g)
  ∘-pres-total {f = f} {g = g} tf tg = begin
    (f ∘ g) ↓   ≈˘⟨ ↓-denestˡ ⟩
    (f ↓ ∘ g) ↓ ≈⟨ ↓-cong (elimˡ tf) ⟩
    g ↓         ≈⟨ tg ⟩
    id ∎

  total-gf⇒total-f : total (g ∘ f) → total f
  total-gf⇒total-f {g = g} {f = f} tgf = begin
    f ↓             ≈⟨ introʳ tgf ⟩
    f ↓ ∘ (g ∘ f) ↓ ≈⟨ ↓-pidˡ-gf ⟩
    (g ∘ f) ↓       ≈⟨ tgf ⟩
    id              ∎

  total-SubCat : SubCat 𝒞 Obj
  total-SubCat = record
    { U = λ x → x
    ; R = total
    ; Rid = Mono⇒Total (Mono-id 𝒞)
    ; _∘R_ = ∘-pres-total
    }

  Total : Category o (ℓ ⊔ e) e
  Total = SubCategory 𝒞 total-SubCat


{-# OPTIONS --safe #-}

module Cubical.Data.FinSet.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure
open import Cubical.Foundations.Equiv

open import Cubical.HITs.PropositionalTruncation

open import Cubical.Data.Nat
open import Cubical.Data.Fin
open import Cubical.Data.Sigma

private
  variable
    ℓ : Level
    A : Type ℓ

isFinSet : Type ℓ → Type ℓ
isFinSet A = ∃[ n ∈ ℕ ] A ≃ Fin n

-- finite sets are sets
isFinSet→isSet : isFinSet A → isSet A
isFinSet→isSet = rec isPropIsSet (λ (_ , p) → isOfHLevelRespectEquiv 2 (invEquiv p) isSetFin)

isPropIsFinSet : isProp (isFinSet A)
isPropIsFinSet = isPropPropTrunc

-- the type of finite sets

FinSet : (ℓ : Level) → Type (ℓ-suc ℓ)
FinSet ℓ = TypeWithStr _ isFinSet


module DataRecordInductive where

module NotMutual where

  record Nil (A : Set) : Set where
    constructor []

  record Cons (A X : Set) : Set where
    constructor _∷_
    field head : A
          tail : X
  open Cons

  data List (A : Set) : Set where
    nil  : Nil A  → List A
    cons : Cons A (List A) → List A

  -- works
  module Constr where

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

  -- works, since projections are size preserving
  module Proj where

    map : {A B : Set} → (A → B) → List A → List B
    map f (nil   _) = nil []
    map f (cons  p) = cons (f (head p) ∷ map f (tail p))

module Mutual where

  mutual

    data List (A : Set) : Set where
      nil  : Nil A  → List A
      cons : Cons A → List A

    record Nil (A : Set) : Set where
      constructor []

    -- since Cons is inductive, we are not creating colists
    record Cons (A : Set) : Set where
      inductive
      constructor _∷_
      field head : A
            tail : List A

  open Cons

  -- works
  module Constr where

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

  -- works, since projections of an inductive record are size-preserving
  module Proj where

    map : {A B : Set} → (A → B) → List A → List B
    map f (nil   _) = nil []
    map f (cons  p) = cons (f (head p) ∷ map f (tail p))


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

open import Categories.Category
open import Categories.Functor hiding (id)

module Categories.Diagram.Colimit.DualProperties
  {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {J : Category o′ ℓ′ e′} where

open import Function.Equality renaming (id to idFun)

open import Categories.Category.Instance.Setoids
open import Categories.Diagram.Duality C
open import Categories.Functor.Hom
open import Categories.Category.Construction.Cocones as Coc
open import Categories.Diagram.Limit as Lim
open import Categories.Diagram.Limit.Properties
open import Categories.Diagram.Colimit as Col
open import Categories.NaturalTransformation
open import Categories.NaturalTransformation.NaturalIsomorphism
open import Categories.Morphism C
open import Categories.Morphism.Duality C

private
    module C = Category C
    module J = Category J
    open C
    open Hom C
    open HomReasoning

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

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

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

-- natural isomorphisms respects limits
module _ {F G : Functor J C} (F≃G : F ≃ G) where
  private
    module F  = Functor F
    module G  = Functor G
    open NaturalIsomorphism F≃G

  ≃-resp-colim : Colimit F → Colimit G
  ≃-resp-colim Cf = coLimit⇒Colimit (≃-resp-lim op′ (Colimit⇒coLimit Cf))

  ≃⇒Cocone⇒ : ∀ (Cf : Colimit F) (Cg : Colimit G) → Cocones G [ Colimit.colimit Cg , Colimit.colimit (≃-resp-colim Cf) ]
  ≃⇒Cocone⇒ Cf Cg = coCone⇒⇒Cocone⇒ (≃⇒Cone⇒ op′ (Colimit⇒coLimit Cf) (Colimit⇒coLimit Cg))

≃⇒colim≅ : ∀ {F G : Functor J C} (F≃G : F ≃ G) (Cf : Colimit F) (Cg : Colimit G) → Colimit.coapex Cf ≅ Colimit.coapex Cg
≃⇒colim≅ F≃G Cf Cg = op-≅⇒≅ (≃⇒lim≅ (NaturalIsomorphism.op′ F≃G) (Colimit⇒coLimit Cf) (Colimit⇒coLimit Cg))


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

module Cubical.Algebra.Group.Morphism where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Algebra.Group.Base
open import Cubical.HITs.PropositionalTruncation hiding (map)
open import Cubical.Data.Sigma

private
  variable
    ℓ ℓ' : Level

-- The following definition of GroupHom and GroupEquiv are level-wise heterogeneous.
-- This allows for example to deduce that G ≡ F from a chain of isomorphisms
-- G ≃ H ≃ F, even if H does not lie in the same level as G and F.

isGroupHom : (G : Group {ℓ}) (H : Group {ℓ'}) (f : ⟨ G ⟩ → ⟨ H ⟩) → Type _
isGroupHom G H f = (x y : ⟨ G ⟩) → f (x G.+ y) ≡ (f x H.+ f y) where
  module G = Group G
  module H = Group H

record GroupHom (G : Group {ℓ}) (H : Group {ℓ'}) : Type (ℓ-max ℓ ℓ') where
  constructor grouphom
  no-eta-equality
  field
    fun : ⟨ G ⟩ → ⟨ H ⟩
    isHom : isGroupHom G H fun

record GroupEquiv (G : Group {ℓ}) (H : Group {ℓ'}) : Type (ℓ-max ℓ ℓ') where
  constructor groupequiv
  no-eta-equality
  field
    eq : ⟨ G ⟩ ≃ ⟨ H ⟩
    isHom : isGroupHom G H (equivFun eq)

  hom : GroupHom G H
  hom = grouphom (equivFun eq) isHom

open GroupHom
open GroupEquiv

η-hom : {G : Group {ℓ}} {H : Group {ℓ'}} → (a  : GroupHom G H)
      → grouphom (fun a) (isHom a) ≡ a
fun (η-hom a i) = fun a
isHom (η-hom a i) = isHom a

η-equiv : {G : Group {ℓ}} {H : Group {ℓ'}} → (a  : GroupEquiv G H)
       → groupequiv (eq a) (isHom a) ≡ a
eq (η-equiv a i) = eq a
isHom (η-equiv a i) = isHom a

×hom : ∀ {ℓ ℓ' ℓ'' ℓ'''} {A : Group {ℓ}} {B : Group {ℓ'}} {C : Group {ℓ''}} {D : Group {ℓ'''}}
    → GroupHom A C → GroupHom B D → GroupHom (dirProd A B) (dirProd C D)
fun (×hom mf1 mf2) = map-× (fun mf1) (fun mf2)
isHom (×hom mf1 mf2) a b = ≡-× (isHom mf1 _ _) (isHom mf2 _ _)

open Group

isInIm : ∀ {ℓ ℓ'} (G : Group {ℓ}) (H : Group {ℓ'}) → (GroupHom G H)
       → ⟨ H ⟩ → Type (ℓ-max ℓ ℓ')
isInIm G H ϕ h = ∃[ g ∈ ⟨ G ⟩ ] (fun ϕ) g ≡ h

isInKer : ∀ {ℓ ℓ'} (G : Group {ℓ}) (H : Group {ℓ'}) → (GroupHom G H)
       → ⟨ G ⟩ → Type ℓ'
isInKer G H ϕ g = (fun ϕ) g ≡ 0g H

isSurjective : ∀ {ℓ ℓ'} (G : Group {ℓ}) (H : Group {ℓ'}) → GroupHom G H → Type (ℓ-max ℓ ℓ')
isSurjective G H ϕ = (x : ⟨ H ⟩) → isInIm G H ϕ x

isInjective : ∀ {ℓ ℓ'} (G : Group {ℓ}) (H : Group {ℓ'}) → GroupHom G H → Type (ℓ-max ℓ ℓ')
isInjective G H ϕ = (x : ⟨ G ⟩) → isInKer G H ϕ x → x ≡ 0g G


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

-- The category of Sets is Monoidal

module Categories.Category.Monoidal.Instance.Sets where

open import Level
open import Data.Product using (Σ; _×_; _,_; proj₁; proj₂; uncurry; map; <_,_>)
open import Data.Sum using (_⊎_; inj₁; inj₂; [_,_]′)
open import Data.Unit using (⊤)
open import Relation.Binary.PropositionalEquality
open import Function.Inverse using (module Inverse; _↔_)
open import Function.Related.TypeIsomorphisms
open import Function.Equality using () renaming (_⟨$⟩_ to fun)
open import Function using (_$_)

open import Categories.Category.Instance.Sets
open import Categories.Category.Monoidal
open import Categories.Functor.Bifunctor
open import Categories.Category.Instance.SingletonSet
open import Categories.Category.Instance.EmptySet
import Categories.Morphism as Morphism
import Categories.Category.Cartesian as Cartesian
import Categories.Category.Cocartesian as Cocartesian

open import Data.Sum.Properties

-- Sets is a Monoidal Category with × as Bifunctor
module Product {o : Level} where
  private
    S = Sets o
    open Cartesian S

  Sets-has-all : BinaryProducts
  Sets-has-all = record { product = λ {A} {B} → record
    { A×B = A × B
    ; π₁ = proj₁
    ; π₂ = proj₂
    ; ⟨_,_⟩ = <_,_>
    ; project₁ = refl
    ; project₂ = refl
    ; unique = λ p₁ p₂ {x} → sym (cong₂ _,_ (p₁ {x}) (p₂ {x}))
    } }

  Sets-is : Cartesian
  Sets-is = record { terminal = SingletonSet-⊤ ; products = Sets-has-all }

  private
    module Cart = Cartesian.Cartesian Sets-is

  Sets-Monoidal : Monoidal S
  Sets-Monoidal = Cart.monoidal

module Coproduct {o : Level} where
  private
    S = Sets o
    open Cocartesian S

  Sets-has-all : BinaryCoproducts
  Sets-has-all = record { coproduct = λ {A} {B} → record
    { A+B = A ⊎ B
    ; i₁ = inj₁
    ; i₂ = inj₂
    ; [_,_] = [_,_]′
    ; inject₁ = refl
    ; inject₂ = refl
    ; unique = λ { i₁ i₂ {inj₁ x} → sym (i₁ {x}) ; i₁ i₂ {inj₂ y} → sym (i₂ {y})} -- stdlib?
    } }

  Sets-is : Cocartesian
  Sets-is = record { initial = EmptySet-⊥ ; coproducts = Sets-has-all }

  private
    module Cocart = Cocartesian.Cocartesian Sets-is

  Sets-Monoidal : Monoidal S
  Sets-Monoidal =  Cocart.+-monoidal


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

module 04-inductive-types where

import 03-natural-numbers
open 03-natural-numbers public

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

-- Section 4.2 The unit type

-- Definition 4.2.1

data unit : UU lzero where
  star : unit

𝟙 = unit

ind-unit : {i : Level} {P : unit → UU i} → P star → ((x : unit) → P x)
ind-unit p star = p

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

-- Section 4.3 The empty type

-- Definition 4.3.1

data empty : UU lzero where

𝟘 = empty

ind-empty : {i : Level} {P : empty → UU i} → ((x : empty) → P x)
ind-empty ()

ex-falso : {i : Level} {A : UU i} → empty → A
ex-falso = ind-empty

-- Definition 4.3.2

¬ : {i : Level} → UU i → UU i
¬ A = A → empty

-- Proposition 4.3.3

functor-neg : {l1 l2 : Level} {P : UU l1} {Q : UU l2} →
  (P → Q) → (¬ Q → ¬ P)
functor-neg f nq p = nq (f p)

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

-- Section 4.4 The booleans

-- Definition 4.4.1

data bool : UU lzero where
  true false : bool

-- Example 4.4.2

neg-𝟚 : bool → bool
neg-𝟚 true = false
neg-𝟚 false = true

conjunction-𝟚 : bool → (bool → bool)
conjunction-𝟚 true true = true
conjunction-𝟚 true false = false
conjunction-𝟚 false true = false
conjunction-𝟚 false false = false

disjunction-𝟚 : bool → (bool → bool)
disjunction-𝟚 true true = true
disjunction-𝟚 true false = true
disjunction-𝟚 false true = true
disjunction-𝟚 false false = false

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

-- Section 4.5 Coproducts

-- Definition 4.5.1

data coprod {i j : Level} (A : UU i) (B : UU j) : UU (i ⊔ j)  where
  inl : A → coprod A B
  inr : B → coprod A B

ind-coprod : {i j k : Level} {A : UU i} {B : UU j} (C : coprod A B → UU k) →
  ((x : A) → C (inl x)) → ((y : B) → C (inr y)) →
  (t : coprod A B) → C t
ind-coprod C f g (inl x) = f x
ind-coprod C f g (inr x) = g x

-- Remark 4.5.2

functor-coprod :
  {l1 l2 l1' l2' : Level} {A : UU l1} {B : UU l2} {A' : UU l1'} {B' : UU l2'} →
  (A → A') → (B → B') → coprod A B → coprod A' B'
functor-coprod f g (inl x) = inl (f x)
functor-coprod f g (inr y) = inr (g y)

-- Proposition 4.5.3

coprod-elim-left :
  {i j : Level} (A : UU i) (B : UU j) →
  ¬ B → coprod A B → A
coprod-elim-left A B nb (inl a) = a
coprod-elim-left A B nb (inr b) = ex-falso (nb b)

coprod-elim-right :
  {i j : Level} (A : UU i) (B : UU j) →
  ¬ A → coprod A B → B
coprod-elim-right A B na (inl a) = ex-falso (na a)
coprod-elim-right A B na (inr b) = b

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

-- Section 4.6 Dependent pair types

-- Definition 4.6.1

data Σ {i j : Level} (A : UU i) (B : A → UU j) : UU (i ⊔ j) where
  pair : (x : A) → (B x → Σ A B)

ind-Σ : {i j k : Level} {A : UU i} {B : A → UU j} {C : Σ A B → UU k} →
  ((x : A) (y : B x) → C (pair x y)) → ((t : Σ A B) → C t)
ind-Σ f (pair x y) = f x y

-- Remark 4.6.2

ev-pair :
  {l1 l2 l3 : Level} {A : UU l1} {B : A → UU l2} {C : Σ A B → UU l3} →
  ((t : Σ A B) → C t) → (x : A) (y : B x) → C (pair x y)
ev-pair f x y = f (pair x y)

-- Definition 4.6.3

pr1 : {i j : Level} {A : UU i} {B : A → UU j} → Σ A B → A
pr1 (pair a b) = a

pr2 : {i j : Level} {A : UU i} {B : A → UU j} → (t : Σ A B) → B (pr1 t)
pr2 (pair a b) = b

-- Definition 4.6.4

prod : {i j : Level} (A : UU i) (B : UU j) → UU (i ⊔ j)
prod A B = Σ A (λ a → B)

pair' :
  {i j : Level} {A : UU i} {B : UU j} → A → B → prod A B
pair' = pair

_×_ :  {i j : Level} (A : UU i) (B : UU j) → UU (i ⊔ j)
A × B = prod A B

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

-- Section 4.7 The type of integers

-- Definition 4.7.1

-- The type of integers

ℤ : UU lzero
ℤ = coprod ℕ (coprod unit ℕ)

-- Inclusion of the negative integers

in-neg : ℕ → ℤ
in-neg n = inl n

-- Negative one

neg-one-ℤ : ℤ
neg-one-ℤ = in-neg zero-ℕ

-- Zero

zero-ℤ : ℤ
zero-ℤ = inr (inl star)

-- One

one-ℤ : ℤ
one-ℤ = inr (inr zero-ℕ)

-- Inclusion of the positive integers

in-pos : ℕ → ℤ
in-pos n = inr (inr n)

-- Inclusion of the natural numbers

int-ℕ : ℕ → ℤ
int-ℕ zero-ℕ = zero-ℤ
int-ℕ (succ-ℕ n) = in-pos n

-- Proposition 4.7.2

ind-ℤ :
  {i : Level} (P : ℤ → UU i) →
  P neg-one-ℤ → ((n : ℕ) → P (inl n) → P (inl (succ-ℕ n))) →
  P zero-ℤ →
  P one-ℤ → ((n : ℕ) → P (inr (inr (n))) → P (inr (inr (succ-ℕ n)))) →
  (k : ℤ) → P k
ind-ℤ P p-1 p-S p0 p1 pS (inl zero-ℕ) = p-1
ind-ℤ P p-1 p-S p0 p1 pS (inl (succ-ℕ x)) =
  p-S x (ind-ℤ P p-1 p-S p0 p1 pS (inl x))
ind-ℤ P p-1 p-S p0 p1 pS (inr (inl star)) = p0
ind-ℤ P p-1 p-S p0 p1 pS (inr (inr zero-ℕ)) = p1
ind-ℤ P p-1 p-S p0 p1 pS (inr (inr (succ-ℕ x))) =
  pS x (ind-ℤ P p-1 p-S p0 p1 pS (inr (inr (x))))

-- Definition 4.7.3

succ-ℤ : ℤ → ℤ
succ-ℤ (inl zero-ℕ) = zero-ℤ
succ-ℤ (inl (succ-ℕ x)) = inl x
succ-ℤ (inr (inl star)) = one-ℤ
succ-ℤ (inr (inr x)) = inr (inr (succ-ℕ x))

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

-- Exercises

-- Exercise 4.1 (a)

pred-ℤ : ℤ → ℤ
pred-ℤ (inl x) = inl (succ-ℕ x)
pred-ℤ (inr (inl star)) = inl zero-ℕ
pred-ℤ (inr (inr zero-ℕ)) = inr (inl star)
pred-ℤ (inr (inr (succ-ℕ x))) = inr (inr x)

-- Exercise 4.1 (b)

-- Addition on ℤ

add-ℤ : ℤ → ℤ → ℤ
add-ℤ (inl zero-ℕ) l = pred-ℤ l
add-ℤ (inl (succ-ℕ x)) l = pred-ℤ (add-ℤ (inl x) l)
add-ℤ (inr (inl star)) l = l
add-ℤ (inr (inr zero-ℕ)) l = succ-ℤ l
add-ℤ (inr (inr (succ-ℕ x))) l = succ-ℤ (add-ℤ (inr (inr x)) l)

add-ℤ' : ℤ → ℤ → ℤ
add-ℤ' x y = add-ℤ y x

-- The negative of an integer

neg-ℤ : ℤ → ℤ
neg-ℤ (inl x) = inr (inr x)
neg-ℤ (inr (inl star)) = inr (inl star)
neg-ℤ (inr (inr x)) = inl x

-- Exercise 4.1 (c)

-- Multiplication on ℤ

mul-ℤ : ℤ → ℤ → ℤ
mul-ℤ (inl zero-ℕ) l = neg-ℤ l
mul-ℤ (inl (succ-ℕ x)) l = add-ℤ (neg-ℤ l) (mul-ℤ (inl x) l)
mul-ℤ (inr (inl star)) l = zero-ℤ
mul-ℤ (inr (inr zero-ℕ)) l = l
mul-ℤ (inr (inr (succ-ℕ x))) l = add-ℤ l (mul-ℤ (inr (inr x)) l)

mul-ℤ' : ℤ → ℤ → ℤ
mul-ℤ' x y = mul-ℤ y x

-- Exercise 4.2

¬¬ : {l : Level} → UU l → UU l
¬¬ P = ¬ (¬ P)

¬¬¬ : {l : Level} → UU l → UU l
¬¬¬ P = ¬ (¬ (¬ P))

-- Exercise 4.2 (a)

no-fixed-points-neg :
  {l1 : Level} (A : UU l1) → ¬ ((A → ¬ A) × (¬ A → A))
no-fixed-points-neg A (pair f g) =
  ( λ (h : ¬ A) → h (g h)) (λ (a : A) → f a a)

-- Exercise 4.2 (b)

intro-dn : {l : Level} {P : UU l} → P → ¬¬ P
intro-dn p f = f p

-- Exercise 4.2 (c)

functor-dn : {l1 l2 : Level} {P : UU l1} {Q : UU l2} →
  (P → Q) → (¬¬ P → ¬¬ Q)
functor-dn f = functor-neg (functor-neg f)

-- Exercise 4.2 (d)

{- In this exercise we were asked to show that (A + ¬A) implies (¬¬A → A). In
   other words, we get double negation elimination for the types that are
   decidable. -}

double-negation-elim-is-decidable :
  {i : Level} (P : UU i) → coprod P (¬ P) → (¬¬ P → P)
double-negation-elim-is-decidable P (inl x) p = x
double-negation-elim-is-decidable P (inr x) p = ind-empty (p x)

-- Exercise 4.2 (e)

dn-is-decidable : {l : Level} {P : UU l} → ¬¬ (coprod P (¬ P))
dn-is-decidable {P = P} f =
  functor-neg (inr {A = P} {B = ¬ P}) f
    ( functor-neg (inl {A = P} {B = ¬ P}) f)

-- Exercise 4.2 (f)

dn-dn-elim : {l : Level} {P : UU l} → ¬¬ (¬¬ P → P)
dn-dn-elim {P = P} f =
  ( λ (np : ¬ P) → f (λ (nnp : ¬¬ P) → ind-empty {P = λ x → P} (nnp np)))
    ( λ (p : P) → f (λ (nnp : ¬¬ P) → p))

-- Exercise 4.2 (g)

tautology-4-2-f :
  {l1 l2 : Level} {P : UU l1} {Q : UU l2} →
  ¬¬ (((P → Q) → P) → P)
tautology-4-2-f {P = P} {Q} f =
  ( λ (np : ¬ P) → f (λ h → h (λ p → ex-falso (np p))))
  ( λ (p : P) → f (λ h → p))

-- Exercise 4.2 (h)

dn-linearity-implication :
  {l1 l2 : Level} {P : UU l1} {Q : UU l2} →
  ¬¬ (coprod (P → Q) (Q → P))
dn-linearity-implication {P = P} {Q = Q} f =
  ( λ (np : ¬ P) →
    functor-neg (inl {A = P → Q} {B = Q → P}) f (λ p → ind-empty (np p)))
    ( λ (p : P) →
      functor-neg (inr {A = P → Q} {B = Q → P}) f (λ q → p))

-- Exercise 4.2 (i)

dn-elim-neg : {l : Level} (P : UU l) → ¬¬¬ P → ¬ P
dn-elim-neg P f p = f (λ g → g p)

-- Exercise 4.2 (j)

dn-extend :
  {l1 l2 : Level} {P : UU l1} {Q : UU l2} →
  (P → ¬¬ Q) → (¬¬ P → ¬¬ Q)
dn-extend {P = P} {Q = Q} f = dn-elim-neg (¬ Q) ∘ (functor-dn f)

-- Exercise 4.2 (k)

dn-elim-exp :
  {l1 l2 : Level} {P : UU l1} {Q : UU l2} →
  ¬¬ (P → ¬¬ Q) → (P → ¬¬ Q)
dn-elim-exp {P = P} {Q = Q} f p =
  dn-elim-neg (¬ Q) (functor-dn (λ (g : P → ¬¬ Q) → g p) f)

-- Exercise 4.2 (l)

dn-elim-prod :
  {l1 l2 : Level} {P : UU l1} {Q : UU l2} →
  ¬¬ ((¬¬ P) × (¬¬ Q)) → (¬¬ P) × (¬¬ Q)
dn-elim-prod {P = P} {Q = Q} f =
  pair
    ( dn-elim-neg (¬ P) (functor-dn pr1 f))
    ( dn-elim-neg (¬ Q) (functor-dn pr2 f))

-- Exercise 4.3

-- Exercise 4.3 (a)

data list {l : Level} (A : UU l) : UU l where
  nil : list A
  cons : A → list A → list A

in-list : {l : Level} {A : UU l} → A → list A
in-list a = cons a nil

-- Exercise 4.3 (b)

fold-list :
  {l1 l2 : Level} {A : UU l1} {B : UU l2} (b : B) (μ : A → (B → B)) →
  list A → B
fold-list b μ nil = b
fold-list b μ (cons a l) = μ a (fold-list b μ l)

-- Exercise 4.3 (c)

length-list :
  {l : Level} {A : UU l} → list A → ℕ
length-list = fold-list zero-ℕ (λ a → succ-ℕ)

-- Exercise 4.3 (d)

sum-list-ℕ :
  list ℕ → ℕ
sum-list-ℕ = fold-list zero-ℕ add-ℕ

-- Exercise 4.3 (e)

concat-list :
  {l : Level} {A : UU l} → list A → (list A → list A)
concat-list {l} {A} = fold-list id (λ a f → (cons a) ∘ f)

-- Exercise 4.3 (f)

flatten-list :
  {l : Level} {A : UU l} → list (list A) → list A
flatten-list = fold-list nil concat-list

-- Exercise 4.3 (g)

reverse-list :
  {l : Level} {A : UU l} → list A → list A
reverse-list nil = nil
reverse-list (cons a l) = concat-list (reverse-list l) (in-list a)


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

-- Left and Right Kan extensions (known as Lan and Ran)

open import Level
open import Categories.Category using (Category)
open import Categories.Functor
open import Categories.NaturalTransformation using (NaturalTransformation; _∘ʳ_; _∘ᵥ_)
open import Categories.NaturalTransformation.Equivalence using (_≃_)

private
  variable
    o₀ ℓ₀ e₀ o₁ ℓ₁ e₁ o₂ ℓ₂ e₂ : Level

module _ {A : Category o₀ ℓ₀ e₀} {B : Category o₁ ℓ₁ e₁} {C : Category o₂ ℓ₂ e₂}
           (F : Functor A B) (X : Functor A C) where

  record Lan : Set (o₀ ⊔ ℓ₀ ⊔ e₀ ⊔ o₁ ⊔ ℓ₁ ⊔ e₁ ⊔ o₂ ⊔ ℓ₂ ⊔ e₂) where
    field
      L : Functor B C
      η : NaturalTransformation X (L ∘F F)

      σ : (M : Functor B C) → (α : NaturalTransformation X (M ∘F F)) → NaturalTransformation L M

      σ-unique : {M : Functor B C} → {α : NaturalTransformation X (M ∘F F)} →
                  (σ′ : NaturalTransformation L M) → α ≃ (σ′ ∘ʳ F) ∘ᵥ η → σ′ ≃ σ M α
      commutes : (M : Functor B C) → (α : NaturalTransformation X (M ∘F F)) → α ≃ (σ M α ∘ʳ F) ∘ᵥ η

    module L = Functor L
    module η = NaturalTransformation η

  record Ran : Set (o₀ ⊔ ℓ₀ ⊔ e₀ ⊔ o₁ ⊔ ℓ₁ ⊔ e₁ ⊔ o₂ ⊔ ℓ₂ ⊔ e₂) where
    field
      R : Functor B C
      ε : NaturalTransformation (R ∘F F) X

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

      δ-unique : {M : Functor B C} → {α : NaturalTransformation (M ∘F F) X} →
                  (δ′ : NaturalTransformation M R) → α ≃ ε ∘ᵥ (δ′ ∘ʳ F) → δ′ ≃ δ M α
      commutes : (M : Functor B C) → (α : NaturalTransformation (M ∘F F) X) → α ≃ ε ∘ᵥ (δ M α ∘ʳ F)

    module R = Functor R
    module ε = NaturalTransformation ε


------------------------------------------------------------------------
-- The Agda standard library
--
-- Indexed binary relations
------------------------------------------------------------------------

-- The contents of this module should be accessed via
-- `Relation.Binary.Indexed.Heterogeneous`.

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

module Relation.Binary.Indexed.Heterogeneous.Definitions where

open import Level
import Relation.Binary.Core as B
import Relation.Binary.Definitions as B
import Relation.Binary.PropositionalEquality.Core as P
open import Relation.Binary.Indexed.Heterogeneous.Core

private
  variable
    i a ℓ : Level
    I : Set i

------------------------------------------------------------------------
-- Simple properties of indexed binary relations

Reflexive : (A : I → Set a) → IRel A ℓ → Set _
Reflexive _ _∼_ = ∀ {i} → B.Reflexive (_∼_ {i})

Symmetric : (A : I → Set a) → IRel A ℓ → Set _
Symmetric _ _∼_ = ∀ {i j} → B.Sym (_∼_ {i} {j}) _∼_

Transitive : (A : I → Set a) → IRel A ℓ → Set _
Transitive _ _∼_ = ∀ {i j k} → B.Trans _∼_ (_∼_ {j}) (_∼_ {i} {k})


{-# OPTIONS --show-implicit #-}
{-# OPTIONS --sized-types #-}
{-# OPTIONS --termination-depth=2 #-}
-- {-# OPTIONS -v term:10 #-}

module SizedBTree where

open import Common.Size

data BTree (A : Set) : {size : Size} → Set where
  leaf : {i : Size} → A → BTree A {↑ i}
  node : {i : Size} → BTree A {i} → BTree A {i} → BTree A {↑ i}

map : ∀ {A B i} → (A → B) → BTree A {i} → BTree B {i}
map f (leaf a) = leaf (f a)
map f (node l r) = node (map f l) (map f r)

-- deep matching

deep : ∀ {i A} → BTree A {i} → A
deep (leaf a) = a
deep (node (leaf _) r) = deep r
deep (node (node l r) _) = deep (node l r)

-- nesting

deep2 : ∀ {i A} → BTree A {i} → BTree A {i}
deep2 (leaf a) = leaf a
deep2 (node (leaf _) r) = r
deep2 (node (node l r) t) with deep2 (deep2 (node l r))
... | leaf a = leaf a
... | node l2 r2 = deep2 (node l2 r2)

-- increasing the termination count does the job!


module Structure.Type.Identity where

import      Lvl
open import Lang.Instance
open import Logic.Propositional
open import Logic
open import Structure.Relator.Properties
open import Structure.Setoid
open import Type
open import Type.Properties.MereProposition
open import Type.Size

module _ {ℓ ℓₑ ℓₚ} {T : Type{ℓ}} (_≡_ : T → T → Stmt{ℓₑ}) where
  -- When a binary relation is the smallest reflexive relation (in the sense of cardinality of the relation set).
  -- This is one of many characterizations of equality.
  MinimalReflexiveRelation : Stmt
  MinimalReflexiveRelation = ∀{_▫_ : T → T → Stmt{ℓₚ}} → ⦃ refl : Reflexivity(_▫_) ⦄ → ((_≡_) ⊆₂ (_▫_))

  -- When a binary relation is able to substitute every unary relation and is satisfied when every unary relation .
  -- This is one of many characterizations of equality.
  GlobalSubstitution : Stmt
  GlobalSubstitution = ∀{x y : T} → ((x ≡ y) ↔ (∀{P : T → Type{ℓₚ}} → P(x) → P(y)))

module _ {ℓ ℓₑ ℓₘₑ} (T : Type{ℓ}) ⦃ equiv-T : Equiv{ℓₑ}(T) ⦄ ⦃ equiv-eq : ∀{x y : T} → Equiv{ℓₘₑ}(x ≡ y) ⦄ where
  -- A proof of identity is unique (there is only one inhabitant of the identity type).
  -- This is interpreted as saying that all proofs of an identity are equal to each other.
  -- Also called: Uniqueness of identity proofs (UIP).
  -- There is an axiom called "axiom UIP" which is a construction of the following type:
  -- • ∀{T} → UniqueIdentityProofs(T)
  UniqueIdentityProofs : Stmt
  UniqueIdentityProofs = ∀{x y : T} → MereProposition(x ≡ y)

module Names where
  module _ {ℓ ℓₑ ℓₚ} {T : Type{ℓ}} (Id : T → T → Stmt{ℓₑ}) ⦃ refl : Reflexivity(Id) ⦄ where
    -- Elimination rule for identity types.
    -- Also called J.
    -- Explanation:
    --   P{x}{y} (eq-proof) is an arbitrary predicate with possible mentions of an identity proof.
       --   A value of type (∀{x : T} → P(reflexivity(_≡_) {x})) means:
    --     reflexivity(_≡_) satisfies P for every pair of equal objects.
    --   The conclusion of the type (∀{x y : T} → (eq : (x ≡ y)) → P{x}{y}(eq)) means:
    --     Every identity proof satisfies P for every pair there is.
    --   In other words, to prove a proposition that depends on an identity proof, one only need to prove it for reflexivity.
    -- When this is joined by reflexivity, they become another characterization of equality.
    -- More information:
    -- • https://homotopytypetheory.org/2011/04/10/just-kidding-understanding-identity-elimination-in-homotopy-type-theory/
    -- • https://stackoverflow.com/questions/22580842/non-trivial-negation-in-agda
    IdentityEliminator : Stmt
    IdentityEliminator = (P : ∀{x y : T} → (Id x y) → Stmt{ℓₚ}) → (∀{x : T} → P(reflexivity(Id) {x})) → (∀{x y : T} → (eq : (Id x y)) → P(eq))

    -- Usage of the trivial equality reflexivity proof can be substituted by any proof of the same type.
    -- There is an axiom called "axiom K" which is a construction of the following type:
    -- • ∀{T} → IntroProofSubstitution(T)
    IntroProofSubstitution : Stmt
    IntroProofSubstitution = ∀{x : T}{P : (Id x x) → Type{ℓₚ}} → P(reflexivity(Id)) → (∀{eq : (Id x x)} → P(eq))

module _ {ℓ ℓₑ ℓₚ} {T : Type{ℓ}} (Id : T → T → Stmt{ℓₑ}) ⦃ refl : Reflexivity(Id) ⦄ where
  record IdentityEliminator : Stmt{ℓ Lvl.⊔ ℓₑ Lvl.⊔ Lvl.𝐒(ℓₚ)} where
    constructor intro
    field elim : Names.IdentityEliminator{ℓₚ = ℓₚ}(Id)
  idElim = inst-fn IdentityEliminator.elim

module _
  {ℓ ℓₘ ℓₑ ℓₘₑ}
  {T : Type{ℓ}}
  (Id : T → T → Type{ℓₑ}) ⦃ refl-T :  Reflexivity(Id) ⦄  ⦃ identElim-T : IdentityEliminator(Id) ⦄
  (_≡_ : ∀{T : Type{ℓₘ}} → T → T → Type{ℓₘₑ})
  where

  open Reflexivity (refl-T) using () renaming (proof to refl)

  -- Reflexivity is an identity element for the identity elimination operation.
  record IdentityEliminationOfIntro : Stmt{ℓ Lvl.⊔ Lvl.𝐒 ℓₘ Lvl.⊔ ℓₑ Lvl.⊔ ℓₘₑ} where
    constructor intro
    field proof : (P : ∀{x y : T} → (Id x y) → Stmt{ℓₘ}) → (p : ∀{x} → P{x}{x}(refl)) → (∀{x : T} → (idElim(Id)(P) p refl ≡ p{x}))
  idElimOfIntro = inst-fn IdentityEliminationOfIntro.proof

module _ {ℓₑ : Lvl.Level → Lvl.Level} (Id : ∀{ℓ}{T : Type{ℓ}} → T → T → Stmt{ℓₑ(ℓ)}) where
  record IdentityType : Stmtω where
    constructor intro
    field
      ⦃ identity-intro ⦄ : ∀{ℓₒ}{T : Type{ℓₒ}} → Reflexivity(Id{T = T})
      ⦃ identity-elim ⦄  : ∀{ℓₒ ℓₚ}{T : Type{ℓₒ}} → IdentityEliminator{ℓₚ = ℓₚ}(Id{T = T})
      ⦃ refl-elim-inverses ⦄ : ∀{ℓ ℓₘ}{T : Type{ℓ}} → IdentityEliminationOfIntro{ℓₘ = ℓₘ}(Id{T = T})(Id)


module Extensions.ListFirst where

open import Prelude hiding (_⊔_)

open import Data.Product
open import Data.List
open import Data.List.Any
open Membership-≡ hiding (find)
open import Level

-- proof that an element is the first in a vector to satisfy the predicate B
data First {a b} {A : Set a} (B : A → Set b) : (x : A) → List A → Set (a ⊔ b) where

  here  : ∀ {x : A} → (p : B x) → (v : List A) → First B x (x ∷ v)
  there : ∀ {x} {v : List A} (x' : A) → ¬ (B x') → First B x v → First B x (x' ∷ v)

-- get the witness of B x from the element ∈ First
first⟶witness : ∀ {A : Set} {B : A → Set} {x l} → First B x l → B x
first⟶witness (here p v) = p
first⟶witness (there x ¬px f) = first⟶witness f

first⟶∈ : ∀ {A : Set} {B : A → Set} {x l} → First B x l → (x ∈ l × B x)
first⟶∈ (here {x = x} p v) = here refl , p
first⟶∈ (there x' ¬px f) with (first⟶∈ f)
first⟶∈ (there x' ¬px f) | x∈l , p = there x∈l , p

-- more likable syntax for the above structure
first_∈_⇔_ : {A : Set} → A → List A → (B : A → Set) → Set
first_∈_⇔_ x v p = First p x v

-- a decision procedure to find the first element in a vector that satisfies a predicate
find : ∀ {A : Set} (P : A → Set) → ((a : A) → Dec (P a)) → (v : List A) →
       Dec (∃ λ e → first e ∈ v ⇔ P)
find P dec [] = no (λ{ (e , ()) })
find P dec (x ∷ v) with dec x
find P dec (x ∷ v) | yes px = yes (x , here px v)
find P dec (x ∷ v) | no ¬px with find P dec v
find P dec (x ∷ v) | no ¬px | yes firstv = yes (, there x ¬px (proj₂ firstv))
find P dec (x ∷ v) | no ¬px | no ¬firstv = no $ helper ¬px ¬firstv
  where
    helper : ¬ (P x) → ¬ (∃ λ e → First P e v) → ¬ (∃ λ e → First P e (x ∷ v))
    helper ¬px ¬firstv (.x , here p .v) = ¬px p
    helper ¬px ¬firstv (u  , there ._ _ firstv) = ¬firstv (u , firstv)

module FirstLemmas where

  first-unique : ∀ {A : Set} {P : A → Set} {x y v} → First P x v → First P y v → x ≡ y
  first-unique (here x v) (here y .v) = refl
  first-unique (here {x = x} px v) (there .x ¬px r) = ⊥-elim (¬px px)
  first-unique (there x ¬px l) (here {x = .x} px v) = ⊥-elim (¬px px)
  first-unique (there x' _ l) (there .x' _ r) = first-unique l r


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

open import Relation.Binary.PropositionalEquality using (_≡_; refl; cong; sym)
open import Relation.Nullary using (Dec; yes; no)

import Data.Bool as Bool
import Data.Empty as Empty
import Data.Unit as Unit
import Data.Sum as Sum
import Data.Product as Product
import Data.Nat as ℕ
import Data.Nat.Properties as ℕₚ

open Empty using (⊥)
open Unit using (⊤; tt)
open Sum using (inj₁; inj₂)
open Product using (∃-syntax; _×_; _,_)
open ℕ using (ℕ)

open import PiCalculus.LinearTypeSystem.Algebras

module PiCalculus.LinearTypeSystem.Algebras.Linear where

open Bool using (Bool; true; false) public
pattern zero = false
pattern one = true

data _≔_∙_ : Bool → Bool → Bool → Set where
  skip  : zero ≔ zero ∙ zero
  right : one  ≔ zero ∙ one
  left  : one  ≔ one  ∙ zero

∙-computeʳ : ∀ x y → Dec (∃[ z ] (x ≔ y ∙ z))
∙-computeʳ zero zero = yes (zero , skip)
∙-computeʳ zero one = no λ ()
∙-computeʳ one zero = yes (one , right)
∙-computeʳ one one = yes (zero , left)

∙-unique : ∀ {x' x y z} → x' ≔ y ∙ z → x ≔ y ∙ z → x' ≡ x
∙-unique skip skip = refl
∙-unique right right = refl
∙-unique left left = refl

∙-uniqueˡ : ∀ {x y' y z} → x ≔ y' ∙ z → x ≔ y ∙ z → y' ≡ y
∙-uniqueˡ skip skip = refl
∙-uniqueˡ right right = refl
∙-uniqueˡ left left = refl

∙-idˡ : ∀ {x} → x ≔ zero ∙ x
∙-idˡ {zero} = skip
∙-idˡ {one} = right

∙-comm : ∀ {x y z} → x ≔ y ∙ z → x ≔ z ∙ y
∙-comm skip = skip
∙-comm right = left
∙-comm left = right

∙-assoc : ∀ {x y z u v} → x ≔ y ∙ z → y ≔ u ∙ v → ∃-syntax (λ w → (x ≔ u ∙ w) × (w ≔ v ∙ z))
∙-assoc skip skip = zero , skip , skip
∙-assoc right skip = one , right , right
∙-assoc left right = one , right , left
∙-assoc left left = zero , left , skip

Linear : Algebra Bool
Algebra.1∙ Linear = true
Algebra.0∙ Linear = false
Algebra._≔_∙_ Linear = _≔_∙_
Algebra.∙-computeʳ Linear = ∙-computeʳ
Algebra.∙-unique Linear = ∙-unique
Algebra.∙-uniqueˡ Linear = ∙-uniqueˡ
Algebra.0∙-minˡ Linear skip = refl
Algebra.∙-idˡ Linear = ∙-idˡ
Algebra.∙-comm Linear = ∙-comm
Algebra.∙-assoc Linear = ∙-assoc


module WellScopedTerms where

open import Library
open import Categories
open import Functors
open import Categories.Sets
open import Functors.Fin hiding (lift)
open import RMonads
open import Relation.Binary.HeterogeneousEquality
open Cat
open Fun

data Tm : ℕ → Set where
  var : ∀{n} → Fin n → Tm n
  lam : ∀{n} → Tm (suc n) → Tm n
  app : ∀{n} → Tm n → Tm n → Tm n

Ren : ℕ → ℕ → Set
Ren m n = Fin m → Fin n

-- Weakening a renaming (to push it under a lambda)

wk : ∀{m n} → Ren m n → Ren (suc m) (suc n)
wk f zero     = zero
wk f (suc i) = suc (f i)

-- Performing a renaming on an expression

ren : ∀{m n} → Ren m n → Tm m → Tm n
ren f (var i)   = var (f i)
ren f (app t u) = app (ren f t) (ren f u)
ren f (lam t)   = lam (ren (wk f) t)

-- Identity renaming

renId : ∀{n} → Ren n n
renId = id

-- Composition of renamings

renComp : ∀{m n o} → Ren n o → Ren m n → Ren m o
renComp f g = f ∘ g

-- we prove that wk is an endofunctor

wkid : ∀{n}(i : Fin (suc n)) → wk renId i ≅ id i
wkid zero    = refl
wkid (suc i) = refl

wkcomp : ∀{m n o}(f : Ren n o)(g : Ren m n)(i : Fin (suc m)) →
            wk (renComp f g) i ≅ renComp (wk f) (wk g) i
wkcomp f g zero    = refl
wkcomp f g (suc i) = refl

-- we prove that renamings is a functor

renid : ∀{n}(t : Tm n) → ren renId t ≅ t
renid (var i)   = refl
renid (app t u) = cong₂ app (renid t) (renid u)
renid (lam t)   =
  proof
  lam (ren (wk renId) t)
  ≅⟨ cong (λ f → lam (ren f t)) (ext wkid) ⟩
  lam (ren renId t)
  ≅⟨ cong lam (renid t) ⟩
  lam t
  ∎

rencomp : ∀{m n o}(f : Ren n o)(g : Ren m n)(t : Tm m) →
          ren (renComp f g) t ≅ ren f (ren g t)
rencomp f g (var i)   = refl
rencomp f g (app t u) = cong₂ app (rencomp f g t) (rencomp f g u)
rencomp f g (lam t)   =
  proof
  lam (ren (wk (renComp f g)) t)
  ≅⟨ cong (λ f → lam (ren f t)) (ext (wkcomp f g)) ⟩
  lam (ren (renComp (wk f) (wk g)) t)
  ≅⟨ cong lam (rencomp (wk f) (wk g) t) ⟩
  lam (ren (wk f) (ren (wk g) t))
  ∎

-- Substitutions

Sub : ℕ → ℕ → Set
Sub m n = Fin m → Tm n

-- Weaken a substitution to push it under a lambda

lift : ∀{m n} → Sub m n → Sub (suc m) (suc n)
lift f zero     = var zero
lift f (suc i) = ren suc (f i)

-- Perform substitution on an expression

sub : ∀{m n} → Sub m n → Tm m → Tm n
sub f (var i)   = f i
sub f (app t u) = app (sub f t) (sub f u)
sub f (lam t)   = lam (sub (lift f) t)

-- Identity substitution

subId : ∀{n} → Sub n n
subId = var

-- Composition of substitutions

subComp : ∀{m n o} → Sub n o → Sub m n → Sub m o
subComp f g = sub f ∘ g

-- lift is an endofunctor on substitutions and sub is a functor, we
-- need some auxilary lemmas for the composition cases

-- the conditions for identity are easy

liftid : ∀{n}(i : Fin (suc n)) → lift subId i ≅ subId i
liftid zero    = refl
liftid (suc i) = refl

subid : ∀{n}(t : Tm n) → sub subId t ≅ id t
subid (var i)   = refl
subid (app t u) =
  proof
  app (sub subId t) (sub subId u)
  ≅⟨ cong₂ app (subid t) (subid u) ⟩
  app t u
  ∎
subid (lam t)   =
  proof
  lam (sub (lift subId) t)
  ≅⟨ cong lam (cong (λ f → sub f t) (ext liftid)) ⟩
  lam (sub subId t)
  ≅⟨ cong lam (subid t) ⟩
  lam t
  ∎

-- for composition of subs (subcomp) and lifts (liftcomp) we need two
-- lemmas about how renaming and subs interact for these two lemmas we
-- need two lemmas about how lift and wk interact.

liftwk : ∀{m n o}(f : Sub n o)(g : Ren m n)(i : Fin (suc m)) →
            (lift f ∘ wk g) i ≅ lift (f ∘ g) i
liftwk f g zero    = refl
liftwk f g (suc i) = refl

subren : ∀{m n o}(f : Sub n o)(g : Ren m n)(t : Tm m) →
         (sub f ∘ ren g) t ≅ sub (f ∘ g) t
subren f g (var i)   = refl
subren f g (app t u) =
  proof
  app (sub f (ren g t)) (sub f (ren g u))
  ≅⟨ cong₂ app (subren f g t) (subren f g u) ⟩
  app (sub (f ∘ g) t) (sub (f ∘ g) u)
  ∎
subren f g (lam t)   =
  proof
  lam (sub (lift f) (ren (wk g) t))
  ≅⟨ cong lam (subren (lift f) (wk g) t) ⟩
  lam (sub (lift f ∘ wk g) t)
  ≅⟨ cong lam (cong (λ f₁ → sub f₁ t) (ext (liftwk f g))) ⟩
  lam (sub (lift (f ∘ g)) t)
  ∎

renwklift : ∀{m n o}(f : Ren n o)(g : Sub m n)(i : Fin (suc m)) →
               (ren (wk f) ∘ lift g) i ≅ lift (ren f ∘ g) i
renwklift f g zero    = refl
renwklift f g (suc i) =
  proof
  ren (wk f) (ren suc (g i))
  ≅⟨ sym (rencomp (wk f) suc (g i)) ⟩
  ren (wk f ∘ suc) (g i)
  ≡⟨⟩
  ren (suc ∘ f) (g i)
  ≅⟨ rencomp suc f (g i) ⟩
  ren suc (ren f (g i))
  ∎

rensub : ∀{m n o}(f : Ren n o)(g : Sub m n)(t : Tm m) →
         (ren f ∘ sub g) t ≅ sub (ren f ∘ g) t
rensub f g (var i)   = refl
rensub f g (app t u) =
  proof
  app (ren f (sub g t)) (ren f (sub g u))
  ≅⟨ cong₂ app (rensub f g t) (rensub f g u) ⟩
  app (sub (ren f ∘ g) t) (sub (ren f ∘ g) u)
  ∎
rensub f g (lam t)   =
  proof
  lam (ren (wk f) (sub (lift g) t))
  ≅⟨ cong lam (rensub (wk f) (lift g) t) ⟩
  lam (sub (ren (wk f) ∘ (lift g)) t)
  ≅⟨ cong (λ f → lam (sub f t)) (ext (renwklift f g)) ⟩
  lam (sub (lift (ren f ∘ g)) t)
  ∎

liftcomp : ∀{m n o}(f : Sub n o)(g : Sub m n)(i : Fin (suc m)) →
           lift (subComp f g) i ≅ subComp (lift f) (lift g) i
liftcomp f g zero    = refl
liftcomp f g (suc i) =
  proof
  ren suc (sub f (g i))
  ≅⟨ rensub suc f (g i) ⟩
  sub (ren suc ∘ f) (g i)
  ≅⟨ sym (subren (lift f) suc (g i)) ⟩
  sub (lift f) (ren suc (g i))
  ∎

subcomp : ∀{m n o}(f : Sub n o)(g : Sub m n)(t : Tm m) →
          sub (subComp f g) t ≅ (sub f ∘ sub g) t
subcomp f g (var i)   = refl
subcomp f g (app t u) =
  proof
  app (sub (subComp f g) t) (sub (subComp f g) u)
  ≅⟨ cong₂ app (subcomp f g t) (subcomp f g u) ⟩
  app (sub f (sub g t)) (sub f (sub g u))
  ∎
subcomp f g (lam t)   =
  proof
  lam (sub (lift (subComp f g)) t)
  ≅⟨ cong (λ f → lam (sub f t)) (ext (liftcomp f g)) ⟩
  lam (sub (subComp (lift f)(lift g)) t)
  ≅⟨ cong lam (subcomp (lift f) (lift g) t) ⟩
  lam (sub (lift f) (sub (lift g) t))
  ∎

TmRMonad : RMonad FinF
TmRMonad = record {
  T    = Tm;
  η    = var;
  bind = sub;
  law1 = ext subid;
  law2 = refl;
  law3 = ext (subcomp _ _)}

-- module

open import RMonads.Modules

-- any functor is a relative monad over itself (including FinF)
FinMonad : RMonad FinF
FinMonad = trivRM FinF

-- TM is module for Fin Monad This is not exactly the same as the
TmModFin : Mod FinMonad
TmModFin = mod Tm ren (ext renid) (ext (rencomp _ _))

-- in fact, any suitable functor is a module over FinMonad
FModFin' : (F : Fun Nats Sets) →  Mod FinMonad
FModFin' F = ModF (\ h → h , refl) id F


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

open import Level
open import Data.Product
open import Relation.Binary using (Rel; IsEquivalence; Setoid)

open import Categories.Category
open import Categories.NaturalTransformation as NT hiding (_∘ʳ_)
open import Categories.Functor
open import Categories.Functor.Construction.Constant
open import Categories.Functor.Bifunctor
open import Categories.Category.Product
import Categories.Morphism.Reasoning as MR

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

record DinaturalTransformation (F G : Bifunctor (Category.op C) C D) : Set (levelOfTerm F) where
  eta-equality
  private
    module C = Category C
    module D = Category D
    module F = Functor F
    module G = Functor G

  open D hiding (op)
  open Commutation

  field
    α          : ∀ X → D [ F.F₀ (X , X) , G.F₀ (X , X) ]
    commute    : ∀ {X Y} (f : C [ X , Y ]) →
                [ F.F₀ (Y , X) ⇒ G.F₀ (X , Y) ]⟨
                  F.F₁ (f , C.id)             ⇒⟨ F.F₀ (X , X) ⟩
                  α X                         ⇒⟨ G.F₀ (X , X) ⟩
                  G.F₁ (C.id , f)
                ≈ F.F₁ (C.id , f)             ⇒⟨ F.F₀ (Y , Y) ⟩
                  α Y                         ⇒⟨ G.F₀ (Y , Y) ⟩
                  G.F₁ (f , C.id)
                ⟩
    -- We add this extra proof, because, again, we want to ensure the opposite of the
    -- opposite of dinatural transformation is definitionally equal to itself.
    op-commute : ∀ {X Y} (f : C [ X , Y ]) →
                [ F.F₀ (Y , X) ⇒ G.F₀ (X , Y) ]⟨
                  F.F₁ (C.id , f)             ⇒⟨ F.F₀ (Y , Y) ⟩
                  (α Y                         ⇒⟨ G.F₀ (Y , Y) ⟩
                  G.F₁ (f , C.id))
                ≈ F.F₁ (f , C.id)             ⇒⟨ F.F₀ (X , X) ⟩
                  (α X                         ⇒⟨ G.F₀ (X , X) ⟩
                  G.F₁ (C.id , f))
                ⟩

  op : DinaturalTransformation G.op F.op
  op = record
    { α          = α
    ; commute    = op-commute
    ; op-commute = commute
    }

-- to reduce the burden of constructing a DinaturalTransformation, we introduce
-- another helper.
record DTHelper (F G : Bifunctor (Category.op C) C D) : Set (levelOfTerm F) where
  private
    module C = Category C
    module D = Category D
    module F = Functor F
    module G = Functor G
  open D hiding (op)
  open Commutation

  field
    α          : ∀ X → D [ F.F₀ (X , X) , G.F₀ (X , X) ]
    commute    : ∀ {X Y} (f : C [ X , Y ]) →
                [ F.F₀ (Y , X) ⇒ G.F₀ (X , Y) ]⟨
                  F.F₁ (f , C.id)             ⇒⟨ F.F₀ (X , X) ⟩
                  α X                         ⇒⟨ G.F₀ (X , X) ⟩
                  G.F₁ (C.id , f)
                ≈ F.F₁ (C.id , f)             ⇒⟨ F.F₀ (Y , Y) ⟩
                  α Y                         ⇒⟨ G.F₀ (Y , Y) ⟩
                  G.F₁ (f , C.id)
                ⟩

dtHelper : ∀ {F G : Bifunctor (Category.op C) C D} → DTHelper F G → DinaturalTransformation F G
dtHelper {D = D} θ = record
  { α          = α
  ; commute    = commute
  ; op-commute = λ f → assoc ○ ⟺ (commute f) ○ sym-assoc
  }
  where open DTHelper θ
        open Category D
        open HomReasoning

module _ {F G H : Bifunctor (Category.op C) C D} where
  private
    module C = Category C
  open Category D
  open HomReasoning
  open Functor
  open MR D

  infixr 9 _<∘_
  infixl 9 _∘>_

  _<∘_ : NaturalTransformation G H → DinaturalTransformation F G → DinaturalTransformation F H
  θ <∘ β = dtHelper record
    { α       = λ X → η (X , X) ∘ α X
    ; commute = λ {X Y} f → begin
      F₁ H (C.id , f) ∘ (η (X , X) ∘ α X) ∘ F₁ F (f , C.id)   ≈˘⟨ pushˡ (pushˡ (θ.commute (C.id , f))) ⟩
      ((η (X , Y) ∘ F₁ G (C.id , f)) ∘ α X) ∘ F₁ F (f , C.id) ≈⟨ assoc ○ pullʳ (β.commute f) ⟩
      η (X , Y) ∘ F₁ G (f , C.id) ∘ α Y ∘ F₁ F (C.id , f)     ≈⟨ pullˡ (θ.commute (f , C.id)) ○ pullʳ (⟺ assoc) ⟩
      F₁ H (f , C.id) ∘ (η (Y , Y) ∘ α Y) ∘ F₁ F (C.id , f)   ∎
    }
    where module θ = NaturalTransformation θ
          module β = DinaturalTransformation β
          open θ
          open β

  _∘>_ : DinaturalTransformation G H → NaturalTransformation F G → DinaturalTransformation F H
  β ∘> θ = dtHelper record
    { α       = λ X → α X ∘ η (X , X)
    ; commute = λ {X Y} f → begin
      F₁ H (C.id , f) ∘ (α X ∘ η (X , X)) ∘ F₁ F (f , C.id) ≈⟨ refl⟩∘⟨ pullʳ (θ.commute (f , C.id)) ⟩
      F₁ H (C.id , f) ∘ α X ∘ F₁ G (f , C.id) ∘ η (Y , X)   ≈˘⟨ assoc ○ ∘-resp-≈ʳ assoc ⟩
      (F₁ H (C.id , f) ∘ α X ∘ F₁ G (f , C.id)) ∘ η (Y , X) ≈⟨ β.commute f ⟩∘⟨refl ⟩
      (F₁ H (f , C.id) ∘ α Y ∘ F₁ G (C.id , f)) ∘ η (Y , X) ≈˘⟨ pushʳ (assoc ○ pushʳ (θ.commute (C.id , f))) ⟩
      F₁ H (f , C.id) ∘ (α Y ∘ η (Y , Y)) ∘ F₁ F (C.id , f) ∎
    }
    where module θ = NaturalTransformation θ
          module β = DinaturalTransformation β
          open θ
          open β

module _ {F G : Bifunctor (Category.op C) C D} where
  private
    module C = Category C
  open Category D
  open HomReasoning
  open Functor
  open MR D

  infixl 9 _∘ʳ_

  _∘ʳ_ : ∀ {E : Category o ℓ e} →
           DinaturalTransformation F G → (K : Functor E C) → DinaturalTransformation (F ∘F ((Functor.op K) ⁂ K)) (G ∘F ((Functor.op K) ⁂ K))
  _∘ʳ_ {E = E} β K = dtHelper record
    { α       = λ X → α (F₀ K X)
    ; commute = λ {X Y} f → begin
      F₁ G (F₁ K E.id , F₁ K f) ∘ α (F₀ K X) ∘ F₁ F (F₁ K f , F₁ K E.id)
        ≈⟨ F-resp-≈ G (identity K , C.Equiv.refl) ⟩∘⟨ refl ⟩∘⟨ F-resp-≈ F (C.Equiv.refl , identity K) ⟩
      F₁ G (C.id , F₁ K f) ∘ α (F₀ K X) ∘ F₁ F (F₁ K f , C.id)
        ≈⟨ commute (F₁ K f) ⟩
      F₁ G (F₁ K f , C.id) ∘ α (F₀ K Y) ∘ F₁ F (C.id , F₁ K f)
        ≈˘⟨ F-resp-≈ G (C.Equiv.refl , identity K) ⟩∘⟨ refl ⟩∘⟨ F-resp-≈ F (identity K , C.Equiv.refl) ⟩
      F₁ G (F₁ K f , F₁ K E.id) ∘ α (F₀ K Y) ∘ F₁ F (F₁ K E.id , F₁ K f)
        ∎
    }
    where module β = DinaturalTransformation β
          module E = Category E
          open β

  infix 4 _≃_

  _≃_ : Rel (DinaturalTransformation F G) _
  β ≃ δ = ∀ {X} → α β X ≈ α δ X
    where open DinaturalTransformation

  ≃-isEquivalence : IsEquivalence _≃_
  ≃-isEquivalence = record
    { refl  = refl
    ; sym   = λ eq → sym eq
    ; trans = λ eq eq′ → trans eq eq′
    }

  ≃-setoid : Setoid _ _
  ≃-setoid = record
    { Carrier       = DinaturalTransformation F G
    ; _≈_           = _≃_
    ; isEquivalence = ≃-isEquivalence
    }

-- for convenience, the following are some helpers for the cases
-- in which the bifunctor on the right is extranatural.
Extranaturalʳ : ∀ {C : Category o ℓ e} → Category.Obj D → (F : Bifunctor (Category.op C) C D) → Set _
Extranaturalʳ A F = DinaturalTransformation (const A) F

Extranaturalˡ : ∀ {C : Category o ℓ e} → (F : Bifunctor (Category.op C) C D) → Category.Obj D → Set _
Extranaturalˡ F A = DinaturalTransformation F (const A)

module _ {F : Bifunctor (Category.op C) C D} where
  open Category D
  private
    module C = Category C
    variable
      A : Obj
      X Y : C.Obj
      f : X C.⇒ Y
  open Functor F
  open HomReasoning
  open MR D

  extranaturalʳ : (a : ∀ X → A ⇒ F₀ (X , X)) →
                  (∀ {X X′ f} → F₁ (C.id , f) ∘ a X ≈ F₁ (f , C.id) ∘ a X′) →
                  Extranaturalʳ A F
  extranaturalʳ a comm = dtHelper record
    { α       = a
    ; commute = λ f → ∘-resp-≈ʳ identityʳ ○ comm ○ ∘-resp-≈ʳ (⟺ identityʳ)
    }

  open DinaturalTransformation

  extranatural-commʳ : (β : DinaturalTransformation (const A) F) →
                       F₁ (C.id , f) ∘ α β X ≈ F₁ (f , C.id) ∘ α β Y
  extranatural-commʳ {f = f} β = ∘-resp-≈ʳ (⟺ identityʳ) ○ commute β f ○ ∘-resp-≈ʳ identityʳ

  -- the dual case, the bifunctor on the left is extranatural.

  extranaturalˡ : (a : ∀ X → F₀ (X , X) ⇒ A) →
                  (∀ {X X′ f} → a X ∘ F₁ (f , C.id) ≈ a X′ ∘ F₁ (C.id , f)) →
                  Extranaturalˡ F A
  extranaturalˡ a comm = dtHelper record
    { α       = a
    ; commute = λ f → pullˡ identityˡ ○ comm ○ ⟺ (pullˡ identityˡ)
    }

  extranatural-commˡ : (β : DinaturalTransformation F (const A)) →
                       α β X ∘ F₁ (f , C.id) ≈ α β Y ∘ F₁ (C.id , f)
  extranatural-commˡ {f = f} β = ⟺ (pullˡ identityˡ) ○ commute β f ○ pullˡ identityˡ


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

open import Relation.Binary
open import Prelude hiding (tt)

module Data.List.Sort.Sorted {e} {E : Type e} {r₁ r₂} (totalOrder : TotalOrder E r₁ r₂) where

open import Relation.Binary.Construct.LowerBound totalOrder

open TotalOrder totalOrder renaming (refl to refl-≤)
open TotalOrder lb-ord renaming (≤-trans to ⌊trans⌋) using ()

open import Data.List
open import Data.Unit.UniversePolymorphic as Poly using (tt)
open import Data.List.Relation.Binary.Permutation
open import Function.Isomorphism
open import Data.Fin
open import Data.List.Membership

private variable lb : ⌊∙⌋

Sorted-cons : E → (⌊∙⌋ → Type (r₁ ℓ⊔ r₂)) → ⌊∙⌋ → Type (r₁ ℓ⊔ r₂)
Sorted-cons x xs lb = (lb ⌊≤⌋ ⌊ x ⌋) × xs ⌊ x ⌋

SortedFrom : ⌊∙⌋ → List E → Type _
SortedFrom = flip (foldr Sorted-cons (const Poly.⊤))

Sorted : List E → Type _
Sorted = SortedFrom ⌊⊥⌋

ord-in : ∀ x xs → SortedFrom lb xs → x ∈ xs → lb ⌊≤⌋ ⌊ x ⌋
ord-in {lb = lb} x (x₁ ∷ xs) p (f0 , x∈xs) = subst (λ z → lb ⌊≤⌋ ⌊ z ⌋) x∈xs (p .fst)
ord-in {lb} x (y ∷ xs) p (fs n , x∈xs) = ⌊trans⌋ {lb} (p .fst) (ord-in x xs (p .snd) (n , x∈xs))

perm-head : ∀ {lbˣ lbʸ} x xs y ys → SortedFrom lbˣ (x ∷ xs) → SortedFrom lbʸ (y ∷ ys) → (x ∷ xs ↭ y ∷ ys) → x ≡ y
perm-head x xs y ys Sxs Sys xs⇔ys with xs⇔ys _ .inv (f0 , refl)
... | f0  , y∈xs = y∈xs
... | fs n , y∈xs with xs⇔ys _ .fun (f0 , refl)
... | f0  , x∈ys = sym x∈ys
... | fs m , x∈ys = antisym (ord-in y xs (Sxs .snd) (n , y∈xs)) (ord-in x ys (Sys .snd) (m , x∈ys))

perm-same : ∀ {lbˣ lbʸ} xs ys → SortedFrom lbˣ xs → SortedFrom lbʸ ys → xs ↭ ys → xs ≡ ys
perm-same [] [] Sxs Sys xs⇔ys = refl
perm-same [] (y ∷ ys) Sxs Sys xs⇔ys = ⊥-elim (xs⇔ys _ .inv (f0 , refl) .fst)
perm-same (x ∷ xs) [] Sxs Sys xs⇔ys = ⊥-elim (xs⇔ys _ .fun (f0 , refl) .fst)
perm-same {lbˣ} {lbʸ} (x ∷ xs) (y ∷ ys) Sxs Sys xs⇔ys =
  let h = perm-head {lbˣ} {lbʸ} x xs y ys Sxs Sys xs⇔ys
  in cong₂ _∷_ h
      (perm-same xs ys (Sxs .snd) (Sys .snd) (tailₚ x xs ys (subst (λ y′ → x ∷ xs ↭ y′ ∷ ys) (sym h) xs⇔ys)))

sorted-perm-eq : ∀ xs ys → Sorted xs → Sorted ys → xs ↭ ys → xs ≡ ys
sorted-perm-eq = perm-same


module Oscar.Category.Category where

open import Oscar.Category.Setoid
open import Oscar.Category.Semigroupoid
open import Oscar.Level

module _
  {𝔬 𝔪 𝔮}
  (semigroupoid : Semigroupoid 𝔬 𝔪 𝔮)
  where
  open Semigroupoid semigroupoid

  record IsCategory (ε : ∀ {x} → x ↦ x) : Set (𝔬 ⊔ 𝔪 ⊔ 𝔮) where
    instance _ = IsSetoid↦
    field
      left-identity : ∀ {x y} (f : x ↦ y) → ε ∙ f ≋ f
      right-identity : ∀ {x y} (f : x ↦ y) → f ∙ ε ≋ f

open IsCategory ⦃ … ⦄ public

record Category 𝔬 𝔪 𝔮 : Set (lsuc (𝔬 ⊔ 𝔪 ⊔ 𝔮)) where
  constructor _,_
  field
    semigroupoid : Semigroupoid 𝔬 𝔪 𝔮
  open Semigroupoid semigroupoid public

  field
    ε : ∀ {x} → x ↦ x
    ⦃ isCategory ⦄ : IsCategory semigroupoid ε
  open IsCategory isCategory public


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

open import Prelude
open import Algebra

module Data.Maybe.Monoid {ℓ} (sgr : Semigroup ℓ) where

open import Data.Maybe

open Semigroup sgr

_«∙»_ : Maybe 𝑆 → Maybe 𝑆 → Maybe 𝑆
nothing «∙» y = y
just x «∙» nothing = just x
just x «∙» just y = just (x ∙ y)

maybeMonoid : Monoid ℓ
maybeMonoid .Monoid.𝑆 = Maybe 𝑆
maybeMonoid .Monoid._∙_ = _«∙»_
maybeMonoid .Monoid.ε = nothing
maybeMonoid .Monoid.assoc nothing y z = refl
maybeMonoid .Monoid.assoc (just x) nothing z = refl
maybeMonoid .Monoid.assoc (just x) (just x₁) nothing = refl
maybeMonoid .Monoid.assoc (just x) (just y) (just z) = cong just (assoc x y z)
maybeMonoid .Monoid.ε∙ _ = refl
maybeMonoid .Monoid.∙ε nothing = refl
maybeMonoid .Monoid.∙ε (just x) = refl


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

open import Relation.Binary.PropositionalEquality using (refl)
open import Relation.Nullary using (yes)

open import Data.Unit using (⊤; tt)
open import Data.Product using (_,_)
open import Data.Sum using (inj₁)

open import PiCalculus.LinearTypeSystem.Algebras

module PiCalculus.LinearTypeSystem.Algebras.Shared where

pattern ω = tt

Shared : Algebra ⊤
Algebra.0∙ Shared = ω
Algebra.1∙ Shared = ω
Algebra._≔_∙_ Shared _ _ _ = ⊤
Algebra.∙-computeʳ Shared _ _ = yes (ω , tt)
Algebra.∙-unique Shared _ _ = refl
Algebra.∙-uniqueˡ Shared _ _ = refl
Algebra.0∙-minˡ Shared _ = refl
Algebra.∙-idˡ Shared = tt
Algebra.∙-comm Shared _ = tt
Algebra.∙-assoc Shared _ _ = ω , tt , tt


{-

Mapping cones or the homotopy cofiber/cokernel

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

module Cubical.HITs.MappingCones.Base where

open import Cubical.Foundations.Prelude

private
  variable
    ℓ ℓ' ℓ'' : Level

data Cone {X : Type ℓ} {Y : Type ℓ'} (f : X → Y) : Type (ℓ-max ℓ ℓ') where
  inj   : Y → Cone f
  hub   : Cone f
  spoke : (x : X) → hub ≡ inj (f x)

-- the attachment of multiple mapping cones

data Cones {X : Type ℓ} {Y : Type ℓ'} (A : Type ℓ'') (f : A → X → Y) : Type (ℓ-max (ℓ-max ℓ ℓ') ℓ'') where
  inj   : Y → Cones A f
  hub   : A → Cones A f
  spoke : (a : A) (x : X) → hub a ≡ inj (f a x)


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

open import Relation.Binary using (Rel; Setoid; IsEquivalence)
module Structures
  {a ℓ} {A : Set a}  -- The underlying set
  (_≈_ : Rel A ℓ)    -- The underlying equality relation
  where

open import Algebra.Core
open import Level using (_⊔_)
open import Data.Product using (_,_; proj₁; proj₂)
open import Algebra.Definitions _≈_
open import Algebra.Structures _≈_
open import Definitions _≈_

record IsInverseSemigroup (∙ : Op₂ A) : Set (a ⊔ ℓ) where
  field
    isSemigroup     : IsSemigroup ∙
    pseudoInverse   : PseudoInverse ∙

  open IsSemigroup isSemigroup public

record IsRng (+ * : Op₂ A) (-_ : Op₁ A) (0# : A) : Set (a ⊔ ℓ) where
  field
    +-isAbelianGroup : IsAbelianGroup + 0# -_
    *-isSemigroup    : IsSemigroup *
    distrib          : * DistributesOver +
    zero             : Zero 0# *

  open IsAbelianGroup +-isAbelianGroup public
    renaming
    ( assoc                   to +-assoc
    ; ∙-cong                  to +-cong
    ; ∙-congˡ                 to +-congˡ
    ; ∙-congʳ                 to +-congʳ
    ; identity                to +-identity
    ; identityˡ               to +-identityˡ
    ; identityʳ               to +-identityʳ
    ; inverse                 to -‿inverse
    ; inverseˡ                to -‿inverseˡ
    ; inverseʳ                to -‿inverseʳ
    ; ⁻¹-cong                 to -‿cong
    ; comm                    to +-comm
    ; isMagma                 to +-isMagma
    ; isSemigroup             to +-isSemigroup
    ; isMonoid                to +-isMonoid
    ; isUnitalMagma           to +-isUnitalMagma
    ; isCommutativeMagma      to +-isCommutativeMagma
    ; isCommutativeMonoid     to +-isCommutativeMonoid
    ; isCommutativeSemigroup  to +-isCommutativeSemigroup
    ; isInvertibleMagma       to +-isInvertibleMagma
    ; isInvertibleUnitalMagma to +-isInvertibleUnitalMagma
    ; isGroup                 to +-isGroup
    )

  open IsSemigroup *-isSemigroup public
    using ()
    renaming
    ( assoc    to *-assoc
    ; ∙-cong   to *-cong
    ; ∙-congˡ  to *-congˡ
    ; ∙-congʳ  to *-congʳ
    ; isMagma  to *-isMagma
    )

record IsNonAssociativeRing (+ * : Op₂ A) (-_ : Op₁ A) (0# 1# : A) : Set (a ⊔ ℓ) where
  field
    +-isAbelianGroup : IsAbelianGroup + 0# -_
    *-isUnitalMagma  : IsUnitalMagma * 1#
    distrib          : * DistributesOver +
    zero             : Zero 0# *

  open IsAbelianGroup +-isAbelianGroup public
    renaming
    ( assoc                   to +-assoc
    ; ∙-cong                  to +-cong
    ; ∙-congˡ                 to +-congˡ
    ; ∙-congʳ                 to +-congʳ
    ; identity                to +-identity
    ; identityˡ               to +-identityˡ
    ; identityʳ               to +-identityʳ
    ; inverse                 to -‿inverse
    ; inverseˡ                to -‿inverseˡ
    ; inverseʳ                to -‿inverseʳ
    ; ⁻¹-cong                 to -‿cong
    ; comm                    to +-comm
    ; isMagma                 to +-isMagma
    ; isSemigroup             to +-isSemigroup
    ; isMonoid                to +-isMonoid
    ; isUnitalMagma           to +-isUnitalMagma
    ; isCommutativeMagma      to +-isCommutativeMagma
    ; isCommutativeMonoid     to +-isCommutativeMonoid
    ; isCommutativeSemigroup  to +-isCommutativeSemigroup
    ; isInvertibleMagma       to +-isInvertibleMagma
    ; isInvertibleUnitalMagma to +-isInvertibleUnitalMagma
    ; isGroup                 to +-isGroup
    )
  open IsUnitalMagma *-isUnitalMagma public
    using ()
    renaming
    ( ∙-cong   to *-cong
    ; ∙-congˡ  to *-congˡ
    ; ∙-congʳ  to *-congʳ
    ; isMagma  to *-isMagma
    )


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

open import Base

open import Homotopy.PushoutDef

module Homotopy.PushoutIsPushout {i} (d : pushout-diag i) where

import Homotopy.PushoutUP as PushoutUP
open PushoutUP d (λ _ → unit) -- A B C f g (λ _ → unit)

pushout-cocone : cocone (pushout d)
pushout-cocone = (left , right , glue)

factor-pushout : (E : Set i) → (cocone E → (pushout d → E))
factor-pushout E (A→top , B→top , h) = pushout-rec-nondep E A→top B→top h

abstract
  pushout-is-pushout : is-pushout (pushout d) pushout-cocone
  pushout-is-pushout E ⦃ tt ⦄ = iso-is-eq _ (factor-pushout E)
    (λ y → ap (λ u → _ , _ , u)
               (funext (λ x → pushout-β-glue-nondep E (cocone.A→top y)
                                    (cocone.B→top y) (cocone.h y) x)))
    (λ f → funext (pushout-rec _ (λ _ → refl) (λ _ → refl)
      (λ c → trans-app≡app
             (pushout-rec-nondep E (f ◯ left) (f ◯ right)
              (λ c' → ap f (glue c')))
             f (glue c) refl
             ∘ (ap (λ u → ! u ∘ ap f (glue c))
                  (pushout-β-glue-nondep E (f ◯ left) (f ◯ right)
                   (λ c' → ap f (glue c')) c)
                  ∘ opposite-left-inverse (ap f (glue c))))))


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

open import Setoids.Setoids
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Numbers.Naturals.Semiring
open import Sets.Cardinality.Finite.Definition
open import Groups.Definition

module Groups.FiniteGroups.Definition where

record FiniteGroup {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_·_ : A → A → A} (G : Group S _·_) {c : _} (quotientSet : Set c) : Set (a ⊔ b ⊔ c) where
  field
    toSet : SetoidToSet S quotientSet
    finite : FiniteSet quotientSet

groupOrder : {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_·_ : A → A → A} {underG : Group S _·_} {c : _} {quotientSet : Set c} (G : FiniteGroup underG quotientSet) → ℕ
groupOrder record { toSet = toSet ; finite = record { size = size ; mapping = mapping ; bij = bij } } = size


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

open import Functions.Definition
open import Orders.WellFounded.Definition

module Orders.WellFounded.Induction {a b : _} {A : Set a} {_<_ : Rel {a} {b} A} (wf : WellFounded _<_) where

private
  foldAcc :
    {c : _}
    (P : A → Set c) →
    (∀ x → (∀ y → y < x → P y) → P x) →
    ∀ z → Accessible _<_ z →
    P z
  foldAcc P inductionProof = go
    where
      go : (z : A) → (Accessible _<_ z) → P z
      go z (access prf) = inductionProof z (λ y yLessZ → go y (prf y yLessZ))

rec :
  {c : _}
  (P : A → Set c) →
  (∀ x → (∀ y → y < x → P y) → P x) → (∀ z → P z)
rec P inductionProof z = foldAcc P inductionProof _ (wf z)


module Integer where

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

data ℤ₃ : Set where
  ℤ₊ : ℕ → ℤ₃
  ℤ₀ : ℤ₃
  ℤ₋ : ℕ → ℤ₃

ℤ₊-injective : ∀ {m n} → ℤ₊ m ≡ ℤ₊ n → m ≡ n
ℤ₊-injective refl = refl

ℤ₋-injective : ∀ {m n} → ℤ₋ m ≡ ℤ₋ n → m ≡ n
ℤ₋-injective refl = refl

data ℕ² : Set where
  _─_ : ℕ → ℕ → ℕ²

ℕ²-≡₊ : ∀ {a₊ a₋ b₊ b₋} → (a₊ ─ a₋) ≡ (b₊ ─ b₋) → a₊ ≡ b₊
ℕ²-≡₊ refl = refl

ℕ²-≡₋ : ∀ {a₊ a₋ b₊ b₋} → (a₊ ─ a₋) ≡ (b₊ ─ b₋) → a₋ ≡ b₋
ℕ²-≡₋ refl = refl

toℕ² : ℤ₃ → ℕ²
toℕ² (ℤ₊ n) = suc n ─ zero
toℕ² ℤ₀ = zero ─ zero
toℕ² (ℤ₋ n) = zero ─ suc n

toℤ₃ : ℕ² → ℤ₃
toℤ₃ (zero ─ zero) = ℤ₀
toℤ₃ (zero ─ suc n₋) = ℤ₋ n₋
toℤ₃ (suc n₊ ─ zero) = ℤ₊ n₊
toℤ₃ (suc n₊ ─ suc n₋) = toℤ₃ (n₊ ─ n₋)

data Dec (A : Set) : Set where
  yes : A → Dec A
  no : (A → ⊥) → Dec A

ℕ≡? : (m n : ℕ) → Dec (m ≡ n)
ℕ≡? zero zero = yes refl
ℕ≡? zero (suc n) = no (λ ())
ℕ≡? (suc m) zero = no (λ ())
ℕ≡? (suc m) (suc n) with ℕ≡? m n
... | yes m≡n = yes (cong suc m≡n)
... | no ¬m≡n = no λ sm≡sn → ¬m≡n (suc-injective sm≡sn)

ℤ₃≡? : (a b : ℤ₃) → Dec (a ≡ b)
ℤ₃≡? (ℤ₊ m) (ℤ₊ n) with ℕ≡? m n
... | yes m≡n = yes (cong ℤ₊ m≡n)
... | no ¬m≡n = no λ ℤ₊m≡ℤ₊n → ¬m≡n (ℤ₊-injective ℤ₊m≡ℤ₊n)
ℤ₃≡? (ℤ₊ _) ℤ₀ = no (λ ())
ℤ₃≡? (ℤ₊ _) (ℤ₋ _) = no (λ ())
ℤ₃≡? ℤ₀ (ℤ₊ _) = no (λ ())
ℤ₃≡? ℤ₀ ℤ₀ = yes refl
ℤ₃≡? ℤ₀ (ℤ₋ _) = no (λ ())
ℤ₃≡? (ℤ₋ _) (ℤ₊ _) = no (λ ())
ℤ₃≡? (ℤ₋ _) ℤ₀ = no (λ ())
ℤ₃≡? (ℤ₋ m) (ℤ₋ n) with ℕ≡? m n
... | yes m≡n = yes (cong ℤ₋ m≡n)
... | no ¬m≡n = no λ ℤ₋m≡ℤ₋n → ¬m≡n (ℤ₋-injective ℤ₋m≡ℤ₋n)

ℕ²≡? : (a b : ℕ²) → Dec (a ≡ b)
ℕ²≡? (a₊ ─ a₋) (b₊ ─ b₋) with ℕ≡? a₊ b₊
ℕ²≡? (a₊ ─ a₋) (b₊ ─ b₋) | yes refl with ℕ≡? a₋ b₋
ℕ²≡? (a₊ ─ a₋) (b₊ ─ b₋) | yes refl | yes refl =
  yes refl
ℕ²≡? (a₊ ─ a₋) (b₊ ─ b₋) | yes refl | no ¬a₋≡b₋ =
  no (λ a≡b → ¬a₋≡b₋ (ℕ²-≡₋ a≡b))
ℕ²≡? (a₊ ─ a₋) (b₊ ─ b₋) | no ¬a₊≡b₊ =
  no λ a≡b → ¬a₊≡b₊ (ℕ²-≡₊ a≡b)

_≃_ : ℕ² → ℕ² → Set
(a₊ ─ a₋) ≃ (b₊ ─ b₋) = a₊ + b₋ ≡ a₋ + b₊

≃? : (a b : ℕ²) → Dec (a ≃ b)
≃? (a₊ ─ a₋) (b₊ ─ b₋) = ℕ≡? (a₊ + b₋) (a₋ + b₊)

_+₂_ : ℕ² → ℕ² → ℕ²
(a₊ ─ a₋) +₂ (b₊ ─ b₋) = (a₊ + b₊) ─ (a₋ + b₋)

{-
≃-cong : {A : Set} {a b : ℕ²} (f : ℕ² → ℕ²) → a ≃ b → f a ≃ f b
≃-cong f a≃b = {!!}
-}

drop-neg : ℕ² → ℕ²
drop-neg (a₊ ─ _) = (a₊ ─ zero)

3-5≃2-4 : (3 ─ 5) ≃ (2 ─ 4)
3-5≃2-4 = refl

_+₃_ : ℤ₃ → ℤ₃ → ℤ₃
a +₃ b = toℤ₃ (toℕ² a +₂ toℕ² b)


module agdaFunction where

addOne : N -> N
addOne Z = suc Z
addOne (suc a) = suc (suc a)


module Acc where

data Acc ( A : Set ) ( Lt : A -> A -> Set) : A -> Set where
  acc :    (   b : A )
        -> ( ( a : A ) -> Lt a b  ->  Acc A Lt a )
        -> ( Acc A Lt b )

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

data Lt : Nat -> Nat -> Set where
  ltzero : ( x : Nat ) -> Lt zero (succ x)
  ltsucc : ( x : Nat ) -> (y : Nat) -> Lt x y -> Lt (succ x) (succ y)

ltcase : ( x : Nat ) -> ( y : Nat ) -> Lt x (succ y) ->
         ( P : Nat -> Set ) -> ( (x' : Nat ) -> Lt x' y -> P x') -> P y -> P x
ltcase zero zero      _ P hx' hy = hy
ltcase zero (succ y') _ P hx' hy = hx' zero (ltzero y')
ltcase (succ x') zero (ltsucc .x' .zero ()) _ _ _
ltcase (succ x') (succ y') (ltsucc ._ ._ p) P hx' hy =
  ltcase x' y' p (\ n -> P (succ n))
    (\ x'' p' -> hx' (succ x'') (ltsucc _ _ p')) hy

accSucc : (x : Nat) -> Acc Nat Lt x -> Acc Nat Lt (succ x)
accSucc x a@(acc .x h) = acc (succ x) (\ y p -> ltcase y x p (Acc Nat Lt) h a)


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

open import Rings.Definition
open import Rings.Orders.Partial.Definition
open import Setoids.Setoids
open import Setoids.Orders.Partial.Definition
open import Functions.Definition
open import Fields.Fields

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

module Fields.Orders.Partial.Definition {m n : _} {A : Set m} {S : Setoid {m} {n} A} {_+_ : A → A → A} {_*_ : A → A → A} {R : Ring S _+_ _*_} (F : Field R) where

open Ring R

record PartiallyOrderedField {p} {_<_ : Rel {_} {p} A} (pOrder : SetoidPartialOrder S _<_) : Set (lsuc (m ⊔ n ⊔ p)) where
  field
    oRing : PartiallyOrderedRing R pOrder


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

open import Groups.Definition
open import Setoids.Setoids
open import Sets.EquivalenceRelations
open import Groups.Subgroups.Normal.Definition

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

open import Groups.Subgroups.Examples G
open Setoid S
open Equivalence eq
open Group G

trivialSubgroupIsNormal : normalSubgroup G trivialSubgroup
trivialSubgroupIsNormal {g} k=0 = transitive (+WellDefined reflexive (transitive (+WellDefined k=0 reflexive) identLeft)) (invRight {g})

improperSubgroupIsNormal : normalSubgroup G improperSubgroup
improperSubgroupIsNormal _ = record {}


module hello-world-dep where

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

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

infixr 5 _∷_


import Data.Empty
import Data.Unit
import Data.Bool
import Data.Nat
import Data.Fin

module SecondOrder.Arity where

  -- A notion of arity is given by a set of possible arities, and a mapping which to each arity assings a set of
  -- argument positions.

  record Arity : Set₁ where
    field
      arity : Set -- the set of permissible arities, e.g., ℕ for finitary arities
      arg : arity → Set -- every arity gives a set of argument (position), e.g. Fin

  -- finitary arities
  arity-finite : Arity
  arity-finite = record { arity = Data.Nat.ℕ ; arg = Data.Fin.Fin }

  module Arity012 where
    -- For example, in algebra we quite often only consider constants, unary and binary
    -- operations. Thus we would only need three arities.

    data arity012 : Set where
      Constant Unary Binary : arity012

    arg012 : arity012 → Set
    arg012 Constant = Data.Empty.⊥
    arg012 Unary = Data.Unit.⊤
    arg012 Binary = Data.Bool.Bool

    arity-012 : Arity
    arity-012 = record { arity =  arity012 ; arg = arg012 }


module Sandbox.IndRec where
-- Ornamental Algebras, Algebraic Ornaments, CONOR McBRIDE
-- https://personal.cis.strath.ac.uk/conor.mcbride/pub/OAAO/Ornament.pdf
-- A Finite Axiomtization of Inductive-Recursion definitions, Peter Dybjer, Anton Setzer
-- http://www.cse.chalmers.se/~peterd/papers/Finite_IR.pdf

open import Data.Product using (_×_; Σ; _,_)
open import Data.Bool
open import Data.Unit
open import Data.Empty
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

data Desc : Set₁ where
    arg : (A : Set)             -- a bag of tags to choose constructors with
        → (A → Desc)            -- given a tag, return the description of the constructor it corresponds to
        → Desc
    rec : Desc → Desc           -- recursive subnode
    ret : Desc                  -- stop

-- the "decoder", "interpreter"
⟦_⟧ : Desc → Set → Set
⟦ arg A D ⟧ R = Σ A (λ a → ⟦ D a ⟧ R)
⟦ rec D   ⟧ R = R × ⟦ D ⟧ R
⟦ ret     ⟧ R = ⊤

-- "μ" in some other literature
data Data (D : Desc) : Set where
    ⟨_⟩ : ⟦ D ⟧ (Data D) → Data D   -- or "in"

out : ∀ {D} → Data D → ⟦ D ⟧ (Data D)
out ⟨ x ⟩ = x

map : ∀ {A B} → (d : Desc) → (A → B) → ⟦ d ⟧ A → ⟦ d ⟧ B
map (arg A  d) f (a , y) = a , (map (d a) f y)
map (rec desc) f (a , x) = (f a) , (map desc f x)
map (ret) f tt = tt

-- fold : ∀ {A} → (F : Desc) → (⟦ F ⟧ A → A) → Data F → A
-- fold F alg ⟨ x ⟩ = alg (map F (fold F alg) x)

-- mapFold F alg x = map F (fold F alg) x
-- fold F alg x = alg (mapFold F alg (out x))
-- mapFold F alg x = map F (λ y → alg (mapFold F alg (out y))) x

mapFold : ∀ {A} (F G : Desc) → (⟦ G ⟧ A → A) → ⟦ F ⟧ (Data G) → ⟦ F ⟧ A
mapFold (arg T decoder) G alg (t , cnstrctr) = t , (mapFold (decoder t) G alg cnstrctr)
mapFold (rec F) G alg (⟨ x ⟩ , xs) = alg (mapFold G G alg x) , mapFold F G alg xs
mapFold ret G alg x = tt

fold : ∀ {A} → (F : Desc) → (⟦ F ⟧ A → A) → Data F → A
fold F alg ⟨ x ⟩ = alg (mapFold F F alg x)

-- ℕ
ℕDesc : Desc
ℕDesc = arg Bool λ { false → ret
                    ; true → rec ret }

ℕ : Set
ℕ = Data ℕDesc

zero : ℕ
zero = ⟨ (false , tt) ⟩

suc : ℕ → ℕ
suc n = ⟨ (true , (n , tt)) ⟩

-- induction principle on ℕ
indℕ : (P : ℕ → Set)
     → (P zero)
     → ((n : ℕ) → (P n) → (P (suc n)))
     → (x : ℕ)
     → P x
indℕ P base step ⟨ true , n-1 , _ ⟩ = step n-1 (indℕ P base step n-1)
indℕ P base step ⟨ false , _ ⟩ = base

_+_ : ℕ → ℕ → ℕ
x + y = indℕ (λ _ → ℕ) y (λ n x → suc x) x

-- Maybe
MaybeDesc : Set → Desc
MaybeDesc A = arg Bool (λ { false → ret ; true → arg A (λ x → ret) })

Maybe : Set → Set
Maybe A = Data (MaybeDesc A)

nothing : ∀ {A} → Maybe A
nothing = ⟨ (false , tt) ⟩

just : ∀ {A} → A → Maybe A
just a = ⟨ (true , (a , tt)) ⟩

mapMaybe : ∀ {A B} → (A → B) → Maybe A → Maybe B
mapMaybe f ⟨ true , a , tt ⟩ = ⟨ (true , ((f a) , tt)) ⟩
mapMaybe f ⟨ false , tt ⟩ = ⟨ false , tt ⟩

-- List
ListDesc : Set → Desc
ListDesc A = arg Bool (λ { false → ret ; true → arg A (λ _ → rec ret )})

List : Set → Set
List A = Data (ListDesc A)

nil : ∀ {A} → List A
nil = ⟨ (false , tt) ⟩

cons : ∀ {A} → A → List A → List A
cons x xs = ⟨ (true , (x , (xs , tt))) ⟩

foldList : ∀ {A B} (f : A → B → B) → B → List A → B
foldList {A} {B} f e xs = fold (ListDesc A) alg xs
    where   alg : ⟦ ListDesc A ⟧ B → B
            alg (true , n , acc , tt) = f n acc
            alg (false , tt) = e


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Data.Int.Base where

open import Cubical.Core.Everything

open import Cubical.Data.Nat

data Int : Type₀ where
  pos    : (n : ℕ) → Int
  negsuc : (n : ℕ) → Int

neg : (n : ℕ) → Int
neg zero = pos zero
neg (suc n) = negsuc n

sucInt : Int → Int
sucInt (pos n)          = pos (suc n)
sucInt (negsuc zero)    = pos zero
sucInt (negsuc (suc n)) = negsuc n

predInt : Int → Int
predInt (pos zero)    = negsuc zero
predInt (pos (suc n)) = pos n
predInt (negsuc n)    = negsuc (suc n)

-- Natural number and negative integer literals for Int

open import Cubical.Data.Nat.Literals public

instance
  fromNatInt : HasFromNat Int
  fromNatInt = record { Constraint = λ _ → Unit ; fromNat = λ n → pos n }

instance
  fromNegInt : HasFromNeg Int
  fromNegInt = record { Constraint = λ _ → Unit ; fromNeg = λ n → neg n }


-- Andreas, 2015-03-26

-- Andrea discovered that unfold for Lists is typable with sized types
-- (and termination checks).
-- Dually, fold for Streams should work.  Therefore, the restriction
-- of coinductive records to recursive records should be lifted.

{-# OPTIONS --copatterns #-}

open import Common.Size

-- StreamF A X i = ∀j<i. A × X j
record StreamF (A : Set) (X : Size → Set) (i : Size) : Set where
  coinductive
  field
    head : A
    tail : ∀{j : Size< i} → X j
module F = StreamF

record Stream (A : Set) (i : Size) : Set where
  coinductive
  field
    head : A
    tail : ∀{j : Size< i} → Stream A j
module S = Stream

module Inlined {A T} (f : ∀ i → StreamF A T i → T i) where

  fix : ∀ i → Stream A i → StreamF A T i
  F.head (fix i s)         = S.head s
  F.tail (fix i s) {j = j} = f j (fix j (S.tail s {j = j}))

module Mutual {A T} (f : ∀ i → StreamF A T i → T i) where

 mutual

  fold : ∀ i → Stream A i → T i
  fold i s = f i (h i s)

  h : ∀ i → Stream A i → StreamF A T i
  F.head (h i s) = S.head s
  F.tail (h i s) {j = j} = fold j (S.tail s {j = j})

module Local where

  fold : ∀{A T}
    → (f : ∀ i → StreamF A T i → T i)
    → ∀ i → Stream A i → T i
  fold {A} {T} f i s = f i (h i s)
    where
      h : ∀ i → Stream A i → StreamF A T i
      F.head (h i s) = S.head s
      F.tail (h i s) {j = j} = fold f j (S.tail s {j = j})

-- Unfold for lists

-- ListF A X i = ⊤ + ∃j<i. A × X j
data ListF (A : Set) (X : Size → Set) (i : Size) : Set where
  []  : ListF A X i
  _∷_ : ∀{j : Size< i} (a : A) (xs : X j) → ListF A X i

data List (A : Set) (i : Size) : Set where
  []  : List A i
  _∷_ : ∀{j : Size< i} (a : A) (xs : List A j) → List A i

module With where

  unfold : ∀{A}{S : Size → Set}
    → (f : ∀ i → S i → ListF A S i)
    → ∀ i → S i → List A i
  unfold f i s with f i s
  ... | [] = []
  ... | _∷_ {j = j} a s' = a ∷ unfold f j s'

unfold : ∀{A}{S : Size → Set}
  → (f : ∀ i → S i → ListF A S i)
  → ∀ i → S i → List A i
unfold {A}{S} f i s = aux (f i s)
  where
    aux : ListF A S i → List A i
    aux [] = []
    aux (_∷_ {j = j} a s') = a ∷ unfold f j s'


module Oscar.Data.Vec.Properties where

open import Oscar.Data.Vec
open import Data.Vec.Properties public

open import Data.Nat
open import Data.Product renaming (map to mapP)
open import Relation.Binary.PropositionalEquality
open import Data.Fin

map-∈ : ∀ {a b} {A : Set a} {B : Set b} {y : B} {f : A → B} {n} {xs : Vec A n} → y ∈ map f xs → ∃ λ x → f x ≡ y
map-∈ {xs = []} ()
map-∈ {xs = x ∷ xs} here = x , refl
map-∈ {xs = x ∷ xs} (there y∈mapfxs) = map-∈ y∈mapfxs

∈-map₂ : ∀ {a b} {A : Set a} {B : Set b} {m n : ℕ}
             → ∀ {c} {F : Set c} (f : A → B → F)
             {xs : Vec A m} {ys : Vec B n}
             {x y} → x ∈ xs → y ∈ ys → (f x y) ∈ map₂ f xs ys
∈-map₂ f {xs = x ∷ xs} {ys} here         y∈ys =
  ∈-++ₗ (∈-map (f x) y∈ys)
∈-map₂ f {xs = x ∷ xs} {ys} (there x∈xs) y∈ys =
  ∈-++ᵣ (map (f x) ys) (∈-map₂ f x∈xs y∈ys)

lookup-delete-thin : ∀ {a n} {A : Set a} (x : Fin (suc n)) (y : Fin n) (v : Vec A (suc n)) →
                     lookup y (delete x v) ≡ lookup (thin x y) v
lookup-delete-thin zero zero (_ ∷ _) = refl
lookup-delete-thin zero (suc _) (_ ∷ _) = refl
lookup-delete-thin (suc _) zero (_ ∷ _) = refl
lookup-delete-thin (suc x) (suc y) (_ ∷ v) = lookup-delete-thin x y v


------------------------------------------------------------------------
-- The Agda standard library
--
-- Existential lifting of predicates over Vectors
------------------------------------------------------------------------

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

module Data.Vec.Functional.Relation.Unary.Any where

open import Data.Fin.Base
open import Data.Fin.Properties
open import Data.Nat.Base
open import Data.Product as Σ using (Σ; ∃; _×_; _,_; proj₁; proj₂)
open import Data.Vec.Functional as VF hiding (map)
open import Function
open import Level using (Level)
open import Relation.Unary

private
  variable
    a b p q ℓ : Level
    A : Set a
    B : Set b

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

Any : Pred A ℓ → ∀ {n} → Vector A n → Set ℓ
Any P xs = ∃ λ i → P (xs i)

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

module _ {P : Pred A p} where

  here : ∀ {x n} {v : Vector A n} → P x → Any P (x ∷ v)
  here px = zero , px

  there : ∀ {x n} {v : Vector A n} → Any P v → Any P (x ∷ v)
  there = Σ.map suc id

module _ {P : Pred A p} {Q : Pred A q} where

  map : P ⊆ Q → ∀ {n} → Any P {n = n} ⊆ Any Q
  map p⊆q = Σ.map id p⊆q

------------------------------------------------------------------------
-- Properties of predicates preserved by Any

module _ {P : Pred A p} where

  any : Decidable P → ∀ {n} → Decidable (Any P {n = n})
  any p? xs = any? λ i → p? (xs i)


{-# OPTIONS --cubical --no-import-sorts --allow-unsolved-metas #-}

open import Cubical.Foundations.Everything renaming (_⁻¹ to _⁻¹ᵖ; assoc to ∙-assoc)

open import Cubical.Relation.Nullary.Base -- ¬_
open import Cubical.Relation.Binary.Base -- Rel
open import Cubical.Data.Sigma.Base renaming (_×_ to infixr 4 _×_)
open import Cubical.Data.Empty renaming (elim to ⊥-elim) -- `⊥` and `elim`
open import Function.Base using (_$_)

open import Cubical.Data.Nat hiding (min)
open import Cubical.Data.Nat.Order
-- open import Cubical.Data.Nat.Properties -- using (+-suc; injSuc; snotz; +-comm; +-assoc; +-zero; inj-m+)

open import MoreNatProperties

module Enumeration
  {ℓ}
  {A   : Type ℓ}
  (f   : A → ℕ)
  (f⁻¹ : ℕ → A)
  (isRetraction : ∀ x → f⁻¹ (f x) ≡ x)
  where

_≤'_ : Rel A A ℓ-zero
a ≤' b = (f a) ≤ (f b)

min' : A → A → A
min' a b = f⁻¹ (min (f a) (f b))

max' : A → A → A
max' a b = f⁻¹ (max (f a) (f b))

max'-sym : ∀ a b → max' a b ≡ max' b a
max'-sym a b with f a ≟ f b | f b ≟ f a
... | lt x | lt y = ⊥-elim {A = λ _ → f⁻¹ (f b) ≡ f⁻¹ (f a)} $  <-asymʷ _ _ x y
... | lt x | eq y = refl
... | lt x | gt y = refl
... | eq x | lt y = refl
... | eq x | eq y = cong f⁻¹ x
... | eq x | gt y = cong f⁻¹ x
... | gt x | lt y = refl
... | gt x | eq y = sym (cong f⁻¹ y)
... | gt x | gt y = ⊥-elim {A = λ _ → f⁻¹ (f a) ≡ f⁻¹ (f b)} $  <-asymʷ _ _ x y

max'-implies-≤'₁ : ∀ a b → a ≤' max' a b
max'-implies-≤'₁ a b with (f a) ≟ (f b)
... | lt (x , p) =  suc x ,  sym (+-suc _ _)  ∙ p ∙ cong f (sym (isRetraction b))
... | eq x = 0 , sym (cong f (isRetraction a) ∙ refl {x = f a})
... | gt x = 0 , sym (cong f (isRetraction a) ∙ refl {x = f a})

max-implies-≤' : ∀ a b → (a ≤' max' a b) × (b ≤' max' a b)
max-implies-≤' a b = max'-implies-≤'₁ a b , transport (λ i → b ≤' max'-sym b a i) (max'-implies-≤'₁ b a)

min'-sym : ∀ a b → min' a b ≡ min' b a
min'-sym a b with f a ≟ f b | f b ≟ f a
... | lt x | lt y = ⊥-elim {A = λ _ → f⁻¹ (f a) ≡ f⁻¹ (f b)} $  <-asymʷ _ _ x y
... | lt x | eq y = sym (cong f⁻¹ y)
... | lt x | gt y = refl
... | eq x | lt y = cong f⁻¹ x
... | eq x | eq y = cong f⁻¹ x
... | eq x | gt y = refl
... | gt x | lt y = refl
... | gt x | eq y = refl
... | gt x | gt y = ⊥-elim {A = λ _ → f⁻¹ (f b) ≡ f⁻¹ (f a)} $  <-asymʷ _ _ x y

min'-implies-≤'₁ : ∀ a b → min' a b ≤' a
min'-implies-≤'₁ a b with (f a) ≟ (f b)
... | lt x = 0 , cong f (isRetraction a) ∙ refl {x = f a}
... | eq x = 0 , cong f (isRetraction a) ∙ refl {x = f a}
... | gt (x , p) = suc x , (λ i → suc (x + cong f (sym (isRetraction b)) (~ i))) ∙ sym (+-suc _ _) ∙ p

min-implies-≤' : ∀ a b → (min' a b ≤' a) × (min' a b ≤' b)
min-implies-≤' a b = min'-implies-≤'₁ a b , transport (λ i → min'-sym b a i ≤' b) (min'-implies-≤'₁ b a)


open import Data.Product using ( ∃ ; _×_ )
open import FRP.LTL.RSet.Core using ( RSet ; _[_,_] ; ⟦_⟧ )
open import FRP.LTL.RSet.Stateless using ( _⇒_ )
open import FRP.LTL.RSet.Globally using ( □ ; [_] )
open import FRP.LTL.Time using ( _≤_ ; ≤-refl ; _≤-trans_ )

module FRP.LTL.RSet.Causal where

infixr 2 _⊵_
infixr 3 _⋙_

-- A ⊵ B is the causal function space from A to B

_⊵_ : RSet → RSet → RSet
(A ⊵ B) t = ∀ {u} → (t ≤ u) → (A [ t , u ]) → B u

-- Categorical structure

arr : ∀ {A B} → ⟦ □ (A ⇒ B) ⇒ (A ⊵ B) ⟧
arr f s≤t σ = f s≤t (σ s≤t ≤-refl)

identity : ∀ {A} → ⟦ A ⊵ A ⟧
identity {A} = arr [( λ {u} (a : A u) → a )]

_before_ : ∀ {A s u v} → (A [ s , v ]) → (u ≤ v) → (A [ s , u ])
(σ before u≤v) s≤t t≤u = σ s≤t (t≤u ≤-trans u≤v)

_after_ : ∀ {A s t v} → (A [ s , v ]) → (s ≤ t) → (A [ t , v ])
(σ after s≤t) t≤u u≤v = σ (s≤t ≤-trans t≤u) u≤v

_$_ : ∀ {A B s u} → (A ⊵ B) s → (A [ s , u ]) → (B [ s , u ])
(f $ σ) s≤t t≤u = f s≤t (σ before t≤u)

_⋙_ : ∀ {A B C} → ⟦ (A ⊵ B) ⇒ (B ⊵ C) ⇒ (A ⊵ C) ⟧
(f ⋙ g) s≤t σ = g s≤t (f $ σ)


module Ag05 where

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

{-
data _≡_ {A : Set} (x : A) : A → Set where
  refl : x ≡ x
-}
data Refine : (A : Set) → (A → Set) → Set where
  MkRefine : ∀ {A : Set} {f : A → Set} → (a : A) → (f a) → Refine A f

data _∧_ : Set → Set → Set where
  and : ∀ (A B : Set) → A ∧ B

-- hl-suc : ∀ {a : Nat} → Refine Nat (λ )

silly : Set
silly = Refine Nat (_≡_ 0)

sillySon : silly
sillySon = MkRefine zero refl

data _≤_ : Nat → Nat → Set where
  z≤s : ∀ {b   : Nat} → 0 ≤ b
  s≤s : ∀ {m n : Nat} → m ≤ n → suc m ≤ suc n

data le-Total (x y : Nat) : Set where
  le-left  : x ≤ y → le-Total x y
  le-right : y ≤ x → le-Total x y

le : Nat → Nat → Bool
le zero    zero    = true
le zero    (suc n) = true
le (suc m) zero    = false
le (suc m) (suc n) = le m n

le-wtf : ∀ (x y : Nat) → le-Total x y
le-wtf zero    zero    = le-left z≤s
le-wtf zero    (suc y) = le-left z≤s
le-wtf (suc x) zero    = le-right z≤s
le-wtf (suc x) (suc y) with le-wtf x y
...                    | le-left  P = le-left  (s≤s P)
...                    | le-right Q = le-right (s≤s Q)
{- with le x y -- x ≤ y
...        | true  = {!!}
...        | false = {!!}
-}
_⟨_⟩ : (A : Set) → (A → Set) → Set
_⟨_⟩ = Refine

and-refine : ∀ {A : Set} (f g : A → Set)
           → (a : A) → f a → g a
           → Refine A (λ x → (f x) ∧ (g x))
and-refine f g x Pa Pb = MkRefine x (and (f x) (g x))

hSuc : ∀ {m : Nat} → ( Nat ⟨ (λ x → x ≤ m     ) ⟩ )
                   → ( Nat ⟨ (λ x → x ≤ suc m ) ⟩ )
hSuc (MkRefine a P) = MkRefine (suc a) (s≤s P)

postulate
  ≤-trans : ∀ {x y z : Nat} → x ≤ y → y ≤ z → x ≤ z

min : ∀ {m n : Nat} → ( Nat ⟨ (λ x → x ≤ m)             ⟩ )
                    → ( Nat ⟨ (λ x → x ≤ n)             ⟩ )
                    → ( Nat ⟨ (λ x → (x ≤ m) ∧ (x ≤ n)) ⟩ )
min (MkRefine a Pa) (MkRefine b Pb) with le-wtf a b
...                    {- a ≤ b -}  | le-left  P = {!and-refine ? ? Pa ? !}
...                    {- b ≤ a -}  | le-right Q = {!and-refine _ _ ? Pb !}
{-
with le-Total a b
...                                 | le-left  a = {!!}
...                                 | le-right b = ? -}
{-
min {m} {n} (MkRefine a P₀) (MkRefine b P₁) with (le a b)
...                                 | true  = {!!}
...                                 | false = {!!}
-}
{-
min {m} {n} (MkRefine zero x)    (MkRefine b y)    = MkRefine 0 (and (zero ≤ m) (zero ≤ n))
min {m} {n} (MkRefine (suc a) x) (MkRefine zero y) = MkRefine 0 (and (zero ≤ m) (zero ≤ n))
min {suc m} {suc n} (MkRefine (suc a) x) (MkRefine (suc b) y) = {!hSuc (min (MkRefine a ?) (MkRefine b ?))!}
-}


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

module ConcretePermutation where

open import Level renaming (zero to lzero) hiding (suc)

open import Data.Nat using (ℕ)
open import Data.Fin using (Fin; zero; inject+; fromℕ)
open import Data.Vec using (Vec; tabulate; allFin; []; _∷_)
open import Data.Vec.Properties using (tabulate∘lookup)

open import Function using (_∘_)
open import Relation.Binary using (Setoid)
open import Relation.Binary.PropositionalEquality using (_≡_; setoid)

--

open import Proofs using (
  -- VectorLemmas
   _!!_
   )

------------------------------------------------------------------------------
-- A concrete permutation has 4 components:
-- - the one-line notation for a permutation
-- - the one-line notation for the inverse permutation
-- - and 2 proofs that these are indeed inverses

-- One-line notation for permutations with identity and composition

FinVec : ℕ → ℕ → Set
FinVec m n = Vec (Fin m) n

1C : {n : ℕ} → FinVec n n
1C {n} = allFin n

_∘̂_ : {n₀ n₁ n₂ : ℕ} → Vec (Fin n₁) n₀ → Vec (Fin n₂) n₁ → Vec (Fin n₂) n₀
π₁ ∘̂ π₂ = tabulate (_!!_ π₂ ∘ _!!_ π₁)

-- Actual permutation

record CPerm (values : ℕ) (size : ℕ) : Set where
  constructor cp
  field
    π  : FinVec values size
    πᵒ : FinVec size values
    αp : π ∘̂ πᵒ ≡ 1C
    βp : πᵒ ∘̂ π ≡ 1C

------------------------------------------------------------------------------
-- We can compare concrete permutations for equality using _≡_
-- It is actually sufficient to compare just the forward π using _≡_

-- The set of permutations under _≡_

SCPerm : ℕ → ℕ → Setoid lzero lzero
SCPerm m n = setoid (CPerm m n)

-- This is just tabulate∘lookup, but it hides the details; should this
-- be called 'join' or 'flatten' ?

cauchyext : {m n : ℕ} (π : FinVec m n) → tabulate (_!!_ π) ≡ π
cauchyext π = tabulate∘lookup π

------------------------------------------------------------------------------
-- I always mix up which way the permutation works. Here is a small
-- example to serve as a reminder:

-- values

0₅ 1₅ 2₅ 3₅ 4₅ : Fin 5
0₅ = zero
1₅ = inject+ 3 (fromℕ 1)
2₅ = inject+ 2 (fromℕ 2)
3₅ = inject+ 1 (fromℕ 3)
4₅ = fromℕ 4

-- indices

0₃ 1₃ 2₃ : Fin 3
0₃ = zero
1₃ = inject+ 1 (fromℕ 1)
2₃ = fromℕ 2

πex : FinVec 5 3
πex = 4₅ ∷ 3₅ ∷ 2₅ ∷ []

fex : Fin 3 → Fin 5
fex i = πex !! i

-- fex 0₃ => 4₅
-- fex 1₃ => 3₅
-- fex 2₃ => 2₅

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


open import Data.Sum using ( _⊎_ )
open import FRP.LTL.RSet.Core using ( RSet )

module FRP.LTL.RSet.Sum where

infixr 2 _∨_

_∨_ : RSet → RSet → RSet
(A ∨ B) t = A t ⊎ B t


open import Data.Product using ( _×_ ; _,_ )
open import Data.Sum using ( _⊎_ )
open import Relation.Unary using ( _∈_ ; _∉_ )
open import Web.Semantic.DL.FOL using  ( Formula ; true ; false ; _∧_ ; _∈₁_ ; _∈₁_⇒_ ; _∈₂_ ; _∈₂_⇒_ ; _∼_ ; _∼_⇒_ ; ∀₁ )
open import Web.Semantic.DL.Signature using ( Signature )
open import Web.Semantic.DL.TBox.Interp using ( Interp ; Δ ; _⊨_≈_ ; con ; rol )
open import Web.Semantic.Util using ( True ; False )

module Web.Semantic.DL.FOL.Model {Σ : Signature} where

_⊨f_ : (I : Interp Σ) → Formula Σ (Δ I) → Set
I ⊨f true = True
I ⊨f false = False
I ⊨f (F ∧ G) = (I ⊨f F) × (I ⊨f G)
I ⊨f (x ∈₁ c) = x ∈ (con I c)
I ⊨f (x ∈₁ c ⇒ F) = (x ∈ (con I c)) → (I ⊨f F)
I ⊨f ((x , y) ∈₂ r) = (x , y) ∈ (rol I r)
I ⊨f ((x , y) ∈₂ r ⇒ F) = ((x , y) ∈ (rol I r)) → (I ⊨f F)
I ⊨f (x ∼ y) = I ⊨ x ≈ y
I ⊨f (x ∼ y ⇒ F) = (I ⊨ x ≈ y) → (I ⊨f F)
I ⊨f ∀₁ F = ∀ x → (I ⊨f F x)