open import bool
open import eq using (_≡_)
open import nat
open import nat-thms
open import z05-01-hc-slist2-base

module z05-01-hc-slist2-test where

data _R≤_ : ℕ → ℕ → Set where

  z≤n : ∀ {n : ℕ}
      --------
    → zero R≤ n

  s≤s : ∀ {m n : ℕ}
    →     m R≤     n
      -------------
    → suc m R≤ suc n

≤-pred : ∀ {m n} → suc m R≤ suc n → m R≤ n
≤-pred (s≤s m≤n) = m≤n

_≤?_ : Decidable _R≤_
zero  ≤? _     = left z≤n
suc m ≤? zero  = right λ()
suc m ≤? suc n with m ≤? n
... | left  m≤n = left  (s≤s m≤n)
... | right m≰n = right λ x → m≰n (≤-pred x)

ℕ-Equivalence : Equivalence {X = ℕ} _≡_
ℕ-Equivalence = record
  { refl  = _≡_.refl
  ; sym   = λ x≡y → eq.sym x≡y
  ; trans = λ {_≡_.refl _≡_.refl → eq.trans _≡_.refl _≡_.refl} }

xR≤y→x≤y≡tt : ∀ {x y : ℕ} → x R≤ y → x ≤ y ≡ bool.𝔹.tt
xR≤y→x≤y≡tt {x} {y}  z≤n       = 0-≤ y
xR≤y→x≤y≡tt {x} {y} (s≤s xR≤y) = xR≤y→x≤y≡tt xR≤y

x≤y≡tt→xR≤y : ∀ {x y : ℕ} → x ≤ y ≡ bool.𝔹.tt → x R≤ y
x≤y≡tt→xR≤y  {zero} {_}         _ = z≤n
x≤y≡tt→xR≤y {suc x} {y} sucx≤y≡tt = {!!} -- TODO

R≤-total : (x y : ℕ) → Either (x R≤ y) (y R≤ x)
R≤-total zero     zero   = left z≤n
R≤-total zero    (suc y) = left z≤n
R≤-total (suc x)  zero   = right z≤n
R≤-total (suc x) (suc y) with R≤-total x y
... | left  l = left  (s≤s l)
... | right r = right (s≤s r)

x≡y→xR≤y : ∀ {x y : ℕ} → x ≡ y → x R≤ y
x≡y→xR≤y  {zero}        {_}        _ = z≤n
x≡y→xR≤y {suc x} {.(suc x)} _≡_.refl = s≤s (x≤y≡tt→xR≤y (≤-refl x))

ℕ-TotalOrder : TotalOrder {X = ℕ} _≡_ _R≤_
ℕ-TotalOrder = record
  { antisym     = λ x≤y y≤x → ≤-antisym (xR≤y→x≤y≡tt x≤y) (xR≤y→x≤y≡tt y≤x)
  ; trans       = λ {x} {y} {z} xR≤y yR≤z →
                    x≤y≡tt→xR≤y (≤-trans {x} {y} {z} (xR≤y→x≤y≡tt xR≤y) (xR≤y→x≤y≡tt yR≤z))
  ; total       = R≤-total
  ; reflexive   = x≡y→xR≤y
  ; equivalence = ℕ-Equivalence
  }

import z05-01-hc-slist2-list as SL
open   SL {ℕ}
          {_≡_}
          {_R≤_}
          _≤?_
          ℕ-TotalOrder

empty : OList ⟦ 0 ⟧ ⟦ 9 ⟧
empty = nil (≤-lift z≤n)

l-9 : OList ⟦ 0 ⟧ ⟦ 9 ⟧
l-9 = insert 9 empty (≤-lift z≤n) (≤-lift (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))))))))

l-5-9 : OList ⟦ 0 ⟧ ⟦ 9 ⟧
l-5-9 = insert 5 l-9 (≤-lift z≤n) (≤-lift (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))))

l-1-5-9 : OList ⟦ 0 ⟧ ⟦ 9 ⟧
l-1-5-9 = insert 1 l-5-9 (≤-lift z≤n) (≤-lift (s≤s z≤n))

l-1-5-9' : OList ⊥ ⊤
l-1-5-9' = isort' (9 ∷ 1 ∷ 5 ∷ [])

-- cannot do because lower/upper indices different : l-1-5-9 ≡ l-1-5-9'
_ : toList l-1-5-9 ≡ toList l-1-5-9'
_ = eq.refl


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

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

module ExampleSheets.LogicAndSets.Sheet1 where

  q1i : {a : _} {A : Set a} → (p1 p2 p3 : Propositions A) → Tautology (implies (implies p1 (implies p2 p3)) (implies p2 (implies p1 p3)))
  Tautology.isTaut (q1i p1 p2 p3) {v} with inspect (Valuation.v v p3)
  Tautology.isTaut (q1i p1 p2 p3) {v} | BoolTrue with≡ p3T = Valuation.vImplicationT v (Valuation.vImplicationT v (Valuation.vImplicationT v p3T))
  Tautology.isTaut (q1i p1 p2 p3) {v} | BoolFalse with≡ p3F with inspect (Valuation.v v p2)
  Tautology.isTaut (q1i p1 p2 p3) {v} | BoolFalse with≡ p3F | BoolTrue with≡ p2T with inspect (Valuation.v v p1)
  Tautology.isTaut (q1i p1 p2 p3) {v} | BoolFalse with≡ p3F | BoolTrue with≡ p2T | BoolTrue with≡ p1T = Valuation.vImplicationVacuous v (Valuation.vImplicationF v p1T (Valuation.vImplicationF v p2T p3F))
  Tautology.isTaut (q1i p1 p2 p3) {v} | BoolFalse with≡ p3F | BoolTrue with≡ p2T | BoolFalse with≡ p1F = Valuation.vImplicationT v (Valuation.vImplicationT v (Valuation.vImplicationVacuous v p1F))
  Tautology.isTaut (q1i p1 p2 p3) {v} | BoolFalse with≡ p3F | BoolFalse with≡ p2F = Valuation.vImplicationT v (Valuation.vImplicationVacuous v p2F)


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

module Demos.Cantor where

open import Prelude
open import Data.Bool.Properties using (false≢true; true≢false)

Stream : Type a → Type a
Stream A = ℕ → A

_∈_ : ∀ {A : Type a} (x : A) → Stream A → Type a
x ∈ xs = ∃ i × (xs i ≡ x)

Countable : Type a → Type a
Countable A = Σ[ xs ⦂ Stream A ] × (∀ x → x ∈ xs)

x≢¬x : ∀ x → x ≢ not x
x≢¬x false = false≢true
x≢¬x true  = true≢false

cantor : ¬ (Countable (Stream Bool))
cantor (support , cover) =
  let p , ps = cover (λ i → not (support i i))
      q = cong (_$ p) ps
  in x≢¬x _ q


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

open import Fragment.Algebra.Signature

module Fragment.Algebra.Homomorphism.Definitions (Σ : Signature) where

open import Fragment.Algebra.Algebra Σ

open import Level using (Level; _⊔_)
open import Relation.Binary using (Setoid)
open import Data.Vec using (Vec; map)

open import Function using (Congruent) public

private
  variable
    a b ℓ₁ ℓ₂ : Level

Homomorphic : (S : Algebra {a} {ℓ₁}) (T : Algebra {b} {ℓ₂})
              → (∥ S ∥ → ∥ T ∥) → Set (a ⊔ ℓ₂)
Homomorphic S T h = ∀ {arity} → (f : ops Σ arity)
                    → (xs : Vec ∥ S ∥ arity)
                    → T ⟦ f ⟧ (map h xs) =[ T ] h (S ⟦ f ⟧ xs)


module Thesis.Syntax where

open import Thesis.Types public
open import Thesis.Contexts public

data Const : (τ : Type) → Set where
   unit : Const unit
   lit : ℤ → Const int
   plus : Const (int ⇒ int ⇒ int)
   minus : Const (int ⇒ int ⇒ int)
   cons : ∀ {t1 t2} → Const (t1 ⇒ t2 ⇒ pair t1 t2)
   fst : ∀ {t1 t2} → Const (pair t1 t2 ⇒ t1)
   snd : ∀ {t1 t2} → Const (pair t1 t2 ⇒ t2)
   linj : ∀ {t1 t2} → Const (t1 ⇒ sum t1 t2)
   rinj : ∀ {t1 t2} → Const (t2 ⇒ sum t1 t2)
   match : ∀ {t1 t2 t3} → Const (sum t1 t2 ⇒ (t1 ⇒ t3) ⇒ (t2 ⇒ t3) ⇒ t3)

data Term (Γ : Context) :
  (τ : Type) → Set where
  -- constants aka. primitives
  const : ∀ {τ} →
    (c : Const τ) →
    Term Γ τ
  var : ∀ {τ} →
    (x : Var Γ τ) →
    Term Γ τ
  app : ∀ {σ τ}
    (s : Term Γ (σ ⇒ τ)) →
    (t : Term Γ σ) →
    Term Γ τ
  -- we use de Bruijn indices, so we don't need binding occurrences.
  abs : ∀ {σ τ}
    (t : Term (σ • Γ) τ) →
    Term Γ (σ ⇒ τ)

-- Weakening

weaken : ∀ {Γ₁ Γ₂ τ} →
  (Γ₁≼Γ₂ : Γ₁ ≼ Γ₂) →
  Term Γ₁ τ →
  Term Γ₂ τ
weaken Γ₁≼Γ₂ (const c) = const c
weaken Γ₁≼Γ₂ (var x) = var (weaken-var Γ₁≼Γ₂ x)
weaken Γ₁≼Γ₂ (app s t) = app (weaken Γ₁≼Γ₂ s) (weaken Γ₁≼Γ₂ t)
weaken Γ₁≼Γ₂ (abs {σ} t) = abs (weaken (keep σ • Γ₁≼Γ₂) t)

-- Shorthands for nested applications
app₂ : ∀ {Γ α β γ} →
  Term Γ (α ⇒ β ⇒ γ) →
  Term Γ α → Term Γ β → Term Γ γ
app₂ f x = app (app f x)

app₃ : ∀ {Γ α β γ δ} →
  Term Γ (α ⇒ β ⇒ γ ⇒ δ) →
  Term Γ α → Term Γ β → Term Γ γ → Term Γ δ
app₃ f x = app₂ (app f x)

app₄ : ∀ {Γ α β γ δ ε} →
  Term Γ (α ⇒ β ⇒ γ ⇒ δ ⇒ ε) →
  Term Γ α → Term Γ β → Term Γ γ → Term Γ δ →
  Term Γ ε
app₄ f x = app₃ (app f x)

app₅ : ∀ {Γ α β γ δ ε ζ} →
  Term Γ (α ⇒ β ⇒ γ ⇒ δ ⇒ ε ⇒ ζ) →
  Term Γ α → Term Γ β → Term Γ γ → Term Γ δ →
  Term Γ ε → Term Γ ζ
app₅ f x = app₄ (app f x)

app₆ : ∀ {Γ α β γ δ ε ζ η} →
  Term Γ (α ⇒ β ⇒ γ ⇒ δ ⇒ ε ⇒ ζ ⇒ η) →
  Term Γ α → Term Γ β → Term Γ γ → Term Γ δ →
  Term Γ ε → Term Γ ζ → Term Γ η
app₆ f x = app₅ (app f x)


{-# OPTIONS --safe #-}

module Cubical.Algebra.CommRing.Instances.Polynomials where

open import Cubical.Foundations.Prelude
open import Cubical.Algebra.CommRing
open import Cubical.Algebra.Polynomials

private
  variable
    ℓ : Level

Poly : (CommRing ℓ) → CommRing ℓ
Poly R = (PolyMod.Poly R) , str
    where
      open CommRingStr --(snd R)
      str : CommRingStr (PolyMod.Poly R)
      0r str = PolyMod.0P R
      1r str = PolyMod.1P R
      _+_ str = PolyMod._Poly+_ R
      _·_ str = PolyMod._Poly*_ R
      - str = PolyMod.Poly- R
      isCommRing str = makeIsCommRing (PolyMod.isSetPoly R)
                                      (PolyMod.Poly+Assoc R)
                                      (PolyMod.Poly+Rid R)
                                      (PolyMod.Poly+Inverses R)
                                      (PolyMod.Poly+Comm  R)
                                      (PolyMod.Poly*Associative R)
                                      (PolyMod.Poly*Rid R)
                                      (PolyMod.Poly*LDistrPoly+ R)
                                      (PolyMod.Poly*Commutative R)


module Cats.Limit.Product where

open import Data.Bool using (Bool ; true ; false)
open import Data.Product using (_×_ ; _,_ ; ∃-syntax ; proj₁ ; proj₂)

open import Cats.Category
open import Cats.Category.Cones using (Cones ; Cone ; HasObj-Cone)
open import Cats.Category.Discrete as Discrete using (Discrete)
open import Cats.Functor using (Functor)
open import Cats.Limit
open import Cats.Util.Conv

module _ {lo la l≈ li}
  {Cat : Category lo la l≈}
  {I : Set li} {O : I → Category.Obj Cat}
  where

  open Category Cat
  open Product using (isProduct)
  open Cone using (arr)

  F : Functor (Discrete I) Cat
  F = Discrete.functor I O

  private
    module Cones = Category (Cones F)

  productData→cone : ∀ {P} → (∀ i → P ⇒ O i) → Cone F
  productData→cone {P} proj = record
      { Apex = P
      ; arr = proj
      ; commute = λ { Discrete.id → ≈.sym id-l }
      }

  cone→productData : Cone F → ∃[ P ] (∀ i → P ⇒ O i)
  cone→productData c = c ᴼ , arr c

  terminal : ∀ {P} {proj : ∀ i → P ⇒ O i}
    → IsProduct O P proj
    → Cones.IsTerminal (productData→cone proj)
  terminal {P} {proj} isProduct c = record
      { arr = record
          { θ = θ
          ; commute = commute
          }
      ; unique = λ where
          {record { θ = θ′ ; commute = commute′ }} _ →
            ∃!′.unique prod (λ i → ≈.sym (commute′ i))
      }
    where
      prod : ∃![ u ] (∀ i → arr c i ≈ proj i ∘ u)
      prod = isProduct (arr c)

      θ : c ᴼ ⇒ P
      θ = prod ⃗

      commute : ∀ j → arr (productData→cone proj) j ∘ θ ≈ arr c j
      commute j = ≈.sym (∃!′.prop prod j)

  product : ∀ {c}
    → Cones.IsTerminal c
    → let (P , proj) = cone→productData c
      in IsProduct O P proj
  product {c} term {X} x = record
      { arr = f
      ; prop = prop
      ; unique = uniq
      }
    where
      open Cats.Category.Cones._⇒_ using (θ ; commute)

      P = proj₁ (cone→productData c)
      proj = proj₂ (cone→productData c)

      u : Cones.∃! (productData→cone x) c
      u = term (productData→cone x)

      f : X ⇒ P
      f = θ (u ⃗)

      prop : ∀ i → x i ≈ proj i ∘ f
      prop i = ≈.sym (commute (u ⃗) _)

      uniq : IsUniqueSuchThat (λ g → ∀ i → x i ≈ proj i ∘ g) f
      uniq {g} eq = Cones.∃!′.unique u {f′} _
        where
          f′ : productData→cone x Cones.⇒ c
          f′ = record
              { θ = g
              ; commute = λ i → ≈.sym (eq i)
              }

  product→limit : Product O → Limit F
  product→limit P = record
      { cone = productData→cone (Product.proj P)
      ; isLimit = terminal (isProduct P)
      }

  limit→product : Limit F → Product O
  limit→product L
      = let (P , proj) = cone→productData (L ᴼ) in
        record
          { prod = P
          ; proj = proj
          ; isProduct = product (Limit.isLimit L)
          }

  product-unique : (P Q : Product O) → P ᴼ ≅ Q ᴼ
  product-unique P Q = obj-unique (product→limit P) (product→limit Q)


module Singleton where

open import Level
open import Data.Unit
open import Data.Product
open import Function
open import Relation.Binary
open import Function.Inverse
open import Function.Equality as FE
open import Relation.Binary.PropositionalEquality as P

open import Pi using (⟦_⟧; _⟷_ )

embed₁ : Set → Set
embed₁ b = Σ b (λ _ → ⊤)

B-to-Σ⊤ : {B : Set} → B → embed₁ B
B-to-Σ⊤ v = (v , tt)

Σ⊤-to-B : {B : Set} → embed₁ B → B
Σ⊤-to-B (v , _) = v

BΣ₁ : ∀ {b} → Inverse (P.setoid b) (P.setoid (embed₁ b))
BΣ₁ = record {
        to = record { _⟨$⟩_ = B-to-Σ⊤; cong = P.cong B-to-Σ⊤  }
      ; from = record { _⟨$⟩_ = Σ⊤-to-B; cong = P.cong Σ⊤-to-B }
      ; inverse-of = record { left-inverse-of = λ _ → refl
                               ; right-inverse-of = λ x → refl } }

data Singleton {c : Level} {A : Set c} : A → Set c where
  singleton : (x : A) -> Singleton x

-- That a Singleton type is a setoid is not needed, but here is the proof anyways.
data _∼_ {c : Level} {A : Set c} {v : A} (x : Singleton v) (y : Singleton v) : Set c where
    uniq : x ∼ y

∼Equiv : {c : Level} {A : Set c} {v : A} → IsEquivalence {_} {_} {Singleton v}  _∼_
∼Equiv {v = v } = record {
                    refl = uniq
                  ; sym = λ _ →  uniq
                  ; trans = λ _ _ → uniq }

SingSetoid : {c c : Level} → (A : Setoid c c) → (Setoid.Carrier A) → Setoid c c
SingSetoid A v = record {
                   Carrier = Singleton v
                 ; _≈_ = _∼_
                 ; isEquivalence = ∼Equiv }

-- We can map a type to its Σ of Singletons and back.
embed₂ : Set → Set
embed₂ b = Σ b Singleton

B-to-ΣS : {B : Set} → B → embed₂ B
B-to-ΣS v = (v , singleton v)

ΣS-to-B : {B : Set} → embed₂ B → B
ΣS-to-B x = proj₁ x

right-inverse : ∀ {c} {b : Set c} → (x : Σ b (Singleton {A = b})) → (proj₁ x , singleton (proj₁ x)) ≡ x
right-inverse (v , singleton .v) = refl

BΣ₂ : ∀ {b} → Inverse (P.setoid b) (P.setoid (embed₂ b))
BΣ₂ =  record {
         to = record { _⟨$⟩_ = B-to-ΣS; cong = P.cong B-to-ΣS }
       ; from = record { _⟨$⟩_ = ΣS-to-B; cong = P.cong ΣS-to-B }
       ; inverse-of = record { left-inverse-of = λ x → refl
                             ; right-inverse-of = right-inverse } }

-- A generalized idea of a permutation: a bijection between any two types
Permutation : Set → Set -> Set
Permutation a b = Inverse (P.setoid a) (P.setoid b)

-- Now, what we really want is to interpret Pi combinators as
-- permutations.  We need a refined version of embed₂ which
-- allows us to use a permutation to transport things.

embed₃ : {l : Level} → (S T : Setoid l l) → Inverse S T → Setoid l l
embed₃ S T f = record {
                 Carrier = Σ A (λ b → Singleton (to f ⟨$⟩ b))
               ; _≈_ = _≡_
               ; isEquivalence = P.isEquivalence }
               where open Inverse {From = S} {T}
                     A = Setoid.Carrier S


------------------------------------------------------------------------
-- The Agda standard library
--
-- Well-founded induction
------------------------------------------------------------------------

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

open import Relation.Binary

module Induction.WellFounded where

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

-- When using well-founded recursion you can recurse arbitrarily, as
-- long as the arguments become smaller, and "smaller" is
-- well-founded.

WfRec : ∀ {a r} {A : Set a} → Rel A r → ∀ {ℓ} → RecStruct A ℓ _
WfRec _<_ P x = ∀ y → y < x → P y

-- The accessibility predicate: x is accessible if everything which is
-- smaller than x is also accessible (inductively).

data Acc {a ℓ} {A : Set a} (_<_ : Rel A ℓ) (x : A) : Set (a ⊔ ℓ) where
  acc : (rs : WfRec _<_ (Acc _<_) x) → Acc _<_ x

-- The accessibility predicate encodes what it means to be
-- well-founded; if all elements are accessible, then _<_ is
-- well-founded.

WellFounded : ∀ {a ℓ} {A : Set a} → Rel A ℓ → Set _
WellFounded _<_ = ∀ x → Acc _<_ x

Well-founded = WellFounded
{-# WARNING_ON_USAGE Well-founded
"Warning: Well-founded was deprecated in v0.15.
Please use WellFounded instead."
#-}

------------------------------------------------------------------------
-- Well-founded induction for the subset of accessible elements:

module Some {a lt} {A : Set a} {_<_ : Rel A lt} {ℓ} where

  wfRecBuilder : SubsetRecursorBuilder (Acc _<_) (WfRec _<_ {ℓ = ℓ})
  wfRecBuilder P f x (acc rs) = λ y y<x →
    f y (wfRecBuilder P f y (rs y y<x))

  wfRec : SubsetRecursor (Acc _<_) (WfRec _<_)
  wfRec = subsetBuild wfRecBuilder

  wfRec-builder = wfRecBuilder
  {-# WARNING_ON_USAGE wfRec-builder
  "Warning: wfRec-builder was deprecated in v0.15.
  Please use wfRecBuilder instead."
  #-}

------------------------------------------------------------------------
-- Well-founded induction for all elements, assuming they are all
-- accessible:

module All {a lt} {A : Set a} {_<_ : Rel A lt}
           (wf : WellFounded _<_) ℓ where

  wfRecBuilder : RecursorBuilder (WfRec _<_ {ℓ = ℓ})
  wfRecBuilder P f x = Some.wfRecBuilder P f x (wf x)

  wfRec : Recursor (WfRec _<_)
  wfRec = build wfRecBuilder

  wfRec-builder = wfRecBuilder
  {-# WARNING_ON_USAGE wfRec-builder
  "Warning: wfRec-builder was deprecated in v0.15.
  Please use wfRecBuilder instead."
  #-}

------------------------------------------------------------------------
-- It might be useful to establish proofs of Acc or Well-founded using
-- combinators such as the ones below (see, for instance,
-- "Constructing Recursion Operators in Intuitionistic Type Theory" by
-- Lawrence C Paulson).

module Subrelation {a ℓ₁ ℓ₂} {A : Set a}
                   {_<₁_ : Rel A ℓ₁} {_<₂_ : Rel A ℓ₂}
                   (<₁⇒<₂ : ∀ {x y} → x <₁ y → x <₂ y) where

  accessible : Acc _<₂_ ⊆ Acc _<₁_
  accessible (acc rs) = acc (λ y y<x → accessible (rs y (<₁⇒<₂ y<x)))

  wellFounded : WellFounded _<₂_ → WellFounded _<₁_
  wellFounded wf = λ x → accessible (wf x)

  well-founded = wellFounded
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
  Please use wellFounded instead."
  #-}

module InverseImage {a b ℓ} {A : Set a} {B : Set b} {_<_ : Rel B ℓ}
                    (f : A → B) where

  accessible : ∀ {x} → Acc _<_ (f x) → Acc (_<_ on f) x
  accessible (acc rs) = acc (λ y fy<fx → accessible (rs (f y) fy<fx))

  wellFounded : WellFounded _<_ → WellFounded (_<_ on f)
  wellFounded wf = λ x → accessible (wf (f x))

  well-founded = wellFounded
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
  Please use wellFounded instead."
  #-}

module TransitiveClosure {a ℓ} {A : Set a} (_<_ : Rel A ℓ) where

  infix 4 _<⁺_

  data _<⁺_ : Rel A (a ⊔ ℓ) where
    [_]   : ∀ {x y} (x<y : x < y) → x <⁺ y
    trans : ∀ {x y z} (x<y : x <⁺ y) (y<z : y <⁺ z) → x <⁺ z

  downwardsClosed : ∀ {x y} → Acc _<⁺_ y → x <⁺ y → Acc _<⁺_ x
  downwardsClosed (acc rs) x<y = acc (λ z z<x → rs z (trans z<x x<y))

  mutual

    accessible : ∀ {x} → Acc _<_ x → Acc _<⁺_ x
    accessible acc-x = acc (accessible′ acc-x)

    accessible′ : ∀ {x} → Acc _<_ x → WfRec _<⁺_ (Acc _<⁺_) x
    accessible′ (acc rs) y [ y<x ]         = accessible (rs y y<x)
    accessible′ acc-x    y (trans y<z z<x) =
      downwardsClosed (accessible′ acc-x _ z<x) y<z

  wellFounded : WellFounded _<_ → WellFounded _<⁺_
  wellFounded wf = λ x → accessible (wf x)

  downwards-closed = downwardsClosed
  {-# WARNING_ON_USAGE downwards-closed
  "Warning: downwards-closed was deprecated in v0.15.
  Please use downwardsClosed instead."
  #-}
  well-founded     = wellFounded
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
  Please use wellFounded instead."
  #-}

module Lexicographic {a b ℓ₁ ℓ₂} {A : Set a} {B : A → Set b}
                     (RelA : Rel A ℓ₁)
                     (RelB : ∀ x → Rel (B x) ℓ₂) where

  data _<_ : Rel (Σ A B) (a ⊔ b ⊔ ℓ₁ ⊔ ℓ₂) where
    left  : ∀ {x₁ y₁ x₂ y₂} (x₁<x₂ : RelA   x₁ x₂) → (x₁ , y₁) < (x₂ , y₂)
    right : ∀ {x y₁ y₂}     (y₁<y₂ : RelB x y₁ y₂) → (x  , y₁) < (x  , y₂)

  mutual

    accessible : ∀ {x y} →
                 Acc RelA x → (∀ {x} → WellFounded (RelB x)) →
                 Acc _<_ (x , y)
    accessible accA wfB = acc (accessible′ accA (wfB _) wfB)

    accessible′ :
      ∀ {x y} →
      Acc RelA x → Acc (RelB x) y → (∀ {x} → WellFounded (RelB x)) →
      WfRec _<_ (Acc _<_) (x , y)
    accessible′ (acc rsA) _    wfB ._ (left  x′<x) = accessible (rsA _ x′<x) wfB
    accessible′ accA (acc rsB) wfB ._ (right y′<y) =
      acc (accessible′ accA (rsB _ y′<y) wfB)

  wellFounded : WellFounded RelA → (∀ {x} → WellFounded (RelB x)) →
                WellFounded _<_
  wellFounded wfA wfB p = accessible (wfA (proj₁ p)) wfB

  well-founded = wellFounded
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
  Please use wellFounded instead."
  #-}

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

-- Version 1.0

module Inverse-image      = InverseImage
module Transitive-closure = TransitiveClosure


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

open import Setoids.Setoids
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Groups.Definition
open import Groups.Actions.Definition
open import Sets.EquivalenceRelations

module Groups.Actions.Orbit where

data Orbit {a b c d : _} {A : Set a} {B : Set b} {S : Setoid {a} {c} A} {T : Setoid {b} {d} B} {_+_ : A → A → A} {G : Group S _+_} (action : GroupAction G T) (x : B) : Set (a ⊔ b ⊔ c ⊔ d) where
  orbitElt : (g : A) → Orbit action x

orbitSetoid : {a b c d : _} {A : Set a} {B : Set b} {S : Setoid {a} {c} A} {T : Setoid {b} {d} B} {_+_ : A → A → A} {G : Group S _+_} (action : GroupAction G T) (x : B) → Setoid (Orbit action x)
Setoid._∼_ (orbitSetoid {T = T} action x) (orbitElt a) (orbitElt b) = Setoid._∼_ T (GroupAction.action action a x) (GroupAction.action action b x)
Equivalence.reflexive (Setoid.eq (orbitSetoid {T = T} action x)) {orbitElt g} = Equivalence.reflexive (Setoid.eq T)
Equivalence.symmetric (Setoid.eq (orbitSetoid {T = T} action x)) {orbitElt g} {orbitElt h} = Equivalence.symmetric (Setoid.eq T)
Equivalence.transitive (Setoid.eq (orbitSetoid {T = T} action x)) {orbitElt g} {orbitElt h} {orbitElt i} = Equivalence.transitive (Setoid.eq T)


open import Oscar.Prelude
open import Oscar.Class.IsPrecategory
open import Oscar.Class.Reflexivity
open import Oscar.Class.Transleftidentity
open import Oscar.Class.Transrightidentity
open import Oscar.Class.Transitivity

module Oscar.Class.IsCategory where

module _
  {𝔬} {𝔒 : Ø 𝔬}
  {𝔯} (_∼_ : 𝔒 → 𝔒 → Ø 𝔯)
  {ℓ} (_∼̇_ : ∀ {x y} → x ∼ y → x ∼ y → Ø ℓ) (let infix 4 _∼̇_ ; _∼̇_ = _∼̇_)
  (ε : Reflexivity.type _∼_)
  (_↦_ : Transitivity.type _∼_)
  where
  record IsCategory : Ø 𝔬 ∙̂ 𝔯 ∙̂ ℓ where
    constructor ∁
    field
      ⦃ `IsPrecategory ⦄ : IsPrecategory _∼_ _∼̇_ _↦_
      ⦃ `𝓣ransleftidentity ⦄ : Transleftidentity.class _∼_ _∼̇_ ε _↦_
      ⦃ `𝓣ransrightidentity ⦄ : Transrightidentity.class _∼_ _∼̇_ ε _↦_


{-# OPTIONS --cubical --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

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)


{-# OPTIONS --universe-polymorphism #-}
module Categories.Monoidal.Symmetric where

open import Level

open import Categories.Category
open import Categories.Monoidal
open import Categories.Monoidal.Braided
open import Categories.Monoidal.Helpers
open import Categories.Monoidal.Braided.Helpers
open import Categories.NaturalIsomorphism
open import Categories.NaturalTransformation using (_∘₁_; _≡_; id)

record Symmetric {o ℓ e} {C : Category o ℓ e} {M : Monoidal C} (B : Braided M) : Set (o ⊔ ℓ ⊔ e) where
  private module C = Category C
  private module M = Monoidal M
  private module B = Braided B

  -- open C hiding (id; identityˡ; identityʳ; assoc; _≡_)
  -- open M hiding (id)
  -- open MonoidalHelperFunctors C ⊗ M.id
  -- open BraidedHelperFunctors C ⊗ M.id

  private module NI = NaturalIsomorphism B.braid

  field
    symmetry : NI.F⇒G ∘₁ NI.F⇐G ≡ id


module Tactic.Monoid.Proofs where

open import Prelude
open import Structure.Monoid.Laws

open import Tactic.Monoid.Exp

⟦_⟧_ : ∀ {a} {A : Set a} {{_ : Monoid A}} → Exp → (Nat → A) → A
⟦ var x  ⟧ ρ = ρ x
⟦ ε      ⟧ ρ = mempty
⟦ e ⊕ e₁ ⟧ ρ = ⟦ e ⟧ ρ <> ⟦ e₁ ⟧ ρ

⟦_⟧n_ : ∀ {a} {A : Set a} {{_ : Monoid A}} → List Nat → (Nat → A) → A
⟦ xs ⟧n ρ = mconcat (map ρ xs)

map/++ : ∀ {a b} {A : Set a} {B : Set b} (f : A → B) (xs ys : List A) → map f (xs ++ ys) ≡ map f xs ++ map f ys
map/++ f [] ys = refl
map/++ f (x ∷ xs) ys = f x ∷_ $≡ map/++ f xs ys

module _ {a} {A : Set a} {{Mon : Monoid A}} {{Laws : MonoidLaws A}} where

  mconcat/++ : (xs ys : List A) → mconcat (xs ++ ys) ≡ mconcat xs <> mconcat ys
  mconcat/++ [] ys = sym (idLeft _)
  mconcat/++ (x ∷ xs) ys = x <>_ $≡ mconcat/++ xs ys ⟨≡⟩ <>assoc x _ _

  sound : ∀ e (ρ : Nat → A) → ⟦ e ⟧ ρ ≡ ⟦ flatten e ⟧n ρ
  sound (var x) ρ = sym (idRight (ρ x))
  sound ε ρ = refl
  sound (e ⊕ e₁) ρ = _<>_ $≡ sound e ρ *≡ sound e₁ ρ ⟨≡⟩ʳ
                     mconcat $≡ map/++ ρ (flatten e) (flatten e₁) ⟨≡⟩
                     mconcat/++ (map ρ (flatten e)) _

  proof : ∀ e e₁ (ρ : Nat → A) → flatten e ≡ flatten e₁ → ⟦ e ⟧ ρ ≡ ⟦ e₁ ⟧ ρ
  proof e e₁ ρ nfeq = eraseEquality $ sound e ρ ⟨≡⟩ (⟦_⟧n ρ) $≡ nfeq ⟨≡⟩ʳ sound e₁ ρ


{-

Cubical Agda - A Dependently Typed PL with Univalence and HITs
==============================================================
                    Anders Mörtberg
       Every Proof Assistant - September 17, 2020

Link to slides: https://staff.math.su.se/anders.mortberg/slides/EPA2020.pdf

Link to video: https://vimeo.com/459020971

-}

-- To make Agda cubical add the following options
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Talks.EPA2020 where

-- The "Foundations" package contain a lot of important results (in
-- particular the univalence theorem)
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Univalence

open import Cubical.Data.Int
open import Cubical.Data.Prod.Base

-- The interval in Cubical Agda is written I and the endpoints i0 and i1.

apply0 : (A : Type) (p : I → A) → A
apply0 A p = p i0

-- We omit the universe level ℓ for simplicity in this talk. In the
-- library everything is maximally universe polymorphic.

-- We can write functions out of the interval using λ-abstraction:
refl' : {A : Type} (x : A) → x ≡ x
refl' x = λ i → x
-- In fact, x ≡ y is short for PathP (λ _ → A) x y

refl'' : {A : Type} (x : A) → PathP (λ _ → A) x x
refl'' x = λ _ → x

-- In general PathP A x y has A : I → Type, x : A i0 and y : A i1
-- PathP = Dependent paths (Path over a Path)

-- We cannot pattern-match on interval variables as I is not inductively defined
-- foo : {A : Type} → I → A
-- foo r = {!r!}   -- Try typing C-c C-c

-- cong has a direct proof
cong' : {A B : Type} (f : A → B) {x y : A} → x ≡ y → f x ≡ f y
cong' f p i = f (p i)

-- function extensionality also has a direct proof.
-- It also has computational content: swap the arguments.
funExt' : {A B : Type} {f g : A → B} (p : (x : A) → f x ≡ g x) → f ≡ g
funExt' p i x = p x i

-- Transport is more complex as ≡ isn't inductively defined (so we
-- can't define it by pattern-matching on p)
transport' : {A B : Type} → A ≡ B → A → B
transport' p a = transp (λ i → p i) i0 a

-- This lets us define subst (which is called "transport" in the HoTT book)
subst' : {A : Type} (P : A → Type) {x y : A} (p : x ≡ y) → P x → P y
subst' P p pa = transport (λ i → P (p i)) pa

-- The transp operation reduces differently for different types
-- formers. For paths it reduces to another primitive operation called
-- hcomp.

-- We can also define the J eliminator (aka path induction)
J' : {A : Type} {B : A → Type} {x : A}
     (P : (z : A) → x ≡ z → Type)
     (d : P x refl) {y : A} (p : x ≡ y) → P y p
J' P d p = transport (λ i → P (p i) (λ j → p (i ∧ j))) d

-- So J is provable, but it doesn't satisfy computation rule
-- definitionally. This is almost never a problem in practice as the
-- cubical primitives satisfy many new definitional equalities.

-- Another key concept in HoTT/UF is the Univalence Axiom. In Cubical
-- Agda this is provable, we hence refer to it as the Univalence
-- Theorem.

-- The univalence theorem: equivalences of types give paths of types
ua' : {A B : Type} → A ≃ B → A ≡ B
ua' = ua

-- Any isomorphism of types gives rise to an equivalence
isoToEquiv' : {A B : Type} → Iso A B → A ≃ B
isoToEquiv' = isoToEquiv

-- And hence to a path
isoToPath' : {A B : Type} → Iso A B → A ≡ B
isoToPath' e = ua' (isoToEquiv' e)

-- ua satisfies the following computation rule
-- This suffices to be able to prove the standard formulation of univalence.
uaβ' : {A B : Type} (e : A ≃ B) (x : A)
     → transport (ua' e) x ≡ fst e x
uaβ' e x = transportRefl (equivFun e x)

-- Time for an example!

-- Booleans
data Bool : Type where
  false true : Bool

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

notPath : Bool ≡ Bool
notPath = isoToPath' (iso not not rem rem)
  where
  rem : (b : Bool) → not (not b) ≡ b
  rem false = refl
  rem true  = refl

_ : transport notPath true ≡ false
_ = refl

-- Another example, integers:

sucPath : Int ≡ Int
sucPath = isoToPath' (iso sucInt predInt sucPred predSuc)

_ : transport sucPath (pos 0) ≡ pos 1
_ = refl

_ : transport (sucPath ∙ sucPath) (pos 0) ≡ pos 2
_ = refl

_ : transport (sym sucPath) (pos 0) ≡ negsuc 0
_ = refl

-----------------------------------------------------------------------------
-- Higher inductive types

-- The following definition of finite multisets is due to Vikraman
-- Choudhury and Marcelo Fiore.

infixr 5 _∷_

data FMSet (A : Type) : Type where
  [] : FMSet A
  _∷_ : (x : A) → (xs : FMSet A) → FMSet A
  comm : (x y : A) (xs : FMSet A) → x ∷ y ∷ xs ≡ y ∷ x ∷ xs
--  trunc : (xs ys : FMSet A) (p q : xs ≡ ys) → p ≡ q

-- We need to add the trunc constructor for FMSets to be sets, omitted
-- here for simplicity.

_++_ : ∀ {A : Type} (xs ys : FMSet A) → FMSet A
[] ++ ys = ys
(x ∷ xs) ++ ys = x ∷ xs ++ ys
comm x y xs i ++ ys = comm x y (xs ++ ys) i
-- trunc xs zs p q i j ++ ys =
--   trunc (xs ++ ys) (zs ++ ys) (cong (_++ ys) p) (cong (_++ ys) q) i j

unitr-++ : {A : Type} (xs : FMSet A) → xs ++ [] ≡ xs
unitr-++ [] = refl
unitr-++ (x ∷ xs) = cong (x ∷_) (unitr-++ xs)
unitr-++ (comm x y xs i) j = comm x y (unitr-++ xs j) i
-- unitr-++ (trunc xs ys x y i j) = {!!}

-- This is a special case of set quotients! Very useful for
-- programming and set level mathematics

data _/_ (A : Type) (R : A → A → Type) : Type where
  [_] : A → A / R
  eq/ : (a b : A) → R a b → [ a ] ≡ [ b ]
  trunc : (a b : A / R) (p q : a ≡ b) → p ≡ q

-- Proving that they are effective ((a b : A) → [ a ] ≡ [ b ] → R a b)
-- requires univalence for propositions.

-------------------------------------------------------------------------
-- Topological examples of things that are not sets

-- We can define the circle as the following simple data declaration:
data S¹ : Type where
  base : S¹
  loop : base ≡ base

-- We can write functions on S¹ using pattern-matching equations:
double : S¹ → S¹
double base = base
double (loop i) = (loop ∙ loop) i

helix : S¹ → Type
helix base     = Int
helix (loop i) = sucPathInt i

ΩS¹ : Type
ΩS¹ = base ≡ base

winding : ΩS¹ → Int
winding p = subst helix p (pos 0)

_ : winding (λ i → double ((loop ∙ loop) i)) ≡ pos 4
_ = refl

-- We can define the Torus as:
data Torus : Type where
  point : Torus
  line1 : point ≡ point
  line2 : point ≡ point
  square : PathP (λ i → line1 i ≡ line1 i) line2 line2

-- And prove that it is equivalent to two circle:
t2c : Torus → S¹ × S¹
t2c point        = (base , base)
t2c (line1 i)    = (loop i , base)
t2c (line2 j)    = (base , loop j)
t2c (square i j) = (loop i , loop j)

c2t : S¹ × S¹ → Torus
c2t (base   , base)   = point
c2t (loop i , base)   = line1 i
c2t (base   , loop j) = line2 j
c2t (loop i , loop j) = square i j

c2t-t2c : (t : Torus) → c2t (t2c t) ≡ t
c2t-t2c point        = refl
c2t-t2c (line1 _)    = refl
c2t-t2c (line2 _)    = refl
c2t-t2c (square _ _) = refl

t2c-c2t : (p : S¹ × S¹) → t2c (c2t p) ≡ p
t2c-c2t (base   , base)   = refl
t2c-c2t (base   , loop _) = refl
t2c-c2t (loop _ , base)   = refl
t2c-c2t (loop _ , loop _) = refl

-- Using univalence we get the following equality:
Torus≡S¹×S¹ : Torus ≡ S¹ × S¹
Torus≡S¹×S¹ = isoToPath' (iso t2c c2t t2c-c2t c2t-t2c)

windingTorus : point ≡ point → Int × Int
windingTorus l = ( winding (λ i → proj₁ (t2c (l i)))
                 , winding (λ i → proj₂ (t2c (l i))))

_ : windingTorus (line1 ∙ sym line2) ≡ (pos 1 , negsuc 0)
_ = refl

-- We have many more topological examples, including Klein bottle, RP^n,
-- higher spheres, suspensions, join, wedges, smash product:
open import Cubical.HITs.KleinBottle
open import Cubical.HITs.RPn
open import Cubical.HITs.S2
open import Cubical.HITs.S3
open import Cubical.HITs.Susp
open import Cubical.HITs.Join
open import Cubical.HITs.Wedge
open import Cubical.HITs.SmashProduct

-- There's also a proof of the "3x3 lemma" for pushouts in less than
-- 200LOC. In HoTT-Agda this took about 3000LOC. For details see:
-- https://github.com/HoTT/HoTT-Agda/tree/master/theorems/homotopy/3x3
open import Cubical.HITs.Pushout

-- We also defined the Hopf fibration and proved that its total space
-- is S³ in about 300LOC:
open import Cubical.HITs.Hopf

-- There is also some integer cohomology:
open import Cubical.ZCohomology.Everything
-- To compute cohomology groups of various spaces we need a bunch of
-- interesting theorems: Freudenthal suspension theorem,
-- Mayer-Vietoris sequence...
open import Cubical.Homotopy.Freudenthal
open import Cubical.ZCohomology.MayerVietorisUnreduced

-------------------------------------------------------------------------
-- The structure identity principle

-- A more efficient version of finite multisets based on association lists
open import Cubical.HITs.AssocList.Base

-- data AssocList (A : Type) : Type where
--  ⟨⟩ : AssocList A
--  ⟨_,_⟩∷_ : (a : A) (n : ℕ) (xs : AssocList A) → AssocList A
--  per : (a b : A) (m n : ℕ) (xs : AssocList A)
--      → ⟨ a , m ⟩∷ ⟨ b , n ⟩∷ xs ≡ ⟨ b , n ⟩∷ ⟨ a , m ⟩∷ xs
--  agg : (a : A) (m n : ℕ) (xs : AssocList A)
--      → ⟨ a , m ⟩∷ ⟨ a , n ⟩∷ xs ≡ ⟨ a , m + n ⟩∷ xs
--  del : (a : A) (xs : AssocList A) → ⟨ a , 0 ⟩∷ xs ≡ xs
--  trunc : (xs ys : AssocList A) (p q : xs ≡ ys) → p ≡ q

-- Programming and proving is more complicated with AssocList compared
-- to FMSet. This kind of example occurs everywhere in programming and
-- mathematics: one representation is easier to work with, but not
-- efficient, while another is efficient but difficult to work with.

-- Solution: substitute using univalence
substIso : {A B : Type} (P : Type → Type) (e : Iso A B) → P A → P B
substIso P e = subst P (isoToPath e)

-- Can transport for example Monoid structure from FMSet to AssocList
-- this way, but the achieved Monoid structure is not very efficient
-- to work with. A better solution is to prove that FMSet and
-- AssocList are equal *as monoids*, but how to do this?

-- Solution: structure identity principle (SIP)
-- This is a very useful consequence of univalence
open import Cubical.Foundations.SIP

sip' : {ℓ : Level} {S : Type ℓ → Type ℓ} {ι : StrEquiv S ℓ}
       (θ : UnivalentStr S ι) (A B : TypeWithStr ℓ S) → A ≃[ ι ] B → A ≡ B
sip' = sip

-- The tricky thing is to prove that (S,ι) is a univalent structure.
-- Luckily we provide automation for this in the library, see for example:
open import Cubical.Algebra.Monoid.Base

-- Another cool application of the SIP: matrices represented as
-- functions out of pairs of Fin's and vectors are equal as abelian
-- groups:
open import Cubical.Algebra.Matrix

-- The end, back to slides!


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

open import LogicalFormulae
open import Functions.Definition
open import Groups.Definition
open import Groups.Abelian.Definition
open import Setoids.Setoids
open import Rings.Definition
open import Sets.FinSet.Definition
open import Vectors
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Sets.EquivalenceRelations

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

module Modules.Span {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+R_ : A → A → A} {_*_ : A → A → A} {R : Ring S _+R_ _*_} {m n : _} {M : Set m} {T : Setoid {m} {n} M} {_+_ : M → M → M} {G' : Group T _+_} {G : AbelianGroup G'} {_·_ : A → M → M} (mod : Module R G _·_) where

open Group G'
open Setoid T
open Equivalence eq

_=V_ : {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ : A → A → A} (G : Group S _+_) {n1 : ℕ} → Rel {a} {b ⊔ n} (Vec A n1)
_=V_ G [] [] = True'
_=V_ {S = S} G (x ,- xs) (y ,- ys) = (Setoid._∼_ S x y) && (_=V_ G xs ys)

dot : {n : ℕ} → (Vec M n) → (Vec A n) → M
dot [] [] = 0G
dot (v ,- vs) (x ,- xs) = (x · v) + (dot vs xs)

Spans : {c : _} {C : Set c} (f : C → M) → Set (a ⊔ m ⊔ n ⊔ c)
Spans {C = C} f = (m : M) → Sg ℕ (λ n → Sg ((Vec C n) && (Vec A n)) (λ t → (dot (vecMap f (_&&_.fst t)) (_&&_.snd t)) ∼ m))

Independent : {c : _} {C : Set c} (f : C → M) → Set (a ⊔ b ⊔ n ⊔ c)
Independent {C = C} f = {n : ℕ} → (r : Vec C n) → ({a b : ℕ} → (a<n : a <N n) → (b<n : b <N n) → vecIndex r a a<n ≡ vecIndex r b b<n → a ≡ b) → (b : Vec A n) → (dot (vecMap f r) b) ∼ 0G → _=V_ (Ring.additiveGroup R) (vecPure (Group.0G (Ring.additiveGroup R))) b

independentSubset : {c : _} {C : Set c} (f : C → M) → {d : _} {D : Set d} {inj : D → C} (isInj : Injection inj) → Independent f → Independent (f ∘ inj)
independentSubset f {inj = inj} isInj indp {n = n} r coeffInj coeffs dotZero = indp {n = n} (vecMap inj r) inj' coeffs (transitive (identityOfIndiscernablesRight _∼_ reflexive (applyEquality (λ i → dot i coeffs) (vecMapCompose inj f r))) dotZero)
  where
    inj' : {a b : ℕ} (a<n : a <N n) (b<n : b <N n) → vecIndex (vecMap inj r) a a<n ≡ vecIndex (vecMap inj r) b b<n → a ≡ b
    inj' a<n b<n x rewrite vecMapAndIndex r inj a<n | vecMapAndIndex r inj b<n = coeffInj a<n b<n (isInj x)

spanSuperset : {c : _} {C : Set c} (f : C → M) → {d : _} {D : Set d} {surj : D → C} (isSurj : Surjection surj) → Spans f → Spans (f ∘ surj)
spanSuperset f {surj = surj} isSurj spans m with spans m
spanSuperset {C = C} f {surj = surj} isSurj spans m | n , ((coeffs ,, basis) , b) = n , ((vecMap (λ c → underlying (isSurj c)) coeffs ,, basis) , transitive (identityOfIndiscernablesLeft _∼_ reflexive (applyEquality (λ i → dot i basis) (equalityCommutative {x = vecMap (λ i → f (surj i)) (vecMap (λ c → underlying (isSurj c)) coeffs)} {vecMap f coeffs} (transitivity (vecMapCompose (λ i → underlying (isSurj i)) (λ z → f (surj z)) coeffs) (t coeffs))))) b)
  where
    t : {n : ℕ} (coeffs : Vec C n) → vecMap (λ i → f (surj (underlying (isSurj i)))) coeffs ≡ vecMap f coeffs
    t [] = refl
    t (x ,- coeffs) with isSurj x
    ... | img , pr rewrite pr | t coeffs = refl

Basis : {c : _} {C : Set c} (f : C → M) → Set (a ⊔ b ⊔ m ⊔ n ⊔ c)
Basis v = Spans v && Independent v


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

module Data.Fin.Injective where

open import Prelude

open import Data.Fin.Base
open import Data.Fin.Properties using (discreteFin)

open import Data.Nat
open import Data.Nat.Properties using (+-comm)

open import Function.Injective

private
  variable n m : ℕ

infix 4 _≢ᶠ_ _≡ᶠ_
_≢ᶠ_ _≡ᶠ_ : Fin n → Fin n → Type _
n ≢ᶠ m = T (not (discreteFin n m .does))
n ≡ᶠ m = T (discreteFin n m .does)

_F↣_ : ℕ → ℕ → Type
n F↣ m = Σ[ f ⦂ (Fin n → Fin m) ] × ∀ {x y} → x ≢ᶠ y → f x ≢ᶠ f y

shift : (x y : Fin (suc n)) → x ≢ᶠ y → Fin n
shift          f0     (fs y)  x≢y = y
shift {suc _}  (fs x)  f0     x≢y = f0
shift {suc _}  (fs x)  (fs y)  x≢y = fs (shift x y x≢y)

shift-inj : ∀ (x y z : Fin (suc n)) x≢y x≢z → y ≢ᶠ z → shift x y x≢y ≢ᶠ shift x z x≢z
shift-inj          f0     (fs y)  (fs z)  x≢y x≢z x+y≢x+z = x+y≢x+z
shift-inj {suc _}  (fs x)  f0     (fs z)  x≢y x≢z x+y≢x+z = tt
shift-inj {suc _}  (fs x)  (fs y)  f0     x≢y x≢z x+y≢x+z = tt
shift-inj {suc _}  (fs x)  (fs y)  (fs z)  x≢y x≢z x+y≢x+z = shift-inj x y z x≢y x≢z x+y≢x+z

shrink : suc n F↣ suc m → n F↣ m
shrink (f , inj) .fst  x  = shift (f f0) (f (fs x)) (inj tt)
shrink (f , inj) .snd  p  = shift-inj (f f0) (f (fs _)) (f (fs _)) (inj tt) (inj tt) (inj p)

¬plus-inj : ∀ n m → ¬ (suc (n + m) F↣ m)
¬plus-inj zero     zero     (f , _)  = f f0
¬plus-inj zero     (suc m)  inj      = ¬plus-inj zero m (shrink inj)
¬plus-inj (suc n)  m        (f , p)  = ¬plus-inj n m (f ∘ fs , p)

toFin-inj : (Fin n ↣ Fin m) → n F↣ m
toFin-inj f .fst = f .fst
toFin-inj (f , inj) .snd {x} {y} x≢ᶠy with discreteFin x y | discreteFin (f x) (f y)
... | no ¬p  | yes p  = ¬p (inj _ _ p)
... | no _   | no _   = tt

n≢sn+m : ∀ n m → Fin n ≢ Fin (suc (n + m))
n≢sn+m n m n≡m =
  ¬plus-inj m n
    (toFin-inj
      (subst
        (_↣ Fin n)
        (n≡m ; cong (Fin ∘ suc) (+-comm n m))
        refl-↣))

Fin-inj : Injective Fin
Fin-inj n m eq with compare n m
... | equal _        = refl
... | less     n  k  = ⊥-elim (n≢sn+m n k eq)
... | greater  m  k  = ⊥-elim (n≢sn+m m k (sym eq))


module Logic.Propositional where

open import Data
open import Data.Either as Either using (_‖_)
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Functional
open import Logic
import      Lvl
open import Type

infixl 1010 ¬_ ¬¬_
infixl 1005 _∧_
infixl 1004 _∨_
infixl 1000 _↔_

------------------------------------------
-- Conjunction (AND)

_∧_ : ∀{ℓ₁ ℓ₂} → Stmt{ℓ₁} → Stmt{ℓ₂} → Stmt
_∧_ = _⨯_

pattern [∧]-intro p q = p , q

[∧]-elimₗ : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P ∧ Q) → P
[∧]-elimₗ = Tuple.left

[∧]-elimᵣ : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P ∧ Q) → Q
[∧]-elimᵣ = Tuple.right

[∧]-map = Tuple.map

------------------------------------------
-- Implication

[→]-elim : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → P → (P → Q) → Q
[→]-elim p f = f(p)

[→]-intro : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P → Q) → (P → Q)
[→]-intro f(p) = f(p)

------------------------------------------
-- Reverse implication

open Functional using (_←_) public

[←]-intro : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P → Q) → (Q ← P)
[←]-intro = [→]-intro

[←]-elim : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → P → (Q ← P) → Q
[←]-elim = [→]-elim

------------------------------------------
-- Equivalence

_↔_ : ∀{ℓ₁ ℓ₂} → Stmt{ℓ₁} → Stmt{ℓ₂} → Stmt
P ↔ Q = ((P ← Q) ⨯ (P → Q))

pattern [↔]-intro l r = l , r

[↔]-elimₗ : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → Q → (P ↔ Q) → P
[↔]-elimₗ = swap Tuple.left

[↔]-elimᵣ : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → P → (P ↔ Q) → Q
[↔]-elimᵣ = swap Tuple.right

[↔]-to-[←] : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P ↔ Q) → (Q → P)
[↔]-to-[←] = Tuple.left

[↔]-to-[→] : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P ↔ Q) → (P → Q)
[↔]-to-[→] = Tuple.right

------------------------------------------
-- Disjunction (OR)

_∨_ : ∀{ℓ₁ ℓ₂} → Stmt{ℓ₁} → Stmt{ℓ₂} → Stmt
_∨_ = _‖_

pattern [∨]-introₗ l = Either.Left l
pattern [∨]-introᵣ r = Either.Right r

[∨]-elim : ∀{ℓ₁ ℓ₂ ℓ₃}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}}{R : Stmt{ℓ₃}} → (P → R) → (Q → R) → (P ∨ Q) → R
[∨]-elim = Either.map1

[∨]-elim2 = Either.map

------------------------------------------
-- Bottom (false, absurdity, empty, contradiction)

⊥ : Stmt{Lvl.𝟎}
⊥ = Empty

[⊥]-intro : ∀{ℓ}{P : Stmt{ℓ}} → P → (P → ⊥) → ⊥
[⊥]-intro = apply

[⊥]-elim : ∀{ℓ}{P : Stmt{ℓ}} → ⊥ → P
[⊥]-elim = empty

------------------------------------------
-- Top (true, truth, unit, validity)

⊤ : Stmt{Lvl.𝟎}
⊤ = Unit

pattern [⊤]-intro = <>

------------------------------------------
-- Negation

¬_ : ∀{ℓ} → Stmt{ℓ} → Stmt
¬_ {ℓ} T = (T → ⊥)

[¬]-intro : ∀{ℓ}{P : Stmt{ℓ}} → (P → ⊥) → (¬ P)
[¬]-intro = id

[¬]-elim : ∀{ℓ}{P : Stmt{ℓ}} → (¬ P) → (P → ⊥) -- written like (P → (¬ P) → ⊥) looks like a [⊥]-intro
[¬]-elim = id

¬¬_ : ∀{ℓ} → Stmt{ℓ} → Stmt
¬¬ p = ¬(¬ p)

------------------------------------------
-- Exclusive disjunction (XOR)

data _⊕_ {ℓ₁ ℓ₂} (P : Stmt{ℓ₁}) (Q : Stmt{ℓ₂}) : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
  [⊕]-introₗ : P → (¬ Q) → (P ⊕ Q)
  [⊕]-introᵣ : Q → (¬ P) → (P ⊕ Q)

------------------------------------------
-- Negative disjunction (NOR)

_⊽_ : ∀{ℓ₁ ℓ₂} → Stmt{ℓ₁} → Stmt{ℓ₂} → Stmt
p ⊽ q = (¬ p) ∧ (¬ q)

[⊽]-intro : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (¬ P) → (¬ Q) → (P ⊽ Q)
[⊽]-intro = [∧]-intro

[⊽]-elimₗ : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P ⊽ Q) → ¬ P
[⊽]-elimₗ = [∧]-elimₗ

[⊽]-elimᵣ : ∀{ℓ₁ ℓ₂}{P : Stmt{ℓ₁}}{Q : Stmt{ℓ₂}} → (P ⊽ Q) → ¬ Q
[⊽]-elimᵣ = [∧]-elimᵣ

------------------------------------------
-- Negative conjunction (NAND)

-- data _⊼_ {P : Stmt} {Q : Stmt} : Stmt where
--   [⊼]-intro ¬(P ∧ Q) → (P ⊼ Q)
--
-- [⊼]-elim : {P Q : Stmt} → (P ⨯ Q ⨯ (P ⊼ Q)) → ⊥
-- [⊼]-elim(p , q , nand)


{-# OPTIONS --without-K #-}
module Equivalence where

open import Homotopy
open import PathOperations
open import Types

infix  1 _≃_

qinv : ∀ {a b} {A : Set a} {B : Set b}
  (f : A → B) → Set _
qinv {A = A} {B = B} f =
  Σ (B → A) λ g → (f ∘ g ∼ id) × (g ∘ f ∼ id)

isequiv : ∀ {a b} {A : Set a} {B : Set b}
  (f : A → B) → Set _
isequiv {A = A} {B = B} f
  = (Σ (B → A) λ g → f ∘ g ∼ id)
  × (Σ (B → A) λ h → h ∘ f ∼ id)

_≃_ : ∀ {a b} (A : Set a) (B : Set b) → Set _
A ≃ B = Σ (A → B) isequiv

qi→eq : ∀ {a b} {A : Set a} {B : Set b}
  {f : A → B} → qinv f → isequiv f
qi→eq (g , p , q) = (g , p) , (g , q)

eq→qi : ∀ {a b} {A : Set a} {B : Set b}
  {f : A → B} → isequiv f → qinv f
eq→qi {f = f} ((g , p) , (h , q)) =
  g , p , λ _ → q _ ⁻¹ · ap h (p _) · q _

≡→eq : ∀ {ℓ} {A : Set ℓ} {B : Set ℓ} → A ≡ B → A ≃ B
≡→eq p
  = tr id p
  , (tr id (p ⁻¹) , λ b → J
      (λ _ B p → (b : B) → tr id p (tr id (p ⁻¹) b) ≡ b)
      (λ _ _ → refl)
      _ _ p b)
  , (tr id (p ⁻¹) , λ a → J
      (λ A _ p → (a : A) → tr id (p ⁻¹) (tr id p a) ≡ a)
      (λ _ _ → refl)
      _ _ p a)

refl-equiv : ∀ {a} {A : Set a} → A ≃ A
refl-equiv = id , (id , λ _ → refl) , (id , λ _ → refl)

sym-equiv : ∀ {a b} {A : Set a} {B : Set b} →
  A ≃ B → B ≃ A
sym-equiv (f , (g , p) , (h , q))
  = g
  , (f , λ _ → q _ ⁻¹ · ap h (p _) · q _)
  , (f , p)

trans-equiv : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c} →
  A ≃ B → B ≃ C → A ≃ C
trans-equiv
  (f₁ , (g₁ , p₁) , (h₁ , q₁)) (f₂ , (g₂ , p₂) , (h₂ , q₂))
  =  f₂ ∘ f₁
  , (g₁ ∘ g₂ , λ _ → ap f₂ (p₁ _) · p₂ _)
  , (h₁ ∘ h₂ , λ _ → ap h₁ (q₂ _) · q₁ _)


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

open import lib.Basics
open import lib.types.Empty
open import lib.types.Group
open import lib.types.Word
open import lib.groups.GeneratedGroup
open import lib.groups.Homomorphism

module lib.groups.FreeGroup where

module FreeGroup {i} (A : Type i) where

  private
    module Gen = GeneratedGroup A empty-rel
  open Gen hiding (GenGroup) public

  FreeGroup : Group i
  FreeGroup = Gen.GenGroup

  module Freeness {j} (G : Group j) where

    private
      module G = Group G
      module HE = HomomorphismEquiv G

    extend-equiv : (A → G.El) ≃ (FreeGroup →ᴳ G)
    extend-equiv =
      HE.extend-equiv ∘e every-function-respects-empty-rel-equiv A G

    extend : (A → G.El) → (FreeGroup →ᴳ G)
    extend = –> extend-equiv

    extend-is-equiv : is-equiv extend
    extend-is-equiv = snd extend-equiv


------------------------------------------------------------------------
-- The Agda standard library
--
-- This module constructs the unit of the monoidal structure on
-- R-modules, and similar for weaker module-like structures.
-- The intended universal property is that the maps out of the tensor
-- unit into M are isomorphic to the elements of M.
------------------------------------------------------------------------

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

module Algebra.Module.Construct.TensorUnit where

open import Algebra.Bundles
open import Algebra.Module.Bundles
open import Level

private
  variable
    c ℓ : Level

leftSemimodule : {R : Semiring c ℓ} → LeftSemimodule R c ℓ
leftSemimodule {R = semiring} = record
  { Carrierᴹ = Carrier
  ; _≈ᴹ_ = _≈_
  ; _+ᴹ_ = _+_
  ; _*ₗ_ = _*_
  ; 0ᴹ = 0#
  ; isLeftSemimodule = record
    { +ᴹ-isCommutativeMonoid = +-isCommutativeMonoid
    ; isPreleftSemimodule = record
      { *ₗ-cong = *-cong
      ; *ₗ-zeroˡ = zeroˡ
      ; *ₗ-distribʳ = distribʳ
      ; *ₗ-identityˡ = *-identityˡ
      ; *ₗ-assoc = *-assoc
      ; *ₗ-zeroʳ = zeroʳ
      ; *ₗ-distribˡ = distribˡ
      }
    }
  } where open Semiring semiring

rightSemimodule : {R : Semiring c ℓ} → RightSemimodule R c ℓ
rightSemimodule {R = semiring} = record
  { Carrierᴹ = Carrier
  ; _≈ᴹ_ = _≈_
  ; _+ᴹ_ = _+_
  ; _*ᵣ_ = _*_
  ; 0ᴹ = 0#
  ; isRightSemimodule = record
    { +ᴹ-isCommutativeMonoid = +-isCommutativeMonoid
    ; isPrerightSemimodule = record
      { *ᵣ-cong = *-cong
      ; *ᵣ-zeroʳ = zeroʳ
      ; *ᵣ-distribˡ = distribˡ
      ; *ᵣ-identityʳ = *-identityʳ
      ; *ᵣ-assoc = *-assoc
      ; *ᵣ-zeroˡ = zeroˡ
      ; *ᵣ-distribʳ = distribʳ
      }
    }
  } where open Semiring semiring

bisemimodule : {R : Semiring c ℓ} → Bisemimodule R R c ℓ
bisemimodule {R = semiring} = record
  { isBisemimodule = record
    { +ᴹ-isCommutativeMonoid = +-isCommutativeMonoid
    ; isPreleftSemimodule =
      LeftSemimodule.isPreleftSemimodule leftSemimodule
    ; isPrerightSemimodule =
      RightSemimodule.isPrerightSemimodule rightSemimodule
    ; *ₗ-*ᵣ-assoc = *-assoc
    }
  } where open Semiring semiring

semimodule : {R : CommutativeSemiring c ℓ} → Semimodule R c ℓ
semimodule {R = commutativeSemiring} = record
  { isSemimodule = record
    { isBisemimodule = Bisemimodule.isBisemimodule bisemimodule
    }
  } where open CommutativeSemiring commutativeSemiring

leftModule : {R : Ring c ℓ} → LeftModule R c ℓ
leftModule {R = ring} = record
  { -ᴹ_ = -_
  ; isLeftModule = record
    { isLeftSemimodule = LeftSemimodule.isLeftSemimodule leftSemimodule
    ; -ᴹ‿cong = -‿cong
    ; -ᴹ‿inverse = -‿inverse
    }
  } where open Ring ring

rightModule : {R : Ring c ℓ} → RightModule R c ℓ
rightModule {R = ring} = record
  { -ᴹ_ = -_
  ; isRightModule = record
    { isRightSemimodule = RightSemimodule.isRightSemimodule rightSemimodule
    ; -ᴹ‿cong = -‿cong
    ; -ᴹ‿inverse = -‿inverse
    }
  } where open Ring ring

bimodule : {R : Ring c ℓ} → Bimodule R R c ℓ
bimodule {R = ring} = record
  { isBimodule = record
    { isBisemimodule = Bisemimodule.isBisemimodule bisemimodule
    ; -ᴹ‿cong = -‿cong
    ; -ᴹ‿inverse = -‿inverse
    }
  } where open Ring ring

⟨module⟩ : {R : CommutativeRing c ℓ} → Module R c ℓ
⟨module⟩ {R = commutativeRing} = record
  { isModule = record
    { isBimodule = Bimodule.isBimodule bimodule
    }
  } where open CommutativeRing commutativeRing


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

-- https://personal.cis.strath.ac.uk/conor.mcbride/pub/DepRep/DepRep.pdf

module Experiment.Outrageous.#03 where

open import Experiment.Outrageous.#02

data U : Set
El : U → Set

data U where
  :Zero: :𝟏: :𝟐: :ℕ: : U
  :Π: :Σ: : (S : U) → (El S → U) → U
El :Zero: = Zero
El :𝟏:    = 𝟏
El :𝟐:    = 𝟐
El :ℕ:    = ℕ
El (:Π: S T) = (s : El S) → El (T s)
El (:Σ: S T) = Σ (El S) λ s → El (T s)

_:→:_ : U → U → U
S :→: T = :Π: S λ _ → T

_:×:_ : U → U → U
S :×: T = :Σ: S λ _ → T

:If: : 𝟐 → U → U → U
:If: tt T F = T
:If: ff T F = F

:Vec: : U → ℕ → U
:Vec: X ze     = :𝟏:
:Vec: X (su n) = X :×: :Vec: X n


open import Data.Product using ( _×_ ; _,_ )
open import Data.Sum using ( _⊎_ ; inj₁ ; inj₂  )
open import FRP.LTL.Time.Interval using ( _⊑_ ; _~_ ; _⌢_∵_ )
open import FRP.LTL.ISet.Core using ( ISet ; [_] ; _,_ ; M⟦_⟧ ; splitM⟦_⟧ ; subsumM⟦_⟧ )

module FRP.LTL.ISet.Sum where

_∨_ : ISet → ISet → ISet
A ∨ B = [ (λ i → M⟦ A ⟧ i ⊎ M⟦ B ⟧ i) , split , subsum ] where

  split : ∀ i j i~j →
    (M⟦ A ⟧ (i ⌢ j ∵ i~j) ⊎ M⟦ B ⟧ (i ⌢ j ∵ i~j)) →
      ((M⟦ A ⟧ i ⊎ M⟦ B ⟧ i) × (M⟦ A ⟧ j ⊎ M⟦ B ⟧ j))
  split i j i~j (inj₁ σ) with splitM⟦ A ⟧ i j i~j σ
  split i j i~j (inj₁ σ) | (σ₁ , σ₂) = (inj₁ σ₁ , inj₁ σ₂)
  split i j i~j (inj₂ τ) with splitM⟦ B ⟧ i j i~j τ
  split i j i~j (inj₂ τ) | (τ₁ , τ₂) = (inj₂ τ₁ , inj₂ τ₂)

  subsum : ∀ i j → (i ⊑ j) → (M⟦ A ⟧ j ⊎ M⟦ B ⟧ j) → (M⟦ A ⟧ i ⊎ M⟦ B ⟧ i)
  subsum i j i⊑j (inj₁ σ) = inj₁ (subsumM⟦ A ⟧ i j i⊑j σ)
  subsum i j i⊑j (inj₂ τ) = inj₂ (subsumM⟦ B ⟧ i j i⊑j τ)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Some defined operations (multiplication by natural number and
-- exponentiation)
------------------------------------------------------------------------

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

open import Algebra

module Algebra.Operations.Semiring {s₁ s₂} (S : Semiring s₁ s₂) where

import Algebra.Operations.CommutativeMonoid as MonoidOperations
open import Data.Nat.Base
  using (zero; suc; ℕ) renaming (_+_ to _ℕ+_; _*_ to _ℕ*_)
open import Data.Product using (module Σ)
open import Function using (_$_)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P using (_≡_)

open Semiring S renaming (zero to *-zero)
open import Relation.Binary.Reasoning.Setoid setoid

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

-- Re-export all monoid operations and proofs
open MonoidOperations +-commutativeMonoid public

-- Exponentiation.
infixr 9 _^_
_^_ : Carrier → ℕ → Carrier
x ^ zero  = 1#
x ^ suc n = x * x ^ n

------------------------------------------------------------------------
-- Properties of _×_

-- _× 1# is homomorphic with respect to _ℕ*_/_*_.

×1-homo-* : ∀ m n → (m ℕ* n) × 1# ≈ (m × 1#) * (n × 1#)
×1-homo-* 0 n = begin
  0#             ≈⟨ sym (Σ.proj₁ *-zero (n × 1#)) ⟩
  0# * (n × 1#)  ∎
×1-homo-* (suc m) n = begin
  (n ℕ+ m ℕ* n) × 1#                  ≈⟨ ×-homo-+ 1# n (m ℕ* n) ⟩
  n × 1# + (m ℕ* n) × 1#              ≈⟨ +-cong refl (×1-homo-* m n) ⟩
  n × 1# + (m × 1#) * (n × 1#)         ≈⟨ sym (+-cong (*-identityˡ _) refl) ⟩
  1# * (n × 1#) + (m × 1#) * (n × 1#)  ≈⟨ sym (distribʳ (n × 1#) 1# (m × 1#)) ⟩
  (1# + m × 1#) * (n × 1#)             ∎

------------------------------------------------------------------------
-- Properties of _×′_

-- _×′ 1# is homomorphic with respect to _ℕ*_/_*_.

×′1-homo-* : ∀ m n → (m ℕ* n) ×′ 1# ≈ (m ×′ 1#) * (n ×′ 1#)
×′1-homo-* m n = begin
  (m ℕ* n) ×′ 1#         ≈⟨ sym $ ×≈×′ (m ℕ* n) 1# ⟩
  (m ℕ* n) ×  1#         ≈⟨ ×1-homo-* m n ⟩
  (m ×  1#) * (n ×  1#)  ≈⟨ *-cong (×≈×′ m 1#) (×≈×′ n 1#) ⟩
  (m ×′ 1#) * (n ×′ 1#)  ∎

------------------------------------------------------------------------
-- Properties of _^_

-- _^_ preserves equality.

^-congˡ : ∀ n → (_^ n) Preserves _≈_ ⟶ _≈_
^-congˡ zero    x≈y = refl
^-congˡ (suc n) x≈y = *-cong x≈y (^-congˡ n x≈y)

^-cong : _^_ Preserves₂ _≈_ ⟶ _≡_ ⟶ _≈_
^-cong {v = n} x≈y P.refl = ^-congˡ n x≈y


------------------------------------------------------------------------------
-- The gcd program is correct
------------------------------------------------------------------------------

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

-- This module proves the correctness of the gcd program using
-- the Euclid's algorithm.

module LTC-PCF.Program.GCD.Partial.CorrectnessProof where

open import LTC-PCF.Base
open import LTC-PCF.Data.Nat.Divisibility.NotBy0.Properties
  using ( 0∤x ; x∣S→x≤S )
open import LTC-PCF.Data.Nat.Type

open import LTC-PCF.Program.GCD.Partial.CommonDivisor using ( gcdCD )
open import LTC-PCF.Program.GCD.Partial.Definitions using ( x≢0≢y ; gcdSpec )
open import LTC-PCF.Program.GCD.Partial.Divisible using ( gcdDivisible )
open import LTC-PCF.Program.GCD.Partial.GCD using ( gcd )

import LTC-PCF.Program.GCD.Partial.GreatestAnyCommonDivisor
open module GreatestAnyCommonDivisor =
  LTC-PCF.Program.GCD.Partial.GreatestAnyCommonDivisor x∣S→x≤S 0∤x
  using ( gcdGACD )

open import LTC-PCF.Program.GCD.Partial.Totality using ( gcd-N )

------------------------------------------------------------------------------
-- The gcd is correct
gcdCorrect : ∀ {m n} → N m → N n → x≢0≢y m n → gcdSpec m n (gcd m n)
gcdCorrect Nm Nn m≢0≢n = gcdCD Nm Nn m≢0≢n
                         , gcdGACD (gcd-N Nm Nn m≢0≢n)
                                   (gcdCD Nm Nn m≢0≢n)
                                   (gcdDivisible Nm Nn m≢0≢n)


-- Ad-hoc monoid typeclass module

module Utils.Monoid where

open import Data.List
open import Data.String

record Monoid {α}(A : Set α) : Set α where
  constructor rec
  field
    append   : A → A → A
    identity : A

infixr 5 _<>_
_<>_ : ∀ {α}{A : Set α} ⦃ _ : Monoid A ⦄ → A → A → A
_<>_ ⦃ dict ⦄ a b = Monoid.append dict a b

mempty : ∀ {α}{A : Set α} ⦃ _ : Monoid A ⦄ → A
mempty ⦃ dict ⦄ = Monoid.identity dict

instance
  MonoidList : ∀ {α A} → Monoid {α} (List A)
  MonoidList = rec Data.List._++_ []

  MonoidString : Monoid String
  MonoidString = rec Data.String._++_ ""


{-

This file contains:

- An implementation of the free groupoid (a free group that has no limitiations
  over the high dimensional path structure). An intermediate construction used
  to calculate the fundamental group of a Bouquet.

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

module Cubical.HITs.FreeGroupoid.Base where

open import Cubical.Foundations.Prelude

private
  variable
    ℓ : Level

data FreeGroupoid (A : Type ℓ) : Type ℓ where
  η     : A → FreeGroupoid A
  _·_     : FreeGroupoid A → FreeGroupoid A → FreeGroupoid A
  ε     : FreeGroupoid A
  inv   : FreeGroupoid A → FreeGroupoid A
  assoc : ∀ x y z → x · (y · z) ≡ (x · y) · z
  idr   : ∀ x → x ≡ x · ε
  idl   : ∀ x → x ≡ ε · x
  invr  : ∀ x → x · (inv x) ≡ ε
  invl  : ∀ x → (inv x) · x ≡ ε


module Esterel.Variable.Sequential where

open import Data.Nat
  using (ℕ) renaming (_≟_ to _≟ℕ_)
open import Function
  using (_∘_)
open import Relation.Nullary
  using (Dec ; yes ; no ; ¬_)
open import Relation.Binary
  using (Decidable)
open import Relation.Binary.PropositionalEquality
  using (_≡_ ; refl ; cong ; trans ; sym)

data SeqVar : Set where
  _ᵥ : ℕ → SeqVar

unwrap : SeqVar → ℕ
unwrap (n ᵥ) = n

unwrap-inverse : ∀ {s} → (unwrap s) ᵥ ≡ s
unwrap-inverse {_ ᵥ} = refl

unwrap-injective : ∀ {s t} → unwrap s ≡ unwrap t → s ≡ t
unwrap-injective s'≡t' = trans (sym unwrap-inverse) (trans (cong _ᵥ s'≡t') unwrap-inverse)

-- for backward compatibility
unwrap-neq : ∀{k1 : SeqVar} → ∀{k2 : SeqVar} → ¬ k1 ≡ k2 → ¬ (unwrap k1) ≡ (unwrap k2)
unwrap-neq = (_∘ unwrap-injective)

wrap : ℕ → SeqVar
wrap = _ᵥ

bijective : ∀{x} → unwrap (wrap x) ≡ x
bijective = refl

_≟_ : Decidable {A = SeqVar} _≡_
(s ᵥ) ≟ (t ᵥ) with s ≟ℕ t
... | yes p = yes (cong _ᵥ p)
... | no ¬p = no (¬p ∘ cong unwrap)


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

open import Setoids.Setoids
open import Groups.SymmetricGroups.Definition
open import Groups.FreeGroup.Definition
open import Decidable.Sets
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import LogicalFormulae
open import Boolean.Definition

module Groups.FreeGroup.Word {a : _} {A : Set a} (decA : DecidableSet A) where

data ReducedWord : Set a
wordLength : ReducedWord → ℕ
firstLetter : (w : ReducedWord) → .(0 <N wordLength w) → FreeCompletion A

data PrependIsValid (w : ReducedWord) (l : FreeCompletion A) : Set a where
  wordEmpty : wordLength w ≡ 0 → PrependIsValid w l
  wordEnding : .(pr : 0 <N wordLength w) → .(freeCompletionEqual decA l (freeInverse (firstLetter w pr)) ≡ BoolFalse) → PrependIsValid w l

data ReducedWord where
  empty : ReducedWord
  prependLetter : (letter : FreeCompletion A) → (w : ReducedWord) → PrependIsValid w letter → ReducedWord

firstLetter empty ()
firstLetter (prependLetter letter w x) pr = letter

wordLength empty = 0
wordLength (prependLetter letter w pr) = succ (wordLength w)

prependLetterRefl : {x : FreeCompletion A} {w : ReducedWord} → {pr1 pr2 : PrependIsValid w x} → prependLetter x w pr1 ≡ prependLetter x w pr2
prependLetterRefl {x} {empty} {wordEmpty refl} {wordEmpty refl} = refl
prependLetterRefl {x} {empty} {wordEmpty refl} {wordEnding () x₂}
prependLetterRefl {x} {empty} {wordEnding () x₁} {pr2}
prependLetterRefl {x} {prependLetter letter w x₁} {wordEmpty ()} {pr2}
prependLetterRefl {x} {prependLetter letter w x₁} {wordEnding pr x₂} {wordEmpty ()}
prependLetterRefl {x} {prependLetter letter w x₁} {wordEnding pr2 r2} {wordEnding pr1 r1} = refl

prependLetterInjective : {x : FreeCompletion A} {w1 w2 : ReducedWord} {pr1 : PrependIsValid w1 x} {pr2 : PrependIsValid w2 x} → prependLetter x w1 pr1 ≡ prependLetter x w2 pr2 → w1 ≡ w2
prependLetterInjective {x = x} {empty} {empty} {pr1} {pr2} pr = refl
prependLetterInjective {x = x} {prependLetter l1 w1 x1} {prependLetter .l1 .w1 .x1} {wordEnding pr₁ x₁} {wordEnding pr₂ x₂} refl = refl

prependLetterInjective' : {x y : FreeCompletion A} {w1 w2 : ReducedWord} {pr1 : PrependIsValid w1 x} {pr2 : PrependIsValid w2 y} → prependLetter x w1 pr1 ≡ prependLetter y w2 pr2 → x ≡ y
prependLetterInjective' refl = refl

badPrepend : {x : A} {w : ReducedWord} {pr : PrependIsValid w (ofInv x)} → (PrependIsValid (prependLetter (ofInv x) w pr) (ofLetter x)) → False
badPrepend (wordEmpty ())
badPrepend {x = x} (wordEnding pr bad) with decidableFreeCompletion decA (ofLetter x) (ofLetter x)
badPrepend {x} (wordEnding pr ()) | inl x₁
badPrepend {x} (wordEnding pr bad) | inr pr2 = pr2 refl

badPrepend' : {x : A} {w : ReducedWord} {pr : PrependIsValid w (ofLetter x)} → (PrependIsValid (prependLetter (ofLetter x) w pr) (ofInv x)) → False
badPrepend' (wordEmpty ())
badPrepend' {x = x} (wordEnding pr x₁) with decidableFreeCompletion decA (ofInv x) (ofInv x)
badPrepend' {x} (wordEnding pr ()) | inl x₂
badPrepend' {x} (wordEnding pr x₁) | inr pr2 = pr2 refl


------------------------------------------------------------------------
-- Convenient syntax for "equational reasoning" using a indexed preorder
------------------------------------------------------------------------

open import Relation.Binary.Indexed.Extra

module Relation.Binary.Indexed.PreorderReasoning {𝒾} {I : Set 𝒾} {𝒸 ℓ₁ ℓ₂} (P : Preorder I 𝒸 ℓ₁ ℓ₂) where

open Preorder P

infix  4 _IsRelatedTo_
infix  1 begin_
infix  3 _∎
infixr 2 _∼⟨_⟩_ _≈⟨_⟩_ _≈⟨⟩_

data _IsRelatedTo_ {i j : I} (x : Carrier i) (y : Carrier j) : Set ℓ₂ where
    relTo : (x∼y : x ∼ y) → x IsRelatedTo y

begin_ : ∀ {i j : I} {x : Carrier i} {y : Carrier j} →  x IsRelatedTo y → x ∼ y
begin relTo x∼y = x∼y

_∼⟨_⟩_ : ∀ {i j k : I} → (x : Carrier i)
    → {y : Carrier j} {z : Carrier k}
    → x ∼ y → y IsRelatedTo z → x IsRelatedTo z
_ ∼⟨ x∼y ⟩ relTo y∼z = relTo (trans x∼y y∼z)

_≈⟨_⟩_ : ∀ {i j k : I} → (x : Carrier i)
    → {y : Carrier j} {z : Carrier k}
    → x ≈ y → y IsRelatedTo z → x IsRelatedTo z
_ ≈⟨ x≈y ⟩ relTo y∼z = relTo (trans (reflexive x≈y) y∼z)

_≈⟨⟩_ : ∀ {i j : I} → (x : Carrier i) → {y : Carrier j}
    → x IsRelatedTo y → x IsRelatedTo y
_ ≈⟨⟩ x∼y = x∼y

_∎ : ∀ {i : I} (x : Carrier i) → x IsRelatedTo x
_∎ _ = relTo refl


-------------------------------------------------
-- Formalisation of the Z axioms of set theory.
-------------------------------------------------
module sv20.assign2.SetTheory.ZAxioms where

open import sv20.assign2.SetTheory.Logic

infix 1 ∃
infix 5 _⊆_ _⊂_
infix 5 _∈_ _∉_
infix 4 _≡_

-- The universe of discourse (pure sets) and the membership
-- relationship. (The letter 𝓢 is type by "\MCS")
postulate
  𝓢   : Set
  _∈_ : 𝓢 → 𝓢 → Set

-- Existential quantifier

data ∃ (A : 𝓢 → Set) : Set where
  _,_ : (t : 𝓢) → A t → ∃ A

-- Sugar syntax for the existential quantifier.

syntax ∃ (λ x → e) = ∃[ x ] e

-- Existential projections.

proj₁ : {A : 𝓢 → Set} → ∃ A → 𝓢
proj₁ (t , _) = t

proj₂ : (A : 𝓢 → Set) → (foo : ∃ A)  → A (proj₁ foo)
proj₂ A (_ , Ax) = Ax

-- Equivalence and non equivalence with some useful properties

data _≡_ (x : 𝓢) : 𝓢 → Set where
  refl : x ≡ x

_≢_ : 𝓢 → 𝓢 → Set
x ≢ y = ¬ x ≡ y

sym : (x y : 𝓢) → x ≡ y → y ≡ x
sym x .x refl = refl

cong : (f :  𝓢 → 𝓢) {x y : 𝓢} → x ≡ y → f x ≡ f y
cong f refl = refl

subs : (P : 𝓢 → Set) {x y : 𝓢} (p : x ≡ y) (h : P x) → P y
subs P {x} {.x} refl h = h

trans : {x y z : 𝓢} → x ≡ y →  y ≡ z → x ≡ z
trans refl refl = refl

-- Property concerning bi-implication, needed in a proof.
⇔-p₂ : (z : 𝓢) → {A B C : Set} →  A ⇔ (B ∧ C) → (C → B) → A ⇔ C
⇔-p₂ z (h₁ , h₂) h₃ = (λ a → ∧-proj₂ (h₁ a)) , (λ c → h₂ ((h₃ c) , c))

-- Definitions of subset and not-membership.

_⊆_ : 𝓢 → 𝓢 → Set
x ⊆ y = (t : 𝓢) → t ∈ x → t ∈ y

_∉_ : 𝓢 → 𝓢 → Set
x ∉ y = ¬ (x ∈ y)
-- {-# ATP definition _∉_ #-}

_⊂_ : 𝓢 → 𝓢 → Set
x ⊂ y = x ⊆ y ∧ x ≢ y

_⊂'_ : 𝓢 → 𝓢 → Set
x ⊂' y = x ⊆ y ∧ ∃ (λ z → z ∈ y ∧ z ∉ x)

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

-- ZFC's axioms
-- From (Suppes 1960, p. 56)

-- ext (Extensionality) : If two sets have exactly the same members,
-- they are equal.

-- empt (Empty Set Axiom) : There is a set having no
-- members. Allows us to define the empty set.

-- pair (Pairing Axiom) : For any sets y and z, there is a set having
-- as members just y and z. Allows to define a set which is just
-- the pair of any two sets.

-- pow (Power Set Axiom): For any x there is a set whose members are
-- exactly the subsets of x. Allows us to define the power set
-- operation.

-- sub (Subset Axiom, or Specification Axiom): This axiom asserts the
-- existence of a set B whose members are exactly those sets x in y
-- such that they satisfy certain property. Allows us to define
-- many operations like cartesian products and difference of sets.

-- uni (Union Axiom) : For any set x, there exists a set A whose
-- elements are exactly the members of x. Allows us to define the
-- union of two sets.

-- pem (Principle of the excluded middle) : To prove some things
-- not valid in intuitionistic logic and valid in classical logic. Taken
-- from the Standford Encyclopedia entry on Intuitionistic Logic.
-- (https://plato.stanford.edu/entries/logic-intuitionistic/).

-- The sum axioms allow us to define the union operation
-- over a family of sets.

postulate
  empt : ∃ (λ B → ∀ x → x ∉ B)
  ext  : (x y : 𝓢) → ∀ {z} → z ∈ x ⇔ z ∈ y → x ≡ y
  union : (x y : 𝓢) → ∃ (λ B → {z : 𝓢} → z ∈ B ⇔ z ∈ x ∨ z ∈ y)
  pair : (x y : 𝓢) → ∃ (λ B → {z : 𝓢} → z ∈ B ⇔ (z ≡ x ∨ z ≡ y))
  pow : (x : 𝓢) → ∃ (λ B → ∀ {y} → y ∈ B ⇔ y ⊆ x)
  sub  : (A : 𝓢 → Set) → (y : 𝓢) → ∃ (λ B → {z : 𝓢} → (z ∈ B ⇔ (z ∈ y ∧ A z)))
  pem : (A : Set) → A ∨ ¬ A
  sum : (A : 𝓢) → ∃ (λ C → (x : 𝓢) → x ∈ C ⇔ ∃ (λ B → x ∈ B ∧ B ∈ A))
-- {-# ATP axioms empt ext union pair pow #-}

-- sub not given to apia since it is an axiom schema and ATPs don't deal
-- with that.

-- pem isn't given either since ATP's use classical logic so it uses
-- this principle by default.

∅ : 𝓢
∅ = proj₁ empt
-- {-# ATP definition ∅ #-}

-- Axiom of regularity: Axiom that have two very intuitive consequences:
-- ∀ A (A ∉ A) and ¬ ∀ A,B (A∈B ∧ B∈A). From Suppes, p. 56 (1960).
postulate
  reg : (A : 𝓢) → A ≢ ∅ → ∃ (λ x → x ∈ A ∧ ∀ y → y ∈ x → y ∉ A)

-- References
--
-- Suppes, Patrick (1960). Axiomatic Set Theory.
-- The University Series in Undergraduate Mathematics.
-- D. Van Nostrand Company, inc.
--
-- Enderton, Herbert B. (1977). Elements of Set Theory.
-- Academic Press Inc.


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties satisfied by preorders
------------------------------------------------------------------------

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

open import Relation.Binary

module Relation.Binary.Properties.Preorder
         {p₁ p₂ p₃} (P : Preorder p₁ p₂ p₃) where

open import Function
open import Data.Product as Prod

open Relation.Binary.Preorder P

-- The inverse relation is also a preorder.

invIsPreorder : IsPreorder _≈_ (flip _∼_)
invIsPreorder = record
  { isEquivalence = isEquivalence
  ; reflexive     = reflexive ∘ Eq.sym
  ; trans         = flip trans
  }

invPreorder : Preorder p₁ p₂ p₃
invPreorder = record { isPreorder = invIsPreorder }

------------------------------------------------------------------------
-- For every preorder there is an induced equivalence

InducedEquivalence : Setoid _ _
InducedEquivalence = record
  { _≈_           = λ x y → x ∼ y × y ∼ x
  ; isEquivalence = record
    { refl  = (refl , refl)
    ; sym   = swap
    ; trans = Prod.zip trans (flip trans)
    }
  }


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of left-scaling
------------------------------------------------------------------------

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

open import Relation.Binary

-- The properties are parameterised by the two carriers and
-- the result equality.

module Algebra.Module.Definitions.Left
  {a b ℓb} (A : Set a) {B : Set b} (_≈_ : Rel B ℓb)
  where

open import Data.Sum
open import Data.Product

------------------------------------------------------------------------
-- Binary operations

open import Algebra.Core

------------------------------------------------------------------------
-- Properties of operations

LeftIdentity : A → Opₗ A B → Set _
LeftIdentity a _∙ᴮ_ = ∀ m → (a ∙ᴮ m) ≈ m

Associative : Op₂ A → Opₗ A B → Set _
Associative _∙ᴬ_ _∙ᴮ_ = ∀ x y m → ((x ∙ᴬ y) ∙ᴮ m) ≈ (x ∙ᴮ (y ∙ᴮ m))

_DistributesOverˡ_ : Opₗ A B → Op₂ B → Set _
_*_ DistributesOverˡ _+_ =
  ∀ x m n → (x * (m + n)) ≈ ((x * m) + (x * n))

_DistributesOverʳ_⟶_ : Opₗ A B → Op₂ A → Op₂ B → Set _
_*_ DistributesOverʳ _+ᴬ_ ⟶ _+ᴮ_ =
  ∀ x m n → ((m +ᴬ n) * x) ≈ ((m * x) +ᴮ (n * x))

LeftZero : A → B → Opₗ A B → Set _
LeftZero zᴬ zᴮ _∙_ = ∀ x → (zᴬ ∙ x) ≈ zᴮ

RightZero : B → Opₗ A B → Set _
RightZero z _∙_ = ∀ x → (x ∙ z) ≈ z

Commutative : Opₗ A B → Set _
Commutative _∙_ = ∀ x y m → (x ∙ (y ∙ m)) ≈ (y ∙ (x ∙ m))

LeftCongruent : Opₗ A B → Set _
LeftCongruent _∙_ = ∀ {x} → (x ∙_) Preserves _≈_ ⟶ _≈_

RightCongruent : ∀ {ℓa} → Rel A ℓa → Opₗ A B → Set _
RightCongruent ≈ᴬ _∙_ = ∀ {m} → (_∙ m) Preserves ≈ᴬ ⟶ _≈_

Congruent : ∀ {ℓa} → Rel A ℓa → Opₗ A B → Set _
Congruent ≈ᴬ ∙ = ∙ Preserves₂ ≈ᴬ ⟶ _≈_ ⟶ _≈_


{-# OPTIONS --universe-polymorphism #-}
module Categories.FunctorCategory where

open import Data.Product

open import Categories.Category
import Categories.Functor as Cat
open import Categories.Functor hiding (equiv; id; _∘_; _≡_)
open import Categories.NaturalTransformation
open import Categories.Product
open import Categories.Square

Functors : ∀ {o ℓ e} {o′ ℓ′ e′} → Category o ℓ e → Category o′ ℓ′ e′ → Category _ _ _
Functors C D = record
  { Obj = Functor C D
  ; _⇒_ = NaturalTransformation
  ; _≡_ = _≡_
  ; _∘_ = _∘₁_
  ; id = id
  ; assoc = λ {_} {_} {_} {_} {f} {g} {h} → assoc₁ {X = f} {g} {h}
  ; identityˡ = λ {_} {_} {f} → identity₁ˡ {X = f}
  ; identityʳ = λ {_} {_} {f} → identity₁ʳ {X = f}
  ; equiv = λ {F} {G} → equiv {F = F} {G = G}
  ; ∘-resp-≡ = λ {_} {_} {_} {f} {h} {g} {i} → ∘₁-resp-≡ {f = f} {h} {g} {i}
  }

eval : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e}{D : Category o′ ℓ′ e′} → Functor (Product (Functors C D) C) D
eval {C = C} {D = D} =
    record {
      F₀ = λ x → let F , c = x in F₀ F c;
      F₁ = λ { {F , c₁} {G , c₂} (ε , f) → F₁ G f D.∘ η ε _};
      identity = λ { {F , c} → begin
                                 F₁ F C.id D.∘ D.id ↓⟨ D.identityʳ ⟩
                                 F₁ F C.id          ↓⟨ identity F ⟩
                                 D.id               ∎};
      homomorphism = λ { {F , c₁} {G , c₂} {H , c₃} {ε₁ , f₁} {ε₂ , f₂} →
         begin
           F₁ H (f₂ C.∘ f₁) D.∘ η ε₂ c₁ D.∘ η ε₁ c₁        ↑⟨ D.assoc ⟩
           (F₁ H (f₂ C.∘ f₁) D.∘ η ε₂ c₁) D.∘ η ε₁ c₁
              ↓⟨ D.∘-resp-≡ˡ (begin
                                F₁ H (C [ f₂ ∘ f₁ ]) D.∘ η ε₂ c₁  ↓⟨ D.∘-resp-≡ˡ (homomorphism H) ⟩
                                (F₁ H f₂ D.∘ F₁ H f₁) D.∘ η ε₂ c₁ ↓⟨ D.assoc ⟩
                                F₁ H f₂ D.∘ F₁ H f₁ D.∘ η ε₂ c₁   ↑⟨ D.∘-resp-≡ʳ (commute ε₂ f₁) ⟩
                                F₁ H f₂ D.∘ η ε₂ c₂ D.∘ F₁ G f₁   ↑⟨ D.assoc ⟩
                                (F₁ H f₂ D.∘ η ε₂ c₂) D.∘ F₁ G f₁ ∎)
               ⟩
           ((F₁ H f₂ D.∘ η ε₂ c₂) D.∘ F₁ G f₁) D.∘ η ε₁ c₁ ↓⟨ D.assoc ⟩
           (F₁ H f₂ D.∘ η ε₂ c₂) D.∘ F₁ G f₁ D.∘ η ε₁ c₁   ∎ };
      F-resp-≡ = λ { {F , c₁} {G , c₂} {ε₁ , f₁} {ε₂ , f₂} (ε₁≡ε₂ , f₁≡f₂)
                        → D.∘-resp-≡ (F-resp-≡ G f₁≡f₂) ε₁≡ε₂} }
  where
    module C = Category C
    module D = Category D

    open Functor
    open NaturalTransformation
    open D.HomReasoning

Cat[-∘_] : ∀ {o₁ ℓ₁ e₁ o₂ ℓ₂ e₂ o₃ ℓ₃ e₃} {A : Category o₁ ℓ₁ e₁} {B : Category o₂ ℓ₂ e₂}
             {C : Category o₃ ℓ₃ e₃} -> Functor A B -> Functor (Functors B C) (Functors A C)
Cat[-∘_] {C = C} r = record
  { F₀ = λ X → X Cat.∘ r
  ; F₁ = λ η → η ∘ʳ r
  ; identity = C.Equiv.refl
  ; homomorphism = C.Equiv.refl
  ; F-resp-≡ = λ x → x
  }
 where
   module C = Category C


module map-Tree where

-- ツリー
data Tree (A B : Set) : Set where
  leaf : A → Tree A B
  node : Tree A B → B → Tree A B → Tree A B

-- ツリーのmap
map-Tree : ∀ {A B C D : Set} → (A → C) → (B → D) → Tree A B → Tree C D
map-Tree f g (leaf a)             = leaf (f a)
map-Tree f g (node treeˡ b treeʳ) = node (map-Tree f g treeˡ) (g b) (map-Tree f g treeʳ)


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

open import Level

open import Categories.Category using (Category)
open import Categories.Functor using (Functor; Endofunctor; _∘F_) renaming (id to idF)
import Categories.Morphism.Reasoning as MR
open import Categories.NaturalTransformation renaming (id to idN)
open import Categories.NaturalTransformation.NaturalIsomorphism hiding (_≃_)
open import Categories.NaturalTransformation.Equivalence
open NaturalIsomorphism

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

record Monad {C : Category o ℓ e} {D : Category o′ ℓ′ e′} (J : Functor C D) : Set (o ⊔ o′ ⊔ ℓ′ ⊔ e′) where
  private
    module C = Category C
    module D = Category D
    module J = Functor J
    open D using (_⇒_; _∘_; _≈_)
  field
    F₀ : C.Obj → D.Obj
    unit : {c : C.Obj} → J.₀ c ⇒ F₀ c
    extend : {x y : C.Obj} → (J.₀ x ⇒ F₀ y) → F₀ x ⇒ F₀ y
    identityʳ : {x y : C.Obj} { k : J.₀ x ⇒ F₀ y} → extend k ∘ unit ≈ k
    identityˡ : {x : C.Obj} → extend {x} unit ≈ D.id
    assoc : {x y z : C.Obj} {k : J.₀ x ⇒ F₀ y} {l : J.₀ y ⇒ F₀ z} → extend (extend l ∘ k) ≈ extend l ∘ extend k
    extend-≈ : {x y : C.Obj} {k h : J.₀ x ⇒ F₀ y} → k ≈ h → extend k ≈ extend h

-- From a Relative Monad, we can extract a functor
RMonad⇒Functor : {J : Functor C D} → Monad J → Functor C D
RMonad⇒Functor {C = C} {D = D} {J = J} r = record
  { F₀ = F₀
  ; F₁ = λ f → extend (unit ∘ J.₁ f)
  ; identity = identity′
  ; homomorphism = hom′
  ; F-resp-≈ = λ f≈g → extend-≈ (∘-resp-≈ʳ (J.F-resp-≈ f≈g))
  }
  where
  open Monad r
  module C = Category C
  module D = Category D
  module J = Functor J
  open Category D hiding (identityˡ; identityʳ; assoc)
  open HomReasoning
  open MR D
  identity′ : {c : C.Obj} → extend {c} (unit ∘ J.₁ C.id) ≈ id
  identity′ = begin
     extend (unit ∘ J.₁ C.id) ≈⟨ extend-≈ (elimʳ J.identity) ⟩
     extend unit              ≈⟨ identityˡ ⟩
     id                       ∎
  hom′ : {X Y Z : C.Obj} {f : X C.⇒ Y} {g : Y C.⇒ Z} →
      extend (unit ∘ J.₁ (g C.∘ f)) ≈ extend (unit ∘ J.₁ g) ∘ extend (unit ∘ J.F₁ f)
  hom′ {f = f} {g} = begin
    extend (unit ∘ J.₁ (g C.∘ f))                     ≈⟨ extend-≈ (pushʳ J.homomorphism) ⟩
    extend ((unit ∘ J.₁ g) ∘ J.₁ f)                   ≈⟨ extend-≈ (pushˡ (⟺ identityʳ)) ⟩
    extend (extend (unit ∘ J.₁ g) ∘ (unit ∘ J.F₁ f))  ≈⟨ assoc ⟩
    extend (unit ∘ J.₁ g) ∘ extend (unit ∘ J.F₁ f)    ∎


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

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

module Setoids.Functions.Definition {a b c d : _} {A : Set a} {B : Set b} where

WellDefined : (S : Setoid {a} {c} A) (T : Setoid {b} {d} B) (f : A → B) → Set (a ⊔ c ⊔ d)
WellDefined S T f = {x y : A} → Setoid._∼_ S x y → Setoid._∼_ T (f x) (f y)


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

module root2 where

-- imports. We use the latest agda stdlib.
open import Data.Nat
open import Data.Nat.DivMod
open import Data.Nat.Properties
open import Data.Nat.Solver
open import Relation.Binary.PropositionalEquality
open import Data.Product
open import Data.Sum renaming (inj₁ to even ; inj₂ to odd)
open import Relation.Nullary
open import Data.Empty

-- Even predicate.
Even : ℕ -> Set
Even n = ∃ λ k → n ≡ 2 * k

-- Odd predicate.
Odd : ℕ -> Set
Odd n = ∃ λ k → n ≡ 1 + 2 * k

open +-*-Solver

-- Lemma: an even number cannot equal to an odd number.
lemma-even-odd-exclusive : ∀ k l ->  ¬ 2 * k ≡ 1 + 2 * l
lemma-even-odd-exclusive k l hyp = z hyp'
  where
    z : ¬ 0 ≡ 1
    z ()

    n*m%n≡0 : ∀ m n .{{_ : NonZero n}} → (n * m) % n ≡ 0
    n*m%n≡0 m n = begin
        (n * m) % n ≡⟨ cong (_% n) (solve 2 (λ n m → n :* m := m :* n) refl n m) ⟩
        (m * n) % n ≡⟨ m*n%n≡0 m n ⟩
        0 ∎
        where
          open ≡-Reasoning

    lem1%2 : 1 % 2 ≡ 1
    lem1%2 = refl

    hyp' : 0 ≡ 1
    hyp' =  begin
        0 ≡⟨ sym (n*m%n≡0 k 2)  ⟩
        (2 * k) % 2 ≡⟨ cong (_% 2) hyp ⟩
        (1 + 2 * l) % 2 ≡⟨ %-distribˡ-+ 1 (2 * l) 2 ⟩
        ((1 % 2) + ((2 * l) % 2)) % 2 ≡⟨ cong (_% 2) (cong₂ (_+_) lem1%2 (n*m%n≡0 l 2)) ⟩
        (1 + 0) % 2 ≡⟨ refl ⟩
        1 % 2 ≡⟨ refl ⟩
        1 ∎
        where
          open ≡-Reasoning

-- Lemma: a natural number cannot be both even and odd.
lemma-even-odd-exclusive' : ∀ n -> ¬ (Even n × Odd n)
lemma-even-odd-exclusive' n ((k , eqn) , (l , eqn')) = lemma-even-odd-exclusive k l claim
  where
    claim : 2 * k ≡ 1 + 2 * l
    claim = begin
        2 * k ≡⟨ sym eqn ⟩
        n ≡⟨ eqn' ⟩
        1 + 2 * l ∎
        where
          open ≡-Reasoning

-- Lemma: a natrual number is either even or odd (but not both as shown by lemma-even-odd-exclusive').
Parity : (n : ℕ) -> Even n ⊎ Odd n
Parity zero = even (zero , refl)
Parity (suc n) with Parity n
... | even (k , eq) = odd (k , cong suc eq)
... | odd (k , eq) = even (suc k , claim)
  where
    claim : suc n ≡ suc (k + suc (k + 0))
    claim = begin
      suc n ≡⟨ refl ⟩
      1 + n ≡⟨ cong (1 +_) eq ⟩
      1 +  suc (k + (k + 0)) ≡⟨ solve 1 (λ k → con 1 :+ (con 1 :+ (k :+ (k :+ con 0))) := con 1 :+ (k :+ (con 1 :+ (k :+ con 0)))) refl k ⟩
      1 + (k + (1 + (k + 0))) ≡⟨ refl ⟩
      suc (k + suc (k + 0)) ∎
      where
        open ≡-Reasoning

-- Auxillary lemmas:
lemma-div2 : ∀ n .{{_ : NonZero n}} -> n / 2 < n
lemma-div2 n = m/n<m n 2 (s≤s (s≤s z≤n))

lemma-<-< : ∀ {a b c} -> a < b -> b < suc c -> a < c
lemma-<-<  (s≤s ab) (s≤s bc) = <-transˡ (s≤s ab) bc

lemma-div2' : ∀ n b .{{_ : NonZero n}} -> n < 1 + b -> n / 2 < b
lemma-div2' n b n1b = lemma-<-< (lemma-div2 n) n1b

-- We do a case split in the parity of m and n. For each of the four
-- cases, we can derive a contradiction using induction on the bound
-- of m and n.
lemma-root2-irra : ∀ b m n -> ¬ m ≡ 0 -> ¬ n ≡ 0 → m < b → n < b → ¬ m * m ≡ 2 * (n * n)
lemma-root2-irra (suc b) 0 0 mnz nnz mlb nlb hyp = mnz refl
lemma-root2-irra (suc b) 0 (suc n) mnz nnz mlb nlb hyp = mnz refl
lemma-root2-irra (suc b) (suc m) 0 mnz nnz mlb nlb hyp = nnz refl
lemma-root2-irra (suc b) m@(suc m') n@(suc n') mnz nnz mlb nlb hyp with Parity m | Parity n
... | even (k , eqm) | even (l , eqn) = ih
  where
    factor-four : 4 * (k * k) ≡ 4 * (2 * (l * l))
    factor-four = begin
      4 * (k * k) ≡⟨ solve 1 (λ k → con 4 :* (k :* k) := (con 2 :* k) :* (con 2 :* k)) refl k ⟩
      (2 * k) * (2 * k) ≡⟨ cong₂ _*_ (sym eqm) (sym eqm) ⟩
      m * m ≡⟨ hyp ⟩
      2 * (n * n) ≡⟨ cong (2 *_) (cong₂ _*_ eqn eqn) ⟩
      2 * ((2 * l) * (2 * l)) ≡⟨ solve 1 (λ l → con 2 :* ((con 2 :* l) :* (con 2 :* l)) := con 4 :* (con 2 :* (l :* l))) refl l ⟩
      4 * (2 * (l * l)) ∎
      where
        open ≡-Reasoning

    hyp' : k * k ≡ 2 * (l * l)
    hyp' = *-cancelˡ-≡ 4 factor-four

    klb : k < b
    klb = begin-strict
      k ≡⟨ sym (m*n/n≡m k 2) ⟩
      (k * 2) / 2 ≡⟨ cong (_/ 2) (solve 1 (λ k → k :* con 2 := con 2 :* k) refl k) ⟩
      (2 * k) / 2 ≡⟨ cong (_/ 2) (sym eqm) ⟩
      m / 2 <⟨ lemma-div2' m b mlb ⟩
      b ∎
      where
        open ≤-Reasoning

    llb : l < b
    llb = begin-strict
      l ≡⟨ sym (m*n/n≡m l 2) ⟩
      (l * 2) / 2 ≡⟨ cong (_/ 2) (solve 1 (λ l → l :* con 2 := con 2 :* l) refl l) ⟩
      (2 * l) / 2 ≡⟨ cong (_/ 2) (sym eqn) ⟩
      n / 2 <⟨ lemma-div2' n b nlb ⟩
      b ∎
      where
        open ≤-Reasoning

    knz : ¬ k ≡ 0
    knz k0 = mnz m0
      where
      m0 : m ≡ 0
      m0 = begin
        m ≡⟨ eqm ⟩
        2 * k ≡⟨ cong (2 *_) k0 ⟩
        2 * 0 ≡⟨ refl ⟩
        0 ∎
        where
          open ≡-Reasoning

    lnz : ¬ l ≡ 0
    lnz l0 = nnz n0
      where
      n0 : n ≡ 0
      n0 = begin
        n ≡⟨ eqn ⟩
        2 * l ≡⟨ cong (2 *_) l0 ⟩
        2 * 0 ≡⟨ refl ⟩
        0 ∎
        where
          open ≡-Reasoning

    ih : ⊥
    ih = lemma-root2-irra b k l knz lnz klb llb hyp'

... | even (k , eqm) | odd (l , eqn) = lemma-even-odd-exclusive' (n * n) (even-right , odd-right)
  where
    even-left : Even (m * m)
    even-left = 2 * (k * k) , claim
      where
        claim : m * m ≡ 2 * (2 * (k * k))
        claim = begin
          m * m ≡⟨ cong₂ _*_ eqm eqm ⟩
          (2 * k) * (2 * k) ≡⟨ solve 1 (λ k → (con 2 :* k) :* (con 2 :* k) := con 2 :* (con 2 :* (k :* k))) refl k ⟩
          2 * (2 * (k * k)) ∎
            where
              open ≡-Reasoning

    odd-right : Odd (n * n)
    odd-right = (2 * (l * l) + 2 * l) , claim
      where
        claim : n * n ≡ 1 + 2 * (2 * (l * l) + 2 * l)
        claim = begin
          n * n ≡⟨ cong₂ _*_ eqn eqn ⟩
          (1 + 2 * l) * (1 + 2 * l) ≡⟨ solve 1 (λ l → (con 1 :+ con 2 :* l) :* (con 1 :+ con 2 :* l) := con 1 :+ (con 2 :* ((con 2 :* (l :* l)) :+ con 2 :* l))) refl l ⟩
          1 + 2 * (2 * (l * l) + 2 * l)  ∎
            where
              open ≡-Reasoning

    2*n*n≡2*2*k*k : 2 * (n * n) ≡ 2 * (2 * (k * k))
    2*n*n≡2*2*k*k = begin
          2 * (n * n) ≡⟨ sym hyp ⟩
          m * m ≡⟨ (let (_ , p) = even-left in p) ⟩
          2 * (2 * (k * k)) ∎
            where
              open ≡-Reasoning

    n*n≡2*k*k : (n * n) ≡ (2 * (k * k))
    n*n≡2*k*k = *-cancelˡ-≡ 2 2*n*n≡2*2*k*k

    even-right : Even (n * n)
    even-right = k * k , (n*n≡2*k*k)

... | odd (k , eqn) | _  = lemma-even-odd-exclusive' (m * m) (even-left , odd-left)
  where
    odd-left : Odd (m * m)
    odd-left = (2 * (k * k) + 2 * k) , claim
      where
        claim : m * m ≡ 1 + 2 * (2 * (k * k) + 2 * k)
        claim = begin
          m * m ≡⟨ cong₂ _*_ eqn eqn ⟩
          (1 + 2 * k) * (1 + 2 * k) ≡⟨ solve 1 (λ k → (con 1 :+ con 2 :* k) :* (con 1 :+ con 2 :* k) := con 1 :+ (con 2 :* ((con 2 :* (k :* k)) :+ con 2 :* k))) refl k ⟩
          1 + 2 * (2 * (k * k) + 2 * k)  ∎
            where
              open ≡-Reasoning

    even-left : Even (m * m)
    even-left = (n * n) , hyp

-- Main theorem: for any natural number m and n, it impossible that m
-- * m ≡ 2 * (n * n) except when m ≡ 0 and n ≡ 0 (in this situation,
-- m/n is not defined), in other words, no rational number equals √2.
theorem-root2-irra : ∀ m n ->  m * m ≡ 2 * (n * n) -> m ≡ 0 × n ≡ 0
theorem-root2-irra zero zero hyp = (refl , refl )
theorem-root2-irra zero n@(suc n') hyp = (refl , sym 0≡n )
  where
    2*0≡2*n*n : 2 * 0 ≡ 2 * (n * n)
    2*0≡2*n*n = hyp
    0≡n*n : 0 ≡ n * n
    0≡n*n = *-cancelˡ-≡ 2 hyp
    n*0≡n*n : n * 0 ≡ n * n
    n*0≡n*n = begin
          n * 0 ≡⟨ *-comm n 0 ⟩
          0 * n ≡⟨ refl ⟩
          0  ≡⟨ 0≡n*n ⟩
          n * n  ∎
            where
              open ≡-Reasoning

    0≡n : 0 ≡ n
    0≡n = *-cancelˡ-≡ n n*0≡n*n

theorem-root2-irra m@(suc m') n@(suc n') hyp = ⊥-elim claim
  where
    -- m ⊔ n = max m n
    b = 1 + (m ⊔ n)
    mlb : m < b
    mlb = s≤s (m≤m⊔n m n)
    nlb : n < b
    nlb = s≤s (m≤n⊔m m n)
    claim = lemma-root2-irra b m n (λ ()) (λ ()) mlb nlb hyp


module Productive where

open import Stream
open import Size
open import Data.Maybe
open import Data.Product
open import Relation.Binary.PropositionalEquality as P

PStream : Set → Set
PStream A = Stream (Maybe A)

mutual
  record Productive {A : Set} (s : PStream A) : Set where
    coinductive
    field
      step : EventualOutput s

  data EventualOutput {A : Set} (s : PStream A) : Set where
    here  : (a : A) → s .hd ≡ just a  → Productive (s .tl)     → EventualOutput s
    there :           s .hd ≡ nothing → EventualOutput (s .tl) → EventualOutput s

open Productive public

ProdStr : Set → Set
ProdStr A = Σ[ s ∈ PStream A ] (Productive s)

injS : {A : Set} → Stream A → ProdStr A
injS {A} s = (toPStream s , prod s)
  where
    toPStream : Stream {∞} A → PStream A
    toPStream s .hd = just (s .hd)
    toPStream s .tl = toPStream (s .tl)

    prod : (s : Stream A) → Productive (toPStream s)
    prod s .step = here (s .hd) refl (prod (s .tl))

extract  : {A : Set} → ProdStr A → Stream A
extract (s , p) = extr s p
  where
    extr  : {A : Set} → (s : PStream A) → Productive s → Stream A
    extrμ  : {A : Set} → (s : PStream A) → EventualOutput s → Stream A

    extr {A} s p = extrμ s (p .step)

    extrμ {A} s (here a q p') .hd = a
    extrμ {A} s (here a q p') .tl = extr (s .tl) p'
    extrμ {A} s (there x p')      = extrμ (s .tl) p'

zipS : ∀{A} → ProdStr A → ProdStr A → ProdStr A
zipS {A} (s , p) (t , q) = (z s t , pz p q)
  where
    z : PStream A → PStream A → PStream A
    cz : Maybe A → PStream A → PStream A → PStream A

    z s t = cz (s .hd) (s .tl) t

    cz (just a) s' t .hd = just a
    cz (just a) s' t .tl = z t s'
    cz nothing  s' t .hd = nothing
    cz nothing  s' t .tl = cz (s' .hd) (s' .tl) t

    pz : {s t : PStream A} → Productive s → Productive t → Productive (z s t)
    pcz : {s t : PStream A} → Productive s → Productive t →
          Productive (cz (s .hd) (s .tl) t)
    pczE : {s t : PStream A} → EventualOutput s → Productive t →
           EventualOutput (cz (s .hd) (s .tl) t)
    pz p q = pcz p q

    pcz p q .step = pczE (p .step) q

    pczE {s} (here a s₀≡a p')  q with s .hd
    pczE {s} (here .a refl p') q | just a = here a refl (pz q p')
    pczE {s} (here a () p')    q | nothing
    pczE {s} (there s₀≡∗ p')   q with s .hd
    pczE {s} (there () p')     q | just a
    pczE {s} (there refl p')   q | nothing = there refl (pczE p' q)


module Sets.IterativeSet where

import      Lvl
open import Logic
open import Type

module _ where
  private variable {ℓ ℓ₁ ℓ₂} : Lvl.Level

  -- A model of constructive set theory (CZF) by using W-types (iterative sets).
  -- The interpretation of Iset being a type of sets comes from the idea that the image of `elem` is a set of elements.
  record Iset : Type{Lvl.𝐒(ℓ)} where
    constructor set
    inductive
    pattern
    field
      {Index} : Type{ℓ}
      elem : Index → Iset{ℓ}
  open Iset

  Iset-index-induction : ∀{P : Iset{ℓ₁} → Stmt{ℓ₂}} → (∀{A : Iset{ℓ₁}} → (∀{i : Index(A)} → P(elem(A)(i))) → P(A)) → (∀{A : Iset{ℓ₁}} → P(A))
  Iset-index-induction {P = P} proof {set elem} = proof{_} \{i} → Iset-index-induction{P = P} proof {elem(i)}


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

open import Level
open import Categories.Category

module Categories.Functor.Power.Functorial {o ℓ e : Level} (C : Category o ℓ e) where

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

open import Categories.Functor renaming (id to idF)
open import Categories.Category.Discrete
open import Categories.Category.Equivalence
open import Categories.Category.Construction.Functors
open import Categories.NaturalTransformation using (NaturalTransformation; ntHelper)
open import Categories.NaturalTransformation.NaturalIsomorphism as NI
  using (module NaturalIsomorphism; _≃_; refl)
import Categories.Morphism.Reasoning as MR
open MR C

import Categories.Functor.Power as Power
open Power C

open Category using (Obj)
open Category C using (_⇒_; _∘_; module Equiv)
module C = Category C
module CE = Equiv

private
  variable
    i : Level
    I : Set i

exp→functor₀ : Obj (Exp I) → Functor (Discrete I) C
exp→functor₀ X = record
  { F₀ = X
  ; F₁ = λ { refl → C.id }
  ; identity = CE.refl
  ; homomorphism = λ { {_} {_} {_} {refl} {refl} → CE.sym C.identityˡ}
  ; F-resp-≈ = λ { {_} {_} {refl} {refl} refl → CE.refl}
  }

exp→functor₁ : {X Y : I → C.Obj} → Exp I [ X , Y ] → NaturalTransformation (exp→functor₀ X) (exp→functor₀ Y)
exp→functor₁ F = record { η = F ; commute = λ { refl → id-comm } ; sym-commute = λ { refl → id-comm-sym } }

exp→functor : Functor (Exp I) (Functors (Discrete I) C)
exp→functor = record
  { F₀ = exp→functor₀
  ; F₁ = exp→functor₁
  ; identity = CE.refl
  ; homomorphism = CE.refl
  ; F-resp-≈ = λ eqs {x} → eqs x
  }

functor→exp : Functor (Functors (Discrete I) C) (Exp I)
functor→exp = record
  { F₀ = Functor.F₀
  ; F₁ = NaturalTransformation.η
  ; identity = λ _ → CE.refl
  ; homomorphism = λ _ → CE.refl
  ; F-resp-≈ = λ eqs i → eqs {i}
  }

exp≋functor : StrongEquivalence (Exp I) (Functors (Discrete I) C)
exp≋functor = record
  { F = exp→functor
  ; G = functor→exp
  ; weak-inverse = record
    { F∘G≈id = record
      { F⇒G = ntHelper record
        { η       = λ DI → record
          { η           = λ _ → C.id
          ; commute     = λ { refl → C.∘-resp-≈ˡ (CE.sym (Functor.identity DI))}
          ; sym-commute = λ { refl → C.∘-resp-≈ˡ (Functor.identity DI)}
          }
        ; commute = λ _ → id-comm-sym
        }
      ; F⇐G = ntHelper record
        { η = λ DI → ntHelper record { η = λ _ → C.id ; commute = λ { refl → C.∘-resp-≈ʳ (Functor.identity DI)} }
        ; commute = λ _ → id-comm-sym
        }
      ; iso = λ X → record { isoˡ = C.identity²; isoʳ = C.identity² }
      }
    ; G∘F≈id = record
      { F⇒G = record { η = λ _ _ → C.id ; commute = λ _ _ → id-comm-sym ; sym-commute = λ _ _ → id-comm }
      ; F⇐G = record { η = λ _ _ → C.id ; commute = λ _ _ → id-comm-sym ; sym-commute = λ _ _ → id-comm }
      ; iso = λ X → record { isoˡ = λ _ → C.identity² ; isoʳ = λ _ → C.identity² }
      }
    }
  }
  where
    open C.HomReasoning


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

-- Monadic Adjunctions
-- https://ncatlab.org/nlab/show/monadic+adjunction
module Categories.Adjoint.Monadic where

open import Level

open import Categories.Adjoint
open import Categories.Adjoint.Properties
open import Categories.Category
open import Categories.Category.Equivalence
open import Categories.Functor
open import Categories.Monad

open import Categories.Category.Construction.EilenbergMoore
open import Categories.Category.Construction.Properties.EilenbergMoore

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

-- An adjunction is monadic if the adjunction "comes from" the induced monad in some sense.
record IsMonadicAdjunction {L : Functor 𝒞 𝒟} {R : Functor 𝒟 𝒞} (adjoint : L ⊣ R) : Set (levelOfTerm 𝒞 ⊔ levelOfTerm 𝒟) where
  private
    T : Monad 𝒞
    T = adjoint⇒monad adjoint

  field
    Comparison⁻¹ : Functor (EilenbergMoore T) 𝒟
    comparison-equiv : WeakInverse (ComparisonF adjoint) Comparison⁻¹


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

open import Level
open import Categories.Category
open import Categories.Monad

module Categories.Monad.Idempotent {o ℓ e} {C : Category o ℓ e} (M : Monad C) where

open import Categories.NaturalTransformation
open import Categories.NaturalTransformation.Equivalence
open import Categories.Functor

private
  module M = Monad M

open NaturalTransformation

record Idempotent : Set (o ⊔ ℓ ⊔ e) where
  field
    Fη≡ηF : ∀ X → C [ η (M.F ∘ˡ M.η) X ≈ η (M.η ∘ʳ M.F) X ]


module DecidableMembership where

open import OscarPrelude
open import Membership
open import Successor

record DecidableMembership {ℓ} (m : Set ℓ) (M : Set ℓ) ⦃ _ : Membership m M ⦄ : Set (⊹ ℓ)
 where
  field _∈?_ : (x : m) → (X : M) → Dec $ x ∈ X
  field _∉?_ : (x : m) → (X : M) → Dec $ x ∉ X

open DecidableMembership ⦃ … ⦄ public

instance DecidableMembershipList : ∀ {ℓ} {A : Set ℓ} ⦃ _ : Eq A ⦄ → DecidableMembership A $ List A
DecidableMembership._∈?_ (DecidableMembershipList {ℓ} {A}) = _∈List?_
 where
  _∈List?_ : (a : A) → (xs : List A) → Dec (a ∈ xs)
  a ∈List? [] = no λ ()
  a ∈List? (x ∷ xs) with a ≟ x
  … | yes a≡x rewrite a≡x = yes zero
  … | no a≢x with a ∈List? xs
  … | yes a∈xs = yes (⊹ a∈xs)
  … | no a∉xs = no (λ {zero → a≢x refl ; (suc a∈xs) → a∉xs a∈xs})
DecidableMembership._∉?_ (DecidableMembershipList {ℓ} {A}) x X with x ∈? X
DecidableMembership._∉?_ (DecidableMembershipList {ℓ} {A}) x X | yes x∈X = no (λ x∉X → x∉X x∈X)
DecidableMembership._∉?_ (DecidableMembershipList {ℓ} {A}) x X | no x∉X = yes x∉X


{-# OPTIONS --type-in-type #-}
module Data where

open import Prelude

data Sigma (A : Set)(B : A -> Set) : Set
data Sigma A B where
  pair : (x : A) -> B x -> Sigma A B

fst : {A : _} {B : _} -> Sigma A B -> A
fst (pair x y) = x

snd : {A : _} {B : _} (p : Sigma A B) -> B (fst p)
snd (pair x y) = y

data Unit : Set
data Unit where
  tt : Unit

Cat : Set
Cat =
  Sigma Set                                                  (\ Obj ->
  Sigma (Obj -> Obj -> Set)                                  (\ Hom ->
  Sigma ((X : _) -> Hom X X)                                 (\ id ->
  Sigma ((X Y Z : _) -> Hom Y Z -> Hom X Y -> Hom X Z)       (\ comp ->
  Sigma ((X Y : _)(f : Hom X Y) -> comp _ _ _ (id Y) f == f) (\ idl ->
  Sigma ((X Y : _)(f : Hom X Y) -> comp _ _ _ f (id X) == f) (\ idr ->
  Sigma ((W X Y Z : _)
         (f : Hom W X)(g : Hom X Y)(h : Hom Y Z) ->
           comp _ _ _ (comp _ _ _ h g) f ==
           comp _ _ _ h (comp _ _ _ g f))                    (\ assoc ->
  Unit)))))))

Obj : (C : Cat) -> Set
Obj C = fst C

Hom : (C : Cat) -> Obj C -> Obj C -> Set
Hom C = fst (snd C)

id : (C : Cat) -> (X : _) -> Hom C X X
id C = fst (snd (snd C))

comp : (C : Cat) -> (X Y Z : _) -> Hom C Y Z -> Hom C X Y -> Hom C X Z
comp C = fst (snd (snd (snd C)))

idl : (C : Cat) -> (X Y : _)(f : Hom C X Y) ->
      comp C _ _ _ (id C Y) f == f
idl C = fst (snd (snd (snd (snd C))))

idr : (C : Cat) -> (X Y : _)(f : Hom C X Y) ->
      comp C _ _ _ f (id C X) == f
idr C = fst (snd (snd (snd (snd (snd C)))))

assoc : (C : Cat) ->
        (W X Y Z : _) (f : Hom C W X)(g : Hom C X Y)(h : Hom C Y Z) ->
        comp C _ _ _ (comp C _ _ _ h g) f ==
        comp C _ _ _ h (comp C _ _ _ g f)
assoc C = fst (snd (snd (snd (snd (snd (snd C))))))


open import Oscar.Prelude
open import Oscar.Class.HasEquivalence
open import Oscar.Class.Smap
open import Oscar.Class.Surjextensionality
open import Oscar.Class.Symmetry
open import Oscar.Class.Symmetrical
open import Oscar.Class.Transitivity
open import Oscar.Data.ProductIndexEquivalence
open import Oscar.Data.Surjextenscollation
import Oscar.Class.HasEquivalence.ExtensionṖroperty
import Oscar.Class.Surjection.⋆
import Oscar.Data.ExtensionṖroperty
import Oscar.Data.Proposequality

module Oscar.Class.Symmetrical.ExtensionalUnifies where

module _
    {𝔵} {𝔛 : Ø 𝔵}
    {𝔞} {𝔄 : 𝔛 → Ø 𝔞}
    {𝔟} {𝔅 : 𝔛 → Ø 𝔟}
    (let _↦_ = Arrow 𝔄 𝔅)
    {𝔠} {ℭ : 𝔛 → Ø 𝔠}
    {ℓ₁} {_↦̇_ : ∀ {x y} → x ↦ y → x ↦ y → Ø ℓ₁}
    {ℓ₂} {_∼₂_ : ∀ {y} → ℭ y → ℭ y → Ø ℓ₂}
    ⦃ _ : ∀ {y} → Symmetry.class (_∼₂_ {y}) ⦄
    ⦃ _ : ∀ {y} → Transitivity.class (_∼₂_ {y}) ⦄
    ⦃ _ : Smap!.class _↦_ (Extension ℭ) ⦄
    ⦃ _ : Surjextensionality!.class _↦_ _↦̇_ (Extension ℭ) (Pointwise _∼₂_) ⦄
  where

  instance

    𝓢ymmetricalExtensionalUnifies : ∀ {m} → Symmetrical {𝔄 = (ℭ m)} {𝔅 = (LeftExtensionṖroperty ℓ₂ _↦_ _↦̇_ m)} surjextenscollation⟦ _↦̇_ ⟧ _≈_
    𝓢ymmetricalExtensionalUnifies .𝓢ymmetrical.symmetrical x y .π₀ = ∁ (symmetry , symmetry)