open import Oscar.Prelude
open import Oscar.Class
open import Oscar.Class.Congruity
open import Oscar.Class.Reflexivity
open import Oscar.Class.Symmetry
open import Oscar.Class.Transitivity
open import Oscar.Class.HasEquivalence
open import Oscar.Class.Transassociativity
open import Oscar.Class.Transleftidentity
open import Oscar.Class.Transrightidentity
open import Oscar.Class.IsPrecategory
open import Oscar.Class.IsCategory
open import Oscar.Class.Precategory
open import Oscar.Class.Category
open import Oscar.Data.¶
open import Oscar.Data.Descender
open import Oscar.Data.Proposequality
import Oscar.Property.Setoid.Proposequality
import Oscar.Class.Congruity.Proposequality
import Oscar.Class.Transextensionality.Proposequality
import Oscar.Data.Constraint

module Oscar.Property.Category.AListProposequality where

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

  private AList = Descender⟨ A ⟩

  instance

    𝓡eflexivityAList : Reflexivity.class AList
    𝓡eflexivityAList .⋆ = ∅

    𝓣ransitivityAList : Transitivity.class AList
    𝓣ransitivityAList .⋆ f ∅ = f
    𝓣ransitivityAList .⋆ f (x , g) =
      let _∙'_ = λ g f → 𝓣ransitivityAList .⋆ f g in -- FIXME needed to help Agda prove termination
      x , g ∙' f

    𝓣ransitivityAList' : Transitivity.class (flip AList)
    𝓣ransitivityAList' .⋆ f g = transitivity g f

    HasEquivalenceAList : ∀ {m n} → HasEquivalence (AList m n) _
    HasEquivalenceAList = ∁ Proposequality

    𝓣ransassociativityAList : Transassociativity.class AList Proposequality transitivity
    𝓣ransassociativityAList .⋆ f g ∅ = ∅
    𝓣ransassociativityAList .⋆ f g (x , h) = congruity (x ,_) $ 𝓣ransassociativityAList .⋆ _ _ h -- h ⟨∙ _ ⟨∙ _

    𝓣ransassociativityAList' : Transassociativity.class (flip AList) Proposequality transitivity
    𝓣ransassociativityAList' .⋆ f g h = symmetry (transassociativity h g f) -- Sym.[] {!!}

    IsPrecategoryAList : IsPrecategory AList Proposequality transitivity
    IsPrecategoryAList = ∁

    IsPrecategoryAList' : IsPrecategory (flip AList) Proposequality transitivity
    IsPrecategoryAList' = ∁

    𝓣ransleftidentityAList : Transleftidentity.class AList Proposequality ε transitivity
    𝓣ransleftidentityAList .⋆ = ∅

    𝓣ransrightidentityAList : Transrightidentity.class AList Proposequality ε transitivity
    𝓣ransrightidentityAList .⋆ {f = ∅} = ∅
    𝓣ransrightidentityAList .⋆ {f = x , f} rewrite 𝓣ransrightidentityAList .⋆ {f = f} = ∅
    -- 𝓣ransrightidentityAList .⋆ {f = x , f} = congruity (x ,_) (transrightidentity {_∼_ = AList} {_∼̇_ = Proposequality})
    -- 𝓣ransrightidentityAList .⋆ {f = x , f} rewrite (f ∙ ε[ AList ] ≡ f) ∋ transrightidentity {_∼_ = AList} = ∅

    𝓣ransleftidentityAList' : Transleftidentity.class (flip AList) Proposequality ε transitivity
    𝓣ransleftidentityAList' .⋆ = transrightidentity {_∼_ = AList}

    𝓣ransrightidentityAList' : Transrightidentity.class (flip AList) Proposequality ε transitivity
    𝓣ransrightidentityAList' .⋆ = transleftidentity {_∼_ = AList}

    IsCategoryAList : IsCategory AList Proposequality ε transitivity
    IsCategoryAList = ∁

    IsCategoryAList' : IsCategory (flip AList) Proposequality ε transitivity
    IsCategoryAList' = ∁

module _ {a} (A : ¶ → Ø a) where

  private AList = Descender⟨ A ⟩

  PrecategoryAListProposequality : Precategory _ _ _
  PrecategoryAListProposequality = ∁ AList Proposequality transitivity

  CategoryAListProposequality : Category _ _ _
  CategoryAListProposequality = ∁ AList Proposequality ε transitivity

  PrecategoryAList'Proposequality : Precategory _ _ _
  PrecategoryAList'Proposequality = ∁ (flip AList) Proposequality transitivity

  CategoryAList'Proposequality : Category _ _ _
  CategoryAList'Proposequality = ∁ (flip AList) Proposequality ε transitivity


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

open import Cubical.Core.Everything
open import Cubical.Algebra.Group

module Cubical.Algebra.Group.Coset {ℓ} (G : Group ℓ) where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Function using (id; _∘_; flip)
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.HLevels
open import Cubical.Functions.Embedding

open import Cubical.Algebra.Group.Subgroup

open import Cubical.Relation.Unary
open import Cubical.Relation.Unary.Properties
open import Cubical.Relation.Binary using (Reflexive; Symmetric; Transitive)
open import Cubical.HITs.PropositionalTruncation
open import Cubical.Relation.Binary.Reasoning.Equality

open Group G
open GroupLemmas G

private
  variable
    ℓ′ : Level

_≅[_]ˡ_ : ⟨ G ⟩ → Subgroup G ℓ′ → ⟨ G ⟩ → hProp _
x ≅[ H ]ˡ y = Subgroup.Member H (x ⁻¹ • y)

module _ (H : Subgroup G ℓ′) where
  private module H = Subgroup H

  ≅ˡ-reflexive : Reflexive _≅[ H ]ˡ_
  ≅ˡ-reflexive = subst⁻ (_∈ H.Member) (inverseˡ _) H.preservesId

  ≅ˡ-symmetric : Symmetric _≅[ H ]ˡ_
  ≅ˡ-symmetric {x} {y} = subst (_∈ H.Member) (invDistr (x ⁻¹) y ∙ cong (y ⁻¹ •_) (invInvo x)) ∘ H.preservesInv

  ≅ˡ-transitive : Transitive _≅[ H ]ˡ_
  ≅ˡ-transitive {i} {j} {k} x y = subst (_∈ H.Member) eq (H.preservesOp x y)
    where
      eq : _
      eq =
        (i ⁻¹ • j) • (j ⁻¹ • k) ≡˘⟨ assoc _ _ _ ⟩
        ((i ⁻¹ • j) • j ⁻¹) • k ≡⟨ cong (_• k) (assoc _ _ _) ⟩
        (i ⁻¹ • (j • j ⁻¹)) • k ≡⟨ cong (λ v → (i ⁻¹ • v) • k) (inverseʳ j) ⟩
        (i ⁻¹ • ε) • k          ≡⟨ cong (_• k) (identityʳ (i ⁻¹)) ⟩
        i ⁻¹ • k                ∎

infix 9 _<•_
infixr 9 _<•′_

_<•′_ : ⟨ G ⟩ → Pred ⟨ G ⟩ ℓ′ → Pred ⟨ G ⟩ _
g <•′ H = (g •_) ⊣ H

_<•_ : ⟨ G ⟩ → Subgroup G ℓ′ → Pred ⟨ G ⟩ _
g <• H = g <•′ Subgroup.Member H

module _ (H : Pred ⟨ G ⟩ ℓ′) where

  cosetˡ-identity→ : ε <•′ H ⊆ H
  cosetˡ-identity→ = rec (isProp[ H ] _)
      λ ((h , subh) , εh≡x) → subst (_∈ H) (sym (identityˡ h) ∙ εh≡x) subh

  cosetˡ-identity← : H ⊆ ε <•′ H
  cosetˡ-identity← x∈H = ∣ (_ , x∈H) , identityˡ _ ∣

  cosetˡ-identity : ε <•′ H ⇔ H
  cosetˡ-identity = cosetˡ-identity→ , cosetˡ-identity←

  cosetˡ-assoc→ : ∀ a b → (a • b) <•′ H ⊆ a <•′ b <•′ H
  cosetˡ-assoc→ a b =
    map λ ((h , subh) , abh≡x) → (b • h ,
            ∣ (h , subh) , refl ∣) ,
          sym (assoc _ _ _) ∙ abh≡x

  cosetˡ-assoc← : ∀ a b → a <•′ b <•′ H ⊆ (a • b) <•′ H
  cosetˡ-assoc← a b {x} =
    rec squash λ ((h , subh) , ah≡x) →
      map (λ ((g , subg) , bg≡h) → (g , subg) , (
            a • b • g   ≡⟨ assoc a b g ⟩
            a • (b • g) ≡⟨ cong (a •_) bg≡h ⟩
            a • h       ≡⟨ ah≡x ⟩
            x           ∎
          )) subh

  cosetˡ-assoc : ∀ a b → (a • b) <•′ H ≡ a <•′ b <•′ H
  cosetˡ-assoc a b = ⇔toPath _ _ (cosetˡ-assoc→ a b , cosetˡ-assoc← a b)

module _ (H : Subgroup G ℓ′) where
  private module H = Subgroup H

  g∈gH : ∀ g → g ∈ g <• H
  g∈gH g = ∣ H.ε , identityʳ _ ∣

  ≅-cosetˡ→ : ∀ x y → ⟨ x ≅[ H ]ˡ y ⟩ → x <• H ⇔ y <• H
  ≅-cosetˡ→ x y x≅y = xH⊆yH , xH⊇yH
    where
      xH⊆yH : x <• H ⊆ y <• H
      xH⊆yH {a} = map λ ((h , subh) , xh≡a) → (y ⁻¹ • x • h , H.preservesOp (≅ˡ-symmetric H x≅y) subh) ,
                                                (
                                                  y • (y ⁻¹ • x • h) ≡˘⟨ assoc y (y ⁻¹ • x) h ⟩
                                                  y • (y ⁻¹ • x) • h ≡˘⟨ cong (_• h) (assoc y (y ⁻¹) x) ⟩
                                                  y • y ⁻¹ • x • h   ≡⟨ cong (λ v → v • x • h) (inverseʳ y) ⟩
                                                  ε • x • h          ≡⟨ cong (_• h) (identityˡ x) ⟩
                                                  x • h              ≡⟨ xh≡a ⟩
                                                  a                  ∎)

      xH⊇yH : x <• H ⊇ y <• H
      xH⊇yH {a} = map λ ((h , subh) , yh≡a) → (x ⁻¹ • y • h , H.preservesOp x≅y subh) ,
                                                (
                                                  x • (x ⁻¹ • y • h) ≡˘⟨ assoc x (x ⁻¹ • y) h ⟩
                                                  x • (x ⁻¹ • y) • h ≡˘⟨ cong (_• h) (assoc x (x ⁻¹) y) ⟩
                                                  x • x ⁻¹ • y • h   ≡⟨ cong (λ v → v • y • h) (inverseʳ x) ⟩
                                                  ε • y • h          ≡⟨ cong (_• h) (identityˡ y) ⟩
                                                  y • h              ≡⟨ yh≡a ⟩
                                                  a                  ∎)

  ≅-cosetˡ← : ∀ x y → x <• H ⇔ y <• H → ⟨ x ≅[ H ]ˡ y ⟩
  ≅-cosetˡ← x y (xH⊆yH , yH⊆xH) = rec ((_ ≅[ H ]ˡ _) .snd)
      (λ ((h , subh) , yh≡x) →
        subst (_∈ H.Member) (cong _⁻¹ (
            h              ≡˘⟨ identityˡ h ⟩
            ε • h          ≡˘⟨ cong (_• h) (inverseˡ y) ⟩
            y ⁻¹ • y • h   ≡⟨ assoc _ _ _ ⟩
            y ⁻¹ • (y • h) ≡⟨ cong (y ⁻¹ •_) yh≡x ⟩
            y ⁻¹ • x       ∎
        ) ∙ invDistr (y ⁻¹) x ∙ cong (x ⁻¹ •_) (invInvo y)) (H.preservesInv subh)
      )
      (xH⊆yH {x} (g∈gH x))

  ≅-cosetˡ : ∀ x y → ⟨ x ≅[ H ]ˡ y ⟩ ≃ (x <• H ⇔ y <• H)
  ≅-cosetˡ x y = isPropEquiv→Equiv ((x ≅[ H ]ˡ y) .snd) (isProp⇔ (x <• H) (y <• H))
                                    (≅-cosetˡ→ x y) (≅-cosetˡ← x y)

  cosetˡ-idem→ : ((h , _) : ⟨ H ⟩) → h <• H ⊆ H.Member
  cosetˡ-idem→ (h , subh) = rec (isProp[ H.Member ] _)
    λ ((g , subg) , hg≡x) → subst (_∈ H.Member) hg≡x (H.preservesOp subh subg)

  cosetˡ-idem← : ((h , _) : ⟨ H ⟩) → H.Member ⊆ h <• H
  cosetˡ-idem← (h , subh) {x} subx =
    ∣
      (h ⁻¹ • x , H.preservesOp (H.preservesInv subh) subx) , (
        h • (h ⁻¹ • x) ≡˘⟨ assoc h (h ⁻¹) x ⟩
        (h • h ⁻¹) • x ≡⟨ cong (_• x) (inverseʳ h) ⟩
        ε • x          ≡⟨ identityˡ x ⟩
        x              ∎)
    ∣

  cosetˡ-idem : ((h , _) : ⟨ H ⟩) → h <• H ⇔ H.Member
  cosetˡ-idem h = cosetˡ-idem→ h , cosetˡ-idem← h

_≅[_]ʳ_ : ⟨ G ⟩ → Subgroup G ℓ′ → ⟨ G ⟩ → hProp _
x ≅[ H ]ʳ y = Subgroup.Member H (x • y ⁻¹)

module _ (H : Subgroup G ℓ′) where
  private module H = Subgroup H

  ≅ʳ-reflexive : Reflexive _≅[ H ]ʳ_
  ≅ʳ-reflexive = subst⁻ (_∈ H.Member) (inverseʳ _) H.preservesId

  ≅ʳ-symmetric : Symmetric _≅[ H ]ʳ_
  ≅ʳ-symmetric {x} {y} = subst (_∈ H.Member) (invDistr x (y ⁻¹) ∙ cong (_• x ⁻¹) (invInvo y)) ∘ H.preservesInv

  ≅ʳ-transitive : Transitive _≅[ H ]ʳ_
  ≅ʳ-transitive {i} {j} {k} x y = subst (_∈ H.Member) eq (H.preservesOp x y)
    where
      eq : _
      eq =
        (i • j ⁻¹) • (j • k ⁻¹) ≡˘⟨ assoc _ _ _ ⟩
        ((i • j ⁻¹) • j) • k ⁻¹ ≡⟨ cong (_• k ⁻¹) (assoc _ _ _) ⟩
        (i • (j ⁻¹ • j)) • k ⁻¹ ≡⟨ cong (λ v → (i • v) • k ⁻¹) (inverseˡ j) ⟩
        (i • ε) • k ⁻¹          ≡⟨ cong (_• k ⁻¹) (identityʳ i) ⟩
        i • k ⁻¹                ∎

infix 9 _•>_
infixl 9 _•>′_

_•>′_ : Pred ⟨ G ⟩ ℓ′ → ⟨ G ⟩ → Pred ⟨ G ⟩ _
H •>′ g = (_• g) ⊣ H

_•>_ : Subgroup G ℓ′ → ⟨ G ⟩ → Pred ⟨ G ⟩ _
H •> g = Subgroup.Member H •>′ g

module _ (H : Pred ⟨ G ⟩ ℓ′) where

  cosetʳ-identity→ : H •>′ ε ⊆ H
  cosetʳ-identity→ = rec (isProp[ H ] _)
      λ ((h , subh) , hε≡x) → subst (_∈ H) (sym (identityʳ h) ∙ hε≡x) subh

  cosetʳ-identity← : H ⊆ H •>′ ε
  cosetʳ-identity← x∈H = ∣ (_ , x∈H) , identityʳ _ ∣

  cosetʳ-identity : H •>′ ε ⇔ H
  cosetʳ-identity = cosetʳ-identity→ , cosetʳ-identity←

  cosetʳ-assoc→ : ∀ a b → H •>′ (a • b) ⊆ H •>′ a •>′ b
  cosetʳ-assoc→ a b =
    map λ ((h , subh) , hab≡x) → (h • a ,
            ∣ (h , subh) , refl ∣) ,
          assoc _ _ _ ∙ hab≡x

  cosetʳ-assoc← : ∀ a b → H •>′ a •>′ b ⊆ H •>′ (a • b)
  cosetʳ-assoc← a b {x} =
    rec squash λ ((h , subh) , hb≡x) →
      map (λ ((g , subg) , ga≡h) → (g , subg) , (
            g • (a • b) ≡˘⟨ assoc g a b ⟩
            (g • a) • b ≡⟨ cong (_• b) ga≡h ⟩
            h • b       ≡⟨ hb≡x ⟩
            x           ∎
          )) subh

  cosetʳ-assoc : ∀ a b → H •>′ (a • b) ≡ H •>′ a •>′ b
  cosetʳ-assoc a b = ⇔toPath _ _ (cosetʳ-assoc→ a b , cosetʳ-assoc← a b)

module _ (H : Subgroup G ℓ′) where
  private module H = Subgroup H

  g∈Hg : ∀ g → g ∈ H •> g
  g∈Hg g = ∣ H.ε , identityˡ _ ∣

  ≅-cosetʳ→ : ∀ x y → ⟨ x ≅[ H ]ʳ y ⟩ → H •> x ⇔ H •> y
  ≅-cosetʳ→ x y x≅y = Hx⊆Hy , Hx⊇Hy
    where
      Hx⊆Hy : H •> x ⊆ H •> y
      Hx⊆Hy {a} = map
        λ ((h , subh) , hx≡a) → (h • (x • y ⁻¹) , H.preservesOp subh x≅y) , (
                                  h • (x • y ⁻¹) • y   ≡˘⟨ cong (_• y) (assoc h x (y ⁻¹)) ⟩
                                  h • x • y ⁻¹ • y     ≡⟨ assoc (h • x) (y ⁻¹) y ⟩
                                  (h • x) • (y ⁻¹ • y) ≡⟨ cong (h • x •_) (inverseˡ y) ⟩
                                  h • x • ε            ≡⟨ identityʳ (h • x) ⟩
                                  h • x                ≡⟨ hx≡a ⟩
                                  a                    ∎)

      Hx⊇Hy : H •> x ⊇ H •> y
      Hx⊇Hy {a} = map
        λ ((h , subh) , hy≡a) → (h • (y • x ⁻¹) , H.preservesOp subh (≅ʳ-symmetric H x≅y)) , (
                                  h • (y • x ⁻¹) • x   ≡˘⟨ cong (_• x) (assoc h y (x ⁻¹)) ⟩
                                  h • y • x ⁻¹ • x     ≡⟨ assoc (h • y) (x ⁻¹) x ⟩
                                  (h • y) • (x ⁻¹ • x) ≡⟨ cong (h • y •_) (inverseˡ x) ⟩
                                  h • y • ε            ≡⟨ identityʳ (h • y) ⟩
                                  h • y                ≡⟨ hy≡a ⟩
                                  a                    ∎)

  ≅-cosetʳ← : ∀ x y → H •> x ⇔ H •> y → ⟨ x ≅[ H ]ʳ y ⟩
  ≅-cosetʳ← x y (Hx⊆Hy , Hy⊆Hx) = rec ((_ ≅[ H ]ʳ _) .snd)
      (λ ((h , subh) , hy≡x) →
        subst (_∈ H.Member) (
          h              ≡˘⟨ identityʳ h ⟩
          h • ε          ≡˘⟨ cong (h •_) (inverseʳ y) ⟩
          h • (y • y ⁻¹) ≡˘⟨ assoc h y (y ⁻¹) ⟩
          (h • y) • y ⁻¹ ≡⟨ cong (_• y ⁻¹) hy≡x ⟩
          x • y ⁻¹       ∎
        ) subh
      )
      (Hx⊆Hy {x} (g∈Hg x))

  ≅-cosetʳ : ∀ x y → ⟨ x ≅[ H ]ʳ y ⟩ ≃ (H •> x ⇔ H •> y)
  ≅-cosetʳ x y = isPropEquiv→Equiv ((x ≅[ H ]ʳ y) .snd) (isProp⇔ (H •> x) (H •> y))
                                    (≅-cosetʳ→ x y) (≅-cosetʳ← x y)

  cosetʳ-idem→ : ((h , _) : ⟨ H ⟩) → H •> h ⊆ H.Member
  cosetʳ-idem→ (h , subh) = rec (isProp[ H.Member ] _)
    λ ((g , subg) , gh≡x) → subst (_∈ H.Member) gh≡x (H.preservesOp subg subh)

  cosetʳ-idem← : ((h , _) : ⟨ H ⟩) → H.Member ⊆ H •> h
  cosetʳ-idem← (h , subh) {x} subx =
    ∣
      (x • h ⁻¹ , H.preservesOp subx (H.preservesInv subh)) , (
        (x • h ⁻¹) • h ≡⟨ assoc x (h ⁻¹) h ⟩
        x • (h ⁻¹ • h) ≡⟨ cong (x •_) (inverseˡ h) ⟩
        x • ε          ≡⟨ identityʳ x ⟩
        x              ∎)
    ∣

  cosetʳ-idem : ((h , _) : ⟨ H ⟩) → H •> h ⇔ H.Member
  cosetʳ-idem h = cosetʳ-idem→ h , cosetʳ-idem← h


------------------------------------------------------------------------
-- The Agda standard library
--
-- An either-or-both data type
------------------------------------------------------------------------

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

module Data.These where

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

------------------------------------------------------------------------
-- Re-exporting the datatype and its operations

open import Data.These.Base public

private
  variable
    a b : Level
    A : Set a
    B : Set b

------------------------------------------------------------------------
-- Additional operations

-- projections

fromThis : These A B → Maybe A
fromThis = fold just (const nothing) (const ∘′ just)

fromThat : These A B → Maybe B
fromThat = fold (const nothing) just (const just)

leftMost : These A A → A
leftMost = fold id id const

rightMost : These A A → A
rightMost = fold id id (flip const)

mergeThese : (A → A → A) → These A A → A
mergeThese = fold id id

-- deletions

deleteThis : These A B → Maybe (These A B)
deleteThis = fold (const nothing) (just ∘′ that) (const (just ∘′ that))

deleteThat : These A B → Maybe (These A B)
deleteThat = fold (just ∘′ this) (const nothing) (const ∘′ just ∘′ this)


------------------------------------------------------------------------
-- Semantics
------------------------------------------------------------------------

module RecursiveTypes.Semantics where

open import Codata.Musical.Notation

open import RecursiveTypes.Syntax
open import RecursiveTypes.Substitution

-- The semantics of a recursive type, i.e. its possibly infinite
-- unfolding.

⟦_⟧ : ∀ {n} → Ty n → Tree n
⟦ ⊥ ⟧       = ⊥
⟦ ⊤ ⟧       = ⊤
⟦ var x ⟧   = var x
⟦ σ ⟶ τ ⟧   = ♯ ⟦ σ ⟧         ⟶ ♯ ⟦ τ ⟧
⟦ μ σ ⟶ τ ⟧ = ♯ ⟦ σ [0≔ χ ] ⟧ ⟶ ♯ ⟦ τ [0≔ χ ] ⟧
              where χ = μ σ ⟶ τ


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

open import LogicalFormulae
open import Groups.Lemmas
open import Groups.Definition
open import Rings.Definition
open import Rings.Orders.Partial.Definition
open import Rings.Orders.Total.Definition
open import Rings.Lemmas
open import Setoids.Setoids
open import Setoids.Orders.Partial.Definition
open import Setoids.Orders.Total.Definition
open import Rings.IntegralDomains.Definition
open import Functions.Definition
open import Sets.EquivalenceRelations
open import Fields.Fields
open import Fields.Orders.Total.Definition
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order

module Fields.Orders.Lemmas {m n o : _} {A : Set m} {S : Setoid {m} {n} A} {_+_ : A → A → A} {_*_ : A → A → A} {_<_ : Rel {_} {o} A} {R : Ring S _+_ _*_} {pOrder : SetoidPartialOrder S _<_} {F : Field R} {pRing : PartiallyOrderedRing R pOrder} (oF : TotallyOrderedField F pRing) where

abstract

  open import Rings.InitialRing R
  open Ring R
  open PartiallyOrderedRing pRing
  open Group additiveGroup
  open TotallyOrderedRing (TotallyOrderedField.oRing oF)
  open SetoidTotalOrder total
  open import Rings.Orders.Partial.Lemmas pRing
  open import Rings.Orders.Total.Lemmas (TotallyOrderedField.oRing oF)
  open import Fields.Lemmas F
  open Setoid S
  open SetoidPartialOrder pOrder
  open Equivalence eq
  open Field F

  clearDenominatorHalf : (x y 1/2 : A) → (1/2 + 1/2 ∼ 1R) → x < (y * 1/2) → (x + x) < y
  clearDenominatorHalf x y 1/2 pr1/2 x<1/2y = <WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (Equivalence.transitive eq (Equivalence.symmetric eq *DistributesOver+) (Equivalence.transitive eq *Commutative (*WellDefined pr1/2 (Equivalence.reflexive eq)))) identIsIdent) (ringAddInequalities x<1/2y x<1/2y)

  clearDenominatorHalf' : (x y 1/2 : A) → (1/2 + 1/2 ∼ 1R) → (x * 1/2) < y → x < (y + y)
  clearDenominatorHalf' x y 1/2 pr1/2 1/2x<y = <WellDefined (Equivalence.transitive eq (Equivalence.symmetric eq *DistributesOver+) (Equivalence.transitive eq (Equivalence.transitive eq *Commutative (*WellDefined pr1/2 (Equivalence.reflexive eq))) identIsIdent)) (Equivalence.reflexive eq) (ringAddInequalities 1/2x<y 1/2x<y)

  halveInequality : (x y 1/2 : A) → (1/2 + 1/2 ∼ 1R) → (x + x) < y → x < (y * 1/2)
  halveInequality x y 1/2 pr1/2 2x<y with totality 0R 1R
  ... | inl (inl 0<1') = <WellDefined (halfHalves 1/2 pr1/2) (Equivalence.reflexive eq) (ringCanMultiplyByPositive {_} {_} {1/2} (halvePositive 1/2 (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq pr1/2) (0<1 λ bad → irreflexive {0R} (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq bad) 0<1')))) 2x<y)
  ... | inl (inr 1<0) = <WellDefined (halfHalves 1/2 pr1/2) (Equivalence.reflexive eq) (ringCanMultiplyByPositive {_} {_} {1/2} (halvePositive 1/2 (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq pr1/2) (0<1 λ bad → irreflexive {0R} (<WellDefined (Equivalence.symmetric eq bad) (Equivalence.reflexive eq) 1<0)))) 2x<y)
  ... | inr 0=1 = exFalso (irreflexive {0R} (<WellDefined (oneZeroImpliesAllZero R 0=1) (oneZeroImpliesAllZero R 0=1) 2x<y))

  halveInequality' : (x y 1/2 : A) → (1/2 + 1/2 ∼ 1R) → x < (y + y) → (x * 1/2) < y
  halveInequality' x y 1/2 pr1/2 x<2y with halveInequality (inverse y) (inverse x) 1/2 pr1/2 (<WellDefined (invContravariant additiveGroup) (Equivalence.reflexive eq) (ringSwapNegatives' x<2y))
  ... | bl = ringSwapNegatives (<WellDefined (Equivalence.reflexive eq) (ringMinusExtracts' R) bl)

  dense : (charNot2 : ((1R + 1R) ∼ 0R) → False) {x y : A} → (x < y) → Sg A (λ i → (x < i) && (i < y))
  dense charNot2 {x} {y} x<y with halve charNot2 1R
  dense charNot2 {x} {y} x<y | 1/2 , pr1/2 = ((x + y) * 1/2) , (halveInequality x (x + y) 1/2 pr1/2 (<WellDefined (Equivalence.reflexive eq) groupIsAbelian (orderRespectsAddition x<y x)) ,, halveInequality' (x + y) y 1/2 pr1/2 (orderRespectsAddition x<y y))

  halfLess : (e/2 e : A) → (0<e : 0G < e) → (pr : e/2 + e/2 ∼ e) → e/2 < e
  halfLess e/2 e 0<e pr with halvePositive e/2 (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq pr) 0<e)
  ... | 0<e/2 = <WellDefined identLeft pr (orderRespectsAddition 0<e/2 e/2)

  inversePositiveIsPositive : {a b : A} → (a * b) ∼ 1R → 0R < b → 0R < a
  inversePositiveIsPositive {a} {b} ab=1 0<b with totality 0R a
  inversePositiveIsPositive {a} {b} ab=1 0<b | inl (inl 0<a) = 0<a
  inversePositiveIsPositive {a} {b} ab=1 0<b | inl (inr a<0) with <WellDefined *Commutative (Equivalence.reflexive eq) (posTimesNeg _ _ 0<b a<0)
  ... | ab<0 = exFalso (1<0False (<WellDefined ab=1 (Equivalence.reflexive eq) ab<0))
  inversePositiveIsPositive {a} {b} ab=1 0<b | inr 0=a = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (oneZeroImpliesAllZero R 0=1) 0<b))
    where
      0=1 : 0R ∼ 1R
      0=1 = Equivalence.transitive eq (Equivalence.symmetric eq (Equivalence.transitive eq (*WellDefined (Equivalence.symmetric eq 0=a) (Equivalence.reflexive eq)) (Equivalence.transitive eq *Commutative timesZero))) ab=1

  halvesEqual : ((1R + 1R ∼ 0R) → False) → (1/2 1/2' : A) → (1/2 + 1/2) ∼ 1R → (1/2' + 1/2') ∼ 1R → 1/2 ∼ 1/2'
  halvesEqual charNot2 1/2 1/2' pr1 pr2 = Equivalence.transitive eq (Equivalence.transitive eq (Equivalence.symmetric eq identIsIdent) (Equivalence.transitive eq *Commutative (*WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (Equivalence.symmetric eq p1) *Commutative)))) (Equivalence.transitive eq r (Equivalence.transitive eq (Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq *Commutative p1)) *Commutative) (identIsIdent)))
    where
      p : 1/2 * (1R + 1R) ∼ 1/2' * (1R + 1R)
      p = Equivalence.transitive eq *DistributesOver+ (Equivalence.transitive eq (Equivalence.transitive eq (Equivalence.transitive eq (+WellDefined (Equivalence.transitive eq *Commutative identIsIdent) (Equivalence.transitive eq *Commutative identIsIdent)) pr1) (Equivalence.transitive eq (Equivalence.symmetric eq pr2) (+WellDefined (Equivalence.symmetric eq (Equivalence.transitive eq *Commutative identIsIdent)) (Equivalence.symmetric eq (Equivalence.transitive eq *Commutative identIsIdent))))) (Equivalence.symmetric eq *DistributesOver+))
      x : A
      x with Field.allInvertible F (1R + 1R) charNot2
      ... | y , _ = y
      p1 : (x * (1R + 1R)) ∼ 1R
      p1 with Field.allInvertible F (1R + 1R) charNot2
      ... | _ , pr = pr
      q : ((1/2 * (1R + 1R)) * x) ∼ ((1/2' * (1R + 1R)) * x)
      q = *WellDefined p (Equivalence.reflexive eq)
      r : (1/2 * ((1R + 1R) * x)) ∼ (1/2' * ((1R + 1R) * x))
      r = Equivalence.transitive eq *Associative (Equivalence.transitive eq q (Equivalence.symmetric eq *Associative))

  private
    orderedFieldIntDom : {a b : A} → (a * b ∼ 0R) → (a ∼ 0R) || (b ∼ 0R)
    orderedFieldIntDom {a} {b} ab=0 with totality 0R a
    ... | inl (inl x) = inr (Equivalence.transitive eq (Equivalence.transitive eq (symmetric identIsIdent) (*WellDefined q reflexive)) p')
      where
        a!=0 : (a ∼ Group.0G additiveGroup) → False
        a!=0 pr = SetoidPartialOrder.irreflexive pOrder (SetoidPartialOrder.<WellDefined pOrder (symmetric pr) reflexive x)
        invA : A
        invA = underlying (Field.allInvertible F a a!=0)
        q : 1R ∼ (invA * a)
        q with Field.allInvertible F a a!=0
        ... | invA , pr = symmetric pr
        p : invA * (a * b) ∼ invA * Group.0G additiveGroup
        p = *WellDefined reflexive ab=0
        p' : (invA * a) * b ∼ Group.0G additiveGroup
        p' = Equivalence.transitive eq (symmetric *Associative) (Equivalence.transitive eq p (Ring.timesZero R))
    orderedFieldIntDom {a} {b} ab=0 | inl (inr x) = inr (Equivalence.transitive eq (Equivalence.transitive eq (symmetric identIsIdent) (*WellDefined q reflexive)) p')
      where
        a!=0 : (a ∼ Group.0G additiveGroup) → False
        a!=0 pr = SetoidPartialOrder.irreflexive pOrder (SetoidPartialOrder.<WellDefined pOrder reflexive (symmetric pr) x)
        invA : A
        invA = underlying (Field.allInvertible F a a!=0)
        q : 1R ∼ (invA * a)
        q with Field.allInvertible F a a!=0
        ... | invA , pr = symmetric pr
        p : invA * (a * b) ∼ invA * Group.0G additiveGroup
        p = *WellDefined reflexive ab=0
        p' : (invA * a) * b ∼ Group.0G additiveGroup
        p' = Equivalence.transitive eq (symmetric *Associative) (Equivalence.transitive eq p (Ring.timesZero R))
    orderedFieldIntDom {a} {b} ab=0 | inr x = inl (Equivalence.symmetric (Setoid.eq S) x)

  orderedFieldIsIntDom :  IntegralDomain R
  IntegralDomain.intDom orderedFieldIsIntDom = decidedIntDom R orderedFieldIntDom
  IntegralDomain.nontrivial orderedFieldIsIntDom pr = Field.nontrivial F (Equivalence.symmetric (Setoid.eq S) pr)

  charZero : (n : ℕ) → (0R ∼ (fromN (succ n))) → False
  charZero n 0=sn = irreflexive (<WellDefined 0=sn reflexive (fromNPreservesOrder (0<1 (Field.nontrivial F)) (succIsPositive n)))
  charZero' : (n : ℕ) → ((fromN (succ n)) ∼ 0R) → False
  charZero' n pr = charZero n (symmetric pr)


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

open import HoTT
open import homotopy.CircleHSpace
open import homotopy.JoinAssocCubical
open import homotopy.JoinSusp

module homotopy.Hopf where

import homotopy.HopfConstruction
module Hopf = homotopy.HopfConstruction S¹-conn ⊙S¹-hSpace

Hopf : S² → Type₀
Hopf = Hopf.H.f

Hopf-fiber : Hopf north == S¹
Hopf-fiber = idp

-- TODO Turn [Hopf.theorem] into an equivalence
Hopf-total : Σ _ Hopf ≃ S³
Hopf-total =
  Σ _ Hopf       ≃⟨ coe-equiv Hopf.theorem ⟩
  S¹ * S¹        ≃⟨ *-Susp-l S⁰ S¹ ⟩
  Susp (S⁰ * S¹) ≃⟨ Susp-emap (*-Bool-l S¹) ⟩
  S³ ≃∎


module Cats.Adjunction where

open import Level using (suc ; _⊔_)

open import Cats.Category
open import Cats.Category.Cat.Facts.Product using (First ; Second)
open import Cats.Category.Fun using (Fun)
open import Cats.Category.Op using (_ᵒᵖ)
open import Cats.Category.Product.Binary using (_×_)
open import Cats.Category.Setoids using (Setoids)
open import Cats.Functor using (Functor ; _∘_)
open import Cats.Functor.Op using (Op)
open import Cats.Functor.Representable using (Hom[_])

open Functor

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

  private
    module Fun = Category (Fun ((C ᵒᵖ) × D) (Setoids la l≈))

  record Adjunction (F : Functor C D) (U : Functor D C)
    : Set (lo ⊔ suc la ⊔ suc l≈)
    where
    field
      iso : (Hom[ D ] ∘ First (Op F)) Fun.≅ (Hom[ C ] ∘ Second U)


{-# OPTIONS --allow-unsolved-metas #-}
module regex1 where

open import Level renaming ( suc to succ ; zero to Zero )
open import Data.Fin
open import Data.Nat hiding ( _≟_ )
open import Data.List hiding ( any ;  [_] )
-- import Data.Bool using ( Bool ; true ; false ; _∧_ )
-- open import Data.Bool using ( Bool ; true ; false ; _∧_ ; _∨_ )
open import  Relation.Binary.PropositionalEquality as RBF hiding ( [_] )
open import Relation.Nullary using (¬_; Dec; yes; no)
open import regex
open import logic

-- postulate a b c d : Set

data In : Set where
   a : In
   b : In
   c : In
   d : In

-- infixr 40 _&_ _||_

r1' =    (< a > & < b >) & < c >                                         --- abc
r1 =    < a > &  < b > & < c >                                            --- abc
r0 : ¬ (r1' ≡ r1)
r0 ()
any = < a > || < b >  || < c > || < d >                                   --- a|b|c|d
r2 =    ( any * ) & ( < a > & < b > & < c > )                            -- .*abc
r3 =    ( any * ) & ( < a > & < b > & < c > & < a > & < b > & < c > )
r4 =    ( < a > & < b > & < c > ) || ( < b > & < c > & < d > )
r5 =    ( any * ) & ( < a > & < b > & < c > || < b > & < c > & < d > )

open import nfa

--    former ++ later  ≡ x
split : {Σ : Set} → ((former : List Σ) → Bool) → ((later :  List Σ) → Bool) → (x : List Σ ) → Bool
split x y  [] = x [] /\ y []
split x y (h  ∷ t) = (x [] /\ y (h  ∷ t)) \/
  split (λ t1 → x (  h ∷ t1 ))  (λ t2 → y t2 ) t

-- tt1 : {Σ : Set} → ( P Q :  List In → Bool ) → split P Q ( a ∷ b ∷ c ∷ [] )
-- tt1 P Q = ?

{-# TERMINATING #-}
repeat : {Σ : Set} → (List Σ → Bool) → List Σ → Bool
repeat x [] = true
repeat {Σ} x ( h  ∷ t ) = split x (repeat {Σ} x) ( h  ∷ t )

-- Meaning of regular expression

regular-language : {Σ : Set} → Regex Σ → ((x y : Σ ) → Dec (x ≡ y))  →  List Σ → Bool
regular-language φ cmp _ = false
regular-language ε cmp [] = true
regular-language ε cmp (_ ∷ _) = false
regular-language (x *) cmp = repeat ( regular-language x cmp  )
regular-language (x & y) cmp  = split ( λ z → regular-language x  cmp z ) (λ z →  regular-language y  cmp z )
regular-language (x || y) cmp  = λ s → ( regular-language x  cmp s )  \/  ( regular-language y  cmp s)
regular-language < h > cmp  [] = false
regular-language < h > cmp  (h1  ∷ [] ) with cmp h h1
... | yes _ = true
... | no _  = false
regular-language < h >  _ (_ ∷ _ ∷ _)  = false

cmpi : (x y : In ) → Dec (x ≡ y)
cmpi a a = yes refl
cmpi b b =  yes refl
cmpi c c =  yes refl
cmpi d d =  yes refl
cmpi a b =  no (λ ())
cmpi a c =  no (λ ())
cmpi a d =  no (λ ())
cmpi b a = no (λ ())
cmpi b c = no (λ ())
cmpi b d = no (λ ())
cmpi c a = no (λ ())
cmpi c b = no (λ ())
cmpi c d = no (λ ())
cmpi d a = no (λ ())
cmpi d b = no (λ ())
cmpi d c = no (λ ())

test-regex : regular-language r1' cmpi ( a ∷ [] ) ≡ false
test-regex = refl

test-regex1 : regular-language r2 cmpi ( a ∷ a ∷ b ∷ c ∷ [] ) ≡ true
test-regex1 = refl

test-AB→split : {Σ : Set} → {A B : List In → Bool} → split A B ( a ∷ b ∷ a ∷ [] ) ≡ (
       ( A [] /\ B ( a ∷ b ∷ a ∷ [] ) ) \/
       ( A ( a ∷ [] ) /\ B ( b ∷ a ∷ [] ) ) \/
       ( A ( a ∷ b ∷ [] ) /\ B ( a ∷ [] ) ) \/
       ( A ( a ∷ b ∷ a ∷ [] ) /\ B  []  )
   )
test-AB→split {_} {A} {B} = refl

list-eq : {Σ : Set} → (cmpi : (s t : Σ)  → Dec (s ≡ t ))  → (s t : List Σ ) → Bool
list-eq cmpi [] [] = true
list-eq cmpi [] (x ∷ t) = false
list-eq cmpi (x ∷ s) [] = false
list-eq cmpi (x ∷ s) (y ∷ t) with cmpi x y
... | yes _ = list-eq cmpi s t
... | no _ = false

-- split-spec-01 :  {s t u : List In } → s ++ t ≡ u → split (list-eq cmpi s) (list-eq cmpi t)  u ≡ true
-- split-spec-01 = {!!}

-- from example 1.53 1

ex53-1 : Set
ex53-1 = (s : List In ) → regular-language ( (< a > *) & < b > & (< a > *) ) cmpi s ≡ true → {!!} -- contains exact one b

ex53-2 : Set
ex53-2 = (s : List In ) → regular-language ( (any * ) & < b > & (any *) ) cmpi s ≡ true → {!!} -- contains at lease one b

evenp : {Σ : Set} →  List Σ → Bool
oddp : {Σ : Set} →  List Σ → Bool
oddp [] = false
oddp (_ ∷ t) = evenp t

evenp [] = true
evenp (_ ∷ t) = oddp t

-- from example 1.53 5
egex-even : Set
egex-even = (s : List In ) → regular-language ( ( any & any ) * ) cmpi s ≡ true → evenp s ≡ true

test11 =  regular-language ( ( any & any ) * ) cmpi (a ∷ [])
test12 =  regular-language ( ( any & any ) * ) cmpi (a ∷ b ∷ [])

-- proof-egex-even : egex-even
-- proof-egex-even [] _ = refl
-- proof-egex-even (a ∷ []) ()
-- proof-egex-even (b ∷ []) ()
-- proof-egex-even (c ∷ []) ()
-- proof-egex-even (x ∷ x₁ ∷ s) y = proof-egex-even s {!!}

open import finiteSet

iFin : FiniteSet In
iFin = record {
     finite = finite0
   ; Q←F = Q←F0
   ; F←Q = F←Q0
   ; finiso→ = finiso→0
   ; finiso← = finiso←0
 } where
     finite0 : ℕ
     finite0 = 4
     Q←F0 : Fin finite0 → In
     Q←F0 zero = a
     Q←F0 (suc zero) = b
     Q←F0 (suc (suc zero)) = c
     Q←F0 (suc (suc (suc zero))) = d
     F←Q0 : In → Fin finite0
     F←Q0 a = # 0
     F←Q0 b = # 1
     F←Q0 c = # 2
     F←Q0 d = # 3
     finiso→0 : (q : In) → Q←F0 ( F←Q0 q ) ≡ q
     finiso→0 a = refl
     finiso→0 b = refl
     finiso→0 c =  refl
     finiso→0 d =  refl
     finiso←0 : (f : Fin finite0 ) → F←Q0 ( Q←F0 f ) ≡ f
     finiso←0 zero = refl
     finiso←0 (suc zero) = refl
     finiso←0 (suc (suc zero)) = refl
     finiso←0 (suc (suc (suc zero))) = refl

open import derive In iFin
open import automaton

ra-ex = trace (regex→automaton cmpi r2) (record { state = r2 ; is-derived = unit }) ( a ∷ b ∷ c ∷ [])


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

module Cubical.Categories.NaturalTransformation.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Univalence
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism renaming (iso to iIso)
open import Cubical.Data.Sigma
open import Cubical.Categories.Category
open import Cubical.Categories.Functor.Base
open import Cubical.Categories.Functor.Properties
open import Cubical.Categories.Commutativity
open import Cubical.Categories.Morphism renaming (isIso to isIsoC)

private
  variable
    ℓC ℓC' ℓD ℓD' : Level

module _ {C : Precategory ℓC ℓC'} {D : Precategory ℓD ℓD'} where
  -- syntax for sequencing in category D
  infixl 15 _⋆ᴰ_
  private
    _⋆ᴰ_ : ∀ {x y z} (f : D [ x , y ]) (g : D [ y , z ]) → D [ x , z ]
    f ⋆ᴰ g = f ⋆⟨ D ⟩ g

  open Precategory
  open Functor

  -- type aliases because it gets tedious typing it out all the time
  N-ob-Type : (F G : Functor C D) → Type _
  N-ob-Type F G = (x : C .ob) → D [(F .F-ob x) , (G .F-ob x)]

  N-hom-Type : (F G : Functor C D) → N-ob-Type F G → Type _
  N-hom-Type F G ϕ = {x y : C .ob} (f : C [ x , y ]) → (F .F-hom f) ⋆ᴰ (ϕ y) ≡ (ϕ x) ⋆ᴰ (G .F-hom f)

  record NatTrans (F G : Functor C D) : Type (ℓ-max (ℓ-max ℓC ℓC') ℓD') where
    constructor natTrans
    field
      -- components of the natural transformation
      N-ob : N-ob-Type F G
      -- naturality condition
      N-hom :  N-hom-Type F G N-ob

  record NatIso (F G : Functor C D): Type (ℓ-max (ℓ-max ℓC ℓC') (ℓ-max ℓD ℓD')) where
    field
      trans : NatTrans F G
    open NatTrans trans

    field
      nIso : ∀ (x : C .ob) → isIsoC {C = D} (N-ob x)

    open isIsoC

    -- the three other commuting squares
    sqRL : ∀ {x y : C .ob} {f : C [ x , y ]}
         → F ⟪ f ⟫ ≡ (N-ob x) ⋆ᴰ G ⟪ f ⟫ ⋆ᴰ (nIso y) .inv
    sqRL {x} {y} {f} = invMoveR (isIso→areInv (nIso y)) (N-hom f)

    sqLL : ∀ {x y : C .ob} {f : C [ x , y ]}
         → G ⟪ f ⟫ ⋆ᴰ (nIso y) .inv ≡ (nIso x) .inv ⋆ᴰ F ⟪ f ⟫
    sqLL {x} {y} {f} = invMoveL (isIso→areInv (nIso x)) (sym sqRL')
      where
        sqRL' : F ⟪ f ⟫ ≡ (N-ob x) ⋆ᴰ ( G ⟪ f ⟫ ⋆ᴰ (nIso y) .inv )
        sqRL' = sqRL ∙ (D .⋆Assoc _ _ _)

    sqLR : ∀ {x y : C .ob} {f : C [ x , y ]}
         → G ⟪ f ⟫ ≡ (nIso x) .inv ⋆ᴰ F ⟪ f ⟫ ⋆ᴰ (N-ob y)
    sqLR {x} {y} {f} = invMoveR (symAreInv (isIso→areInv (nIso y))) sqLL

  open NatTrans
  open NatIso

  infix 10 NatTrans
  syntax NatTrans F G = F ⇒ G

  infix 9 NatIso
  syntax NatIso F G = F ≅ᶜ G -- c superscript to indicate that this is in the context of categories

  -- component of a natural transformation
  infix 30 _⟦_⟧
  _⟦_⟧ : ∀ {F G : Functor C D} → (F ⇒ G) → (x : C .ob) → D [(F .F-ob x) , (G .F-ob x)]
  _⟦_⟧ = N-ob

  idTrans : (F : Functor C D) → NatTrans F F
  idTrans F .N-ob x = D .id (F .F-ob x)
  idTrans F .N-hom f =
      (F .F-hom f) ⋆ᴰ (idTrans F .N-ob _)
    ≡⟨ D .⋆IdR _ ⟩
      F .F-hom f
    ≡⟨ sym (D .⋆IdL _) ⟩
      (D .id (F .F-ob _)) ⋆ᴰ (F .F-hom f)
    ∎

  syntax idTrans F = 1[ F ]

  -- vertical sequencing
  seqTrans : {F G H : Functor C D} (α : NatTrans F G) (β : NatTrans G H) → NatTrans F H
  seqTrans α β .N-ob x = (α .N-ob x) ⋆ᴰ (β .N-ob x)
  seqTrans {F} {G} {H} α β .N-hom f =
    (F .F-hom f) ⋆ᴰ ((α .N-ob _) ⋆ᴰ (β .N-ob _))
      ≡⟨ sym (D .⋆Assoc _ _ _) ⟩
    ((F .F-hom f) ⋆ᴰ (α .N-ob _)) ⋆ᴰ (β .N-ob _)
      ≡[ i ]⟨ (α .N-hom f i) ⋆ᴰ (β .N-ob _) ⟩
    ((α .N-ob _) ⋆ᴰ (G .F-hom f)) ⋆ᴰ (β .N-ob _)
      ≡⟨ D .⋆Assoc _ _ _ ⟩
    (α .N-ob _) ⋆ᴰ ((G .F-hom f) ⋆ᴰ (β .N-ob _))
      ≡[ i ]⟨ (α .N-ob _) ⋆ᴰ (β .N-hom f i) ⟩
    (α .N-ob _) ⋆ᴰ ((β .N-ob _) ⋆ᴰ (H .F-hom f))
      ≡⟨ sym (D .⋆Assoc _ _ _) ⟩
    ((α .N-ob _) ⋆ᴰ (β .N-ob _)) ⋆ᴰ (H .F-hom f)
      ∎

  compTrans : {F G H : Functor C D} (β : NatTrans G H) (α : NatTrans F G) → NatTrans F H
  compTrans β α = seqTrans α β

  infixl 8 seqTrans
  syntax seqTrans α β = α ●ᵛ β

  -- vertically sequence natural transformations whose
  -- common functor is not definitional equal
  seqTransP : {F G G' H : Functor C D} (p : G ≡ G')
            → (α : NatTrans F G) (β : NatTrans G' H)
            → NatTrans F H
  seqTransP {F} {G} {G'} {H} p α β .N-ob x
    -- sequence morphisms with non-judgementally equal (co)domain
    = seqP {C = D} {p = Gx≡G'x} (α ⟦ x ⟧) (β ⟦ x ⟧)
    where
      Gx≡G'x : ∀ {x} → G ⟅ x ⟆ ≡ G' ⟅ x ⟆
      Gx≡G'x {x} i = F-ob (p i) x
  seqTransP {F} {G} {G'} {H} p α β .N-hom {x = x} {y} f
    -- compose the two commuting squares
    -- 1. α's commuting square
    -- 2. β's commuting square, but extended to G since β is only G' ≡> H
    = compSq {C = D} (α .N-hom f) βSq
    where
      -- functor equality implies equality of actions on objects and morphisms
      Gx≡G'x : G ⟅ x ⟆ ≡ G' ⟅ x ⟆
      Gx≡G'x i = F-ob (p i) x

      Gy≡G'y : G ⟅ y ⟆ ≡ G' ⟅ y ⟆
      Gy≡G'y i = F-ob (p i) y

      Gf≡G'f : PathP (λ i → D [ Gx≡G'x i , Gy≡G'y i ]) (G ⟪ f ⟫) (G' ⟪ f ⟫)
      Gf≡G'f i = p i ⟪ f ⟫

      -- components of β extended out to Gx and Gy respectively
      βx' = subst (λ a → D [ a , H ⟅ x ⟆ ]) (sym Gx≡G'x) (β ⟦ x ⟧)
      βy' = subst (λ a → D [ a , H ⟅ y ⟆ ]) (sym Gy≡G'y) (β ⟦ y ⟧)

      -- extensions are equal to originals
      βy'≡βy : PathP (λ i → D [ Gy≡G'y i , H ⟅ y ⟆ ]) βy' (β ⟦ y ⟧)
      βy'≡βy = symP (toPathP {A = λ i → D [ Gy≡G'y (~ i) , H ⟅ y ⟆ ]} refl)

      βx≡βx' : PathP (λ i → D [ Gx≡G'x (~ i) , H ⟅ x ⟆ ]) (β ⟦ x ⟧) βx'
      βx≡βx' = toPathP refl

      -- left wall of square
      left : PathP (λ i → D [ Gx≡G'x i , H ⟅ y ⟆ ]) (G ⟪ f ⟫ ⋆⟨ D ⟩ βy') (G' ⟪ f ⟫ ⋆⟨ D ⟩ β ⟦ y ⟧)
      left i = Gf≡G'f i ⋆⟨ D ⟩ βy'≡βy i

      -- right wall of square
      right : PathP (λ i → D [ Gx≡G'x (~ i) , H ⟅ y ⟆ ]) (β ⟦ x ⟧ ⋆⟨ D ⟩ H ⟪ f ⟫) (βx' ⋆⟨ D ⟩ H ⟪ f ⟫)
      right i = βx≡βx' i ⋆⟨ D ⟩ refl {x = H ⟪ f ⟫} i

      -- putting it all together
      βSq : G ⟪ f ⟫ ⋆⟨ D ⟩ βy' ≡ βx' ⋆⟨ D ⟩ H ⟪ f ⟫
      βSq i = comp (λ k → D [ Gx≡G'x (~ k) , H ⟅ y ⟆ ])
                   (λ j → λ { (i = i0) → left (~ j)
                            ; (i = i1) → right j })
                   (β .N-hom f i)

  module _  ⦃ isCatD : isCategory D ⦄ {F G : Functor C D} {α β : NatTrans F G} where
    open Precategory
    open Functor
    open NatTrans

    makeNatTransPath : α .N-ob ≡ β .N-ob → α ≡ β
    makeNatTransPath p i .N-ob = p i
    makeNatTransPath p i .N-hom f = rem i
      where
        rem : PathP (λ i → (F .F-hom f) ⋆ᴰ (p i _) ≡ (p i _) ⋆ᴰ (G .F-hom f)) (α .N-hom f) (β .N-hom f)
        rem = toPathP (isCatD .isSetHom _ _ _ _)

  module _  ⦃ isCatD : isCategory D ⦄ {F F' G G' : Functor C D}
            {α : NatTrans F G}
            {β : NatTrans F' G'} where
    open Precategory
    open Functor
    open NatTrans
    makeNatTransPathP : ∀ (p : F ≡ F') (q : G ≡ G')
                      → PathP (λ i → (x : C .ob) → D [ (p i) .F-ob x , (q i) .F-ob x ]) (α .N-ob) (β .N-ob)
                      → PathP (λ i → NatTrans (p i) (q i)) α β
    makeNatTransPathP p q P i .N-ob = P i
    makeNatTransPathP p q P i .N-hom f = rem i
      where
        rem : PathP (λ i → ((p i) .F-hom f) ⋆ᴰ (P i _) ≡ (P i _) ⋆ᴰ ((q i) .F-hom f)) (α .N-hom f) (β .N-hom f)
        rem = toPathP (isCatD .isSetHom _ _ _ _)

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

module _ {B : Precategory ℓB ℓB'} {C : Precategory ℓC ℓC'} {D : Precategory ℓD ℓD'} where
  open NatTrans
  -- whiskering
  -- αF
  _∘ˡ_ : ∀ {G H : Functor C D} (α : NatTrans G H) → (F : Functor B C)
        → NatTrans (G ∘F F) (H ∘F F)
  (_∘ˡ_ {G} {H} α F) .N-ob x = α ⟦ F ⟅ x ⟆ ⟧
  (_∘ˡ_ {G} {H} α F) .N-hom f = (α .N-hom) _

  -- Kβ
  _∘ʳ_ : ∀ (K : Functor C D) → {G H : Functor B C} (β : NatTrans G H)
       → NatTrans (K ∘F G) (K ∘F H)
  (_∘ʳ_ K {G} {H} β) .N-ob x = K ⟪ β ⟦ x ⟧ ⟫
  (_∘ʳ_ K {G} {H} β) .N-hom f = preserveCommF {C = C} {D = D} {K} (β .N-hom f)


------------------------------------------------------------------------
-- The "interval"
------------------------------------------------------------------------

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

-- Partly based on the HoTT book.

-- The module is parametrised by a notion of equality. The higher
-- constructor of the HIT defining the interval uses path equality,
-- but the supplied notion of equality is used for many other things.

import Equality.Path as P

module Interval
  {c⁺} (eq : ∀ {a p} → P.Equality-with-paths a p c⁺) where

private
  open module D = P.Derived-definitions-and-properties eq hiding (elim)

open import Logical-equivalence using (_⇔_)
open import Prelude

open import Bijection equality-with-J using (_↔_)
import Equality.Path.Isomorphisms eq as I
open import Equivalence equality-with-J hiding (_∘_)
open import Function-universe equality-with-J hiding (_∘_)
open import H-level equality-with-J
open import H-level.Closure equality-with-J using (ext⁻¹)

private
  variable
    a p   : Level
    A B C : Type a

------------------------------------------------------------------------
-- The interval

-- The interval, defined as a higher inductive type.

data Interval : Type where
  [0] [1] : Interval
  0≡1ᴾ    : [0] P.≡ [1]

-- [0] is equal to [1].

0≡1 : [0] ≡ [1]
0≡1 = _↔_.from ≡↔≡ 0≡1ᴾ

-- An eliminator, expressed using paths.

elimᴾ :
  (P : Interval → Type p)
  (p₀ : P [0])
  (p₁ : P [1]) →
  P.[ (λ i → P (0≡1ᴾ i)) ] p₀ ≡ p₁ →
  (x : Interval) → P x
elimᴾ P p₀ p₁ p₀≡p₁ = λ where
  [0]      → p₀
  [1]      → p₁
  (0≡1ᴾ i) → p₀≡p₁ i

-- A non-dependent eliminator, expressed using paths.

recᴾ : (p₀ p₁ : A) → p₀ P.≡ p₁ → Interval → A
recᴾ = elimᴾ _

-- An eliminator.

module Elim
  (P : Interval → Type p)
  (p₀ : P [0])
  (p₁ : P [1])
  (p₀≡p₁ : subst P 0≡1 p₀ ≡ p₁)
  where

  -- The eliminator.

  elim : (x : Interval) → P x
  elim = elimᴾ P p₀ p₁ (I.subst≡→[]≡ p₀≡p₁)

  -- A "computation" rule for elim.

  elim-0≡1 : dcong elim 0≡1 ≡ p₀≡p₁
  elim-0≡1 = I.dcong-subst≡→[]≡ (refl _)

open Elim public

-- A non-dependent eliminator.

module Rec
  (p₀ p₁ : A)
  (p₀≡p₁ : p₀ ≡ p₁)
  where

  -- The eliminator.

  rec : Interval → A
  rec = recᴾ p₀ p₁ (_↔_.to ≡↔≡ p₀≡p₁)

  -- A computation rule for rec.

  rec-0≡1 : cong rec 0≡1 ≡ p₀≡p₁
  rec-0≡1 = I.cong-≡↔≡ (refl _)

open Rec public

------------------------------------------------------------------------
-- Contractibility

-- The interval is contractible.

interval-contractible : Contractible Interval
interval-contractible = [1] , sym ∘ f
  where
  f : (x : Interval) → x ≡ [1]
  f = elim (_≡ [1]) 0≡1 (refl _)
        (subst (_≡ [1]) 0≡1 0≡1              ≡⟨ cong (λ p → subst (_≡ [1]) p 0≡1)
                                                     (sym $ sym-sym 0≡1) ⟩
         subst (_≡ [1]) (sym (sym 0≡1)) 0≡1  ≡⟨ subst-trans (sym 0≡1) ⟩
         trans (sym 0≡1) 0≡1                 ≡⟨ trans-symˡ 0≡1 ⟩∎
         refl _                              ∎)

-- A simplification lemma for rec p p.

rec-const :
  ∀ {p} {P : Type p} (p : P) (p≡p : p ≡ p) i →
  rec p p p≡p i ≡ p
rec-const p p≡p i =
  rec p p p≡p i    ≡⟨ cong (rec p p p≡p) (mono₁ 0 interval-contractible i [0]) ⟩∎
  rec p p p≡p [0]  ∎

------------------------------------------------------------------------
-- Extensionality

-- The definition of bad-ext has been placed in a separate abstract
-- block to ensure that the definitions in the other abstract block
-- below do not accidentally depend on the implementation of bad-ext.

private
 module Separate-abstract-block where

  abstract

    -- The interval can be used to prove that equality of functions is
    -- extensional.
    --
    -- The proof bad-ext is perhaps not less "good" than ext (I don't
    -- know), it is called this simply because it is not defined using
    -- good-ext.

    private

      -- ext-helper {f = f} {g = g} f≡g reduces to λ x → f x when the
      -- input is [0], and to λ x → g x when the input is [1].

      ext-helper :
        ∀ {a b} {A : Type a} {B : A → Type b} {f g : (x : A) → B x} →
        (∀ x → f x ≡ g x) → Interval → (x : A) → B x
      ext-helper {f = f} {g} f≡g i =
        λ x → rec (f x) (g x) (f≡g x) i

    bad-ext : ∀ {a b} → Extensionality a b
    apply-ext bad-ext {f = f} {g = g} f≡g =
      f                   ≡⟨⟩
      ext-helper f≡g [0]  ≡⟨ cong (ext-helper f≡g) 0≡1 ⟩∎
      ext-helper f≡g [1]  ∎

open Separate-abstract-block public

ext : ∀ {a b} → Extensionality a b
ext = good-ext bad-ext

⟨ext⟩ : ∀ {a b} {A : Type a} {B : A → Type b} → Extensionality′ A B
⟨ext⟩ = apply-ext ext

abstract

  -- The function ⟨ext⟩ is an equivalence.

  ext-is-equivalence :
    ∀ {a b} {A : Type a} {B : A → Type b} {f g : (x : A) → B x} →
    Is-equivalence {A = ∀ x → f x ≡ g x} ⟨ext⟩
  ext-is-equivalence = good-ext-is-equivalence bad-ext

  -- Equality rearrangement lemmas for ⟨ext⟩.

  ext-refl :
    ∀ {a b} {A : Type a} {B : A → Type b} (f : (x : A) → B x) →
    ⟨ext⟩ (λ x → refl (f x)) ≡ refl f
  ext-refl = good-ext-refl bad-ext

  ext-const :
    ∀ {a b} {A : Type a} {B : Type b} {x y : B}
    (x≡y : x ≡ y) →
    ⟨ext⟩ (const {B = A} x≡y) ≡ cong const x≡y
  ext-const = good-ext-const bad-ext

  cong-ext :
    ∀ {a b} {A : Type a} {B : A → Type b} {f g : (x : A) → B x}
    (f≡g : ∀ x → f x ≡ g x) {x} →
    cong (_$ x) (⟨ext⟩ f≡g) ≡ f≡g x
  cong-ext = cong-good-ext bad-ext

  ext-cong :
    ∀ {a b c} {A : Type a} {B : Type b} {C : B → Type c}
    {f : A → (x : B) → C x} {x y : A} {x≡y : x ≡ y} →
    ⟨ext⟩ (λ z → cong (flip f z) x≡y) ≡ cong f x≡y
  ext-cong = good-ext-cong bad-ext

  subst-ext :
    ∀ {a b p} {A : Type a} {B : A → Type b} {f g : (x : A) → B x} {x}
    (P : B x → Type p) {p} (f≡g : ∀ x → f x ≡ g x) →
    subst (λ f → P (f x)) (⟨ext⟩ f≡g) p ≡ subst P (f≡g x) p
  subst-ext = subst-good-ext bad-ext

  elim-ext :
    ∀ {a b p} {A : Type a} {B : A → Type b} {x : A}
    (P : B x → B x → Type p)
    (p : (y : B x) → P y y)
    {f g : (x : A) → B x}
    (f≡g : ∀ x → f x ≡ g x) →
    D.elim (λ {f g} _ → P (f x) (g x)) (p ∘ (_$ x)) (⟨ext⟩ f≡g) ≡
    D.elim (λ {x y} _ → P x y) p (f≡g x)
  elim-ext = elim-good-ext bad-ext

  -- I based the statements of the following three lemmas on code in
  -- the Lean Homotopy Type Theory Library with Jakob von Raumer and
  -- Floris van Doorn listed as authors. The file was claimed to have
  -- been ported from the Coq HoTT library. (The third lemma has later
  -- been generalised.)

  ext-sym :
    ∀ {a b} {A : Type a} {B : A → Type b} {f g : (x : A) → B x}
    (f≡g : ∀ x → f x ≡ g x) →
    ⟨ext⟩ (sym ∘ f≡g) ≡ sym (⟨ext⟩ f≡g)
  ext-sym = good-ext-sym bad-ext

  ext-trans :
    ∀ {a b} {A : Type a} {B : A → Type b} {f g h : (x : A) → B x}
    (f≡g : ∀ x → f x ≡ g x) (g≡h : ∀ x → g x ≡ h x) →
    ⟨ext⟩ (λ x → trans (f≡g x) (g≡h x)) ≡ trans (⟨ext⟩ f≡g) (⟨ext⟩ g≡h)
  ext-trans = good-ext-trans bad-ext

  cong-post-∘-ext :
    ∀ {a b c} {A : Type a} {B : A → Type b} {C : A → Type c}
      {f g : (x : A) → B x} {h : ∀ {x} → B x → C x}
    (f≡g : ∀ x → f x ≡ g x) →
    cong (h ∘_) (⟨ext⟩ f≡g) ≡ ⟨ext⟩ (cong h ∘ f≡g)
  cong-post-∘-ext {h = h} = cong-post-∘-good-ext {h = h} bad-ext bad-ext

  cong-pre-∘-ext :
    ∀ {a b c} {A : Type a} {B : Type b} {C : B → Type c}
      {f g : (x : B) → C x} {h : A → B}
    (f≡g : ∀ x → f x ≡ g x) →
    cong (_∘ h) (⟨ext⟩ f≡g) ≡ ⟨ext⟩ (f≡g ∘ h)
  cong-pre-∘-ext = cong-pre-∘-good-ext bad-ext bad-ext

  cong-∘-ext :
    {f g : B → C}
    (f≡g : ∀ x → f x ≡ g x) →
    cong {B = (A → B) → (A → C)}
         (λ f → f ∘_) (⟨ext⟩ f≡g) ≡
    ⟨ext⟩ λ h → ⟨ext⟩ λ x → f≡g (h x)
  cong-∘-ext = cong-∘-good-ext bad-ext bad-ext bad-ext


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

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

open import Relation.Binary.Lattice

module Relation.Binary.Properties.Lattice
  {c ℓ₁ ℓ₂} (L : Lattice c ℓ₁ ℓ₂) where

open Lattice L

import Algebra as Alg
import Algebra.Structures as Alg
open import Algebra.FunctionProperties _≈_
open import Data.Product using (_,_)
open import Function using (flip)
open import Relation.Binary
open import Relation.Binary.Properties.Poset poset
import Relation.Binary.Properties.JoinSemilattice joinSemilattice as J
import Relation.Binary.Properties.MeetSemilattice meetSemilattice as M
import Relation.Binary.Reasoning.Setoid as EqReasoning
import Relation.Binary.Reasoning.PartialOrder as POR

∨-absorbs-∧ : _∨_ Absorbs _∧_
∨-absorbs-∧ x y =
  let x≤x∨[x∧y] , _ , least = supremum  x (x ∧ y)
      x∧y≤x     , _ , _     = infimum x y
  in antisym (least x refl x∧y≤x) x≤x∨[x∧y]

∧-absorbs-∨ : _∧_ Absorbs _∨_
∧-absorbs-∨ x y =
  let x∧[x∨y]≤x , _ , greatest = infimum  x (x ∨ y)
      x≤x∨y     , _ , _        = supremum x y
  in antisym x∧[x∨y]≤x (greatest x refl x≤x∨y)

absorptive : Absorptive _∨_ _∧_
absorptive = ∨-absorbs-∧ , ∧-absorbs-∨

∧≤∨ : ∀ {x y} → x ∧ y ≤ x ∨ y
∧≤∨ {x} {y} = begin
  x ∧ y ≤⟨ x∧y≤x x y ⟩
  x     ≤⟨ x≤x∨y x y ⟩
  x ∨ y ∎
  where open POR poset

-- two quadrilateral arguments

quadrilateral₁ : ∀ {x y} → x ∨ y ≈ x → x ∧ y ≈ y
quadrilateral₁ {x} {y} x∨y≈x = begin
  x ∧ y       ≈⟨ M.∧-cong (Eq.sym x∨y≈x) Eq.refl ⟩
  (x ∨ y) ∧ y ≈⟨ M.∧-comm _ _ ⟩
  y ∧ (x ∨ y) ≈⟨ M.∧-cong Eq.refl (J.∨-comm _ _) ⟩
  y ∧ (y ∨ x) ≈⟨ ∧-absorbs-∨ _ _ ⟩
  y           ∎
  where open EqReasoning setoid

quadrilateral₂ : ∀ {x y} → x ∧ y ≈ y → x ∨ y ≈ x
quadrilateral₂ {x} {y} x∧y≈y = begin
  x ∨ y       ≈⟨ J.∨-cong Eq.refl (Eq.sym x∧y≈y) ⟩
  x ∨ (x ∧ y) ≈⟨ ∨-absorbs-∧ _ _ ⟩
  x           ∎
  where open EqReasoning setoid

-- collapsing sublattice

collapse₁ : ∀ {x y} → x ≈ y → x ∧ y ≈ x ∨ y
collapse₁ {x} {y} x≈y = begin
  x ∧ y ≈⟨ M.y≤x⇒x∧y≈y y≤x ⟩
  y     ≈⟨ Eq.sym x≈y ⟩
  x     ≈⟨ Eq.sym (J.x≤y⇒x∨y≈y y≤x) ⟩
  y ∨ x ≈⟨ J.∨-comm _ _ ⟩
  x ∨ y ∎
  where
  y≤x = reflexive (Eq.sym x≈y)
  open EqReasoning setoid

-- this can also be proved by quadrilateral argument, but it's much less symmetric.
collapse₂ : ∀ {x y} → x ∨ y ≤ x ∧ y → x ≈ y
collapse₂ {x} {y} ∨≤∧ = antisym
  (begin x     ≤⟨ x≤x∨y _ _ ⟩
         x ∨ y ≤⟨ ∨≤∧ ⟩
         x ∧ y ≤⟨ x∧y≤y _ _ ⟩
         y     ∎)
  (begin y     ≤⟨ y≤x∨y _ _ ⟩
         x ∨ y ≤⟨ ∨≤∧ ⟩
         x ∧ y ≤⟨ x∧y≤x _ _ ⟩
         x     ∎)
  where open POR poset

------------------------------------------------------------------------
-- The dual construction is also a lattice.

∧-∨-isLattice : IsLattice _≈_ (flip _≤_) _∧_ _∨_
∧-∨-isLattice = record
  { isPartialOrder = invIsPartialOrder
  ; supremum       = infimum
  ; infimum        = supremum
  }

∧-∨-lattice : Lattice c ℓ₁ ℓ₂
∧-∨-lattice = record
  { _∧_       = _∨_
  ; _∨_       = _∧_
  ; isLattice = ∧-∨-isLattice
  }

------------------------------------------------------------------------
-- Every order-theoretic lattice can be turned into an algebraic one.

isAlgLattice : Alg.IsLattice _≈_ _∨_ _∧_
isAlgLattice = record
  { isEquivalence = isEquivalence
  ; ∨-comm        = J.∨-comm
  ; ∨-assoc       = J.∨-assoc
  ; ∨-cong        = J.∨-cong
  ; ∧-comm        = M.∧-comm
  ; ∧-assoc       = M.∧-assoc
  ; ∧-cong        = M.∧-cong
  ; absorptive    = absorptive
  }

algLattice : Alg.Lattice c ℓ₁
algLattice = record { isLattice = isAlgLattice }


------------------------------------------------------------------------------
-- First-order logic base
------------------------------------------------------------------------------

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

module FOL.Base where

infix  2 ⋀
infixr 1 _⇒_
infixr 0 _⇔_

------------------------------------------------------------------------------
-- First-order logic (without equality).
open import Common.FOL.FOL public

------------------------------------------------------------------------------
-- We added extra symbols for the implication, the biconditional and
-- the universal quantification (see module Common.FOL.FOL).

-- The implication data type.
data _⇒_ (A B : Set) : Set where
  fun : (A → B) → A ⇒ B

app : {A B : Set} → A ⇒ B → A → B
app (fun f) a = f a

-- Biconditional.
_⇔_ : Set → Set → Set
A ⇔ B = (A ⇒ B) ∧ (B ⇒ A)

-- The universal quantifier type on D.
data  ⋀ (A : D → Set) : Set where
  dfun : ((t : D) → A t) → ⋀ A

-- Sugar syntax for the universal quantifier.
syntax ⋀ (λ x → e) = ⋀[ x ] e

dapp : {A : D → Set}(t : D) → ⋀ A → A t
dapp t (dfun f) = f t

------------------------------------------------------------------------------
-- In first-order logic it is assumed that the universe of discourse
-- is non-empty.
postulate D≢∅ : D

------------------------------------------------------------------------------
-- The ATPs work in classical logic, therefore we add the principle of
-- the exclude middle for prove some non-intuitionistic theorems. Note
-- that we do not need to add the postulate as an ATP axiom.

-- The principle of the excluded middle.
postulate pem : ∀ {A} → A ∨ ¬ A


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

module Categories.Category.Instance.Properties.Setoids.Exact where

open import Categories.Category using (Category)
open import Categories.Category.Exact using (Exact)
open import Categories.Category.Instance.Properties.Setoids.Limits.Canonical using (pullback; FiberProduct; mk-×; FP-≈)
open import Categories.Category.Instance.Setoids using (Setoids)
open import Categories.Category.Monoidal.Instance.Setoids using (Setoids-Cartesian)
open import Categories.Category.Regular using (Regular)
open import Categories.Diagram.Coequalizer using (Coequalizer; IsCoequalizer; Coequalizer⇒Epi)
open import Categories.Diagram.Coequalizer.Properties
open import Categories.Diagram.KernelPair using (KernelPair)
open import Categories.Diagram.Pullback using (Pullback; up-to-iso)
open import Categories.Diagram.Pullback.Properties
open import Categories.Morphism using (_≅_; Epi)
open import Categories.Morphism.Regular using (RegularEpi)
open import Categories.Object.InternalRelation using (Equivalence; EqSpan; KP⇒Relation; KP⇒EqSpan; KP⇒Equivalence; module Relation; rel)

open import Data.Bool.Base using (Bool; true; false; T)
open import Data.Empty.Polymorphic using (⊥)
open import Data.Fin using (Fin; zero) renaming (suc to nzero)
open import Data.Product using (∃; proj₁; proj₂; _,_; Σ-syntax; _×_; -,_; map; zip; swap; map₂)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Unit.Polymorphic.Base using (⊤; tt)
open import Function using (flip) renaming (id to id→; _∘′_ to _∘→_)
open import Function.Equality as SΠ using (Π; _⇨_) renaming (id to ⟶-id; _∘_ to _∘⟶_)
open import Function.Definitions using (Surjective)
open import Level
open import Relation.Binary using (Setoid; Rel; IsEquivalence)
import Relation.Binary.Reasoning.Setoid as SR

open import Categories.Category.Instance.SingletonSet

open Setoid renaming (_≈_ to [_][_≈_]; Carrier to ∣_∣) using (isEquivalence; refl; sym; trans)
open Π using (_⟨$⟩_; cong)

module _ ℓ where
  private
    S = Setoids ℓ ℓ
    open Category S hiding (_≈_)
    module S = Category S

  open Pullback using (P; p₁; p₂)

  -- the next bits all depend on a Setoid X and an Equivalence E, factor those out
  module _ {X : Setoid ℓ ℓ} (E : Equivalence S X) where
    -- let some things have short names
    open Equivalence E using (R; module R; eqspan)
    module ES = EqSpan eqspan

    private
      module X = Setoid X using (refl; sym; trans; _≈_)
    -- convenient inline versions
    infix 2 ⟺
    infixr 3 _○_
    ⟺ : {x₁ x₂ : ∣ X ∣} → x₁ X.≈ x₂ → x₂ X.≈ x₁
    ⟺ = Setoid.sym X
    _○_ : {x₁ x₂ x₃ : ∣ X ∣} → x₁ X.≈ x₂ → x₂ X.≈ x₃ → x₁ X.≈ x₃
    _○_ = Setoid.trans X

    record Equation (x₁ x₂ : ∣ X ∣) : Set ℓ where
      constructor eqn
      open Setoid X using (_≈_)
      field
        name : ∣ R.dom ∣
        x₁≈  : R.p₁ ⟨$⟩ name ≈ x₁
        ≈x₂  : R.p₂ ⟨$⟩ name ≈ x₂

    open Equation

    -- is re-used below, so make it easier to do so by exposing directly
    quotient-trans : {x₁ x₂ y₁ y₂ : ∣ X ∣} →
      (p : Equation x₁ y₁) → (q : Equation x₂ y₂) →
      [ X ][ x₁ ≈ x₂ ] → [ X ][ y₁ ≈ y₂ ] → [ R.dom ][ name p ≈ name q ]

    quotient-trans {x₁} {x₂} {y₁} {y₂} (eqn eq x₁≈ ≈y₁) (eqn eq′ x₂≈ ≈y₂) x₁≈x₂ y₁≈y₂ =
      R.relation {SingletonSetoid}
      (record { _⟨$⟩_ = λ _ → eq  ; cong = λ _ → refl R.dom})
      (record { _⟨$⟩_ = λ _ → eq′ ; cong = λ _ → refl R.dom})
      (λ { zero      _ → x₁≈ ○ x₁≈x₂ ○ ⟺ x₂≈
         ; (nzero _) _ → ≈y₁ ○ y₁≈y₂ ○ ⟺ ≈y₂}) tt

    Quotient-Equivalence : IsEquivalence Equation
    Quotient-Equivalence = record
        {
          refl  = eqn _ (ES.is-refl₁ X.refl) (ES.is-refl₂ X.refl)
        ; sym   = λ { (eqn r eq₁ eq₂) → eqn (ES.sym ⟨$⟩ r) (ES.is-sym₁ D.refl ○ eq₂) (ES.is-sym₂ D.refl ○ eq₁) }
        ; trans = λ { (eqn r x≈ ≈y) (eqn s y≈ ≈z) →
           let t = record { elem₁ = _ ; elem₂ = _ ; commute = y≈ ○ ⟺ ≈y } in
             eqn
               (ES.trans ∘⟶ P₀⇒P₁ ⟨$⟩ t)
               (ES.is-trans₁ R×R.refl ○ (cong R.p₁ (p₂-≈ {t} {t} (D.refl , D.refl)) ○ x≈))
               (ES.is-trans₂ R×R.refl ○ (cong R.p₂ (p₁-≈ {t} {t} (D.refl , D.refl)) ○ ≈z))
           }
        }
          where
            module D = Setoid R.dom         using (refl)
            module R×R = Setoid ES.R×R.dom  using (refl)

            fp : Pullback S R.p₁ R.p₂
            fp = pullback ℓ ℓ R.p₁ R.p₂
            open IsoPb S fp ES.R×R using (P₀⇒P₁; p₁-≈; p₂-≈)

    Quotient-Setoid : Setoid ℓ ℓ
    Quotient-Setoid = record { Carrier = ∣ X ∣ ; _≈_ = Equation; isEquivalence = Quotient-Equivalence }

    Quotient-Coequalizer : Coequalizer S (Equivalence.R.p₁ E) (Equivalence.R.p₂ E)
    Quotient-Coequalizer = record
      { obj = X∼
      ; arr = inj
      ; isCoequalizer = record
         { equality   = inj-≈
         ; coequalize = λ {_}{h} → quotient h
         ; universal  = λ {_}{h} → cong h
         ; unique     = λ {_}{h}{i}{eq′} → unique {_}{h}{i}{eq′}
         }
      }
      where
        X∼ : Setoid ℓ ℓ
        X∼ = Quotient-Setoid

        inj : X ⇒ X∼
        inj = record
         { _⟨$⟩_ = id→
         ; cong = λ {x₁} eq → eqn (ES.refl ⟨$⟩ x₁) (ES.is-refl₁ X.refl) (ES.is-refl₂ X.refl ○ eq)
         }

        inj-≈ : inj ∘ R.p₁ S.≈ inj ∘ R.p₂
        inj-≈ {x} x≈y = eqn x X.refl (cong R.p₂ x≈y)

        -- coEqualizer wants the 'h' to be implicit, but can't figure it out, so make it explicit here
        quotient : {C : Obj} (h : X ⇒ C) → h ∘ R.p₁ S.≈ h ∘ R.p₂ → X∼ ⇒ C
        quotient {C} h eq = record
          { _⟨$⟩_ = h ⟨$⟩_
          ; cong = λ { (eqn r x≈ ≈y) → trans C (cong h (X.sym x≈)) (trans C (eq (refl R.dom)) (cong h ≈y))}
          }

        unique : {C : Obj} {h : X ⇒ C} {i : X∼ ⇒ C} {eq : h ∘ R.p₁ S.≈ h ∘ R.p₂} → h S.≈ i ∘ inj → i S.≈ quotient h eq
        unique {C} {h} {i} {eq′} eq {x} {y} (eqn r x≈ ≈y) = begin
          i ⟨$⟩ x           ≈˘⟨ eq X.refl ⟩
          h ⟨$⟩ x           ≈˘⟨ cong h x≈ ⟩
          h ⟨$⟩ (R.p₁ ⟨$⟩ r) ≈⟨ eq′ (refl R.dom) ⟩
          h ⟨$⟩ (R.p₂ ⟨$⟩ r) ≈⟨ cong h ≈y ⟩
          h ⟨$⟩ y ∎
          where open SR C

  -- Setoid Surjectivity
  SSurj : {A B : Setoid ℓ ℓ} (f : A ⇒ B) → Set ℓ
  SSurj {A} {B} f = Surjective (Setoid._≈_ A) (Setoid._≈_ B) (f ⟨$⟩_)

  -- Proposition 1 from "Olov Wilander, Setoids and universes"
  Epi⇒Surjective : ∀ {A B : Setoid ℓ ℓ} (f : A ⇒ B) → Epi S f → SSurj f
  Epi⇒Surjective {A}{B} f epi y = g≈h (refl B {y}) .proj₁ (λ ()) _

    where
      infix 3 _↔_

      _↔_ : Set ℓ → Set ℓ → Set ℓ
      A ↔ B = (A → B) × (B → A)

      B′ : Setoid ℓ ℓ
      B′ = record
        { Carrier =  Bool × ∣ B ∣
        ; _≈_ = λ { (a , x)  (b , y) → ((T a → Σ[ z ∈ ∣ A ∣ ] [ B ][ f ⟨$⟩ z ≈ x ]) ↔ (T b → Σ[ z ∈ ∣ A ∣ ] [ B ][ f ⟨$⟩ z ≈ y ])) }
        ; isEquivalence = record
            { refl  = id→ , id→
            ; sym   = swap
            ; trans = zip (flip _∘→_) _∘→_
            }
        }

      g : B ⇒ B′
      g = record { _⟨$⟩_ = λ x → false , x ; cong = λ _ → (λ _ ()) , (λ _ ()) }

      h : B ⇒ B′
      h = record
          { _⟨$⟩_ = true ,_
          ; cong = λ x≈y →
                (λ eq _ → map₂ (λ z → trans B z x≈y) (eq _))
              , (λ eq _ → let (a , eq′) = eq _ in a , (trans B eq′ (sym B x≈y)))
          }

      g≈h : [ B ⇨ B′ ][ g ≈ h ]
      g≈h = epi g h λ {x}{y} x≈y → (λ u _ → x , cong f x≈y) , λ _ ()

  -- not needed for exactness, but worthwhile
  Surjective⇒RegularEpi : ∀ {A B : Setoid ℓ ℓ} (f : A ⇒ B) → ((y : ∣ B ∣) → Σ[ x ∈ ∣ A ∣ ] [ B ][ f ⟨$⟩ x ≈ y ]) → RegularEpi S f
  Surjective⇒RegularEpi {A}{B} f surj = record
    { h = p₁ kp
    ; g = p₂ kp
    ; coequalizer = record
        { equality   = λ {x} {y} → commute kp {x} {y}
        ; coequalize = λ {_} {h} → Coeq.coeq {h = h}
        ; universal = λ {C} {h} {eq} → Coeq.universal′ {C} {h} (λ {x} {y} → eq {x} {y})
        ; unique = λ {_}{h}{i}{eq} h≈i∘f x≈y → Coeq.unique″ {_} {h} (λ {x} {y} → eq {x} {y}) {i} h≈i∘f x≈y
        }
    }
    where
      kp = pullback ℓ ℓ f f
      open Pullback
      module Coeq {C : S.Obj} {h : A S.⇒ C} where
        open SR C
        f⁻¹∘h : ∣ B ∣ → ∣ C ∣
        f⁻¹∘h b = h ⟨$⟩ proj₁ (surj b)
        module _ (h∘p₁≈h∘p₂ : h S.∘ p₁ kp S.≈ h S.∘ p₂ kp) where
          cong′ : {i j : ∣ B ∣} → [ B ][ i ≈ j ] → [ C ][ h ⟨$⟩ proj₁ (surj i) ≈ h ⟨$⟩ proj₁ (surj j) ]
          cong′ {y₁}{y₂} y₁≈y₂ = h∘p₁≈h∘p₂ {pt₁} {pt₁} (refl A , refl A)
            where
              x₁ x₂ : ∣ A ∣
              x₁ = surj y₁ .proj₁
              x₂ = surj y₂ .proj₁
              eq₁ : [ B ][ f ⟨$⟩ x₁ ≈ y₁ ]
              eq₁ = surj y₁ .proj₂
              eq₂ : [ B ][ f ⟨$⟩ x₂ ≈ y₂ ]
              eq₂ = surj y₂ .proj₂
              pt₁ : FiberProduct f f
              pt₁ = mk-× x₁ x₂ (trans B eq₁ (trans B y₁≈y₂ (sym B eq₂)))
          coeq : B S.⇒ C
          coeq = record { _⟨$⟩_ = f⁻¹∘h ; cong = cong′ }
          universal′ : h S.≈ coeq S.∘ f
          universal′ {x} {y} x≈y = begin
            h ⟨$⟩ x                     ≈⟨ cong h x≈y ⟩
            h ⟨$⟩ y                     ≈⟨ h∘p₁≈h∘p₂ {mk-× y x₁ (sym B eq₁)} {mk-× x x₁ (trans B (cong f x≈y) (sym B eq₁))} (sym A x≈y , refl A) ⟩
            h ⟨$⟩ proj₁ (surj (f ⟨$⟩ y)) ≡⟨⟩ -- by definition of f⁻¹∘h
            f⁻¹∘h (f ⟨$⟩ y)             ≡⟨⟩ -- by definition of coeq
            coeq S.∘ f ⟨$⟩ y            ∎
            where
              x₁ : ∣ A ∣
              x₁ = surj (f ⟨$⟩ y) .proj₁
              eq₁ : [ B ][ f ⟨$⟩ x₁ ≈ f ⟨$⟩ y ]
              eq₁ = surj (f ⟨$⟩ y) .proj₂
          unique″ : {i : B S.⇒ C} → h S.≈ i S.∘ f → i S.≈ coeq
          unique″ {i} h≈i∘f {x} {y} x≈y = begin
            i ⟨$⟩ x              ≈⟨ cong i x≈y ⟩
            i ⟨$⟩ y              ≈⟨ cong i (sym B eq₁) ⟩
            i ∘ f ⟨$⟩ x₁         ≈⟨ sym C (h≈i∘f (refl A)) ⟩
            h ⟨$⟩ x₁             ≡⟨⟩ -- by definition of f⁻¹∘h
            f⁻¹∘h y             ∎
            where
              x₁ : ∣ A ∣
              x₁ = surj y .proj₁
              eq₁ : [ B ][ f ⟨$⟩ x₁ ≈ y ]
              eq₁ = surj y .proj₂

  Setoids-Regular : Regular (Setoids ℓ ℓ)
  Setoids-Regular = record
    { finitely-complete = record
       { cartesian = Setoids-Cartesian
       ; equalizer = λ _ _ → pullback×cartesian⇒equalizer S (pullback ℓ ℓ) Setoids-Cartesian
       }
    ; coeq-of-kernelpairs = λ f kp → Quotient-Coequalizer record
       { R = KP⇒Relation S f kp
       ; eqspan = KP⇒EqSpan S f kp (pb kp)
       }
    ; pullback-of-regularepi-is-regularepi = pb-of-re-is-re
    }
    where
      pb : ∀ {A B} {f : A ⇒ B} (kp : KernelPair S f) → Pullback S (p₁ kp) (p₂ kp)
      pb kp = pullback ℓ ℓ (p₁ kp) (p₂ kp)

      pb-of-re-is-re : {A B D : Setoid ℓ ℓ} (f : B ⇒ A) {u : D ⇒ A} →
        RegularEpi S f → (pb : Pullback S f u) → RegularEpi S (p₂ pb)
      pb-of-re-is-re {A}{B}{D} f {u} record { C = C ; h = _ ; g = _ ; coequalizer = coeq } pb =
        Surjective⇒RegularEpi (p₂ pb) λ y →
          let (x , eq) = Epi⇒Surjective f (Coequalizer⇒Epi S record { arr = f ; isCoequalizer = coeq }) (u ⟨$⟩ y) in
          let pt = mk-× x y eq in
          P₀⇒P₁ ⟨$⟩ pt , p₂-≈ {pt} {pt} (refl B , refl D)
         where

           pb-fu : Pullback S f u
           pb-fu = pullback ℓ ℓ f u
           pb-ff : Pullback S f f
           pb-ff = pullback ℓ ℓ f f
           module B = Setoid B
           module C = Setoid C
           module D = Setoid D
           open IsoPb S pb-fu pb

  Setoids-Exact : Exact (Setoids ℓ ℓ)
  Setoids-Exact = record
    { regular   = Setoids-Regular
    ; quotient  = Quotient-Coequalizer
    ; effective = λ {X} E → record
        { commute   = λ eq → eqn _ (refl X) (cong (Relation.p₂ (R E)) eq)
        ; universal = λ { {Z}{h₁}{h₂} → universal E h₁ h₂ }
        ; unique    = λ {Z}{h₁}{h₂}{u}{eq} eq₁ eq₂ {x}{y} → Relation.relation (R E) u (universal E h₁ h₂ eq)
            λ { zero {x}{y} eq′      → trans X (eq₁ eq′) (sym X (p₁∘universal≈h₁ E h₁ h₂ eq (refl Z)))
              ; (nzero _) {x}{y} eq′ → trans X (eq₂ eq′) (sym X (p₂∘universal≈h₂ E h₁ h₂ eq (refl Z)))
              }
        ; p₁∘universal≈h₁ = λ {Z}{h₁}{h₂}{eq} → p₁∘universal≈h₁ E h₁ h₂ eq
        ; p₂∘universal≈h₂ = λ {Z}{h₁}{h₂}{eq} → p₂∘universal≈h₂ E h₁ h₂ eq
        }
    }
      where
        open Equivalence
        open Setoid
        open Coequalizer using (arr)

        universal : {X Z : Setoid ℓ ℓ} → (E : Equivalence S X) → (h₁ h₂ : Z ⇒ X) →
          (eq : [ Z ⇨ Quotient-Setoid E ][ arr (Quotient-Coequalizer E) ∘ h₁ ≈ arr (Quotient-Coequalizer E) ∘ h₂ ]) →
          Z ⇒ Relation.dom (R E)
        universal {X}{Z} E h₁ h₂ eq = record
          { _⟨$⟩_ = λ z → let (eqn eq _ _) = eq {z}{z} (refl Z) in eq
          ; cong = λ {z}{z′} z≈z′ → quotient-trans E (eq {z}{z} (refl Z)) (eq {z′}{z′} (refl Z)) (cong h₁ z≈z′) (cong h₂ z≈z′)
          }
        p₁∘universal≈h₁ : {X Z : Setoid ℓ ℓ} → (E : Equivalence S X) → (h₁ h₂ : Z ⇒ X) →
          (eq : [ Z ⇨ Quotient-Setoid E ][ arr (Quotient-Coequalizer E) ∘ h₁ ≈ arr (Quotient-Coequalizer E) ∘ h₂ ]) →
          [ Z ⇨ X ][ Relation.p₁ (R E) ∘ (universal E h₁ h₂ eq) ≈ h₁ ]
        p₁∘universal≈h₁ {X}{Z} _ h₁ h₂ eq x≈y = let (eqn _ p₁z≈ _) = eq (refl Z) in trans X p₁z≈ (cong h₁ x≈y)

        p₂∘universal≈h₂ : {X Z : Setoid ℓ ℓ} → (E : Equivalence S X) → (h₁ h₂ : Z ⇒ X) →
          (eq : [ Z ⇨ Quotient-Setoid E ][ arr (Quotient-Coequalizer E) ∘ h₁ ≈ arr (Quotient-Coequalizer E) ∘ h₂ ]) →
          [ Z ⇨ X ][ Relation.p₂ (R E) ∘ (universal E h₁ h₂ eq) ≈ h₂ ]
        p₂∘universal≈h₂ {X}{Z} _ h₁ h₂ eq x≈y = let (eqn _ _ p₂z≈) = eq (refl Z) in trans X p₂z≈ (cong h₂ x≈y)


{-# OPTIONS --without-K #-}
module HoTT.Equivalence.Proposition where

open import HoTT.Base
open import HoTT.HLevel
open import HoTT.Equivalence

open variables

-- Proven by Theorem 4.3.2
postulate
  isequiv-prop : {f : A → B} → isProp (isequiv f)

{-
  fib : B → 𝒰 _
  fib y = Σ[ x ∶ A ] (f x == y)

  -- Left inverse with coherence
  lcoh : linv → 𝒰 _
  lcoh (g , η) = Σ[ ε ∶ f ∘ g ~ id ] ap g ∘ ε ~ η ∘ g

  -- Right inverse with coherence
  rcoh : rinv → 𝒰 _
  rcoh (g , ε) = Σ[ η ∶ g ∘ f ~ id ] ap f ∘ η ~ ε ∘ f
-}

{-
hae-fib-contr : {f : A → B} → ishae f → (y : B) → isContr (fib f y)
hae-fib-contr {A = A} {f = f} (g , η , ε , τ) y = (g y , ε y) , contr
  where
  contr : (z : fib f y) → (g y , ε y) == z
  contr (x , p) = pair⁼ (qₓ , qₚ)
    where
    qₓ : g y == x
    qₓ = ap g p ⁻¹ ∙ η x
    qₚ : transport (λ x → f x == y) qₓ (ε y) == p
    qₚ = begin
      transport (λ x → f x == y) qₓ (ε y)      =⟨ transport=-constᵣ f y qₓ (ε y) ⟩
      ap f qₓ ⁻¹ ∙ ε y                         =⟨ ap (λ p → p ⁻¹ ∙ ε y) (ap-∙ f (ap g p ⁻¹) (η x)) ⟩
      (ap f (ap g p ⁻¹) ∙ ap f (η x)) ⁻¹ ∙ ε y =⟨ ap (λ p → p ⁻¹ ∙ ε y) (ap (ap f) (ap-⁻¹ g p ⁻¹) ⋆ τ x) ⟩
      (ap f (ap g (p ⁻¹)) ∙ ε (f x)) ⁻¹ ∙ ε y  =⟨ ap (λ p → (p ∙ ε (f x)) ⁻¹ ∙ ε y) (ap-∘ f g (p ⁻¹)) ⟩
      (ap (f ∘ g) (p ⁻¹) ∙ ε (f x)) ⁻¹ ∙ ε y   =⟨ ap (λ p → p ⁻¹ ∙ ε y) (~-naturality ε (p ⁻¹) ⁻¹) ⟩
      (ε y ∙ ap id (p ⁻¹)) ⁻¹ ∙ ε y            =⟨ ap (λ p → (ε y ∙ p) ⁻¹ ∙ ε y) (ap-id (p ⁻¹)) ⟩
      (ε y ∙ p ⁻¹) ⁻¹ ∙ ε y                    =⟨ ∙-⁻¹ (ε y) (p ⁻¹) ∙ᵣ ε y ⟩
      p ⁻¹ ⁻¹ ∙ ε y ⁻¹ ∙ ε y                   =⟨ ∙-assoc _ _ _ ⁻¹ ⟩
      p ⁻¹ ⁻¹ ∙ (ε y ⁻¹ ∙ ε y)                 =⟨ invinv p ⋆ ∙-invₗ (ε y) ⟩
      p ∙ refl                                 =⟨ ∙-unitᵣ p ⁻¹ ⟩
      p                                        ∎
      where
      open =-Reasoning
      ∙-⁻¹ : {A : 𝒰 i} {x y z : A} (p : x == y) (q : y == z) → (p ∙ q) ⁻¹ == q ⁻¹ ∙ p ⁻¹
      ∙-⁻¹ refl refl = refl
      invinv : {A : 𝒰 i} {x y : A} (p : x == y) → p ⁻¹ ⁻¹ == p
      invinv refl = refl

linv-contr : {f : A → B} → qinv f → isContr (linv f)
linv-contr {f = f} (g , η , ε) = {!hae-fib-contr (qinv→ishae e)!}
  where
  q' : qinv (_∘ f)
  q' = _∘ g , (λ x → ap (x ∘_) {!funext ?!}) , {!!}
rinv-contr : {f : A → B} → qinv f → isContr (rinv f)
rinv-contr = {!!}
-}


------------------------------------------------------------------------
-- The Agda standard library
--
-- Coinductive "natural" numbers
------------------------------------------------------------------------

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

module Codata.Musical.Conat where

open import Codata.Musical.Notation
open import Data.Nat.Base using (ℕ; zero; suc)
open import Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P using (_≡_)

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

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

module Coℕ-injective where

 suc-injective : ∀ {m n} → (Coℕ ∋ suc m) ≡ suc n → m ≡ n
 suc-injective P.refl = P.refl

------------------------------------------------------------------------
-- Some operations

pred : Coℕ → Coℕ
pred zero    = zero
pred (suc n) = ♭ n

fromℕ : ℕ → Coℕ
fromℕ zero    = zero
fromℕ (suc n) = suc (♯ fromℕ n)

fromℕ-injective : ∀ {m n} → fromℕ m ≡ fromℕ n → m ≡ n
fromℕ-injective {zero}  {zero}  eq = P.refl
fromℕ-injective {zero}  {suc n} ()
fromℕ-injective {suc m} {zero}  ()
fromℕ-injective {suc m} {suc n} eq = P.cong suc (fromℕ-injective (P.cong pred eq))

∞ℕ : Coℕ
∞ℕ = suc (♯ ∞ℕ)

infixl 6 _+_

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

------------------------------------------------------------------------
-- Equality

data _≈_ : Coℕ → Coℕ → Set where
  zero :                                 zero  ≈ zero
  suc  : ∀ {m n} (m≈n : ∞ (♭ m ≈ ♭ n)) → suc m ≈ suc n

module ≈-injective where

 suc-injective : ∀ {m n p q} → (suc m ≈ suc n ∋ suc p) ≡ suc q → p ≡ q
 suc-injective P.refl = P.refl

setoid : Setoid _ _
setoid = record
  { Carrier       = Coℕ
  ; _≈_           = _≈_
  ; isEquivalence = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }
  }
  where
  refl : Reflexive _≈_
  refl {zero}  = zero
  refl {suc n} = suc (♯ refl)

  sym : Symmetric _≈_
  sym zero      = zero
  sym (suc m≈n) = suc (♯ sym (♭ m≈n))

  trans : Transitive _≈_
  trans zero      zero      = zero
  trans (suc m≈n) (suc n≈k) = suc (♯ trans (♭ m≈n) (♭ n≈k))

------------------------------------------------------------------------
-- Legacy

import Codata.Conat as C
open import Codata.Thunk
import Size

fromMusical : ∀ {i} → Coℕ → C.Conat i
fromMusical zero    = C.zero
fromMusical (suc n) = C.suc λ where .force → fromMusical (♭ n)

toMusical : C.Conat Size.∞ → Coℕ
toMusical C.zero    = zero
toMusical (C.suc n) = suc (♯ toMusical (n .force))


open import Algebra.Bundles using (CommutativeRing)

module Algebra.Module.Diff
  {r ℓr} {CR : CommutativeRing r ℓr}
  where

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

open import Relation.Binary using (Rel)

open import Algebra.Module using (Module)
open Module

open import Function using (_∘_)
open import Data.Product using (proj₁; proj₂; _,_)

open import Algebra.Module.Morphism.Module using (→-module'; →-module; ⊸-module; _⊸_)
open import Algebra.Module.Construct.DirectProduct using () renaming (⟨module⟩ to ×-module)
open import Level using (_⊔_; Level)

private
  variable
    ma mℓa mb mℓb mc mℓc : Level

D-module : (MA : Module CR ma mℓa) (MB : Module CR mb mℓb) → Module CR _ _
D-module MA MB = →-module' MA (×-module MB (⊸-module MA MB))

instance
  D-module' : {MA : Module CR ma mℓa} {MB : Module CR mb mℓb} → Module CR _ _
  D-module' {MA = MA} {MB = MB} = →-module' MA (×-module MB (⊸-module MA MB))

D : (MA : Module CR ma mℓa) (MB : Module CR mb mℓb) → Set (r ⊔ ma ⊔ mℓa ⊔ mb ⊔ mℓb)
D MA MB = Carrierᴹ (→-module' MA (×-module MB (⊸-module MA MB)))

compose
  : {MA : Module CR ma mℓa} {MB : Module CR mb mℓb} {MC : Module CR mc mℓc}
  → D MB MC → D MA MB → D MA MC
compose {MA = MA} {MB = MB} {MC = MC} dbc dab a =
  let (b , a⊸b) = dab a
      (c , b⊸c) = dbc b
  in c , ⊸-compose b⊸c a⊸b
  where
    ⊸-compose : MB ⊸ MC → MA ⊸ MB → MA ⊸ MC
    ⊸-compose (b→c , b→c-ishom) (a→b , a→b-ishom) = b→c ∘ a→b , assume

run
  : ∀ {ma mℓa mb mℓb} {MA : Module CR ma mℓa} {MB : Module CR mb mℓb}
  → D MA MB → Carrierᴹ MA → Carrierᴹ MB
run f = proj₁ ∘ f

∇_[_]∙_
  : ∀ {ma mℓa mb mℓb} {MA : Module CR ma mℓa} {MB : Module CR mb mℓb}
  → D MA MB → Carrierᴹ MA → Carrierᴹ MA → Carrierᴹ MB
∇_[_]∙_ f = proj₁ ∘ proj₂ ∘ f

grad
  : ∀ {ma mℓa mb mℓb} {MA : Module CR ma mℓa} {MB : Module CR mb mℓb}
  → D MA MB → Carrierᴹ MA → Carrierᴹ MA → Carrierᴹ MB
grad f = proj₁ ∘ proj₂ ∘ f


module Data.QuadTree.LensProofs.Valid-LensLeaf where

open import Haskell.Prelude renaming (zero to Z; suc to S)
open import Data.Lens.Lens
open import Data.Logic
open import Agda.Primitive
open import Data.Lens.Proofs.LensLaws
open import Data.Lens.Proofs.LensPostulates
open import Data.Lens.Proofs.LensComposition
open import Data.QuadTree.InternalAgda
open import Data.QuadTree.Implementation.QuadrantLenses
open import Data.QuadTree.Implementation.Definition
open import Data.QuadTree.Implementation.ValidTypes

--- Lens laws for lensLeaf

ValidLens-Leaf-ViewSet : {t : Set} {{eqT : Eq t}} -> ViewSet (lensLeaf {t})
ValidLens-Leaf-ViewSet v (CVQuadrant (Leaf x)) = refl

ValidLens-Leaf-SetView :
    {t : Set} {{eqT : Eq t}}
    -> SetView (lensLeaf {t})
ValidLens-Leaf-SetView (CVQuadrant (Leaf x)) = refl

ValidLens-Leaf-SetSet :
    {t : Set} {{eqT : Eq t}}
    -> SetSet (lensLeaf {t})
ValidLens-Leaf-SetSet v1 v2 (CVQuadrant (Leaf x)) = refl

ValidLens-Leaf :
    {t : Set} {{eqT : Eq t}}
    -> ValidLens (VQuadrant t {0}) t
ValidLens-Leaf = CValidLens lensLeaf ValidLens-Leaf-ViewSet ValidLens-Leaf-SetView ValidLens-Leaf-SetSet


module Cats.Limit where

open import Level

open import Cats.Category.Base
open import Cats.Category.Cones using
  (Cone ; Cones ; HasObj-Cone ; HasArrow-⇒ ; cone-iso→obj-iso ; apFunctor)
open import Cats.Functor using (Functor)
open import Cats.Util.Conv

import Cats.Category.Constructions.Terminal as Terminal
import Cats.Category.Constructions.Iso as Iso

module _ {lo la l≈ lo′ la′ l≈′}
  {J : Category lo la l≈}
  {Z : Category lo′ la′ l≈′}
  where

  IsLimit : {D : Functor J Z} → Cone D → Set (lo ⊔ la ⊔ lo′ ⊔ la′ ⊔ l≈′)
  IsLimit {D} = Terminal.Build.IsTerminal (Cones D)

  record Limit (D : Functor J Z) : Set (lo ⊔ la ⊔ lo′ ⊔ la′ ⊔ l≈′) where
    field
      cone : Cone D
      isLimit : IsLimit cone

  instance
    HasObj-Limit : ∀ D → HasObj (Limit D) _ _ _
    HasObj-Limit D = record { Cat = Cones D ; _ᴼ = Limit.cone }

  module _ {D : Functor J Z} where

    open Iso.Build (Cones D) using (_≅_)
    open Iso.Build Z using () renaming (_≅_ to _≅Z_)
    open Limit using (isLimit)

    unique : (l m : Limit D) → l ᴼ ≅ m ᴼ
    unique l m = Terminal.Build.terminal-unique (Cones D) (isLimit l) (isLimit m)

    obj-unique : (l m : Limit D) → l ᴼ ᴼ ≅Z m ᴼ ᴼ
    obj-unique l m = cone-iso→obj-iso _ (unique l m)

module _ {lo la l≈ lo′ la′ l≈′}
  {C : Category lo la l≈}
  {D : Category lo′ la′ l≈′}
  where

  preservesLimits : (lo″ la″ l≈″ : Level) → (F : Functor C D) → Set _
  preservesLimits lo″ la″ l≈″ F
      = {J : Category lo″ la″ l≈″}
      → {D : Functor J C}
      → {c : Cone D}
      → IsLimit c
      → IsLimit (apFunctor F c)


{-
This second-order signature was created from the following second-order syntax description:

syntax QIO

type
  T : 0-ary
  P : 0-ary

term
  new      : P.T  ->  T
  measure  : P  T  T  ->  T
  applyX   : P  P.T  ->  T
  applyI2  : P  P.T  ->  T
  applyDuv : P  P  (P,P).T  ->  T
  applyDu  : P  P.T  ->  T
  applyDv  : P  P.T  ->  T

theory
  (A) a:P   t u:T         |> applyX (a, b.measure(b, t, u)) = measure(a, u, t)
  (B) a:P   b:P  t u:P.T  |> measure(a, applyDu(b, b.t[b]), applyDv(b, b.u[b])) = applyDuv(a, b, a b.measure(a, t[b], u[b]))
  (D) t u:T               |> new(a.measure(a, t, u)) = t
  (E) b:P  t:(P, P).T     |> new(a.applyDuv(a, b, a b. t[a,b])) = applyDu(b, b.new(a.t[a,b]))
-}

module QIO.Signature where

open import SOAS.Context

-- Type declaration
data QIOT : Set where
  T : QIOT
  P : QIOT

open import SOAS.Syntax.Signature QIOT public
open import SOAS.Syntax.Build QIOT public

-- Operator symbols
data QIOₒ : Set where
  newₒ measureₒ applyXₒ applyI2ₒ applyDuvₒ applyDuₒ applyDvₒ : QIOₒ

-- Term signature
QIO:Sig : Signature QIOₒ
QIO:Sig = sig λ
  {  newₒ       → (P ⊢₁ T) ⟼₁ T
  ;  measureₒ   → (⊢₀ P) , (⊢₀ T) , (⊢₀ T) ⟼₃ T
  ;  applyXₒ    → (⊢₀ P) , (P ⊢₁ T) ⟼₂ T
  ;  applyI2ₒ   → (⊢₀ P) , (P ⊢₁ T) ⟼₂ T
  ;  applyDuvₒ  → (⊢₀ P) , (⊢₀ P) , (P , P ⊢₂ T) ⟼₃ T
  ;  applyDuₒ   → (⊢₀ P) , (P ⊢₁ T) ⟼₂ T
  ;  applyDvₒ   → (⊢₀ P) , (P ⊢₁ T) ⟼₂ T
  }

open Signature QIO:Sig public


{-# OPTIONS --cubical --allow-unsolved-metas #-}

open import Agda.Builtin.Cubical.Path
open import Agda.Builtin.Nat

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

data [0-1] : Set where
  𝟎 𝟏 : [0-1]
  int : 𝟎 ≡ 𝟏

-- The following holes can be filled, so they should not cause a
-- typechecking failure.

0=x : ∀ i → 𝟎 ≡ int i
0=x i = \ j → int {!!}

si : {n m : Nat} → suc n ≡ suc m → n ≡ m
si p i = pred (p {!!})


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

module Number.InclusionModules where

import Number.Postulates
import Number.Inclusions

-- NOTE: the following takes a very long time to typecheck
-- see https://lists.chalmers.se/pipermail/agda-dev/2015-September/000201.html
-- see https://github.com/agda/agda/issues/1646
--     Exponential module chain leads to infeasible scope checking

module Isℕ↪ℤ = Number.Inclusions.IsROrderedCommSemiringInclusion Number.Postulates.ℕ↪ℤinc
module Isℕ↪ℚ = Number.Inclusions.IsROrderedCommSemiringInclusion Number.Postulates.ℕ↪ℚinc
module Isℕ↪ℂ = Number.Inclusions.Isℕ↪ℂ                           Number.Postulates.ℕ↪ℂinc
module Isℕ↪ℝ = Number.Inclusions.IsROrderedCommSemiringInclusion Number.Postulates.ℕ↪ℝinc
module Isℤ↪ℚ = Number.Inclusions.IsROrderedCommRingInclusion     Number.Postulates.ℤ↪ℚinc
module Isℤ↪ℝ = Number.Inclusions.IsROrderedCommRingInclusion     Number.Postulates.ℤ↪ℝinc
module Isℤ↪ℂ = Number.Inclusions.Isℤ↪ℂ                           Number.Postulates.ℤ↪ℂinc
module Isℚ↪ℝ = Number.Inclusions.IsROrderedFieldInclusion        Number.Postulates.ℚ↪ℝinc
module Isℚ↪ℂ = Number.Inclusions.IsRFieldInclusion               Number.Postulates.ℚ↪ℂinc
module Isℝ↪ℂ = Number.Inclusions.IsRFieldInclusion               Number.Postulates.ℝ↪ℂinc

{-
-- NOTE: the following is a little faster but does not help us

module Isℕ↪ℤ = Number.Inclusions.IsROrderedCommSemiringInclusion
module Isℕ↪ℚ = Number.Inclusions.IsROrderedCommSemiringInclusion
module Isℕ↪ℂ = Number.Inclusions.Isℕ↪ℂ
module Isℕ↪ℝ = Number.Inclusions.IsROrderedCommSemiringInclusion
module Isℤ↪ℚ = Number.Inclusions.IsROrderedCommRingInclusion
module Isℤ↪ℝ = Number.Inclusions.IsROrderedCommRingInclusion
module Isℤ↪ℂ = Number.Inclusions.Isℤ↪ℂ
module Isℚ↪ℝ = Number.Inclusions.IsROrderedFieldInclusion
module Isℚ↪ℂ = Number.Inclusions.IsRFieldInclusion
module Isℝ↪ℂ = Number.Inclusions.IsRFieldInclusion
-}


{-# OPTIONS --without-K --rewriting #-}
open import HoTT.Base
open import HoTT.Identity
open import HoTT.Identity.Sigma
open import HoTT.Identity.Pi
open import HoTT.Identity.Universe
open import HoTT.Identity.Product
open import HoTT.HLevel
open import HoTT.HLevel.Truncate
open import HoTT.Equivalence
open import HoTT.Equivalence.Lift

module HoTT.Logic where

private variable i j k : Level

LiftProp : Prop𝒰 i → Prop𝒰 (i ⊔ j)
LiftProp {i} {j} P = type (Lift {j} (P ty))

⊤ : Prop𝒰 i
⊤ = type 𝟏

⊥ : Prop𝒰 i
⊥ = type 𝟎

_∧_ : Prop𝒰 i → Prop𝒰 j → Prop𝒰 (i ⊔ j)
P ∧ Q = type (P ty × Q ty) ⦃ ×-hlevel ⦄

_⇒_ : Prop𝒰 i → Prop𝒰 j → Prop𝒰 (i ⊔ j)
P ⇒ Q = type (P ty → Q ty)
infix 10 _⇒_

_⇔_ : Prop𝒰 i → Prop𝒰 i → Prop𝒰 (lsuc i)
P ⇔ Q = type (P ty == Q ty) ⦃ equiv-hlevel (=𝒰-equiv ⁻¹ₑ) ⦄
  where
  instance
    _ = Σ-hlevel
    _ = raise ⦃ hlevel𝒰.h P ⦄
    _ = raise ⦃ hlevel𝒰.h Q ⦄

_∨_ : Prop𝒰 i → Prop𝒰 j → Prop𝒰 (i ⊔ j)
P ∨ Q = type ∥ P ty + Q ty ∥

∃ : (A : 𝒰 i) → (A → Prop𝒰 j) → Prop𝒰 (i ⊔ j)
∃ A P = type ∥ Σ A (_ty ∘ P) ∥
syntax ∃ A (λ x → Φ) = ∃[ x ∶ A ] Φ

∀' : (A : 𝒰 i) → (P : A → Prop𝒰 j) → Prop𝒰 (i ⊔ j)
∀' A P = type (Π A (_ty ∘ P))
  where instance _ = λ {x} → hlevel𝒰.h (P x)
syntax ∀' A (λ x → Φ) = ∀[ x ∶ A ] Φ

LEM : 𝒰 (lsuc i)
LEM {i} = (A : Prop𝒰 i) → A ty + ¬ A ty

LEM∞ : 𝒰 (lsuc i)
LEM∞ {i} = (A : 𝒰 i) → A + ¬ A

LDN : 𝒰 (lsuc i)
LDN {i} = (A : Prop𝒰 i) → ¬ ¬ A ty → A ty

AC : 𝒰 (lsuc i ⊔ lsuc j ⊔ lsuc k)
AC {i} {j} {k} =
  {X : 𝒰 i} {A : X → 𝒰 j} {P : (x : X) → A x → 𝒰 k} →
  ⦃ hlevel 2 X ⦄ → ⦃ {x : X} → hlevel 2 (A x) ⦄ →
  ⦃ {x : X} {a : A x} → hlevel 1 (P x a) ⦄ →
  Π[ x ∶ X ] ∥ Σ[ a ∶ A x ] P x a ∥ →
  ∥ Σ[ g ∶ Π[ x ∶ X ] A x ] Π[ x ∶ X ] P x (g x) ∥

Lemma3/9/1 : (P : 𝒰 i) → ⦃ hlevel 1 P ⦄ → P ≃ ∥ P ∥
Lemma3/9/1 P = let open Iso in iso→eqv λ where
  .f → ∣_∣ ; .g → ∥-rec id ; .η _ → refl ; .ε _ → center

-- Principle of unique choice
Corollary3/9/2 : {A : 𝒰 i} {P : A → 𝒰 i} → ⦃ {x : A} → hlevel 1 (P x) ⦄ →
                 ((x : A) → ∥ P x ∥) → (x : A) → P x
Corollary3/9/2 {P = P} f = ∥-rec id ∘ f


module Syntax.Number where

import      Lvl
open import Logic.Propositional
open import Numeral.Natural
open import Type

record Numeral {ℓ} (T : Type{ℓ}) : Typeω where
  field
    {restriction-ℓ} : Lvl.Level
    restriction : ℕ → Type{restriction-ℓ}
    num : (n : ℕ) → ⦃ _ : restriction(n) ⦄ → T
open Numeral ⦃ ... ⦄ public using (num)
{-# BUILTIN FROMNAT num #-}

InfiniteNumeral = Numeral
module InfiniteNumeral {ℓ} {T : Type{ℓ}} where
  intro : (ℕ → T) → InfiniteNumeral(T)
  Numeral.restriction-ℓ (intro(_))         = Lvl.𝟎
  Numeral.restriction   (intro(_)) _       = ⊤
  Numeral.num           (intro(f)) n ⦃ _ ⦄ = f(n)

-- record InfiniteNumeral {ℓ} (T : Type{ℓ}) : Type{ℓ} where
-- record InfiniteNumeral {ℓ} (T : Type{ℓ}) : Type{ℓ} where
--   field
--     num : ℕ → T

-- instance
--   Numeral-from-InfiniteNumeral : ∀{ℓ}{T} → ⦃ _ : InfiniteNumeral{ℓ}(T) ⦄ → Numeral{ℓ}(T)
--   Numeral.restriction-ℓ ( Numeral-from-InfiniteNumeral ) = Lvl.𝟎
--   Numeral.restriction ( Numeral-from-InfiniteNumeral ) (_) = ⊤
--   num ⦃ Numeral-from-InfiniteNumeral ⦃ infNum ⦄ ⦄ (n) ⦃ _ ⦄ = InfiniteNumeral.num(infNum) (n)

instance
  ℕ-InfiniteNumeral : InfiniteNumeral (ℕ)
  ℕ-InfiniteNumeral = InfiniteNumeral.intro(id) where
    id : ℕ → ℕ
    id x = x

instance
  Level-InfiniteNumeral : InfiniteNumeral (Lvl.Level)
  Level-InfiniteNumeral = InfiniteNumeral.intro(f) where
    f : ℕ → Lvl.Level
    f(ℕ.𝟎)    = Lvl.𝟎
    f(ℕ.𝐒(n)) = Lvl.𝐒(f(n))

record NegativeNumeral {ℓ} (T : Type{ℓ}) : Typeω where
  field
    {restriction-ℓ} : Lvl.Level
    restriction : ℕ → Type{restriction-ℓ}
    num : (n : ℕ) → ⦃ _ : restriction(n) ⦄ → T
open NegativeNumeral ⦃ ... ⦄ public using () renaming (num to -num)
{-# BUILTIN FROMNEG -num #-}

InfiniteNegativeNumeral = NegativeNumeral
module InfiniteNegativeNumeral {ℓ} {T : Type{ℓ}} where
  intro : (ℕ → T) → InfiniteNegativeNumeral(T)
  NegativeNumeral.restriction-ℓ (intro(_))         = Lvl.𝟎
  NegativeNumeral.restriction   (intro(_)) _       = ⊤
  NegativeNumeral.num           (intro(f)) n ⦃ _ ⦄ = f(n)

-- record InfiniteNegativeNumeral {ℓ} (T : Type{ℓ}) : Type{ℓ} where
--   field
--     num : ℕ → T
-- open InfiniteNegativeNumeral ⦃ ... ⦄ public

-- instance
--   NegativeNumeral-from-InfiniteNegativeNumeral : ∀{ℓ}{T} → ⦃ _ : InfiniteNegativeNumeral{ℓ}(T) ⦄ → NegativeNumeral{ℓ}(T)
--   NegativeNumeral.restriction-ℓ ( NegativeNumeral-from-InfiniteNegativeNumeral ) = Lvl.𝟎
--   NegativeNumeral.restriction ( NegativeNumeral-from-InfiniteNegativeNumeral ) (_) = ⊤
--   -num ⦃ NegativeNumeral-from-InfiniteNegativeNumeral ⦃ infNegNum ⦄ ⦄ (n) ⦃ _ ⦄ = InfiniteNegativeNumeral.num(infNegNum) (n)


module Formalization.LambdaCalculus.SyntaxTransformation where

open import Formalization.LambdaCalculus
open import Lang.Instance
open import Numeral.Natural
open import Numeral.Finite
open import Numeral.Finite.Bound
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals

private variable d d₁ d₂ : ℕ
private variable x y : Term(d)

-- Increase the depth level of the given term by something.
-- Example: `depth-[≤](Var(2) : Term(5)) = Var(2) : Term(50)`
depth-[≤] : ⦃ _ : (d₁ ≤ d₂) ⦄ → Term(d₁) → Term(d₂)
depth-[≤] (Apply t1 t2) = Apply(depth-[≤] t1) (depth-[≤] t2)
depth-[≤] (Abstract t)  = Abstract(depth-[≤] t)
depth-[≤] (Var x)       = Var(bound-[≤] infer x)

-- Increment the depth level of the given term by 1.
-- Example: `depth-𝐒(Var(2) : Term(5)) = Var(2) : Term(6)`
depth-𝐒 : Term(d) → Term(𝐒(d))
depth-𝐒 = depth-[≤]
-- depth-𝐒 (Apply(f)(x))       = Apply (depth-𝐒(f)) (depth-𝐒(x))
-- depth-𝐒 (Abstract(body))    = Abstract(depth-𝐒(body))
-- depth-𝐒 (Var(n))            = Var(bound-𝐒 (n))

Apply₊ : ⦃ _ : (d₁ ≤ d₂) ⦄ → Term(d₂) → Term(d₁) → Term(d₂)
Apply₊ {d₁}{d₂} f(x) = Apply f(depth-[≤] {d₁}{d₂} (x))

{-
-- Increase all variables of the given term
var-[≤] : ∀{d₁ d₂} → ⦃ _ : (d₁ ≤ d₂) ⦄ → Term(d₁) → Term(d₂)
var-[≤] (Apply t1 t2) = Apply(depth-[≤] t1) (depth-[≤] t2)
var-[≤] (Abstract t)  = Abstract(depth-[≤] t)
var-[≤] (Var x) = Var({!x + (d₂ − d₁)!}) where
  open import Numeral.Natural.TotalOper
-}

-- Increment all variables of the given term.
-- Example: `var-𝐒(Var(2) : Term(5)) = Var(3) : Term(6)`
-- Examples:
--   term : Term(1)
--   term = (1 ↦ (2 ↦ 2 ← 2) ← 0 ← 1 ← 0)
--
--   Then:
--   term               = 1 ↦ (2 ↦ 2 ← 2) ← 0 ← 1 ← 0
--   var-𝐒(term)        = 2 ↦ (3 ↦ 3 ← 3) ← 1 ← 2 ← 1
--   var-𝐒(var-𝐒(term)) = 3 ↦ (4 ↦ 4 ← 4) ← 2 ← 3 ← 2
var-𝐒 : Term(d) → Term(𝐒(d))
var-𝐒 (Apply(f)(x))       = Apply (var-𝐒(f)) (var-𝐒(x))
var-𝐒 (Abstract{d}(body)) = Abstract{𝐒(d)} (var-𝐒(body))
var-𝐒 (Var{𝐒(d)}(n))      = Var{𝐒(𝐒(d))} (𝐒(n))

-- Substitutes the most recent free variable with a term in a term, while also decrementing them.
-- `substitute val term` is the term where all occurences in `term` of the outer-most variable is replaced with the term `val`.
-- Examples:
--   substituteOuterVar x (Var(0) : Term(1)) = x
--   substituteOuterVar x ((Apply (Var(1)) (Var(0))) : Term(2)) = Apply (Var(0)) x
--   substituteOuterVar (𝜆 0 0) ((𝜆 1 1) ← 0) = ((𝜆 0 0) ← (𝜆 0 0))
--   substituteOuterVar (𝜆 0 0) ((𝜆 1 1 ← 0) ← 0) = (((𝜆 0 0) ← (𝜆 0 0)) ← (𝜆 0 0))
substituteVar0 : Term(d) → Term(𝐒(d)) → Term(d)
substituteVar0 val (Apply(f)(x))    = Apply (substituteVar0 val f) (substituteVar0 val x)
substituteVar0 val (Abstract(body)) = Abstract (substituteVar0 (var-𝐒 val) body)
substituteVar0 val (Var(𝟎))         = val
substituteVar0 val (Var(𝐒(v)))      = Var v

{-
substituteMap : (𝕟(d₁) → Term(d₂)) → Term(d₁) → Term(d₂)
substituteMap F (Apply(f)(x))    = Apply (substituteMap F (f)) (substituteMap F (x))
substituteMap F (Var(v))         = F(v)
substituteMap F (Abstract(body)) = Abstract (substituteMap F (body)) -- TODO: Probably incorrect
-}

-- Substituting the outer variable of `var-𝐒 x` yields `x`.
-- This is useful because `substituteVar0` uses `var-𝐒` in its definition.
substituteVar0-var-𝐒 : (substituteVar0 y (var-𝐒 x) ≡ x)
substituteVar0-var-𝐒 {d}{y}{Apply f x}  rewrite substituteVar0-var-𝐒 {d}{y}{f} rewrite substituteVar0-var-𝐒 {d}{y}{x} = [≡]-intro
substituteVar0-var-𝐒 {d}{y}{Abstract x} rewrite substituteVar0-var-𝐒 {𝐒 d}{var-𝐒 y}{x} = [≡]-intro
substituteVar0-var-𝐒 {_}{_}{Var 𝟎}      = [≡]-intro
substituteVar0-var-𝐒 {_}{_}{Var(𝐒 _)}   = [≡]-intro
{-# REWRITE substituteVar0-var-𝐒 #-}


------------------------------------------------------------------------------
-- Arithmetic properties (added for the Collatz function example)
------------------------------------------------------------------------------

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

module FOTC.Program.Collatz.Data.Nat.PropertiesATP where

open import FOTC.Base
open import FOTC.Data.Nat
open import FOTC.Data.Nat.Inequalities
open import FOTC.Data.Nat.Inequalities.PropertiesATP
  using ( x≤x
        ; 2*SSx≥2
        )
open import FOTC.Data.Nat.PropertiesATP
  using ( *-N
        ; *-rightZero
        ; *-rightIdentity
        ; x∸x≡0
        ; +-rightIdentity
        ; +-comm
        ; +-N
        ; xy≡0→x≡0∨y≡0
        ; Sx≢x
        ; xy≡1→x≡1
        ; 0∸x
        ; S∸S
        )
open import FOTC.Data.Nat.UnaryNumbers
open import FOTC.Program.Collatz.Data.Nat

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

^-N : ∀ {m n} → N m → N n → N (m ^ n)
^-N {m} Nm nzero = prf
  where postulate prf : N (m ^ zero)
        {-# ATP prove prf #-}
^-N {m} Nm (nsucc {n} Nn) = prf (^-N Nm Nn)
  where postulate prf : N (m ^ n) → N (m ^ succ₁ n)
        {-# ATP prove prf *-N #-}

div-2x-2≡x : ∀ {n} → N n → div (2' * n) 2' ≡ n
div-2x-2≡x nzero = prf
  where postulate prf : div (2' * zero) 2' ≡ zero
        {-# ATP prove prf *-rightZero #-}
div-2x-2≡x (nsucc nzero) = prf
  where postulate prf : div (2' * (succ₁ zero)) 2' ≡ succ₁ zero
        {-# ATP prove prf *-rightIdentity x≤x x∸x≡0 #-}
div-2x-2≡x (nsucc (nsucc {n} Nn)) = prf (div-2x-2≡x (nsucc Nn))
  where postulate prf : div (2' * succ₁ n) 2' ≡ succ₁ n →
                        div (2' * (succ₁ (succ₁ n))) 2' ≡ succ₁ (succ₁ n)
        {-# ATP prove prf 2*SSx≥2 +-rightIdentity +-comm +-N #-}

postulate div-2^[x+1]-2≡2^x : ∀ {n} → N n → div (2' ^ succ₁ n) 2' ≡ 2' ^ n
{-# ATP prove div-2^[x+1]-2≡2^x ^-N div-2x-2≡x #-}

+∸2 : ∀ {n} → N n → n ≢ zero → n ≢ 1' → n ≡ succ₁ (succ₁ (n ∸ 2'))
+∸2 nzero                  n≢0 n≢1 = ⊥-elim (n≢0 refl)
+∸2 (nsucc nzero)          n≢0 n≢1 = ⊥-elim (n≢1 refl)
+∸2 (nsucc (nsucc {n} Nn)) n≢0 n≢1 = prf
  where
  -- TODO (06 December 2012). We do not use the ATPs because we do not
  -- how to erase a term.
  --
  -- See the interactive proof.
  postulate prf : succ₁ (succ₁ n) ≡ succ₁ (succ₁ (succ₁ (succ₁ n) ∸ 2'))
  -- {-# ATP prove prf S∸S #-}

2^x≢0 : ∀ {n} → N n → 2' ^ n ≢ zero
2^x≢0 nzero          h = ⊥-elim (0≢S (trans (sym h) (^-0 2')))
2^x≢0 (nsucc {n} Nn) h = prf (2^x≢0 Nn)
  where postulate prf : 2' ^ n ≢ zero → ⊥
        {-# ATP prove prf xy≡0→x≡0∨y≡0 ^-N #-}

postulate 2^[x+1]≢1 : ∀ {n} → N n → 2' ^ succ₁ n ≢ 1'
{-# ATP prove 2^[x+1]≢1 Sx≢x xy≡1→x≡1 ^-N #-}

Sx-Even→x-Odd : ∀ {n} → N n → Even (succ₁ n) → Odd n
Sx-Even→x-Odd nzero  h = ⊥-elim prf
  where postulate prf : ⊥
        {-# ATP prove prf #-}
Sx-Even→x-Odd (nsucc {n} Nn) h = prf
  where postulate prf : odd (succ₁ n) ≡ true
        {-# ATP prove prf #-}

Sx-Odd→x-Even : ∀ {n} → N n → Odd (succ₁ n) → Even n
Sx-Odd→x-Even nzero          _ = even-0
Sx-Odd→x-Even (nsucc {n} Nn) h = trans (sym (odd-S (succ₁ n))) h

postulate 2-Even : Even 2'
{-# ATP prove 2-Even #-}

∸-Even : ∀ {m n} → N m → N n → Even m → Even n → Even (m ∸ n)
∸-Odd : ∀ {m n} → N m → N n → Odd m → Odd n → Even (m ∸ n)

∸-Even {m} Nm nzero                      h₁ _  = subst Even (sym (∸-x0 m)) h₁
∸-Even     nzero          (nsucc {n} Nn) h₁ _  = subst Even (sym (0∸x (nsucc Nn))) h₁
∸-Even     (nsucc {m} Nm) (nsucc {n} Nn) h₁ h₂ = prf
  where postulate prf : Even (succ₁ m ∸ succ₁ n)
        {-# ATP prove prf ∸-Odd Sx-Even→x-Odd S∸S #-}

∸-Odd nzero          Nn             h₁ _  = ⊥-elim (t≢f (trans (sym h₁) odd-0))
∸-Odd (nsucc Nm)     nzero          _  h₂ = ⊥-elim (t≢f (trans (sym h₂) odd-0))
∸-Odd (nsucc {m} Nm) (nsucc {n} Nn) h₁ h₂ = prf
  where postulate prf : Even (succ₁ m ∸ succ₁ n)
        {-# ATP prove prf ∸-Even Sx-Odd→x-Even S∸S #-}

x-Even→SSx-Even : ∀ {n} → N n → Even n → Even (succ₁ (succ₁ n))
x-Even→SSx-Even nzero h = prf
  where postulate prf : Even (succ₁ (succ₁ zero))
        {-# ATP prove prf #-}

x-Even→SSx-Even (nsucc {n} Nn) h = prf
  where postulate prf : Even (succ₁ (succ₁ (succ₁ n)))
        {-# ATP prove prf #-}

x+x-Even : ∀ {n} → N n → Even (n + n)
x+x-Even nzero  = prf
  where postulate prf : even (zero + zero) ≡ true
        {-# ATP prove prf #-}
x+x-Even (nsucc {n} Nn) = prf (x+x-Even Nn)
  where postulate prf : Even (n + n) → Even (succ₁ n + succ₁ n)
        {-# ATP prove prf x-Even→SSx-Even +-N +-comm #-}

2x-Even : ∀ {n} → N n → Even (2' * n)
2x-Even nzero = prf
  where postulate prf : Even (2' * zero)
        {-# ATP prove prf #-}
2x-Even (nsucc {n} Nn) = prf
  where
  postulate prf : Even (2' * succ₁ n)
  {-# ATP prove prf x-Even→SSx-Even x+x-Even +-N +-comm +-rightIdentity #-}

postulate 2^[x+1]-Even : ∀ {n} → N n → Even (2' ^ succ₁ n)
{-# ATP prove 2^[x+1]-Even ^-N 2x-Even #-}