------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of binary relations
------------------------------------------------------------------------

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

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

module Relation.Binary.Definitions where

open import Agda.Builtin.Equality using (_≡_)

open import Data.Maybe.Base using (Maybe)
open import Data.Product using (_×_)
open import Data.Sum.Base using (_⊎_)
open import Function.Base using (_on_; flip)
open import Level
open import Relation.Binary.Core
open import Relation.Nullary using (Dec; ¬_)

private
  variable
    a b c ℓ ℓ₁ ℓ₂ ℓ₃ : Level
    A : Set a
    B : Set b
    C : Set c

------------------------------------------------------------------------
-- Definitions
------------------------------------------------------------------------

-- Reflexivity - defined without an underlying equality. It could
-- alternatively be defined as `_≈_ ⇒ _∼_` for some equality `_≈_`.

-- Confusingly the convention in the library is to use the name "refl"
-- for proofs of Reflexive and `reflexive` for proofs of type `_≈_ ⇒ _∼_`,
-- e.g. in the definition of `IsEquivalence` later in this file. This
-- convention is a legacy from the early days of the library.

Reflexive : Rel A ℓ → Set _
Reflexive _∼_ = ∀ {x} → x ∼ x

-- Generalised symmetry.

Sym : REL A B ℓ₁ → REL B A ℓ₂ → Set _
Sym P Q = P ⇒ flip Q

-- Symmetry.

Symmetric : Rel A ℓ → Set _
Symmetric _∼_ = Sym _∼_ _∼_

-- Generalised transitivity.

Trans : REL A B ℓ₁ → REL B C ℓ₂ → REL A C ℓ₃ → Set _
Trans P Q R = ∀ {i j k} → P i j → Q j k → R i k

-- A flipped variant of generalised transitivity.

TransFlip : REL A B ℓ₁ → REL B C ℓ₂ → REL A C ℓ₃ → Set _
TransFlip P Q R = ∀ {i j k} → Q j k → P i j → R i k

-- Transitivity.

Transitive : Rel A ℓ → Set _
Transitive _∼_ = Trans _∼_ _∼_ _∼_

-- Generalised antisymmetry

Antisym : REL A B ℓ₁ → REL B A ℓ₂ → REL A B ℓ₃ → Set _
Antisym R S E = ∀ {i j} → R i j → S j i → E i j

-- Antisymmetry.

Antisymmetric : Rel A ℓ₁ → Rel A ℓ₂ → Set _
Antisymmetric _≈_ _≤_ = Antisym _≤_ _≤_ _≈_

-- Irreflexivity - this is defined terms of the underlying equality.

Irreflexive : REL A B ℓ₁ → REL A B ℓ₂ → Set _
Irreflexive _≈_ _<_ = ∀ {x y} → x ≈ y → ¬ (x < y)

-- Asymmetry.

Asymmetric : Rel A ℓ → Set _
Asymmetric _<_ = ∀ {x y} → x < y → ¬ (y < x)

-- Generalised connex - exactly one of the two relations holds.

Connex : REL A B ℓ₁ → REL B A ℓ₂ → Set _
Connex P Q = ∀ x y → P x y ⊎ Q y x

-- Totality.

Total : Rel A ℓ → Set _
Total _∼_ = Connex _∼_ _∼_

-- Generalised trichotomy - exactly one of three types has a witness.

data Tri (A : Set a) (B : Set b) (C : Set c) : Set (a ⊔ b ⊔ c) where
  tri< : ( a :   A) (¬b : ¬ B) (¬c : ¬ C) → Tri A B C
  tri≈ : (¬a : ¬ A) ( b :   B) (¬c : ¬ C) → Tri A B C
  tri> : (¬a : ¬ A) (¬b : ¬ B) ( c :   C) → Tri A B C

-- Trichotomy.

Trichotomous : Rel A ℓ₁ → Rel A ℓ₂ → Set _
Trichotomous _≈_ _<_ = ∀ x y → Tri (x < y) (x ≈ y) (x > y)
  where _>_ = flip _<_

-- Generalised maximum element.

Max : REL A B ℓ → B → Set _
Max _≤_ T = ∀ x → x ≤ T

-- Maximum element.

Maximum : Rel A ℓ → A → Set _
Maximum = Max

-- Generalised minimum element.

Min : REL A B ℓ → A → Set _
Min R = Max (flip R)

-- Minimum element.

Minimum : Rel A ℓ → A → Set _
Minimum = Min

-- Unary relations respecting a binary relation.

_⟶_Respects_ : (A → Set ℓ₁) → (B → Set ℓ₂) → REL A B ℓ₃ → Set _
P ⟶ Q Respects _∼_ = ∀ {x y} → x ∼ y → P x → Q y

-- Unary relation respects a binary relation.

_Respects_ : (A → Set ℓ₁) → Rel A ℓ₂ → Set _
P Respects _∼_ = P ⟶ P Respects _∼_

-- Right respecting - relatedness is preserved on the right by equality.

_Respectsʳ_ : REL A B ℓ₁ → Rel B ℓ₂ → Set _
_∼_ Respectsʳ _≈_ = ∀ {x} → (x ∼_) Respects _≈_

-- Left respecting - relatedness is preserved on the left by equality.

_Respectsˡ_ : REL A B ℓ₁ → Rel A ℓ₂ → Set _
P Respectsˡ _∼_ = ∀ {y} → (flip P y) Respects _∼_

-- Respecting - relatedness is preserved on both sides by equality

_Respects₂_ : Rel A ℓ₁ → Rel A ℓ₂ → Set _
P Respects₂ _∼_ = (P Respectsʳ _∼_) × (P Respectsˡ _∼_)

-- Substitutivity - any two related elements satisfy exactly the same
-- set of unary relations. Note that only the various derivatives
-- of propositional equality can satisfy this property.

Substitutive : Rel A ℓ₁ → (ℓ₂ : Level) → Set _
Substitutive {A = A} _∼_ p = (P : A → Set p) → P Respects _∼_

-- Decidability - it is possible to determine whether a given pair of
-- elements are related.

Decidable : REL A B ℓ → Set _
Decidable _∼_ = ∀ x y → Dec (x ∼ y)

-- Weak decidability - it is sometimes possible to determine if a given
-- pair of elements are related.

WeaklyDecidable : REL A B ℓ → Set _
WeaklyDecidable _∼_ = ∀ x y → Maybe (x ∼ y)

-- Propositional equality is decidable for the type.

DecidableEquality : (A : Set a) → Set _
DecidableEquality A = Decidable {A = A} _≡_

-- Irrelevancy - all proofs that a given pair of elements are related
-- are indistinguishable.

Irrelevant : REL A B ℓ → Set _
Irrelevant _∼_ = ∀ {x y} (a b : x ∼ y) → a ≡ b

-- Recomputability - we can rebuild a relevant proof given an
-- irrelevant one.

Recomputable : REL A B ℓ → Set _
Recomputable _∼_ = ∀ {x y} → .(x ∼ y) → x ∼ y

-- Universal - all pairs of elements are related

Universal : REL A B ℓ → Set _
Universal _∼_ = ∀ x y → x ∼ y

-- Non-emptiness - at least one pair of elements are related.

record NonEmpty {A : Set a} {B : Set b}
                (T : REL A B ℓ) : Set (a ⊔ b ⊔ ℓ) where
  constructor nonEmpty
  field
    {x}   : A
    {y}   : B
    proof : T x y

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

-- Version 1.1

Conn = Connex
{-# WARNING_ON_USAGE Conn
"Warning: Conn was deprecated in v1.1.
Please use Connex instead."
#-}


{-# OPTIONS --cubical --safe #-}
module Cubical.Foundations.TotalFiber where

open import Cubical.Core.Everything
open import Cubical.Data.Prod
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Surjection
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv
open import Cubical.HITs.PropositionalTruncation

private
  variable
    ℓ ℓ' : Level

module _ {A : Type ℓ} {B : Type ℓ'} (f : A → B) where
  private
    ℓ'' : Level
    ℓ'' = ℓ-max ℓ ℓ'

    LiftA : Type ℓ''
    LiftA = Lift {j = ℓ'} A

  Total-fiber : Type ℓ''
  Total-fiber = Σ B \ b → fiber f b

  A→Total-fiber : A → Total-fiber
  A→Total-fiber a = f a , a , refl

  Total-fiber→A : Total-fiber → A
  Total-fiber→A (b , a , p) = a

  Total-fiber→A→Total-fiber : ∀ t → A→Total-fiber (Total-fiber→A t) ≡ t
  Total-fiber→A→Total-fiber (b , a , p) i = p i , a , λ j → p (i ∧ j)

  A→Total-fiber→A : ∀ a → Total-fiber→A (A→Total-fiber a) ≡ a
  A→Total-fiber→A a = refl

  LiftA→Total-fiber : LiftA → Total-fiber
  LiftA→Total-fiber x = A→Total-fiber (lower x)

  Total-fiber→LiftA : Total-fiber → LiftA
  Total-fiber→LiftA x = lift (Total-fiber→A x)

  Total-fiber→LiftA→Total-fiber : ∀ t → LiftA→Total-fiber (Total-fiber→LiftA t) ≡ t
  Total-fiber→LiftA→Total-fiber (b , a , p) i = p i , a , λ j → p (i ∧ j)

  LiftA→Total-fiber→LiftA : ∀ a → Total-fiber→LiftA (LiftA→Total-fiber a) ≡ a
  LiftA→Total-fiber→LiftA a = refl

  A≡Total : Lift A ≡ Total-fiber
  A≡Total = isoToPath (iso
    LiftA→Total-fiber
    Total-fiber→LiftA
    Total-fiber→LiftA→Total-fiber
    LiftA→Total-fiber→LiftA)

  -- HoTT Lemma 4.8.2
  A≃Total : Lift A ≃ Total-fiber
  A≃Total = isoToEquiv (iso
    LiftA→Total-fiber
    Total-fiber→LiftA
    Total-fiber→LiftA→Total-fiber
    LiftA→Total-fiber→LiftA)


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

module P where

open import Data.Empty
open import Data.Unit
open import Data.Sum
open import Data.Product
open import Relation.Binary.PropositionalEquality

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

-- For now, a groupoid is just a set

Groupoid : Set₁
Groupoid = Set

mutual

-- types
  data B : Set where
    ZERO : B
    ONE : B
    _+_ : B → B → B
    _*_ : B → B → B
    _~_ : {b : B} → ⟦ b ⟧ → ⟦ b ⟧ → B

-- values
  ⟦_⟧ : B → Groupoid
  ⟦ ZERO ⟧ = ⊥
  ⟦ ONE ⟧ = ⊤
  ⟦ b₁ + b₂ ⟧ = ⟦ b₁ ⟧ ⊎ ⟦ b₂ ⟧
  ⟦ b₁ * b₂ ⟧ = ⟦ b₁ ⟧ × ⟦ b₂ ⟧
  ⟦ v₁ ~ v₂ ⟧ = v₁ ≡ v₂

-- pointed types
data PB : Set where
  POINTED : Σ B (λ b → ⟦ b ⟧) → PB
  RECIP : PB → PB

-- lift B type constructors to pointed types

_++_ : PB → PB → PB
(POINTED (b₁ , v₁)) ++ (POINTED (b₂ , v₂)) = POINTED (b₁ + b₂ , inj₁ v₁)
_ ++ _ = {!!}

_**_ : PB → PB → PB
(POINTED (b₁ , v₁)) ** (POINTED (b₂ , v₂)) = POINTED (b₁ * b₂ , (v₁ , v₂))
_ ** _ = {!!}

-- All the pi combinators now work on pointed types

data _⟷_ : PB → PB → Set₁ where
  swap⋆ : {pb₁ pb₂ : PB} → (pb₁ ** pb₂) ⟷ (pb₂ ** pb₁)
  eta : {pb : PB} → POINTED (ONE , tt) ⟷ RECIP pb

-- induction principle to reason about identities; needed ???

ind : {b : B} →
      (C : (v₁ v₂ : ⟦ b ⟧) → (p : ⟦ _~_ {b} v₁ v₂ ⟧) → Set) →
      (c : (v : ⟦ b ⟧) → C v v refl) →
      (v₁ v₂ : ⟦ b ⟧) → (p : ⟦ _~_ {b} v₁ v₂ ⟧) → C v₁ v₂ p
ind C c v .v refl = c v

-- Examples

Bool : B
Bool = ONE + ONE

false : ⟦ Bool ⟧
false = inj₁ tt

true : ⟦ Bool ⟧
true = inj₂ tt

pb1 : PB
pb1 = POINTED (Bool , false)

pb2 : PB
pb2 = POINTED (Bool , true)

FalseID : B
FalseID = _~_ {Bool} false false

pb3 : PB
pb3 = POINTED (FalseID , refl)

FalseID^2 : B
FalseID^2 = _~_ {FalseID} refl refl

pb4 : PB
pb4 = POINTED (FalseID^2 , refl)

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


------------------------------------------------------------------------------
-- Properties of the divisibility relation
------------------------------------------------------------------------------

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

module FOTC.Data.Nat.Divisibility.By0.PropertiesATP where

open import FOTC.Base
open import FOTC.Data.Nat
open import FOTC.Data.Nat.Divisibility.By0
open import FOTC.Data.Nat.Inequalities
open import FOTC.Data.Nat.Inequalities.PropertiesATP
open import FOTC.Data.Nat.PropertiesATP

------------------------------------------------------------------------------
-- Any positive number divides 0.
postulate S∣0 : ∀ n → succ₁ n ∣ zero
{-# ATP prove S∣0 #-}

-- 0 divides 0.
postulate 0∣0 : zero ∣ zero
{-# ATP prove 0∣0 #-}

-- The divisibility relation is reflexive.
postulate ∣-refl : ∀ {n} → N n → n ∣ n
{-# ATP prove ∣-refl *-leftIdentity #-}

-- If x divides y and z then x divides y ∸ z.
postulate
  x∣y→x∣z→x∣y∸z-helper : ∀ {m n o k k'} → N m → N k → N k' →
                         n ≡ k * m →
                         o ≡ k' * m →
                         n ∸ o ≡ (k ∸ k') * m
{-# ATP prove x∣y→x∣z→x∣y∸z-helper *∸-leftDistributive #-}

x∣y→x∣z→x∣y∸z : ∀ {m n o} → N m → N n → N o → m ∣ n → m ∣ o → m ∣ n ∸ o
x∣y→x∣z→x∣y∸z Nm Nn No (k , Nk , h₁) (k' , Nk' , h₂) =
  k ∸ k' , ∸-N Nk Nk' , x∣y→x∣z→x∣y∸z-helper Nm Nk Nk' h₁ h₂

-- If x divides y and z then x divides y + z.
postulate
  x∣y→x∣z→x∣y+z-helper : ∀ {m n o k k'} → N m → N k → N k' →
                         n ≡ k * m →
                         o ≡ k' * m →
                         n + o ≡ (k + k') * m
{-# ATP prove x∣y→x∣z→x∣y+z-helper *+-leftDistributive #-}

x∣y→x∣z→x∣y+z : ∀ {m n o} → N m → N n → N o → m ∣ n → m ∣ o → m ∣ n + o
x∣y→x∣z→x∣y+z Nm Nn No (k , Nk , h₁) (k' , Nk' , h₂) =
  k + k' , +-N Nk Nk' , x∣y→x∣z→x∣y+z-helper Nm Nk Nk' h₁ h₂

-- If x divides y and y is positive, then x ≤ y.
postulate x∣S→x≤S-helper₁ : ∀ {m n} → succ₁ n ≡ zero * m → ⊥
{-# ATP prove x∣S→x≤S-helper₁ #-}

-- Nice proof by the ATPa.
postulate x∣S→x≤S-helper₂ : ∀ {m n o} → N m → N n → N o →
                            succ₁ n ≡ succ₁ o * m →
                            m ≤ succ₁ n
{-# ATP prove x∣S→x≤S-helper₂ x≤x+y *-N #-}

x∣S→x≤S : ∀ {m n} → N m → N n → m ∣ (succ₁ n) → m ≤ succ₁ n
x∣S→x≤S Nm Nn (.zero , nzero , Sn≡0*m) = ⊥-elim (x∣S→x≤S-helper₁ Sn≡0*m)
x∣S→x≤S Nm Nn (.(succ₁ k) , nsucc {k} Nk , Sn≡Sk*m) =
  x∣S→x≤S-helper₂ Nm Nn Nk Sn≡Sk*m


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

module Identity where

open import Basic_Types

-- ------------------------------------
-- the identity type, or path type
infix  1 _≡_

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

{-# BUILTIN EQUALITY _≡_ #-}

-- path induction
p-ind : ∀ {A : Set} {B : ∀ (x y : A) (p : x ≡ y) → Set} →
       (∀ (z : A) → B z z (refl z)) → ∀ (x y : A) (p : x ≡ y) → B x y p
p-ind f z z (refl z) = f z
-- notice here that, in the proof system of agda, the induction principle is
-- builtin for a data type, for their constructor is given expicitly. Hence,
-- one way to prove identity type is to use p-ind, which is itself proved by
-- agda using implicit path induction, or we can use agda's induction expicitly
-- which is the case when we construct apd and ass-p

-- the groupoid structure of path type
concat : ∀ {A : Set} → ∀ (x y : A) (p : x ≡ y) → ∀ (z : A) (q : y ≡ z) → x ≡ z
concat {A} x x (refl x) x (refl x) = refl x

infix  3 _∙_
_∙_ : ∀ {A : Set} {x y z : A} → ∀ (p : x ≡ y) (q : y ≡ z) → x ≡ z
_∙_ {_} {x} {y} {z} p q = concat x y p z q

inv : ∀ {A : Set} {x y : A} → ∀ (p : x ≡ y) → y ≡ x
inv {_} {x} {x} (refl x) = refl x

-- the groupoid structure of identities, viewed as higher paths
p-ass : ∀ {A : Set} {x y z w : A} → ∀ (p : x ≡ y) (q : y ≡ z) (r : z ≡ w) →
        p ∙ (q ∙ r) ≡ (p ∙ q) ∙ r
p-ass {_} {x} {x} {x} {x} (refl x) (refl x) (refl x) =
      refl (((refl x) ∙ (refl x)) ∙ (refl x))

left_unit : ∀ {A : Set} {x y : A} → ∀ (p : x ≡ y) → (refl x) ∙ p ≡ p
left_unit {_} {x} {x} (refl x) = refl (refl x)

right_unit : ∀ {A : Set} {x y : A} → ∀ (p : x ≡ y) → p ∙ (refl y) ≡ p
right_unit {_} {x} {x} (refl x) = refl (refl x)

rinv-unit : ∀ {A : Set} {x y : A} → ∀ (p : x ≡ y) → (inv p) ∙ p ≡ refl y
rinv-unit {_} {x} {x} (refl x) = refl (refl x)

linv-unit : ∀ {A : Set} {x y : A} → ∀ (p : x ≡ y) → p ∙ (inv p) ≡ refl x
linv-unit {_} {x} {x} (refl x) = refl (refl x)

invinv : ∀ {A : Set} {x y : A} → ∀ (p : x ≡ y) → inv (inv p) ≡ p
invinv {_} {x} {x} (refl x) = refl (refl x)

-- ------------------------------------
-- loop spaces
Ω : ∀ {A : Set} (a : A) → Set
Ω {_} a = a ≡ a

-- commutativity on 2-dimensional loops
-- prove the commutativity by proving a general result in the groupoid
pwr : ∀ {A : Set} {a b c : A} {p q : a ≡ b} → ∀ (r : b ≡ c) → ∀ (α : p ≡ q) →
      p ∙ r ≡ q ∙ r
pwr {_} {_} {b} {b} {p} {p} (refl b) (refl p) = refl (p ∙ (refl b))

pwl : ∀ {A : Set} {a b c : A} {q r : b ≡ c} → ∀ (p : a ≡ b) → ∀ (β : q ≡ r) →
      p ∙ q ≡ p ∙ r
pwl {_} {_} {_} {_} {q} {q} p (refl q) = refl (p ∙ q)

_*_ : ∀ {A : Set} {a b c : A} {p q : a ≡ b} {r s : b ≡ c} →
      ∀ (α : p ≡ q) (β : r ≡ s) → p ∙ r ≡ q ∙ s
_*_ {_} {_} {_} {_} {p} {q} {r} {s} α β = α∙r ∙ q∙β
  where α∙r : p ∙ r ≡ q ∙ r
        α∙r = pwr r α
        q∙β : q ∙ r ≡ q ∙ s
        q∙β = pwl q β

_*'_ : ∀ {A : Set} {a b c : A} {p q : a ≡ b} {r s : b ≡ c} →
       ∀ (α : p ≡ q) (β : r ≡ s) → p ∙ r ≡ q ∙ s
_*'_ {_} {_} {_} {_} {p} {q} {r} {s} α β = p∙β ∙ α∙s
  where p∙β : p ∙ r ≡ p ∙ s
        p∙β = pwl p β
        α∙s : p ∙ s ≡ q ∙ s
        α∙s = pwr s α

pwr-ru : ∀ {A : Set} {a : A} (p : a ≡ a) (α : refl a ≡ p) →
         pwr (refl a) α ≡ α ∙ (inv (right_unit p))
pwr-ru {_} {_} (refl a) (refl (refl a)) = refl (refl (refl a))

pwl-lu : ∀ {A : Set} {a : A} (p : a ≡ a) (α : refl a ≡ p) →
         pwl (refl a) α ≡ α ∙ (inv (left_unit p))
pwl-lu {_} {_} (refl a) (refl (refl a)) = refl (refl (refl a))

*≡*' : ∀ {A : Set} {a b c : A} {p q : a ≡ b} {r s : b ≡ c} →
       ∀ (α : p ≡ q) (β : r ≡ s) → (α * β) ≡ (α *' β)
*≡*' {_} {a} {a} {a} {refl a} {refl a} {refl a} {refl a}
     (refl (refl a)) (refl (refl a))
     = refl ((refl ((refl a) ∙ (refl a))) ∙ (refl ((refl a) ∙ (refl a))))

∙≡* : ∀ {A : Set} {a : A} → ∀ (α β : Ω (refl a)) → α ∙ β ≡ α * β
∙≡* {_} {a} α β = inv (redua)
  where redul : α * β ≡ α ∙ (pwl (refl a) β)
        redul = (pwr (pwl (refl a) β) (pwr-ru (refl a) α)) ∙
                (pwr (pwl (refl a) β) (right_unit α))
        redua : α * β ≡ α ∙ β
        redua = (redul ∙ (pwl α (pwl-lu (refl a) β))) ∙ (pwl α (right_unit β))

*'≡∙ : ∀ {A : Set} {a : A} → ∀ (α β : Ω (refl a)) → α *' β ≡ β ∙ α
*'≡∙ {_} {a} α β = redua'
  where redul' : α *' β ≡ β ∙ (pwr (refl a) α)
        redul' = (pwr (pwr (refl a) α) (pwl-lu (refl a) β)) ∙
                 (pwr (pwr (refl a) α) (right_unit β))
        redua' : α *' β ≡ β ∙ α
        redua' = redul' ∙ ((pwl β (pwr-ru (refl a) α)) ∙ (pwl β (right_unit α)))

-- finally, we are able to prove that the higher path group is commutative
Ω²-comm : ∀ {A : Set} {a : A} → ∀ (α β : Ω (refl a)) → α ∙ β ≡ β ∙ α
Ω²-comm α β = ((∙≡* α β) ∙ (*≡*' α β)) ∙ (*'≡∙ α β)

-- ------------------------------------
-- functions behave functorially
-- the action on paths
ap : ∀ {A B : Set} {x y : A} → ∀ (f : A → B) (p : x ≡ y) → f x ≡ f y
ap {_} {_} {x} {x} f (refl x) = refl (f x)

-- ap acts like a functor
ap∙ : ∀ {A B : Set} {x y z : A} → ∀ (f : A → B) (p : x ≡ y) (q : y ≡ z) →
      ap f (p ∙ q) ≡ (ap f p) ∙ (ap f q)
ap∙ {_} {_} {x} {x} {x} f (refl x) (refl x) = inv (left_unit (refl (f x)))

apinv : ∀ {A B : Set} {x y : A} → ∀ (f : A → B) (p : x ≡ y) →
        ap f (inv p) ≡ inv (ap f p)
apinv {_} {_} {x} {x} f (refl x) = refl (refl (f x))

apcomp : ∀ {A B C : Set} {x y : A} → ∀ (f : A → B) (g : B → C) (p : x ≡ y) →
         ap g (ap f p) ≡ ap (comp g f) p
apcomp {_} {_} {_} {x} {x} f g (refl x) = refl (refl (g (f x)))

apid : ∀ {A : Set} {x y : A} → ∀ (p : x ≡ y) →
       ap id p ≡ p
apid {_} {x} {x} (refl x) = refl (refl x)

-- the transport action, which is action on dependent types
tr : ∀ {A : Set} {B : A → Set} → ∀ {x y : A} → ∀ (p : x ≡ y) → B x → B y
tr {A} {B} {x} {x} (refl x) = id

<<<<<<< HEAD
=======
trc : ∀ {A B : Set} {x y : A} (p : x ≡ y) (b : B) → tr {A} {λ x → B} p b ≡ b
trc {_} {_} {x} {x} (refl x) b = refl b
>>>>>>> a0dc66dca08059f740d9290f3d1cad1bb007d721
-- If you think about this, this is not obvious from a classical point of view.
-- The existence of the transport function tells us that the dependent type
-- B : A → Set is always going to be continuous, since whenever we have a path
-- in the base A from x to y, and whenever we're given a point in B x, we can
-- construct a value in B y, using the path in the base.

-- path lifting
lift : ∀ {A : Set} {B : A → Set} → ∀ {x y : A} → ∀ (p : x ≡ y) → ∀ (b : B x) →
       (x , b) ≡ y , (tr {A} {B} p b)
lift {A} {B} {x} {x} (refl x) b = refl (x , b)

-- the dependent mapping functor
<<<<<<< HEAD
apd : ∀ {A : Set} {B : A → Set} {x y : A} → ∀ (f : (∀ (a : A) → B a)) →
      ∀ (p : x ≡ y) → tr {A} {B} {x} {y} p (f x) ≡ f y
apd {A} {B} {x} {x} f (refl x) = refl (tr {A} {B} {x} {x} (refl x) (f x))

-- the dependent and non-dependent ap(d) is closely related
trc : ∀ {A B : Set} {x y : A} (p : x ≡ y) (b : B) → tr {A} {λ x → B} p b ≡ b
trc {_} {_} {x} {x} (refl x) b = refl b

-- and now we can prove the following:
apd≡ap : ∀ {A B : Set} {x y : A} →
         ∀ (f : A → B) (p : x ≡ y) → apd f p ≡ trc p (f x) ∙ (ap f p)
apd≡ap {_} {_} {x} {x} f (refl x) = refl (refl (f x))

-- some useful properties about transport
tr∙ : ∀ {A : Set} {B : A → Set} {x y z : A} → ∀ (p : x ≡ y) (q : y ≡ z) →
      ∀ (b : B x) → tr {A} {B} q (tr {A} {B} p b) ≡ tr {A} {B} (p ∙ q) b
tr∙ {_} {_} {x} {x} {x} (refl x) (refl x) b = refl b

trcomp : ∀ {A B : Set} {P : B → Set} {x y : A} → ∀ (f : A → B) (p : x ≡ y) →
         ∀ (b : P (f x)) → tr {A} {λ a → P (f a)} p b ≡ tr {B} {P} (ap f p) b
trcomp {_} {_} {_} {x} {x} f (refl x) b = refl b

trhi : ∀ {A : Set} {P Q : A → Set} {x y : A} → ∀ (f : ∀ (x : A) → P x → Q x) →
       ∀ (p : x ≡ y) (b : P x) → f y (tr {A} {P} p b) ≡ tr {A} {Q} p (f x b)
trhi {_} {_} {_} {x} {x} f (refl x) b = refl (f x b)
=======
apd : ∀ {A : Set} {B : A → Set} → ∀ (f : (∀ (a : A) → B a)) →
      ∀ (x y : A) (p : x ≡ y) → tr {A} {B} {x} {y} p (f x) ≡ f y
apd {A} {B} f x x (refl x) = refl (tr {A} {B} {x} {x} (refl x) (f x))

-- apd helps to construct a
>>>>>>> a0dc66dca08059f740d9290f3d1cad1bb007d721


------------------------------------------------------------------------
-- The Agda standard library
--
-- Pointwise lifting of relations over Vector
------------------------------------------------------------------------

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

module Data.Vec.Functional.Relation.Binary.Pointwise where

open import Data.Fin.Base
open import Data.Nat.Base
open import Data.Vec.Functional as VF hiding (map)
open import Level using (Level)
open import Relation.Binary

private
  variable
    a b r s ℓ : Level
    A : Set a
    B : Set b

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

Pointwise : REL A B ℓ → ∀ {n} → Vector A n → Vector B n → Set ℓ
Pointwise R xs ys = ∀ i → R (xs i) (ys i)

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

module _ {R : REL A B r} {S : REL A B s} where

  map : R ⇒ S → ∀ {n} → Pointwise R ⇒ Pointwise S {n = n}
  map f rs i = f (rs i)


{-
Module in which the Grothendieck Group ("Groupification") of a commutative monoid is defined.
-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.CommMonoid.GrothendieckGroup where

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

open import Cubical.Algebra.Monoid
open import Cubical.Algebra.CommMonoid
open import Cubical.Algebra.CommMonoid.CommMonoidProd
open import Cubical.Algebra.Group
open import Cubical.Algebra.Group.Morphisms
open import Cubical.Algebra.AbGroup

open import Cubical.HITs.SetQuotients.Base
open import Cubical.HITs.SetQuotients.Properties

open import Cubical.Relation.Binary.Base

private
  variable
    ℓ ℓ' : Level

module _ (M : CommMonoid ℓ) where
  open BinaryRelation

  M² : CommMonoid _
  M² = CommMonoidProd M M

  open CommMonoidStr ⦃...⦄
  private
    instance
      _ = snd M
      _ = snd M²

  R : ⟨ M² ⟩  → ⟨ M² ⟩ → Type _
  R (a₁ , b₁) (a₂ , b₂) =  Σ[ k ∈ ⟨ M ⟩ ] k · (a₁ · b₂) ≡ k · (b₁ · a₂)

  M²/R : Type _
  M²/R = ⟨ M² ⟩ / R

  0/R : M²/R
  0/R = [ ε , ε ]

  private
    _+/_ : M²/R → M²/R → M²/R
    x +/ y = setQuotBinOp isReflR isReflR _·_ isCongR x y
      where
      isReflR : isRefl R
      isReflR (a , b) = ε , cong (ε ·_) (·Comm a b)

      isCongR : ∀ u u' v v' → R u u' → R v v' → R (u · v) (u' · v')
      isCongR (a₁ , b₁) (a₂ , b₂) (a₃ , b₃) (a₄ , b₄) (k , p) (s , q) = k · s , proof
        where
        proof =
          (k · s) · ((a₁ · a₃) · (b₂ · b₄)) ≡⟨ lemma ⟩
          (k · (a₁ · b₂)) · (s · (a₃ · b₄)) ≡⟨ cong₂ _·_ p q ⟩
          (k · (b₁ · a₂)) · (s · (b₃ · a₄)) ≡⟨ sym lemma ⟩
          (k · s) · ((b₁ · b₃) · (a₂ · a₄)) ∎
            where
            rExp : ∀ {x y z} → x ≡ y → x · z ≡ y · z
            rExp r = cong₂ _·_ r refl

            lExp : ∀ {x y z} → x ≡ y → z · x ≡ z · y
            lExp r = cong₂ _·_ refl r

            -- remove proof when MonoidSolver is done
            lemma : ∀ {k s a b c d} → (k · s) · ((a · b) · (c · d)) ≡ (k · (a · c)) · (s · (b · d))
            lemma = sym (·Assoc _ _ _) ∙ lExp (
                                   (·Assoc _ _ _) ∙ (·Assoc _ _ _) ∙ rExp (
                                       ·Comm _ _ ∙ (·Assoc _ _ _) ∙ (·Assoc _ _ _) ∙ rExp (
                                            ·Comm _ _ ∙ (·Assoc _ _ _)
                                       ) ∙ sym (·Assoc _ _ _)
                                   ) ∙ sym (·Assoc _ _ _) ∙ lExp (sym (·Assoc _ _ _))
                              ) ∙ (·Assoc _ _ _)

    -/_ : M²/R → M²/R
    -/_ = setQuotUnaryOp swap h
      where
      swap : ⟨ M² ⟩  → ⟨ M² ⟩
      swap = λ (a , b) → b , a

      h : ∀ u v → R u v → R (swap u) (swap v)
      h _ _ (k , p) = k , sym p

    assoc/R : (x y z : M²/R) → x +/ ( y +/ z) ≡ (x +/ y) +/ z
    assoc/R = elimProp3 (λ x y z → squash/ _ _) (λ u v w → cong [_] (·Assoc _ _ _))

    rid/R : (x : M²/R) → x +/ 0/R ≡ x
    rid/R = elimProp (λ x → squash/ _ _) (λ u → cong [_] (·IdR u))

    rinv/R : (x : M²/R) → x +/ (-/ x) ≡ 0/R
    rinv/R = elimProp (λ x → squash/ _ _)
                      (λ (a , b) →  eq/ _ _ (ε , cong (λ x → ε · (x · ε)) (·Comm _ _)))

    comm/R : (x y : M²/R) → x +/ y ≡ y +/ x
    comm/R = elimProp2 (λ x y → squash/ _ _) (λ u v → cong [_] (·Comm _ _))

  asAbGroup : AbGroup ℓ
  asAbGroup = makeAbGroup 0/R _+/_ -/_ squash/ assoc/R rid/R rinv/R comm/R

Groupification : CommMonoid ℓ → AbGroup ℓ
Groupification M = asAbGroup M

module UniversalProperty (M : CommMonoid ℓ) where
  open IsMonoidHom
  open CommMonoidStr ⦃...⦄

  private
    instance
      _ = snd M

{-
The "groupification" of a monoid comes with a universal morphism and a universal property:

            M ----- ∀φ -----> A
             \               Λ
              \             /
       universalHom    ∃! inducedHom
                \         /
                 V       /
             Groupification M
-}

  universalHom : CommMonoidHom M (AbGroup→CommMonoid (Groupification M))
  fst universalHom = λ m → [ m , ε ]
  pres· (snd universalHom) =
    λ _ _ → eq/ _ _ (ε , cong (ε ·_) (·Comm _ _ ∙ cong₂ _·_ (·IdR ε) refl))
  presε (snd universalHom) = refl

  private
    i = fst universalHom

  module _ {A : AbGroup ℓ} (φ : CommMonoidHom M (AbGroup→CommMonoid A)) where
    open IsGroupHom

    open GroupTheory (AbGroup→Group A)

    open AbGroupStr ⦃...⦄ using (-_; _-_; _+_; +InvR; +InvL)
    private
      instance
        AAsGroup  = snd A
        MAsGroup  = snd (Groupification M)
        AAsMonoid = snd (AbGroup→CommMonoid A)

    private
      module φ = IsMonoidHom (snd φ)
      f = fst φ

    inducedHom : AbGroupHom (Groupification M) A
    fst inducedHom = elim (λ x → isSetAbGroup A) g proof
        where
        g = λ (a , b) → f a - f b
        proof : (u v : ⟨ M² M ⟩) (r : R M u v) → g u ≡ g v
        proof _ _ (k , p) = lemma (lemma₂ p)
            where
            lemma₂ : ∀ {k a b c d} → k · (a · d) ≡ k · (b · c) → f a + f d ≡ f b + f c
            lemma₂ {k} {a} {b} {c} {d} p =
              f a + f d   ≡⟨ sym (φ.pres· _ _) ⟩
              f (a · d)   ≡⟨ ·CancelL _ (sym (φ.pres· _ _) ∙ (cong f p) ∙ φ.pres· _ _) ⟩
              f (b · c)   ≡⟨ φ.pres· _ _ ⟩
              f b + f c   ∎

            lemma : ∀ {a b c d} → f a + f d ≡ f b + f c → f a - f b ≡ f c - f d
            lemma {a} {b} {c} {d} p =
              f a - f b
                ≡⟨ cong (λ x → x - f b) (sym (·IdR _)) ⟩
              f a + ε - f b
                ≡⟨ cong (λ x → f a + x - f b) (sym (+InvR _)) ⟩
              f a + (f d - f d) - f b
                ≡⟨ cong (λ x → x - f b) (·Assoc _ _ _) ⟩
              f a + f d - f d - f b
                ≡⟨ cong (λ x → x - f d - f b) p ⟩
              f b + f c - f d - f b
                ≡⟨ ·Comm _ _ ∙ ·Assoc _ _ _ ⟩
              (- f b + (f b + f c)) - f d
                ≡⟨ cong (λ x → x - f d) (·Assoc _ _ _) ⟩
              ((- f b + f b) + f c) - f d
                ≡⟨ cong (λ x → (x + f c) - f d) (+InvL _) ∙ sym (·Assoc _ _ _) ∙ ·IdL _ ⟩
              f c - f d
                ∎

    pres· (snd inducedHom) = elimProp2 (λ _ _ → isSetAbGroup A _ _) proof
      where
        rExp : ∀ {x y z} → x ≡ y → x + z ≡ y + z
        rExp r = cong₂ _+_ r refl

        lExp : ∀ {x y z} → x ≡ y → z + x ≡ z + y
        lExp r = cong₂ _+_ refl r

        proof : ((a , b) (c , d) : ⟨ M² M ⟩) → (f (a · c)) - (f (b · d)) ≡ (f a - f b) + (f c - f d)
        proof (a , b) (c , d) =
          f (a · c) - f (b · d)     ≡⟨ cong₂ _-_ (φ.pres· _ _) (φ.pres· _ _) ⟩
          (f a + f c) - (f b + f d) ≡⟨ lExp (invDistr _ _ ∙ ·Comm _ _) ∙ ·Assoc _ _ _ ⟩
          ((f a + f c) - f b) - f d ≡⟨ lemma ⟩
          (f a - f b) + (f c - f d) ∎
          where
            lemma = rExp (sym (·Assoc _ _ _) ∙ lExp (·Comm _ _) ∙ ·Assoc _ _ _) ∙ sym (·Assoc _ _ _)

    pres1 (snd inducedHom)   = +InvR _
    presinv (snd inducedHom) = elimProp (λ _ → isSetAbGroup A _ _)
                                        (λ _ → sym (invDistr _ _ ∙ cong₂ _-_ (invInv _) refl))

    solution : (m : ⟨ M ⟩) → (fst inducedHom) (i m) ≡ f m
    solution m = cong ((f m)+_) ((cong (-_) φ.presε) ∙ inv1g) ∙ ·IdR _

    unique : (ψ : AbGroupHom (Groupification M) A)
             → (ψIsSolution : (m : ⟨ M ⟩) → ψ .fst (i m) ≡ f m)
             → (u : ⟨ M² M ⟩) → ψ .fst [ u ] ≡ inducedHom .fst [ u ]
    unique ψ ψIsSolution (a , b) =
       ψ .fst [ a , b ]                    ≡⟨ lemma ⟩
       ψ .fst ([ a , ε ] - [ b , ε ])      ≡⟨ (snd ψ).pres· _ _ ∙ cong₂ _+_ refl ((snd ψ).presinv _) ⟩
       ψ .fst [ a , ε ] - ψ .fst [ b , ε ] ≡⟨ cong₂ _-_ (ψIsSolution a) (ψIsSolution b) ⟩
       f a - f b                           ∎
       where
         lemma = cong (ψ .fst) (eq/ _ _ (ε , cong (ε ·_) (·Assoc _ _ _ ∙ ·Comm _ _)))


------------------------------------------------------------------------
-- The Agda standard library
--
-- Dependent product combinators for propositional equality
-- preserving functions
------------------------------------------------------------------------

{-# OPTIONS --with-K --safe #-}

module Data.Product.Function.Dependent.Propositional.WithK where

open import Data.Product
open import Data.Product.Function.Dependent.Setoid
open import Data.Product.Relation.Binary.Pointwise.Dependent
open import Data.Product.Relation.Binary.Pointwise.Dependent.WithK
open import Function.Equality using (_⟨$⟩_)
open import Function.Injection as Inj using (_↣_; module Injection)
open import Function.Inverse as Inv using (_↔_; module Inverse)
import Relation.Binary.HeterogeneousEquality as H

------------------------------------------------------------------------
-- Combinator for Injection

module _ {a₁ a₂} {A₁ : Set a₁} {A₂ : Set a₂}
         {b₁ b₂} {B₁ : A₁ → Set b₁} {B₂ : A₂ → Set b₂}
         where

  ↣ : ∀ (A₁↣A₂ : A₁ ↣ A₂) →
      (∀ {x} → B₁ x ↣ B₂ (Injection.to A₁↣A₂ ⟨$⟩ x)) →
      Σ A₁ B₁ ↣ Σ A₂ B₂
  ↣ A₁↣A₂ B₁↣B₂ =
    Inverse.injection Pointwise-≡↔≡ ⟨∘⟩
    injection (H.indexedSetoid B₂) A₁↣A₂
      (Inverse.injection (H.≡↔≅ B₂) ⟨∘⟩
       B₁↣B₂ ⟨∘⟩
       Inverse.injection (Inv.sym (H.≡↔≅ B₁))) ⟨∘⟩
    Inverse.injection (Inv.sym Pointwise-≡↔≡)
    where open Inj using () renaming (_∘_ to _⟨∘⟩_)


module BBHeap.Last {A : Set}(_≤_ : A → A → Set) where

open import BBHeap _≤_
open import BBHeap.Compound _≤_
open import BBHeap.DropLast _≤_
open import Bound.Lower A
open import Data.Sum

last : {b : Bound}(h : BBHeap b) → Compound h → A
last (left {b} {x} {l} {r} b≤x l⋘r) (cl .b≤x .l⋘r)
    with l | r | l⋘r | lemma-dropLast⋘ l⋘r
... | leaf | leaf | lf⋘ | _ = x
... | left x≤y₁ l₁⋘r₁ | left x≤y₂ l₂⋘r₂ | ll⋘ .x≤y₁ .x≤y₂ .l₁⋘r₁ .l₂⋘r₂ l₂≃r₂ r₁≃l₂ | inj₁ l≃r = last (left x≤y₂ l₂⋘r₂) (cl x≤y₂ l₂⋘r₂)
... | left x≤y₁ l₁⋘r₁ | left x≤y₂ l₂⋘r₂ | ll⋘ .x≤y₁ .x≤y₂ .l₁⋘r₁ .l₂⋘r₂ l₂≃r₂ r₁≃l₂ | inj₂ dl⋘r = last (left x≤y₁ l₁⋘r₁) (cl x≤y₁ l₁⋘r₁)
... | right x≤y₁ l₁⋙r₁ | left x≤y₂ l₂⋘r₂ | lr⋘ .x≤y₁ .x≤y₂ .l₁⋙r₁ .l₂⋘r₂ l₂≃r₂ l₁⋗l₂ | inj₁ ()
... | right x≤y₁ l₁⋙r₁ | left x≤y₂ l₂⋘r₂ | lr⋘ .x≤y₁ .x≤y₂ .l₁⋙r₁ .l₂⋘r₂ l₂≃r₂ l₁⋗l₂ | inj₂ dl⋘r = last (right x≤y₁ l₁⋙r₁) (cr x≤y₁ l₁⋙r₁)
last (right {b} {x} {l} {r} b≤x l⋙r) (cr .b≤x .l⋙r)
    with l | r | l⋙r | lemma-dropLast⋙ l⋙r
... | left x≤y lf⋘ | leaf | ⋙lf {x = y} .x≤y | _ = y
... | left x≤y₁ l₁⋘r₁ | left x≤y₂ l₂⋘r₂ | ⋙rl .x≤y₁ .x≤y₂ .l₁⋘r₁ l₁≃r₁ .l₂⋘r₂ l₁⋗r₂ | inj₁ l⋗r = last (left x≤y₁ l₁⋘r₁) (cl x≤y₁ l₁⋘r₁)
... | left x≤y₁ l₁⋘r₁ | left x≤y₂ l₂⋘r₂ | ⋙rl .x≤y₁ .x≤y₂ .l₁⋘r₁ l₁≃r₁ .l₂⋘r₂ l₁⋗r₂ | inj₂ l⋙dr = last (left x≤y₂ l₂⋘r₂) (cl x≤y₂ l₂⋘r₂)
... | left x≤y₁ l₁⋘r₁ | right x≤y₂ l₂⋙r₂ | ⋙rr .x≤y₁ .x≤y₂ .l₁⋘r₁ l₁≃r₁ .l₂⋙r₂ l₁≃l₂ | inj₁ ()
... | left x≤y₁ l₁⋘r₁ | right x≤y₂ l₂⋙r₂ | ⋙rr .x≤y₁ .x≤y₂ .l₁⋘r₁ l₁≃r₁ .l₂⋙r₂ l₁≃l₂ | inj₂ l⋙dr = last (right x≤y₂ l₂⋙r₂) (cr x≤y₂ l₂⋙r₂)


module Bound.Lower.Order {A : Set}(_≤_ : A → A → Set) where

open import Bound.Lower A

data LeB : Bound → Bound → Set where
  lebx : {b : Bound}
                   → LeB bot b
  lexy : {a b : A}
                   → a ≤ b
                   → LeB (val a) (val b)


-- Copyright:  (c) 2016 Ertugrul Söylemez
-- License:    BSD3
-- Maintainer: Ertugrul Söylemez <esz@posteo.de>

module Data.Fin.Core where

open import Core
open import Data.Nat
import Data.Nat.Core as Nat

data Fin : ℕ → Set where
  fzero : {n : ℕ} → Fin (suc n)
  fsuc  : {n : ℕ} → Fin n → Fin (suc n)

instance
  Fin-Number : {n : ℕ} → Number (Fin (suc n))
  Fin-Number {n} =
    record {
      Constraint = λ x → x ℕ,≤.≤ n;
      fromNat = f n
    }

    where
    f : ∀ n x {{_ : x ℕ,≤.≤ n}} → Fin (suc n)
    f n .0 {{Nat.0≤s}} = fzero
    f (suc n) (suc x) {{Nat.s≤s p}} = fsuc (f n x {{p}})

  Fin,≡ : ∀ {n} → Equiv (Fin n)
  Fin,≡ = PropEq _

fsuc-inj : ∀ {n} {x y : Fin (suc n)} → fsuc x ≡ fsuc y → x ≡ y
fsuc-inj ≡-refl = ≡-refl

fromℕ : ∀ {n} (x : ℕ) → x Nat.≤ n → Fin (suc n)
fromℕ zero p = fzero
fromℕ (suc x) (Nat.s≤s p) = fsuc (fromℕ x p)

toℕ : ∀ {n} → Fin (suc n) → ∃ (λ x → x Nat.≤ n)
toℕ fzero = zero , Nat.0≤s
toℕ {zero} (fsuc ())
toℕ {suc n} (fsuc x) with toℕ x
toℕ {suc n} (fsuc x) | x' , p = suc x' , Nat.s≤s p

embed : ∀ {n} → Fin n → Fin (suc n)
embed fzero = fzero
embed (fsuc x) = fsuc (embed x)

_≤_ : ∀ {n} (x y : Fin (suc n)) → Set _
x ≤ y = fst (toℕ x) Nat.≤ fst (toℕ y)

infix 1 _≤_

_≤?_ : ∀ {n} (x y : Fin (suc n)) → Decision (x ≤ y)
x ≤? y = fst (toℕ x) Nat.≤? fst (toℕ y)

-- Fin,≤ : ∀ {n} → TotalOrder (Fin (suc n))
-- Fin,≤ {n} =
--   record {
--     partialOrder = record {
--       Eq = Fin,≡;
--       _≤_ = _≤_;
--       antisym = antisym;
--       refl' = refl';
--       trans = λ {x} {y} {z} → trans {x} {y} {z}
--     };
--     total = total
--   }

--   where
--   not-s≤0 : ∀ {n} {x : Fin (suc n)} → not (fsuc x ≤ fzero)
--   not-s≤0 ()

--   antisym : ∀ {x y} → x ≤ y → y ≤ x → x ≡ y
--   antisym {fzero} {fzero} p q = ≡-refl
--   antisym {fzero} {fsuc y} p q with not-s≤0 {!!}
--   antisym {fzero} {fsuc y} p q | ()
--   antisym {fsuc x} p q = {!!}

--   refl' : ∀ {x y} → x ≡ y → x ≤ y
--   refl' = {!!}

--   trans : ∀ {x y z} → x ≤ y → y ≤ z → x ≤ z
--   trans = {!!}

--   total : ∀ x y → Either (x ≤ y) (y ≤ x)
--   total = {!!}


open import Logic
open import Logic.Classical
open import Structure.Setoid
open import Structure.OrderedField
open import Type

module Structure.Function.Metric
  {ℓF ℓₑF ℓ≤}
  {F : Type{ℓF}}
  ⦃ equiv-F : Equiv{ℓₑF}(F) ⦄
  {_+_}{_⋅_}
  {_≤_ : _ → _ → Type{ℓ≤}}
  ⦃ orderedField-F : OrderedField{F = F}(_+_)(_⋅_)(_≤_) ⦄
  ⦃ classical : ∀{ℓ}{P : Stmt{ℓ}} → Classical(P) ⦄
  where

open OrderedField(orderedField-F)

import      Lvl
open import Data.Boolean
open import Data.Boolean.Proofs
import      Data.Either as Either
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Functional as Fn
open import Logic.Propositional
open import Logic.Predicate
open import Relator.Ordering
open import Sets.PredicateSet renaming (_≡_ to _≡ₛ_)
open import Structure.Setoid.Uniqueness
open import Structure.Function.Ordering
open import Structure.Operator.Field
open import Structure.Operator.Monoid
open import Structure.Operator.Group
open import Structure.Operator.Proofs
open import Structure.Operator.Properties
open import Structure.Operator
open import Structure.Relator.Ordering
open        Structure.Relator.Ordering.Weak.Properties
open import Structure.Relator.Properties
open import Syntax.Transitivity

F₊ = ∃(Positive)

module _ where
  record MetricSpace {ℓₘ ℓₑₘ} {M : Type{ℓₘ}} ⦃ equiv-M : Equiv{ℓₑₘ}(M) ⦄ (d : M → M → F) : Type{ℓF Lvl.⊔ ℓ≤ Lvl.⊔ ℓₘ Lvl.⊔ ℓₑₘ Lvl.⊔ ℓₑF} where
    field
      ⦃ distance-binary-operator ⦄ : BinaryOperator(d)
      self-distance : ∀{x y} → (d(x)(y) ≡ 𝟎) ↔ (x ≡ y)
      ⦃ distance-commutativity ⦄ : Commutativity(d)
      triangle-inequality : ∀{x y z} → (d(x)(z) ≤ (d(x)(y) + d(y)(z)))
      ⦃ non-negativity ⦄ : ∀{x y} → NonNegative(d(x)(y))
      {-
      non-negativity{x}{y} =
        ([≤]ₗ-of-[+] (
          𝟎
          d(x)(x)
          d(x)(y) + d(y)(x)
          d(x)(y) + d(x)(y)
          2 ⋅ d(x)(y)
        ))
      -}

    distance-to-self : ∀{x} → (d(x)(x) ≡ 𝟎)
    distance-to-self = [↔]-to-[←] self-distance (reflexivity(_≡_))

    Neighborhood : M → F₊ → PredSet(M)
    Neighborhood(p)([∃]-intro r)(q) = (d(p)(q) < r)

    Neighborhoods : ∀{ℓ} → M → PredSet(PredSet{ℓ}(M))
    Neighborhoods(p)(N) = ∃(r ↦ N ≡ₛ Neighborhood(p)(r))

    PuncturedNeighborhood : M → F₊ → PredSet(M)
    PuncturedNeighborhood(p)([∃]-intro r)(q) = (𝟎 < d(p)(q) < r)

    LimitPoint : ∀{ℓ} → PredSet{ℓ}(M) → PredSet(M)
    LimitPoint(E)(p) = ∀{r} → Overlapping(PuncturedNeighborhood(p)(r)) (E)

    IsolatedPoint : ∀{ℓ} → PredSet{ℓ}(M) → PredSet(M)
    IsolatedPoint(E)(p) = ∃(r ↦ Disjoint(PuncturedNeighborhood(p)(r)) (E))

    Interior : ∀{ℓ} → PredSet{ℓ}(M) → PredSet(M)
    Interior(E)(p) = ∃(r ↦ Neighborhood(p)(r) ⊆ E)

    Closed : ∀{ℓ} → PredSet(PredSet{ℓ}(M))
    Closed(E) = LimitPoint(E) ⊆ E

    Open : ∀{ℓ} → PredSet(PredSet{ℓ}(M))
    Open(E) = E ⊆ Interior(E)

    Perfect : ∀{ℓ} → PredSet(PredSet{ℓ}(M))
    Perfect(E) = LimitPoint(E) ≡ₛ E

    Bounded : ∀{ℓ} → PredSet(PredSet{ℓ}(M))
    Bounded(E) = ∃(p ↦ ∃(r ↦ E ⊆ Neighborhood(p)(r)))

    Discrete : ∀{ℓ} → PredSet(PredSet{ℓ}(M))
    Discrete(E) = E ⊆ IsolatedPoint(E)

    Closure : ∀{ℓ} → PredSet{ℓ}(M) → PredSet(M)
    Closure(E) = E ∪ LimitPoint(E)

    Dense : ∀{ℓ} → PredSet(PredSet{ℓ}(M))
    Dense(E) = ∀{p} → (p ∈ Closure(E))

    -- Compact

    Separated : ∀{ℓ₁ ℓ₂} → PredSet{ℓ₁}(M) → PredSet{ℓ₂}(M) → Stmt
    Separated(A)(B) = Disjoint(A)(Closure(B)) ∧ Disjoint(Closure(A))(B)

    Connected : ∀{ℓ} → PredSet{ℓ}(M) → Stmtω
    Connected(E) = ∀{ℓ₁ ℓ₂}{A : PredSet{ℓ₁}(M)}{B : PredSet{ℓ₂}(M)} → ((A ∪ B) ≡ₛ E) → Separated(A)(B) → ⊥

    -- Complete = Sequence.Cauchy ⊆ Sequence.Converging

    neighborhood-contains-center : ∀{p}{r} → (p ∈ Neighborhood(p)(r))
    neighborhood-contains-center {p}{[∃]-intro r ⦃ intro positive-r ⦄} =
      d(p)(p) 🝖-[ sub₂(_≡_)(_≤_) distance-to-self ]-sub
      𝟎       🝖-semiend
      r       🝖-end-from-[ positive-r ]

    -- TODO: Not always the case?
    -- subneighborhood-subradius : ∀{p₁ p₂}{r₁ r₂} → (Neighborhood(p₁)(r₁) ⊆ Neighborhood(p₂)(r₂)) → ([∃]-witness r₁ ≤ [∃]-witness r₂)

    subneighborhood-radius : ∀{p₁ p₂}{r₁ r₂} → (Neighborhood(p₁)(r₁) ⊆ Neighborhood(p₂)(r₂)) ← (d(p₂)(p₁) ≤ ([∃]-witness r₂ − [∃]-witness r₁))
    subneighborhood-radius {p₁} {p₂} {[∃]-intro r₁} {[∃]-intro r₂} p {q} qN₁ =
      d(p₂)(q)             🝖[ _≤_ ]-[ triangle-inequality ]-sub
      d(p₂)(p₁) + d(p₁)(q) 🝖[ _<_ ]-[ [<][+]-preserve-subₗ p qN₁ ]-super
      (r₂ − r₁) + r₁       🝖[ _≡_ ]-[ {!inverseOperₗ ? ?!} ] -- inverseOperatorᵣ(_+_)(_−_)
      r₂                   🝖-end
      {-where
        r₁r₂ : (r₁ ≤ r₂) -- TODO: This seems to be provable, but not used here
        r₁r₂ =
          r₁             🝖-[ {!!} ]
          d(p₁)(p₂) + r₁ 🝖-[ {!!} ]
          r₂             🝖-end
      -}

    subneighborhood-radius-on-same : ∀{p}{r₁ r₂} → (Neighborhood(p)(r₁) ⊆ Neighborhood(p)(r₂)) ← ([∃]-witness r₁ ≤ [∃]-witness r₂)
    subneighborhood-radius-on-same {p} {[∃]-intro r₁} {[∃]-intro r₂} r₁r₂ {x} xN₁ xN₂ = xN₁ (r₁r₂ 🝖 xN₂)

    interior-is-subset : ∀{ℓ}{E : PredSet{ℓ}(M)} → Interior(E) ⊆ E
    interior-is-subset {ℓ} {E} {x} ([∃]-intro ([∃]-intro r ⦃ intro positive-r ⦄) ⦃ N⊆E ⦄) =
      N⊆E {x} (p ↦ positive-r (
        r       🝖[ _≤_ ]-[ p ]-super
        d(x)(x) 🝖[ _≡_ ]-[ distance-to-self ]
        𝟎       🝖[ _≡_ ]-end
      ))

    neighborhood-interior-is-self : ∀{p}{r} → (Interior(Neighborhood(p)(r)) ≡ₛ Neighborhood(p)(r))
    ∃.witness (Tuple.left (neighborhood-interior-is-self {p} {r}) x) = r
    ∃.proof (Tuple.left (neighborhood-interior-is-self {p} {r} {x}) Nx) = {!!}
    Tuple.right (neighborhood-interior-is-self {p} {r}) = {!!}

    neighborhood-is-open : ∀{p}{r} → Open(Neighborhood(p)(r))

    interior-is-largest-subspace : ∀{ℓ₁ ℓ₂}{E : PredSet{ℓ₁}(M)}{Eₛ : PredSet{ℓ₂}(M)} → Open(Eₛ) → (Eₛ ⊆ E) → (Eₛ ⊆ Interior(E))

    nested-interior : ∀{ℓ}{E : PredSet{ℓ}(M)} → Interior(Interior(E)) ≡ₛ Interior(E)

    isolated-limit-eq : ∀{ℓ}{E : PredSet{ℓ}(M)} → (IsolatedPoint(E) ⊆ ∅ {Lvl.𝟎}) ↔ (E ⊆ LimitPoint(E))

    interior-closure-eq1 : ∀{ℓ}{E : PredSet{ℓ}(M)} → ((∁ Interior(E)) ≡ₛ Closure(∁ E))

    interior-closure-eq2 : ∀{ℓ}{E : PredSet{ℓ}(M)} → (Interior(∁ E) ≡ₛ (∁ Closure(E)))

    open-closed-eq1 : ∀{ℓ}{E : PredSet{ℓ}(M)} → (Open(E) ↔ Closed(∁ E))

    open-closed-eq2 : ∀{ℓ}{E : PredSet{ℓ}(M)} → (Open(∁ E) ↔ Closed(E))

    union-is-open : ∀{ℓ₁ ℓ₂}{A : PredSet{ℓ₁}(M)}{B : PredSet{ℓ₂}(M)} → Open(A) → Open(B) → Open(A ∪ B)

    intersection-is-open : ∀{ℓ₁ ℓ₂}{A : PredSet{ℓ₁}(M)}{B : PredSet{ℓ₂}(M)} → Open(A) → Open(B) → Open(A ∩ B)

    -- open-subsubspace : ∀{ℓ₁ ℓ₂}{Eₛ : PredSet{ℓ₁}(M)}{E : PredSet{ℓ₂}(M)} →

    separated-is-disjoint : ∀{ℓ₁ ℓ₂}{A : PredSet{ℓ₁}(M)}{B : PredSet{ℓ₂}(M)} → Separated(A)(B) → Disjoint(A)(B)

    unionₗ-is-connected : ∀{ℓ₁ ℓ₂}{A : PredSet{ℓ₁}(M)}{B : PredSet{ℓ₂}(M)} → Connected(A ∪ B) → Connected(A)

    unionᵣ-is-connected : ∀{ℓ₁ ℓ₂}{A : PredSet{ℓ₁}(M)}{B : PredSet{ℓ₂}(M)} → Connected(A ∪ B) → Connected(B)

    intersection-is-connected : ∀{ℓ₁ ℓ₂}{A : PredSet{ℓ₁}(M)}{B : PredSet{ℓ₂}(M)} → Connected(A) → Connected(B) → Connected(A ∩ B)

module Sequence {ℓ} {M : Type{ℓ}} ⦃ equiv-M : Equiv(M) ⦄ (d : M → M → F) where
  open import Numeral.Natural
  import      Numeral.Natural.Relation.Order as ℕ

  ConvergesTo : (ℕ → M) → M → Stmt
  ConvergesTo f(L) = ∃{Obj = F₊ → ℕ}(N ↦ ∀{ε : F₊}{n} → (n ℕ.≥ N(ε)) → (d(f(n))(L) < [∃]-witness ε))

  Converging : (ℕ → M) → Stmt
  Converging(f) = ∃(ConvergesTo(f))

  Diverging : (ℕ → M) → Stmt
  Diverging(f) = ∀{L} → ¬(ConvergesTo f(L))

  lim : (f : ℕ → M) → ⦃ Converging(f) ⦄ → M
  lim(f) ⦃ [∃]-intro L ⦄ = L

  Cauchy : (ℕ → M) → Stmt
  Cauchy(f) = ∃{Obj = F₊ → ℕ}(N ↦ ∀{ε : F₊}{a b} → (a ℕ.≥ N(ε)) → (b ℕ.≥ N(ε)) → (d(f(a))(f(b)) < [∃]-witness ε))

  Complete : Stmt
  Complete = Cauchy ⊆ Converging

  Bounded : (ℕ → M) → Stmt
  Bounded(f) = ∃(r ↦ ∃(p ↦ ∀{n} → (d(p)(f(n)) < r)))

  unique-converges-to : ∀{f} → Unique(ConvergesTo(f))

  converging-bounded : Converging ⊆ Bounded

  -- strictly-ordered-sequence-limit : ∀{f g : ℕ → M} → (∀{n} → (f(n) < g(n))) → (lim f < lim g)
  -- ordered-sequence-limit : ∀{f g : ℕ → M} → (∀{n} → (f(n) ≤ g(n))) → (lim f ≤ lim g)

  -- limit-point-converging-sequence : ∀{E}{p} → LimitPoint(E)(p) → ∃(f ↦ (ConvergesTo f(p)) ∧ (∀{x} → (f(x) ∈ E)))

  -- TODO: Apparently, this requires both axiom of choice and excluded middle? At least the (←)-direction?
  -- continuous-sequence-convergence-composition : (ContinuousOn f(p)) ↔ (∀{g} → (ConvergesTo g(p)) → (ConvergesTo(f ∘ g)(f(p))))

  {-
  module Series where
    ∑ : (ℕ → M) → ℕ → M
    ∑ f(𝟎)    = 𝟎
    ∑ f(𝐒(n)) = (∑ f(n)) + f(𝐒(n))

    ∑₂ : (ℕ → M) → (ℕ ⨯ ℕ) → M
    ∑₂ f(a , b) = ∑ (f ∘ (a +_))(b − a)

    ConvergesTo : (ℕ → M) → M → Stmt
    ConvergesTo f(L) = Sequence.ConvergesTo(∑ f)(L)

    Converging : (ℕ → M) → Stmt
    Converging(f) = ∃(ConvergesTo(f))

    Diverging : (ℕ → M) → Stmt
    Diverging(f) = ∀{L} → ¬(ConvergesTo f(L))

    ConvergesTo : (ℕ → M) → M → Stmt
    AbsolutelyConvergesTo f(L) = ConvergesTo (‖_‖ ∘ f)(L)

    AbsolutelyConverging : (ℕ → M) → Stmt
    AbsolutelyConverging(f) = ∃(AbsolutelyConvergesTo(f))

    AbsolutelyDiverging : (ℕ → M) → Stmt
    AbsolutelyDiverging(f) = ∀{L} → ¬(AbsolutelyConvergesTo f(L))

    ConditionallyConverging : (ℕ → M) → Stmt
    ConditionallyConverging(f) = AbsolutelyDiverging(f) ∧ Converging(f)

    sequence-of-converging-series-converges-to-0 : Converging(f) → (Sequence.ConvergesTo f(𝟎))

    convergence-by-ordering : (∀{n} → f(n) ≤ g(n)) → (Converging(f) ← Converging(g))
    divergence-by-ordering : (∀{n} → f(n) ≤ g(n)) → (Diverging(f) → Diverging(g))
    convergence-by-quotient : Sequence.Converging(n ↦ f(n) / g(n)) → (Converging(f) ↔ Converging(g))
  -}

module Analysis
  {ℓ₁ ℓ₂}
  {M₁ : Type{ℓ₁}} ⦃ equiv-M₁ : Equiv(M₁) ⦄ (d₁ : M₁ → M₁ → F)
  ⦃ space₁ : MetricSpace(d₁) ⦄
  {M₂ : Type{ℓ₂}} ⦃ equiv-M₂ : Equiv(M₂) ⦄ (d₂ : M₂ → M₂ → F)
  ⦃ space₂ : MetricSpace(d₂) ⦄
  where

  open MetricSpace

  Lim : ∀{ℓ}{E : PredSet{ℓ}(M₁)} → ((x : M₁) → ⦃ x ∈ E ⦄ → M₂) → M₁ → M₂ → Stmt
  Lim {E = E} f(p)(L) = ∃{Obj = F₊ → F₊}(δ ↦ ∀{ε : F₊}{x} → ⦃ ex : x ∈ E ⦄ → (p ∈ PuncturedNeighborhood(space₁)(x)(δ(ε))) → (L ∈ Neighborhood(space₂)(f(x) ⦃ ex ⦄)(ε)))

  lim : ∀{ℓ}{E : PredSet{ℓ}(M₁)} → (f : (x : M₁) → ⦃ x ∈ E ⦄ → M₂) → (p : M₁) → ⦃ ∃(Lim f(p)) ⦄ → M₂
  lim f(p) ⦃ [∃]-intro L ⦄ = L

  ContinuousOn : ∀{ℓ}{E : PredSet{ℓ}(M₁)} → ((x : M₁) → ⦃ x ∈ E ⦄ → M₂) → (p : M₁) → ⦃ p ∈ E ⦄ → Stmt
  ContinuousOn f(p) = Lim f(p) (f(p))

  Continuous : ∀{ℓ}{E : PredSet{ℓ}(M₁)} → ((x : M₁) → ⦃ x ∈ E ⦄ → M₂) → Stmt
  Continuous{E = E}(f) = ∀{p} → ⦃ ep : p ∈ E ⦄ → ContinuousOn f(p) ⦃ ep ⦄

  -- continuous-mapping-connected : Continuous(f) → Connected(E) → Connected(map f(E))


{-# OPTIONS --without-K --safe #-}
open import Categories.Category
open import Categories.Functor hiding (id)

-- Cone over a Functor F (from shape category J into category C)

module Categories.Diagram.Cone
  {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {J : Category o′ ℓ′ e′} (F : Functor J C) where

open Category C
open Functor F

open import Level

record Apex (N : Obj) : Set (ℓ′ ⊔ o′ ⊔ e ⊔ ℓ) where
  field
    ψ       : (X : Category.Obj J) → (N ⇒ F₀ X)
    commute : ∀ {X Y} (f : J [ X , Y ]) → F₁ f ∘ ψ X ≈ ψ Y

record Cone : Set (o ⊔ ℓ′ ⊔ o′ ⊔ e ⊔ ℓ) where
  field
    {N}  : Obj
    apex : Apex N

  open Apex apex public

open Apex
open Cone

record Cone⇒ (c c′ : Cone) : Set (ℓ ⊔ e ⊔ o′) where
  field
    arr     : N c ⇒ N c′
    commute : ∀ {X} → ψ c′ X ∘ arr ≈ ψ c X

open Cone⇒


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.RingSolver.CommRingAsAlmostRing where

open import Cubical.Foundations.Prelude
open import Cubical.Algebra.CommRing.Base
open import Cubical.Algebra.RingSolver.AlmostRing
open import Cubical.Algebra.Semigroup
open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Group
open import Cubical.Algebra.AbGroup
open import Cubical.Algebra.Ring.Base
open import Cubical.Algebra.Ring.Properties

private
  variable
    ℓ : Level

open Cubical.Algebra.Ring.Properties.Theory

CommRingAsAlmostRing : CommRing {ℓ} → AlmostRing {ℓ}
CommRingAsAlmostRing {ℓ}
  (R , commringstr _ _ _ _ _
         (iscommring (isring
                       (isabgroup (isgroup +-isMonoid inverse) +-comm)
                       ·-isMonoid dist)
                     ·-comm)) =
  let
    R' : CommRing {ℓ}
    R' = (R , commringstr _ _ _ _ _
         (iscommring (isring
                       (isabgroup (isgroup +-isMonoid inverse) +-comm) ·-isMonoid dist)
                     ·-comm))
    R″ = CommRing→Ring R'
  in almostring R _ _ _ _ _
     (isalmostring
       +-isMonoid
       ·-isMonoid
       +-comm
       ·-comm
       (λ x y z → fst (dist x y z))
       (λ x y z → snd (dist x y z))
       (λ x y → sym (-DistL· R″ x y))
       (λ x y → sym (-Dist R″ x y))
       (λ x → 0LeftAnnihilates R″ x)
       λ x → 0RightAnnihilates R″ x)


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

open import Groups.Definition
open import Setoids.Setoids
open import Groups.Subgroups.Definition

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

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

normalSubgroup : {c : _} {pred : A → Set c} (sub : Subgroup G pred) → Set (a ⊔ c)
normalSubgroup {pred = pred} sub = {g k : A} → pred k → pred (g + (k + Group.inverse G g))


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.HITs.Ints.DiffInt.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Univalence

open import Cubical.HITs.Ints.DiffInt.Base
open import Cubical.Data.Nat
open import Cubical.Data.Sigma
open import Cubical.Data.Bool

open import Cubical.Relation.Binary.Base
open import Cubical.Relation.Nullary

open import Cubical.HITs.SetQuotients

open BinaryRelation

relIsEquiv : isEquivRel rel
relIsEquiv = equivRel {A = ℕ × ℕ} relIsRefl relIsSym relIsTrans
  where
    relIsRefl : isRefl rel
    relIsRefl (a0 , a1) = refl

    relIsSym : isSym rel
    relIsSym (a0 , a1) (b0 , b1) p = sym p

    relIsTrans : isTrans rel
    relIsTrans (a0 , a1) (b0 , b1) (c0 , c1) p0 p1 =
      inj-m+ {m = (b0 + b1)} ((b0 + b1) + (a0 + c1) ≡⟨ +-assoc (b0 + b1) a0 c1  ⟩
            ((b0 + b1) + a0) + c1 ≡[ i ]⟨ +-comm b0 b1 i + a0   + c1 ⟩
            ((b1 + b0) + a0) + c1 ≡[ i ]⟨ +-comm (b1 + b0) a0 i + c1 ⟩
            (a0 + (b1 + b0)) + c1 ≡[ i ]⟨ +-assoc a0 b1 b0 i    + c1 ⟩
            (a0 + b1) + b0 + c1 ≡⟨ sym (+-assoc (a0 + b1) b0 c1) ⟩
            (a0 + b1) + (b0 + c1) ≡⟨ cong (λ p → p . fst + p .snd) (transport ΣPath≡PathΣ (p0 , p1))⟩
            (b0 + a1) + (c0 + b1) ≡⟨ sym (+-assoc b0 a1 (c0 + b1))⟩
            b0 + (a1 + (c0 + b1)) ≡[ i ]⟨ b0 + (a1 + +-comm c0 b1 i) ⟩
            b0 + (a1 + (b1 + c0)) ≡[ i ]⟨ b0 + +-comm a1 (b1 + c0) i ⟩
            b0 + ((b1 + c0) + a1) ≡[ i ]⟨ b0 + +-assoc b1 c0 a1 (~ i) ⟩
            b0 + (b1 + (c0 + a1)) ≡⟨ +-assoc b0 b1 (c0 + a1)⟩
            (b0 + b1) + (c0 + a1) ∎ )

relIsProp : BinaryRelation.isPropValued rel
relIsProp a b x y = isSetℕ _ _ _ _

discreteℤ : Discrete ℤ
discreteℤ = discreteSetQuotients (discreteΣ discreteℕ λ _ → discreteℕ) relIsProp relIsEquiv (λ _ _ → discreteℕ _ _)

private
  _ : Dec→Bool (discreteℤ [ (3 , 5) ] [ (4 , 6) ]) ≡ true
  _ = refl

  _ : Dec→Bool (discreteℤ [ (3 , 5) ] [ (4 , 7) ]) ≡ false
  _ = refl


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

open import Semirings.Definition
open import LogicalFormulae
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Numbers.Integers.RingStructure.Ring
open import Groups.Orders.Archimedean
open import Rings.Orders.Partial.Definition
open import Numbers.Integers.Order

module Numbers.Integers.RingStructure.Archimedean where

open import Groups.Cyclic.Definition ℤGroup
open import Semirings.Solver ℕSemiring multiplicationNIsCommutative

private
  lemma : (x y : ℕ) → positiveEltPower (nonneg x) y ≡ nonneg (x *N y)
  lemma x zero rewrite Semiring.productZeroRight ℕSemiring x = refl
  lemma x (succ y) rewrite lemma x y | multiplicationNIsCommutative x (succ y) | multiplicationNIsCommutative y x = equalityCommutative (+Zinherits x (x *N y))

ℤArchimedean : Archimedean (toGroup ℤRing ℤPOrderedRing)
ℤArchimedean (nonneg (succ a)) (nonneg (succ b)) 0<a 0<b = succ (succ b) , t
  where
    v : b +N (a +N (a +N a *N b)) ≡ a +N (a +N (b +N a *N b))
    v rewrite Semiring.+Associative ℕSemiring a a (a *N b) | Semiring.+Associative ℕSemiring b (a +N a) (a *N b) | Semiring.+Associative ℕSemiring a b (a *N b) | Semiring.+Associative ℕSemiring a (a +N b) (a *N b) | Semiring.commutative ℕSemiring b (a +N a) | Semiring.+Associative ℕSemiring a a b = refl
    u : succ ((a +N (a +N a *N b)) +N b) ≡ a +N succ (a +N (b +N a *N b))
    u = from (succ (plus (plus (const a) (plus (const a) (times (const a) (const b)))) (const b))) to (plus (const a) (succ (plus (const a) (plus (const b) (times (const a) (const b)))))) by applyEquality succ v
    t : nonneg (succ b) <Z nonneg (succ a) +Z (nonneg (succ a) +Z positiveEltPower (nonneg (succ a)) b)
    t rewrite lemma (succ a) b = lessInherits (succPreservesInequality (le (a +N (a +N a *N b)) u))


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

module Function.Injective.Base where

open import Level
open import Path
open import Data.Sigma

Injective : (A → B) → Type _
Injective f = ∀ x y → (f⟨x⟩≡f⟨y⟩ : f x ≡ f y) → x ≡ y

infixr 0 _↣_
_↣_ : Type a → Type b → Type (a ℓ⊔ b)
A ↣ B = Σ[ f ⦂ (A → B) ] × Injective f
refl-↣ : A ↣ A
refl-↣ .fst x = x
refl-↣ .snd x y x≡y = x≡y


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

open import LogicalFormulae
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Functions.Definition
open import Setoids.Setoids
open import Setoids.Subset
open import Graphs.Definition
open import Sets.FinSet.Definition
open import Sets.FinSet.Lemmas
open import Numbers.Naturals.Semiring
open import Sets.EquivalenceRelations

module Graphs.PathGraph where

nNotSucc : {n : ℕ} → (n ≡ succ n) → False
nNotSucc {zero} ()
nNotSucc {succ n} pr = nNotSucc (succInjective pr)

PathGraph : (n : ℕ) → Graph _ (reflSetoid (FinSet (succ n)))
Graph._<->_ (PathGraph n) x y = (toNat x ≡ succ (toNat y)) || (toNat y ≡ succ (toNat x))
Graph.noSelfRelation (PathGraph n) x (inl bad) = nNotSucc bad
Graph.noSelfRelation (PathGraph n) x (inr bad) = nNotSucc bad
Graph.symmetric (PathGraph n) (inl x) = inr x
Graph.symmetric (PathGraph n) (inr x) = inl x
Graph.wellDefined (PathGraph n) refl refl i = i


------------------------------------------------------------------------------
-- Inductive PA properties using the induction principle
------------------------------------------------------------------------------

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

module PA.Inductive.PropertiesByInductionI where

open import PA.Inductive.Base

open import PA.Inductive.PropertiesByInduction
open import PA.Inductive.Relation.Binary.EqReasoning

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

+-comm : ∀ m n → m + n ≡ n + m
+-comm m n = ℕ-ind A A0 is m
  where
  A : ℕ → Set
  A i = i + n ≡ n + i

  A0 : A zero
  A0 = sym (+-rightIdentity n)

  is : ∀ i → A i → A (succ i)
  is i ih = succ (i + n) ≡⟨ succCong ih ⟩
            succ (n + i) ≡⟨ sym (x+Sy≡S[x+y] n i) ⟩
            n + succ i   ∎


------------------------------------------------------------------------
-- The Agda standard library
--
-- Equality over container extensions parametrised by some setoid
------------------------------------------------------------------------

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

open import Relation.Binary using (Setoid)

module Data.Container.Relation.Binary.Equality.Setoid {c e} (S : Setoid c e) where

open import Level using (_⊔_; suc)
open import Relation.Binary

open import Data.Container.Core
open import Data.Container.Relation.Binary.Pointwise
import Data.Container.Relation.Binary.Pointwise.Properties as Pw

private
  module S = Setoid S
open S using (_≈_) renaming (Carrier to X)

------------------------------------------------------------------------
-- Definition of equality

module _ {s p} (C : Container s p) where

  Eq : Rel (⟦ C ⟧ X) (e ⊔ s ⊔ p)
  Eq = Pointwise C _≈_

------------------------------------------------------------------------
-- Relational properties

  refl : Reflexive Eq
  refl = Pw.refl C _ S.refl

  sym : Symmetric Eq
  sym = Pw.sym C _ S.sym

  trans : Transitive Eq
  trans = Pw.trans C _ S.trans

  isEquivalence : IsEquivalence Eq
  isEquivalence = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }

  setoid : Setoid (s ⊔ p ⊔ c) (s ⊔ p ⊔ e)
  setoid = record
    { isEquivalence = isEquivalence
    }


------------------------------------------------------------------------------
-- Exclusive disjunction base
------------------------------------------------------------------------------

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

module FOL.ExclusiveDisjunction.Base where

open import FOL.Base

infixr 1 _⊻_

------------------------------------------------------------------------------
-- Exclusive disjunction.
_⊻_ : Set → Set → Set
P ⊻ Q = (P ∨ Q) ∧ ¬ (P ∧ Q)


open import Oscar.Prelude
open import Oscar.Class.IsEquivalence

module Oscar.Class.Setoid where

record Setoid 𝔬 ℓ : Ø ↑̂ (𝔬 ∙̂ ℓ) where
  constructor ∁
  field
    {Object} : Ø 𝔬
    ObjectEquivalence : Object → Object → Ø ℓ
    ⦃ `IsEquivalence ⦄ : IsEquivalence ObjectEquivalence


{-

Definition of subfinite sets

A set is subfinite if it is merely a subset of `Fin n` for some `n`. This
definition is weaker than `isFinSet` if we don't assume LEM, but they
are equivalent if we do.

Every subfinite set is guaranteed to be a set and discrete.

-}

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

module Cubical.Data.SubFinSet where

open import Cubical.Data.Nat
open import Cubical.Data.Fin
open import Cubical.Data.Sigma
open import Cubical.Data.FinSet
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Functions.Embedding
open import Cubical.HITs.PropositionalTruncation as PT
open import Cubical.Relation.Nullary

private
  variable
    ℓ : Level
    A B : Type ℓ

isSubFinSet : Type ℓ → Type ℓ
isSubFinSet A = ∃[ n ∈ ℕ ] A ↪ Fin n

isFinSet→isSubFinSet : isFinSet A → isSubFinSet A
isFinSet→isSubFinSet = PT.map
  λ (n , f , isEquiv-f) →
    n , f , isEquiv→isEmbedding isEquiv-f

isSubFinSet→isSet : isSubFinSet A → isSet A
isSubFinSet→isSet = PT.rec
  isPropIsSet
  λ (n , emb) → Embedding-into-isSet→isSet emb isSetFin

isSubFinSet→Discrete : isSubFinSet A → Discrete A
isSubFinSet→Discrete isSubFinSet-A x y = PT.rec
  (isPropDec (isSubFinSet→isSet isSubFinSet-A x y))
  (λ (n , emb) → Embedding-into-Discrete→Discrete emb discreteFin x y)
  isSubFinSet-A


module Type.Size.Countable where

import      Data.Either as Type
import      Data.Either.Equiv as Either
import      Data.Tuple as Type
import      Data.Tuple.Equiv as Tuple
import      Lvl
open import Logic
open import Logic.Predicate
open import Numeral.Natural
open import Numeral.Natural.Sequence
open import Numeral.Natural.Sequence.Proofs
open import Relator.Equals.Proofs.Equivalence
open import Structure.Setoid
open import Type
open import Type.Size
open import Type.Size.Proofs

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

-- Definition of a countable type
Countable : (T : Type{ℓ}) → ⦃ _ : Equiv{ℓₑ}(T) ⦄ → Stmt
Countable(T) = (ℕ ≽ T)

-- Definition of a countably infinite type
CountablyInfinite : (T : Type{ℓ}) → ⦃ equiv : Equiv{ℓₑ}(T) ⦄ → Stmt
CountablyInfinite(T) ⦃ equiv ⦄ = _≍_ ℕ ⦃ [≡]-equiv ⦄ T

private variable A : Type{ℓ₁}
private variable B : Type{ℓ₂}
private variable ⦃ equiv-A ⦄ : Equiv{ℓₑ}(A)
private variable ⦃ equiv-B ⦄ : Equiv{ℓₑ}(B)
private variable ⦃ equiv-A‖B ⦄ : Equiv{ℓₑ}(A Type.‖ B)
private variable ⦃ equiv-A⨯B ⦄ : Equiv{ℓₑ}(A Type.⨯ B)

module Countable where
  -- TODO: Do something similar to CountablyInfinite here

  -- _+_ : Countable (A) ⦃ equiv-A ⦄ → Countable(B) ⦃ equiv-B ⦄ → Countable(A ‖ B) ⦃ equiv-A‖B ⦄
  -- [∃]-intro a ⦃ intro pa ⦄ + [∃]-intro b ⦃ intro pb ⦄ = [∃]-intro (Left ∘ a) ⦃ intro (\{y} → [∃]-intro ([∃]-witness pa) ⦃ {!!} ⦄) ⦄
  -- [∃]-intro (Left ∘ a) ⦃ intro (\{y} → [∃]-intro ([∃]-witness pa) ⦃ {!!} ⦄) ⦄

  -- _⋅_ : Countable (A) ⦃ equiv-A ⦄ → Countable(B) ⦃ equiv-B ⦄ → Countable(A ⨯ B) ⦃ equiv-A⨯B ⦄

module CountablyInfinite where
  index : ∀{ℓ} → (T : Type{ℓ}) → ⦃ equiv-T : Equiv{ℓₑ}(T) ⦄ → ⦃ size : CountablyInfinite(T) ⦄ → (ℕ → T)
  index(_) ⦃ size = size ⦄ = [∃]-witness size

  indexing : ∀{ℓ} → (T : Type{ℓ}) → ⦃ equiv-T : Equiv{ℓₑ}(T) ⦄ → ⦃ size : CountablyInfinite(T) ⦄ → (T → ℕ)
  indexing(T) ⦃ size = size ⦄ = [∃]-witness([≍]-symmetry-raw ⦃ [≡]-equiv ⦄ size ⦃ [≡]-to-function ⦄)

  _+_ : ⦃ ext : Either.Extensionality ⦃ equiv-A ⦄ ⦃ equiv-B ⦄ (equiv-A‖B) ⦄ → CountablyInfinite(A) ⦃ equiv-A ⦄ → CountablyInfinite(B) ⦃ equiv-B ⦄ → CountablyInfinite(A Type.‖ B) ⦃ equiv-A‖B ⦄
  [∃]-intro a + [∃]-intro b = [∃]-intro (interleave a b)

  _⨯_ : ⦃ ext : Tuple.Extensionality ⦃ equiv-A ⦄ ⦃ equiv-B ⦄ (equiv-A⨯B) ⦄ → CountablyInfinite(A) ⦃ equiv-A ⦄ → CountablyInfinite(B) ⦃ equiv-B ⦄ → CountablyInfinite(A Type.⨯ B) ⦃ equiv-A⨯B ⦄
  [∃]-intro a ⨯ [∃]-intro b = [∃]-intro (pair a b)


module Data.List.Setoid where

import      Lvl
open import Data.List
open import Data.List.Equiv
open import Data.List.Relation.Quantification
open import Logic.Propositional
open import Structure.Operator
open import Structure.Setoid
open import Structure.Relator.Equivalence
import      Structure.Relator.Names as Names
open import Structure.Relator.Properties
open import Type

private variable ℓ ℓₑ ℓₚ : Lvl.Level
private variable T : Type{ℓ}

instance
  List-equiv : ⦃ Equiv{ℓₑ}(T) ⦄ → Equiv(List(T))
  List-equiv = intro (AllElements₂(_≡_)) ⦃ intro ⦃ intro refl ⦄ ⦃ intro sym ⦄ ⦃ intro trans ⦄ ⦄ where
    refl : Names.Reflexivity(AllElements₂(_≡_))
    refl{∅}     = ∅
    refl{x ⊰ l} = reflexivity(_≡_) ⊰ refl{l}

    sym : Names.Symmetry(AllElements₂(_≡_))
    sym ∅        = ∅
    sym (p ⊰ ps) = symmetry(_≡_) p ⊰ sym ps

    trans : Names.Transitivity(AllElements₂(_≡_))
    trans ∅        ∅        = ∅
    trans (p ⊰ ps) (q ⊰ qs) = (transitivity(_≡_) p q) ⊰ (trans ps qs)

instance
  List-equiv-extensionality : ⦃ equiv : Equiv{ℓₑ}(T) ⦄ → Extensionality(List-equiv ⦃ equiv ⦄)
  List-equiv-extensionality ⦃ equiv ⦄ = intro ⦃ binaryOperator = intro(_⊰_) ⦄ (\{(p ⊰ _) → p}) (\{(_ ⊰ pl) → pl}) \()


{-# OPTIONS --prop --rewriting --confluence-check #-}

open import Agda.Primitive
open import Agda.Builtin.Equality
open import Agda.Builtin.Nat renaming (Nat to ℕ; _+_ to _+ℕ_)

infix 4 _≐_
data _≐_ {ℓ} {A : Set ℓ} (x : A) : A → Prop ℓ where
  refl : x ≐ x

{-# BUILTIN REWRITE _≐_ #-}

variable
  ℓ : Level
  A B C : Set ℓ
  x y z : A

cong : (f : A → B) → x ≐ y → f x ≐ f y
cong f refl = refl

data ℤ : Set where
  zero : ℤ
  pred suc : ℤ → ℤ

postulate
  pred-suc : (x : ℤ) → pred (suc x) ≐ x
  suc-pred : (x : ℤ) → suc (pred x) ≐ x

{-# REWRITE pred-suc suc-pred #-}

_+_ : ℤ → ℤ → ℤ
zero   + y = y
pred x + y = pred (x + y)
suc x  + y = suc (x + y)

-_ : ℤ → ℤ
- zero = zero
- pred x = suc (- x)
- suc x = pred (- x)

data ℤ′ : Set where
  +[_]   : ℕ → ℤ′
  -[1+_] : ℕ → ℤ′

suc′ : ℤ′ → ℤ′
suc′ +[ x ] = +[ suc x ]
suc′ -[1+ zero ] = +[ zero ]
suc′ -[1+ suc x ] = -[1+ x ]

pred′ : ℤ′ → ℤ′
pred′ +[ zero ] = -[1+ zero ]
pred′ +[ suc x ] = +[ x ]
pred′ -[1+ x ] = -[1+ suc x ]

suc-pred′ : suc′ (pred′ x) ≐ x
suc-pred′ {+[ zero ]} = refl
suc-pred′ {+[ suc x ]} = refl
suc-pred′ { -[1+ x ]} = refl

pred-suc′ : pred′ (suc′ x) ≐ x
pred-suc′ {+[ x ]} = refl
pred-suc′ { -[1+ zero ]} = refl
pred-suc′ { -[1+ suc x ]} = refl

{-# REWRITE suc-pred′ pred-suc′ #-}

norm : ℤ → ℤ′
norm zero = +[ 0 ]
norm (pred x) = pred′ (norm x)
norm (suc x) = suc′ (norm x)

free : ℤ′ → ℤ
free +[ zero ] = zero
free +[ suc x ] = suc (free +[ x ])
free -[1+ zero ] = pred zero
free -[1+ suc x ] = pred (free -[1+ x ])


-- Martin-Löf identity type

{-# OPTIONS --without-K --safe #-}
module TypeTheory.Identity where

open import Level renaming (zero to lzero; suc to lsuc)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P using (refl; _≡_)
  renaming (trans to ≡-trans; sym to ≡-sym; cong to ≡-cong)
import Relation.Binary.Reasoning.Setoid as SetoidReasoning

record JBundle a : Set (lsuc a) where
  field
    Carrier : Set a
    _≈_     : Rel Carrier a
    ≈-refl  : ∀ {x} → x ≈ x
    J       : (C : ∀ x y → x ≈ y → Set a) → (∀ x → C x x ≈-refl) →
              ∀ x y (p : x ≈ y) → C x y p
    J-β     : ∀ (C : ∀ x y → x ≈ y → Set a) (c : ∀ x → C x x ≈-refl) x →
              J C c x x ≈-refl ≡ c x

module JBundleProperties {a} (jBundle : JBundle a) where
  open JBundle jBundle renaming (Carrier to A)
  sym : ∀ {x y} → x ≈ y → y ≈ x
  sym {x} {y} x≈y = J (λ x₁ y₁ x₁≈y₁ → y₁ ≈ x₁) (λ _ → ≈-refl) x y x≈y

  sym-≈-refl : ∀ x → sym (≈-refl {x}) ≡ ≈-refl
  sym-≈-refl x = J-β (λ x₁ y₁ x₁≈y₁ → y₁ ≈ x₁) (λ _ → ≈-refl) x

  sym-involutive : ∀ {x y} (p : x ≈ y) → sym (sym p) ≡ p
  sym-involutive {x} {y} p =
   J (λ x₁ y₁ x₁≈y₁ → sym (sym x₁≈y₁) ≡ x₁≈y₁)
     (λ z → ≡-trans (≡-cong sym (sym-≈-refl z)) (sym-≈-refl z)) x y p

  sym-injective : ∀ {x y} {p q : x ≈ y} → sym p ≡ sym q → p ≡ q
  sym-injective {p = p} {q} eq = begin
    p           ≡⟨ ≡-sym (sym-involutive p) ⟩
    sym (sym p) ≡⟨ ≡-cong sym eq ⟩
    sym (sym q) ≡⟨ sym-involutive q ⟩
    q           ∎
    where open P.≡-Reasoning
{-
  trans : ∀ {x y z} → x ≈ y → y ≈ z → x ≈ z
  trans {x} {y} {z} x≈y y≈z = J D (λ u → λ w q → q) x y x≈y z y≈z
    where
    D : ∀ u v → u ≈ v → Set _
    D u v u≈v = ∀ w → (q : v ≈ w) → u ≈ w
-}
  trans : ∀ {x y z} → x ≈ y → y ≈ z → x ≈ z
  trans {x} {y} {z} x≈y y≈z = J D (λ u → λ w q → J E (λ _ → ≈-refl) u w q) x y x≈y z y≈z
    where
    D : ∀ u v → u ≈ v → Set _
    D u v u≈v = ∀ w → v ≈ w → u ≈ w
    E : ∀ u v → u ≈ v → Set _
    E u v q = u ≈ v


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

open import Setoids.Setoids
open import Functions.Definition
open import Groups.Definition
open import Sets.EquivalenceRelations
open import Groups.Homomorphisms.Definition

module Groups.Homomorphisms.Examples where

identityHom : {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+A_ : A → A → A} (G : Group S _+A_) → GroupHom G G id
GroupHom.groupHom (identityHom {S = S} G) = Equivalence.reflexive (Setoid.eq S)
GroupHom.wellDefined (identityHom G) = id


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

{-
  Extremal Mono and Epimorphisms.

  https://ncatlab.org/nlab/show/extremal+epimorphism
-}

open import Categories.Category.Core

module Categories.Morphism.Extremal {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level
open import Categories.Morphism 𝒞

open Category 𝒞

IsExtremalEpi : ∀ {A B} {f : A ⇒ B} → Epi f → Set (o ⊔ ℓ ⊔ e)
IsExtremalEpi {A = A} {B = B} {f = f} epi =
  ∀ {X} {i : X ⇒ B} {g : A ⇒ X} → Mono i → f ≈ i ∘ g → IsIso i

IsExtremalMono : ∀ {A B} {f : A ⇒ B} → Mono f → Set (o ⊔ ℓ ⊔ e)
IsExtremalMono {A = A} {B = B} {f = f} mono =
  ∀ {X} {g : X ⇒ B} {i : A ⇒ X} → Epi i → f ≈ g ∘ i → IsIso i

record ExtremalEpi {A B} (f : A ⇒ B) : Set (o ⊔ ℓ ⊔ e) where
  field
    epi : Epi f
    extremal : IsExtremalEpi epi

record ExtremalMono {A B} (f : A ⇒ B) : Set (o ⊔ ℓ ⊔ e) where
  field
    mono : Mono f
    extremal : IsExtremalMono mono


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

open import Data.Nat hiding ( _≟_ )
open import Data.Fin renaming ( _<_ to _<<_ ) hiding (_≤_)
-- open import Data.Fin.Properties  hiding ( ≤-refl )
open import Data.Empty
open import Relation.Nullary
open import Relation.Binary.Definitions
open import Relation.Binary.PropositionalEquality
open import logic
open import nat
open import Data.Nat.Properties hiding ( _≟_ )

open import Relation.Binary.HeterogeneousEquality as HE using (_≅_ )

record FiniteSet ( Q : Set ) : Set  where
     field
        finite : ℕ
        Q←F : Fin finite → Q
        F←Q : Q → Fin finite
        finiso→ : (q : Q) → Q←F ( F←Q q ) ≡ q
        finiso← : (f : Fin finite ) → F←Q ( Q←F f ) ≡ f
     exists1 : (m : ℕ ) → m Data.Nat.≤ finite → (Q → Bool) → Bool
     exists1  zero  _ _ = false
     exists1 ( suc m ) m<n p = p (Q←F (fromℕ< {m} {finite} m<n)) \/ exists1 m (<to≤ m<n) p
     exists : ( Q → Bool ) → Bool
     exists p = exists1 finite ≤-refl p

     open import Data.List
     list1 : (m : ℕ ) → m Data.Nat.≤ finite → (Q → Bool) → List Q
     list1  zero  _ _ = []
     list1 ( suc m ) m<n p with bool-≡-? (p (Q←F (fromℕ< {m} {finite} m<n))) true
     ... | yes _ = Q←F (fromℕ< {m} {finite} m<n) ∷ list1 m (<to≤ m<n) p
     ... | no  _ = list1 m (<to≤ m<n) p
     to-list : ( Q → Bool ) → List Q
     to-list p = list1 finite ≤-refl p

     equal? : Q → Q → Bool
     equal? q0 q1 with F←Q q0 ≟ F←Q q1
     ... | yes p = true
     ... | no ¬p = false


------------------------------------------------------------------------
-- The Agda standard library
--
-- Indexed W-types aka Petersson-Synek trees
------------------------------------------------------------------------

module Data.W.Indexed where

open import Level
open import Data.Container.Indexed.Core
open import Data.Product
open import Relation.Unary

-- The family of indexed W-types.

module _ {ℓ c r} {O : Set ℓ} (C : Container O O c r) where

  open Container C

  data W (o : O) : Set (ℓ ⊔ c ⊔ r) where
    sup : ⟦ C ⟧ W o → W o

  -- Projections.

  head : W ⊆ Command
  head (sup (c , _)) = c

  tail : ∀ {o} (w : W o) (r : Response (head w)) → W (next (head w) r)
  tail (sup (_ , k)) r = k r

  -- Induction, (primitive) recursion and iteration.

  ind : ∀ {ℓ} (P : Pred (Σ O W) ℓ) →
        (∀ {o} (cs : ⟦ C ⟧ W o) → □ C P (o , cs) → P (o , sup cs)) →
        ∀ {o} (w : W o) → P (o , w)
  ind P φ (sup (c , k)) = φ (c , k) (λ r → ind P φ (k r))

  rec : ∀ {ℓ} {X : Pred O ℓ} → (⟦ C ⟧ (W ∩ X) ⊆ X) → W ⊆ X
  rec φ (sup (c , k))= φ (c , λ r → (k r , rec φ (k r)))

  iter : ∀ {ℓ} {X : Pred O ℓ} → (⟦ C ⟧ X ⊆ X) → W ⊆ X
  iter φ (sup (c , k))= φ (c , λ r → iter φ (k r))


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

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

open VectorSpace(vectorSpace)

open import Logic.Predicate
open import Logic.Propositional
open import Numeral.CoordinateVector as Vec using () renaming (Vector to Vec)
open import Numeral.Finite
open import Numeral.Natural
open import Sets.ExtensionalPredicateSet as PredSet using (PredSet ; _∈_ ; _∪_ ; ⋂ᵢ ; _⊇_ ; _⊆_)
open import Structure.Container.SetLike using (SetElement)
private open module SetLikeFunctionProperties{ℓ} = Structure.Container.SetLike.FunctionProperties{C = PredSet{ℓ}(V)}{E = V}(_∈_)
open import Structure.Function.Multi
open import Structure.Operator
open import Structure.Operator.Vector.LinearCombination        ⦃ vectorSpace = vectorSpace ⦄
open import Structure.Operator.Vector.LinearCombination.Proofs
open import Structure.Operator.Vector.Subspace                 ⦃ vectorSpace = vectorSpace ⦄
open import Structure.Relator.Properties
open import Syntax.Function
open import Syntax.Transitivity

private variable ℓ ℓ₁ ℓ₂ : Lvl.Level
private variable I : Type{ℓ}
private variable n : ℕ
private variable vf : Vec(n)(V)
private variable sf : Vec(n)(S)

-- TODO
[⋂ᵢ]-subspace : ∀{Vsf : I → PredSet{ℓ}(V)} → (∀{i} → Subspace(Vsf(i))) → Subspace(⋂ᵢ Vsf)
[∪]-subspace : ∀{Vₛ₁ Vₛ₂} → Subspace{ℓ₁}(Vₛ₁) → Subspace{ℓ₂}(Vₛ₂) → (((Vₛ₁ ⊇ Vₛ₂) ∨ (Vₛ₁ ⊆ Vₛ₂)) ↔ Subspace(Vₛ₁ ∪ Vₛ₂))


module DifferentArities where

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

f : Nat -> Nat -> Nat
f zero      = \x -> x
f (suc n) m = f n (suc m)


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

open import Categories.Category
open import Categories.Object.Zero

-- Cokernels of morphisms.
-- https://ncatlab.org/nlab/show/cokernel
module Categories.Object.Cokernel {o ℓ e} {𝒞 : Category o ℓ e} (𝟎 : Zero 𝒞) where

open import Level

open import Categories.Morphism 𝒞
open import Categories.Morphism.Reasoning 𝒞
  hiding (glue)

open Category 𝒞
open Zero 𝟎

open HomReasoning

private
  variable
    A B X : Obj
    f h i j k : A ⇒ B

record IsCokernel {A B K} (f : A ⇒ B) (k : B ⇒ K) : Set (o ⊔ ℓ ⊔ e) where
  field
    commute   : k ∘ f ≈ zero⇒
    universal : ∀ {X} {h : B ⇒ X} → h ∘ f ≈ zero⇒ → K ⇒ X
    factors   : ∀ {eq : h ∘ f ≈ zero⇒} → h ≈ universal eq ∘ k
    unique    : ∀ {eq : h ∘ f ≈ zero⇒} → h ≈ i ∘ k → i ≈ universal eq

  universal-resp-≈ : ∀ {eq : h ∘ f ≈ zero⇒} {eq′ : i ∘ f ≈ zero⇒} →
    h ≈ i → universal eq ≈ universal eq′
  universal-resp-≈ h≈i = unique (⟺ h≈i ○ factors)

  universal-∘ : h ∘ k ∘ f ≈ zero⇒
  universal-∘ {h = h} = begin
    h ∘ k ∘ f ≈⟨ refl⟩∘⟨ commute ⟩
    h ∘ zero⇒ ≈⟨ zero-∘ˡ h ⟩
    zero⇒     ∎

record Cokernel {A B} (f : A ⇒ B) : Set (o ⊔ ℓ ⊔ e) where
  field
    {cokernel} : Obj
    cokernel⇒  : B ⇒ cokernel
    isCokernel : IsCokernel f cokernel⇒

  open IsCokernel isCokernel public

IsCokernel⇒Cokernel : IsCokernel f k → Cokernel f
IsCokernel⇒Cokernel {k = k} isCokernel = record
  { cokernel⇒ = k
  ; isCokernel = isCokernel
  }


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

module Categories.Category.Extensive where

-- https://ncatlab.org/nlab/show/extensive+category

open import Level

open import Categories.Category.Core
open import Categories.Diagram.Pullback
open import Categories.Category.Cocartesian
open import Categories.Object.Coproduct
open import Categories.Morphism

record Extensive {o ℓ e : Level} (𝒞 : Category o ℓ e) : Set (suc (o ⊔ ℓ ⊔ e)) where
  open Category 𝒞
  open Pullback

  field
    cocartesian : Cocartesian 𝒞

  module CC = Cocartesian cocartesian
  open CC using (_+_; i₁; i₂; ¡)

  field
    pullback₁ : {A B C : Obj} (f : A ⇒ B + C) → Pullback 𝒞 f i₁
    pullback₂ : {A B C : Obj} (f : A ⇒ B + C) → Pullback 𝒞 f i₂
    pullback-of-cp-is-cp : {A B C : Obj} (f : A ⇒ _+_ B C) → IsCoproduct 𝒞 (p₁ (pullback₁ f)) (p₁ (pullback₂ f))

    pullback₁-is-mono : ∀ {A B : Obj} → Mono 𝒞 (i₁ {A = A}{B = B})
    pullback₂-is-mono : ∀ {A B : Obj} → Mono 𝒞 (i₂ {A = A}{B = B})

    disjoint : ∀ {A B : Obj} → IsPullback 𝒞 ¡ ¡ (i₁ {A = A}{B = B}) i₂


{-# OPTIONS --safe #-}
module Cubical.Data.FinData.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function

import Cubical.Data.Empty as ⊥
open import Cubical.Data.Nat using (ℕ; zero; suc; _+_; _·_; +-assoc)
open import Cubical.Data.Bool.Base
open import Cubical.Relation.Nullary

private
  variable
    ℓ : Level
    A B : Type ℓ

data Fin : ℕ → Type₀ where
  zero : {n : ℕ} → Fin (suc n)
  suc  : {n : ℕ} (i : Fin n) → Fin (suc n)

-- useful patterns
pattern one = suc zero
pattern two = suc one

toℕ : ∀ {n} → Fin n → ℕ
toℕ zero    = 0
toℕ (suc i) = suc (toℕ i)

fromℕ : (n : ℕ) → Fin (suc n)
fromℕ zero    = zero
fromℕ (suc n) = suc (fromℕ n)

toFromId : ∀ (n : ℕ) → toℕ (fromℕ n) ≡ n
toFromId zero = refl
toFromId (suc n) = cong suc (toFromId n)

¬Fin0 : ¬ Fin 0
¬Fin0 ()

_==_ : ∀ {n} → Fin n → Fin n → Bool
zero == zero   = true
zero == suc _  = false
suc _ == zero  = false
suc m == suc n = m == n

weakenFin : {n : ℕ} → Fin n → Fin (suc n)
weakenFin zero = zero
weakenFin (suc i) = suc (weakenFin i)

predFin : {n : ℕ} → Fin (suc (suc n)) → Fin (suc n)
predFin zero = zero
predFin (suc x) = x

foldrFin : ∀ {n} → (A → B → B) → B → (Fin n → A) → B
foldrFin {n = zero}  _ b _ = b
foldrFin {n = suc n} f b l = f (l zero) (foldrFin f b (l ∘ suc))

elim
  : ∀(P : ∀{k} → Fin k → Type ℓ)
  → (∀{k} → P {suc k} zero)
  → (∀{k} → {fn : Fin k} → P fn → P (suc fn))
  → {k : ℕ} → (fn : Fin k) → P fn

elim P fz fs {zero} = ⊥.rec ∘ ¬Fin0
elim P fz fs {suc k} zero = fz
elim P fz fs {suc k} (suc fj) = fs (elim P fz fs fj)

rec : ∀{k} → (a0 aS : A) → Fin k → A
rec a0 aS zero = a0
rec a0 aS (suc x) = aS

FinVec : (A : Type ℓ) (n : ℕ) → Type ℓ
FinVec A n = Fin n → A

replicateFinVec : (n : ℕ) → A → FinVec A n
replicateFinVec _ a _ = a

_++Fin_ : {n m : ℕ} → FinVec A n → FinVec A m → FinVec A (n + m)
_++Fin_ {n = zero} _ W i = W i
_++Fin_ {n = suc n} V _ zero = V zero
_++Fin_ {n = suc n} V W (suc i) = ((V ∘ suc) ++Fin W) i


{-# OPTIONS --safe #-}
module Cubical.Algebra.NatSolver.Examples where

open import Cubical.Foundations.Prelude

open import Cubical.Data.FinData
open import Cubical.Data.Nat
open import Cubical.Data.Vec.Base

open import Cubical.Algebra.NatSolver.NatExpression
open import Cubical.Algebra.NatSolver.HornerForms
open import Cubical.Algebra.NatSolver.Solver
open import Cubical.Algebra.NatSolver.Reflection

private
  variable
    ℓ : Level

module ReflectionSolving where
  _ : (x y : ℕ) → (x + y) · (x + y) ≡ x · x + 2 · x · y + y · y
  _ = solve

  {-
    If you want to use the solver in some more complex situation,
    you have to declare a helper variable (`useSolver` below) that
    is a term of a dependent function type as above:
  -}
  module _ (SomeType : Type ℓ-zero) where
    complexSolverApplication :
      (someStuff : SomeType) → (x y : ℕ) → (moreStuff : SomeType)
      → x + y ≡ y + x
    complexSolverApplication someStuff x y moreStuff = useSolver x y
                              where useSolver : (x y : ℕ) → x + y ≡ y + x
                                    useSolver = solve

module SolvingExplained where
  open EqualityToNormalform renaming (solve to natSolve)
  open IteratedHornerOperations hiding (X)

  ℕ[X₀,X₁] = IteratedHornerForms 2
  X₀ : ℕ[X₀,X₁]
  X₀ = Variable 2 (Fin.zero)

  X₁ : ℕ[X₀,X₁]
  X₁ = Variable 2 (suc Fin.zero)

  Two : ℕ[X₀,X₁]
  Two = Constant 2 2

  _ : eval X₀ (1 ∷ 0 ∷ []) ≡ 1
  _ = refl

  _ : eval X₁ (0 ∷ 1 ∷ []) ≡ 1
  _ = refl

  X : Expr 3
  X = ∣ Fin.zero

  Y : Expr 3
  Y = ∣ (suc Fin.zero)

  Z : Expr 3
  Z = ∣ (suc (suc Fin.zero))

  {-
     'normalize' maps an expression to its Horner Normalform.
     Two expressions evaluating to the same ring element
     have the same Horner Normal form.
     This means equality of the represented ring elements
     can be checked by agda's unification (so refl is a proof)

   -}
  _ : normalize ((K 2) ·' X) ≡
      normalize (X +' X)
  _ = refl

  _ : normalize ((K 2) ·' X) ≡ normalize (X +' X)
  _ = refl

  _ : normalize (((K 2) ·' X) ·' Y) ≡ normalize (Y ·' (X +' X))
  _ = refl

  _ : normalize (Z ·' (((K 2) ·' X) ·' Y)) ≡ normalize (Z ·' (Y ·' (X +' X)))
  _ = refl

  {-
    The solver needs to produce an equality between
    actual ring elements. So we need a proof that
    those actual ring elements are equal to a normal form:
  -}
  _ : (x y z : ℕ) →
      eval (normalize ((K 2) ·' X ·' Y)) (x ∷ y ∷ z ∷ [])
      ≡ 2 · x · y
  _ = λ x y z → isEqualToNormalform ((K 2) ·' X ·' Y) (x ∷ y ∷ z ∷ [])

  {-
    Now two of these proofs can be plugged together
    to solve an equation:
  -}
  open Eval
  _ : (x y z : ℕ) → 3 + x + y · y ≡ y · y + x + 1 + 2
  _ = let
        lhs = (K 3) +' X +' (Y ·' Y)
        rhs = Y ·' Y +' X +' (K 1) +' (K 2)
      in (λ x y z →
          ⟦ lhs ⟧ (x ∷ y ∷ z ∷ [])
        ≡⟨ sym (isEqualToNormalform lhs (x ∷ y ∷ z ∷ [])) ⟩
          eval (normalize lhs) (x ∷ y ∷ z ∷ [])
        ≡⟨ refl ⟩
          eval (normalize rhs) (x ∷ y ∷ z ∷ [])
        ≡⟨ isEqualToNormalform rhs (x ∷ y ∷ z ∷ []) ⟩
          ⟦ rhs ⟧ (x ∷ y ∷ z ∷ []) ∎)

  {-
    Parts of that can be automated easily:
  -}
  _ : (x y z : ℕ) → (x + y) · (x + y) ≡ x · x + 2 · x · y + y · y
  _ = λ x y z → let
              lhs = (X +' Y) ·' (X +' Y)
              rhs = X ·' X +' (K 2) ·' X ·' Y +' Y ·' Y
             in natSolve lhs rhs (x ∷ y ∷ z ∷ []) refl

  {-
    A bigger example
  -}
  _ : (x y z : ℕ) → (x + y) · (x + y) · (x + y) · (x + y)
                ≡ x · x · x · x + 4 · x · x · x · y + 6 · x · x · y · y
                  +  4 · x · y · y · y + y · y · y · y
  _ = λ x y z → let
              lhs = (X +' Y) ·' (X +' Y) ·' (X +' Y) ·' (X +' Y)
              rhs = X ·' X ·' X ·' X
                  +' (K 4) ·' X ·' X ·' X ·' Y
                  +' (K 6) ·' X ·' X ·' Y ·' Y
                  +' (K 4) ·' X ·' Y ·' Y ·' Y
                  +' Y ·' Y ·' Y ·' Y
             in natSolve lhs rhs (x ∷ y ∷ z ∷ []) refl
  {-
    this one cannot work so far:

  _ : (x y z : ℕ) → (x + y) · (x - y) ≡ (x · x - (y · y))
  _ = λ x y z → let
                lhs = (X +' Y) ·' (X +' (-' Y))
                rhs = (X ·' X) +' (-' (Y ·' Y))
              in natSolve lhs rhs (x ∷ y ∷ z ∷ []) {!!}
  -}


module New.Types where

open import Data.Integer public
open import Data.Product public hiding (map)
open import Data.Sum public hiding (map)
infixr 5 _⇒_

data Type : Set where
  _⇒_ : (σ τ : Type) → Type
  int : Type
  pair : (σ τ : Type) → Type
  sum : (σ τ : Type) → Type

⟦_⟧Type : Type → Set
⟦ σ ⇒ τ ⟧Type = ⟦ σ ⟧Type → ⟦ τ ⟧Type
⟦ int ⟧Type = ℤ
⟦ pair σ τ ⟧Type = ⟦ σ ⟧Type × ⟦ τ ⟧Type
⟦ sum σ τ ⟧Type = ⟦ σ ⟧Type ⊎ ⟦ τ ⟧Type

Δt : Type → Type
Δt (σ ⇒ τ) = σ ⇒ Δt σ ⇒ Δt τ
Δt int = int
Δt (pair σ τ) = pair (Δt σ) (Δt τ)
Δt (sum σ τ) = sum (sum (Δt σ) (Δt τ)) (sum σ τ)


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

open import Categories.Category
open import Categories.Category.Complete

module Categories.Category.Complete.Properties.SolutionSet where

open import Level

open import Categories.Functor
open import Categories.Object.Initial
open import Categories.Object.Product.Indexed
open import Categories.Object.Product.Indexed.Properties
open import Categories.Diagram.Equalizer
open import Categories.Diagram.Equalizer.Limit
open import Categories.Diagram.Equalizer.Properties

import Categories.Diagram.Limit as Lim
import Categories.Morphism.Reasoning as MR

private
  variable
    o ℓ e : Level
    o′ ℓ′ e′ : Level
    J : Category o ℓ e

module _ (C : Category o ℓ e) where
  open Category C

  record SolutionSet : Set (o ⊔ ℓ) where
    field
      D : Obj → Obj
      arr : ∀ X → D X ⇒ X

module _ {C : Category o ℓ e} (Com : Complete (o ⊔ ℓ ⊔ o′) (o ⊔ ℓ ⊔ ℓ′) (o ⊔ ℓ ⊔ e′) C) (S : SolutionSet C) where
  private
    module S = SolutionSet S
    module C = Category C

    open S
    open Category C
    open HomReasoning
    open MR C

    W : IndexedProductOf C D
    W = Complete⇒IndexedProductOf C {o′ = ℓ ⊔ o′} {ℓ′ = ℓ ⊔ ℓ′} {e′ = ℓ ⊔ e′} Com D
    module W = IndexedProductOf W

    W⇒W : Set ℓ
    W⇒W = W.X ⇒ W.X

    Warr : IndexedProductOf C {I = W⇒W} λ _ → W.X
    Warr = Complete⇒IndexedProductOf C {o′ = o ⊔ o′} {ℓ′ = o ⊔ ℓ′} {e′ = o ⊔ e′} Com _
    module Warr = IndexedProductOf Warr

    Δ : W.X ⇒ Warr.X
    Δ = Warr.⟨ (λ _ → C.id) ⟩

    Γ : W.X ⇒ Warr.X
    Γ = Warr.⟨ (λ f → f) ⟩

    equalizer : Equalizer C Δ Γ
    equalizer = complete⇒equalizer C Com Δ Γ
    module equalizer = Equalizer equalizer

    prop : (f : W.X ⇒ W.X) → f ∘ equalizer.arr ≈ equalizer.arr
    prop f = begin
      f ∘ equalizer.arr            ≈˘⟨ pullˡ (Warr.commute _ f) ⟩
      Warr.π f ∘ Γ ∘ equalizer.arr ≈˘⟨ refl⟩∘⟨ equalizer.equality ⟩
      Warr.π f ∘ Δ ∘ equalizer.arr ≈⟨ cancelˡ (Warr.commute _ f) ⟩
      equalizer.arr                ∎

    ! : ∀ A → equalizer.obj ⇒ A
    ! A = arr A ∘ W.π A ∘ equalizer.arr

    module _ {A} (f : equalizer.obj ⇒ A) where

      equalizer′ : Equalizer C (! A) f
      equalizer′ = complete⇒equalizer C Com (! A) f
      module equalizer′ = Equalizer equalizer′

      s : W.X ⇒ equalizer′.obj
      s = arr _ ∘ W.π (equalizer′.obj)

      t : W.X ⇒ W.X
      t = equalizer.arr ∘ equalizer′.arr ∘ s

      t′ : equalizer.obj ⇒ equalizer.obj
      t′ = equalizer′.arr ∘ s ∘ equalizer.arr

      t∘eq≈eq∘1 : equalizer.arr ∘ t′ ≈ equalizer.arr ∘ C.id
      t∘eq≈eq∘1 = begin
        equalizer.arr ∘ t′                                   ≈⟨ refl⟩∘⟨ sym-assoc ⟩
        equalizer.arr ∘ (equalizer′.arr ∘ s) ∘ equalizer.arr ≈⟨ sym-assoc ⟩
        t ∘ equalizer.arr                                    ≈⟨ prop _ ⟩
        equalizer.arr                                        ≈˘⟨ identityʳ ⟩
        equalizer.arr ∘ C.id                                 ∎

      t′≈id : t′ ≈ C.id
      t′≈id = Equalizer⇒Mono C equalizer _ _ t∘eq≈eq∘1

      !-unique : ! A ≈ f
      !-unique = equalizer-≈⇒≈ C equalizer′ t′≈id

  SolutionSet⇒Initial : Initial C
  SolutionSet⇒Initial = record
    { ⊥            = equalizer.obj
    ; ⊥-is-initial = record
      { !        = ! _
      ; !-unique = !-unique
      }
    }


------------------------------------------------------------------------
-- Lexicographic induction
------------------------------------------------------------------------

module Induction.Lexicographic where

open import Induction
open import Data.Product

-- The structure of lexicographic induction.

_⊗_ : ∀ {a b} → RecStruct a → RecStruct b → RecStruct (a × b)
_⊗_ RecA RecB P (x , y) =
  -- Either x is constant and y is "smaller", ...
  RecB (λ y' → P (x , y')) y
    ×
  -- ...or x is "smaller" and y is arbitrary.
  RecA (λ x' → ∀ y' → P (x' , y')) x

-- Constructs a recursor builder for lexicographic induction.

[_⊗_] : ∀ {a} {RecA : RecStruct a} → RecursorBuilder RecA →
        ∀ {b} {RecB : RecStruct b} → RecursorBuilder RecB →
        RecursorBuilder (RecA ⊗ RecB)
[_⊗_] {RecA = RecA} recA {RecB = RecB} recB P f (x , y) =
  (p₁ x y p₂x , p₂x)
  where
  p₁ : ∀ x y →
       RecA (λ x' → ∀ y' → P (x' , y')) x →
       RecB (λ y' → P (x , y')) y
  p₁ x y x-rec = recB (λ y' → P (x , y'))
                      (λ y y-rec → f (x , y) (y-rec , x-rec))
                      y

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

  p₂x = p₂ x

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

private

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

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

  ackermann : ℕ → ℕ → ℕ
  ackermann m n = build [ N.rec-builder ⊗ N.rec-builder ]
                        AckPred ack (m , n)
    where
    AckPred : ℕ × ℕ → Set
    AckPred _ = ℕ

    ack : ∀ p → (N.Rec ⊗ N.Rec) AckPred p → AckPred p
    ack (zero  , n)     _                   = 1 + n
    ack (suc m , zero)  (_         , ackm•) = ackm• 1
    ack (suc m , suc n) (ack[1+m]n , ackm•) = ackm• ack[1+m]n


module Numeral.Natural.Proofs where

import Lvl
open import Numeral.Natural
open import Relator.Equals
open import Relator.Equals.Proofs.Equiv
open import Structure.Function
open import Structure.Function.Domain

private variable n : ℕ

[𝐒]-not-0 : (𝐒(n) ≢ 𝟎)
[𝐒]-not-0 ()

𝐒-not-self : (𝐒(n) ≢ n)
𝐒-not-self ()

instance
  [𝐒]-injectivity : Injective(𝐒)
  Injective.proof([𝐒]-injectivity) = congruence₁(𝐏)

instance
  [𝐏][𝐒]-inverseᵣ : Inverseᵣ(𝐏)(𝐒)
  [𝐏][𝐒]-inverseᵣ = intro [≡]-intro


{-# OPTIONS --cubical --safe #-}
module Cubical.HITs.FiniteMultiset.Base where

open import Cubical.Foundations.Prelude
open import Cubical.HITs.SetTruncation
open import Cubical.Foundations.HLevels

private
  variable
    A : Type₀

infixr 5 _∷_

data FMSet (A : Type₀) : Type₀ where
  []    : FMSet A
  _∷_   : (x : A) → (xs : FMSet A) → FMSet A
  comm  : ∀ x y xs → x ∷ y ∷ xs ≡ y ∷ x ∷ xs
  trunc : isSet (FMSet A)

pattern [_] x = x ∷ []

module FMSetElim {ℓ} {B : FMSet A → Type ℓ}
  ([]* : B []) (_∷*_ : (x : A) {xs : FMSet A} → B xs → B (x ∷ xs))
  (comm* : (x y : A) {xs : FMSet A} (b : B xs)
         → PathP (λ i → B (comm x y xs i)) (x ∷* (y ∷* b)) (y ∷* (x ∷* b)))
  (trunc* : (xs : FMSet A) → isSet (B xs)) where

  f : (xs : FMSet A) → B xs
  f [] = []*
  f (x ∷ xs) = x ∷* f xs
  f (comm x y xs i) = comm* x y (f xs) i
  f (trunc xs zs p q i j) =
    isOfHLevel→isOfHLevelDep {n = 2} trunc*  (f xs) (f zs) (cong f p) (cong f q) (trunc xs zs p q) i j

module FMSetElimProp {ℓ} {B : FMSet A → Type ℓ} (BProp : {xs : FMSet A} → isProp (B xs))
  ([]* : B []) (_∷*_ : (x : A) {xs : FMSet A} → B xs → B (x ∷ xs)) where

  f : (xs : FMSet A) → B xs
  f = FMSetElim.f []* _∷*_
        (λ x y {xs} b →
          toPathP (BProp (transp (λ i → B (comm x y xs i)) i0 (x ∷* (y ∷* b))) (y ∷* (x ∷* b))))
        (λ xs → isProp→isSet BProp)

module FMSetRec {ℓ} {B : Type ℓ} (BType : isSet B)
  ([]* : B) (_∷*_ : A → B → B)
  (comm* : (x y : A) (b : B) → x ∷* (y ∷* b) ≡ y ∷* (x ∷* b)) where

  f : FMSet A → B
  f = FMSetElim.f []* (λ x b → x ∷* b) (λ x y b → comm* x y b) (λ _ → BType)


{-# OPTIONS --without-K #-}
module HIT.Interval where

open import PathOperations
open import PathStructure.Id.Tr
open import Types

module I-Definition where
  private
    data #I : Set where
      #0 : #I
      #1 : #I

  I : Set
  I = #I

  0ᵢ : I
  0ᵢ = #0

  1ᵢ : I
  1ᵢ = #1

  postulate
    seg : 0ᵢ ≡ 1ᵢ

  I-ind : ∀ {p} (P : I → Set p)
    (x₀ : P 0ᵢ) (x₁ : P 1ᵢ) (p : tr P seg x₀ ≡ x₁) →
    ∀ i → P i
  I-ind P x₀ x₁ p #0 = x₀
  I-ind P x₀ x₁ p #1 = x₁

  postulate
    I-β-i : ∀ {p} (P : I → Set p)
      (x₀ : P 0ᵢ) (x₁ : P 1ᵢ)
      (p : tr P seg x₀ ≡ x₁) →
      apd (I-ind P x₀ x₁ p) seg ≡ p

  I-rec : ∀ {p} {P : Set p}
    (x₀ x₁ : P) (p : x₀ ≡ x₁)
    (i : I) → P
  I-rec x₀ x₁ p #0 = x₀
  I-rec x₀ x₁ p #1 = x₁

  postulate
    I-β-r : ∀ {p} {P : Set p}
      (x₀ x₁ : P) (p : x₀ ≡ x₁) →
      ap (I-rec x₀ x₁ p) seg ≡ p

open I-Definition public

from-path-space : ∀ {a} {A : Set a} →
  (Σ A λ x → Σ A λ y → x ≡ y) → I → A
from-path-space (x , y , p) = I-rec x y p

to-path-space : ∀ {a} {A : Set a} →
  (I → A) → Σ A λ x → Σ A λ y → x ≡ y
to-path-space f = f 0ᵢ , f 1ᵢ , ap f seg


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

syntax Lens | L

type
  S : 0-ary
  A : 0-ary

term
  get : S  ->  A
  put : S  A  ->  S

theory
  (PG) s : S  a : A   |> get (put (s, a))   = a
  (GP) s : S          |> put (s, get(s))    = s
  (PP) s : S  a b : A |> put (put(s, a), b) = put (s, a)
-}

module Lens.Equality where

open import SOAS.Common
open import SOAS.Context
open import SOAS.Variable
open import SOAS.Families.Core
open import SOAS.Families.Build
open import SOAS.ContextMaps.Inductive

open import Lens.Signature
open import Lens.Syntax

open import SOAS.Metatheory.SecondOrder.Metasubstitution L:Syn
open import SOAS.Metatheory.SecondOrder.Equality L:Syn

private
  variable
    α β γ τ : LT
    Γ Δ Π : Ctx

infix 1 _▹_⊢_≋ₐ_

-- Axioms of equality
data _▹_⊢_≋ₐ_ : ∀ 𝔐 Γ {α} → (𝔐 ▷ L) α Γ → (𝔐 ▷ L) α Γ → Set where
  PG : ⁅ S ⁆ ⁅ A ⁆̣       ▹ ∅ ⊢   get (put 𝔞 𝔟) ≋ₐ 𝔟
  GP : ⁅ S ⁆̣             ▹ ∅ ⊢   put 𝔞 (get 𝔞) ≋ₐ 𝔞
  PP : ⁅ S ⁆ ⁅ A ⁆ ⁅ A ⁆̣ ▹ ∅ ⊢ put (put 𝔞 𝔟) 𝔠 ≋ₐ put 𝔞 𝔟

open EqLogic _▹_⊢_≋ₐ_
open ≋-Reasoning


{-# OPTIONS --cubical --no-import-sorts --no-exact-split --safe #-}
module Cubical.Data.Nat.Order where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels

open import Cubical.Data.Empty as ⊥
open import Cubical.Data.Sigma
open import Cubical.Data.Sum as ⊎

open import Cubical.Data.Nat.Base
open import Cubical.Data.Nat.Properties

open import Cubical.Induction.WellFounded

open import Cubical.Relation.Nullary

infix 4 _≤_ _<_

_≤_ : ℕ → ℕ → Type₀
m ≤ n = Σ[ k ∈ ℕ ] k + m ≡ n

_<_ : ℕ → ℕ → Type₀
m < n = suc m ≤ n

data Trichotomy (m n : ℕ) : Type₀ where
  lt : m < n → Trichotomy m n
  eq : m ≡ n → Trichotomy m n
  gt : n < m → Trichotomy m n

private
  variable
    k l m n : ℕ

private
  witness-prop : ∀ j → isProp (j + m ≡ n)
  witness-prop {m} {n} j = isSetℕ (j + m) n

m≤n-isProp : isProp (m ≤ n)
m≤n-isProp {m} {n} (k , p) (l , q)
  = Σ≡Prop witness-prop lemma
  where
  lemma : k ≡ l
  lemma = inj-+m (p ∙ (sym q))

zero-≤ : 0 ≤ n
zero-≤ {n} = n , +-zero n

suc-≤-suc : m ≤ n → suc m ≤ suc n
suc-≤-suc (k , p) = k , (+-suc k _) ∙ (cong suc p)

≤-+k : m ≤ n → m + k ≤ n + k
≤-+k {m} {k = k} (i , p)
  = i , +-assoc i m k ∙ cong (_+ k) p

≤-k+ : m ≤ n → k + m ≤ k + n
≤-k+ {m} {n} {k}
  = subst (_≤ k + n) (+-comm m k)
  ∘ subst (m + k ≤_) (+-comm n k)
  ∘ ≤-+k

pred-≤-pred : suc m ≤ suc n → m ≤ n
pred-≤-pred (k , p) = k , injSuc ((sym (+-suc k _)) ∙ p)

≤-refl : m ≤ m
≤-refl = 0 , refl

≤-suc : m ≤ n → m ≤ suc n
≤-suc (k , p) = suc k , cong suc p

≤-predℕ : predℕ n ≤ n
≤-predℕ {zero} = ≤-refl
≤-predℕ {suc n} = ≤-suc ≤-refl

≤-trans : k ≤ m → m ≤ n → k ≤ n
≤-trans {k} {m} {n} (i , p) (j , q) = i + j , l2 ∙ (l1 ∙ q)
  where
  l1 : j + i + k ≡ j + m
  l1 = (sym (+-assoc j i k)) ∙ (cong (j +_) p)
  l2 : i + j + k ≡ j + i + k
  l2 = cong (_+ k) (+-comm i j)

≤-antisym : m ≤ n → n ≤ m → m ≡ n
≤-antisym {m} (i , p) (j , q) = (cong (_+ m) l3) ∙ p
  where
  l1 : j + i + m ≡ m
  l1 = (sym (+-assoc j i m)) ∙ ((cong (j +_) p) ∙ q)
  l2 : j + i ≡ 0
  l2 = m+n≡n→m≡0 l1
  l3 : 0 ≡ i
  l3 = sym (snd (m+n≡0→m≡0×n≡0 l2))

≤-k+-cancel : k + m ≤ k + n → m ≤ n
≤-k+-cancel {k} {m} (l , p) = l , inj-m+ (sub k m ∙ p)
 where
 sub : ∀ k m → k + (l + m) ≡ l + (k + m)
 sub k m = +-assoc k l m ∙ cong (_+ m) (+-comm k l) ∙ sym (+-assoc l k m)

≤-+k-cancel : m + k ≤ n + k → m ≤ n
≤-+k-cancel {m} {k} {n} (l , p) = l , cancelled
 where
 cancelled : l + m ≡ n
 cancelled = inj-+m (sym (+-assoc l m k) ∙ p)

≤-·k : m ≤ n → m · k ≤ n · k
≤-·k {m} {n} {k} (d , r) = d · k , reason where
  reason : d · k + m · k ≡ n · k
  reason = d · k + m · k ≡⟨ ·-distribʳ d m k ⟩
           (d + m) · k   ≡⟨ cong (_· k) r ⟩
           n · k         ∎

<-k+-cancel : k + m < k + n → m < n
<-k+-cancel {k} {m} {n} = ≤-k+-cancel ∘ subst (_≤ k + n) (sym (+-suc k m))

¬-<-zero : ¬ m < 0
¬-<-zero (k , p) = snotz ((sym (+-suc k _)) ∙ p)

¬m<m : ¬ m < m
¬m<m {m} = ¬-<-zero ∘ ≤-+k-cancel {k = m}

≤0→≡0 : n ≤ 0 → n ≡ 0
≤0→≡0 {zero} ineq = refl
≤0→≡0 {suc n} ineq = ⊥.rec (¬-<-zero ineq)

predℕ-≤-predℕ : m ≤ n → (predℕ m) ≤ (predℕ n)
predℕ-≤-predℕ {zero} {zero}   ineq = ≤-refl
predℕ-≤-predℕ {zero} {suc n}  ineq = zero-≤
predℕ-≤-predℕ {suc m} {zero}  ineq = ⊥.rec (¬-<-zero ineq)
predℕ-≤-predℕ {suc m} {suc n} ineq = pred-≤-pred ineq

¬m+n<m : ¬ m + n < m
¬m+n<m {m} {n} = ¬-<-zero ∘ <-k+-cancel ∘ subst (m + n <_) (sym (+-zero m))

<-weaken : m < n → m ≤ n
<-weaken (k , p) = suc k , sym (+-suc k _) ∙ p

≤<-trans : l ≤ m → m < n → l < n
≤<-trans p = ≤-trans (suc-≤-suc p)

<≤-trans : l < m → m ≤ n → l < n
<≤-trans = ≤-trans

<-trans : l < m → m < n → l < n
<-trans p = ≤<-trans (<-weaken p)

<-asym : m < n → ¬ n ≤ m
<-asym m<n = ¬m<m ∘ <≤-trans m<n

<-+k : m < n → m + k < n + k
<-+k p = ≤-+k p

<-k+ : m < n → k + m < k + n
<-k+ {m} {n} {k} p = subst (λ km → km ≤ k + n) (+-suc k m) (≤-k+ p)

<-·sk : m < n → m · suc k < n · suc k
<-·sk {m} {n} {k} (d , r) = (d · suc k + k) , reason where
  reason : (d · suc k + k) + suc (m · suc k) ≡ n · suc k
  reason = (d · suc k + k) + suc (m · suc k) ≡⟨ sym (+-assoc (d · suc k) k _) ⟩
           d · suc k + (k + suc (m · suc k)) ≡[ i ]⟨ d · suc k + +-suc k (m · suc k) i ⟩
           d · suc k + suc m · suc k         ≡⟨ ·-distribʳ d (suc m) (suc k) ⟩
           (d + suc m) · suc k               ≡⟨ cong (_· suc k) r ⟩
           n · suc k                         ∎

≤-∸-+-cancel : m ≤ n → (n ∸ m) + m ≡ n
≤-∸-+-cancel {zero} {n} _ = +-zero _
≤-∸-+-cancel {suc m} {zero} m≤n = ⊥.rec (¬-<-zero m≤n)
≤-∸-+-cancel {suc m} {suc n} m+1≤n+1 = +-suc _ _ ∙ cong suc (≤-∸-+-cancel (pred-≤-pred m+1≤n+1))

left-≤-max : m ≤ max m n
left-≤-max {zero} {n} = zero-≤
left-≤-max {suc m} {zero} = ≤-refl
left-≤-max {suc m} {suc n} = suc-≤-suc left-≤-max

right-≤-max : n ≤ max m n
right-≤-max {zero} {m} = zero-≤
right-≤-max {suc n} {zero} = ≤-refl
right-≤-max {suc n} {suc m} = suc-≤-suc right-≤-max

min-≤-left : min m n ≤ m
min-≤-left {zero} {n} = ≤-refl
min-≤-left {suc m} {zero} = zero-≤
min-≤-left {suc m} {suc n} = suc-≤-suc min-≤-left

min-≤-right : min m n ≤ n
min-≤-right {zero} {n} = zero-≤
min-≤-right {suc m} {zero} = ≤-refl
min-≤-right {suc m} {suc n} = suc-≤-suc min-≤-right

Trichotomy-suc : Trichotomy m n → Trichotomy (suc m) (suc n)
Trichotomy-suc (lt m<n) = lt (suc-≤-suc m<n)
Trichotomy-suc (eq m=n) = eq (cong suc m=n)
Trichotomy-suc (gt n<m) = gt (suc-≤-suc n<m)

_≟_ : ∀ m n → Trichotomy m n
zero ≟ zero = eq refl
zero ≟ suc n = lt (n , +-comm n 1)
suc m ≟ zero = gt (m , +-comm m 1)
suc m ≟ suc n = Trichotomy-suc (m ≟ n)

<-split : m < suc n → (m < n) ⊎ (m ≡ n)
<-split {n = zero} = inr ∘ snd ∘ m+n≡0→m≡0×n≡0 ∘ snd ∘ pred-≤-pred
<-split {zero} {suc n} = λ _ → inl (suc-≤-suc zero-≤)
<-split {suc m} {suc n} = ⊎.map suc-≤-suc (cong suc) ∘ <-split ∘ pred-≤-pred

private
  acc-suc : Acc _<_ n → Acc _<_ (suc n)
  acc-suc a
    = acc λ y y<sn
    → case <-split y<sn of λ
    { (inl y<n) → access a y y<n
    ; (inr y≡n) → subst _ (sym y≡n) a
    }

<-wellfounded : WellFounded _<_
<-wellfounded zero = acc λ _ → ⊥.rec ∘ ¬-<-zero
<-wellfounded (suc n) = acc-suc (<-wellfounded n)

<→≢ : n < m → ¬ n ≡ m
<→≢ {n} {m} p q = ¬m<m (subst (_< m) q p)

module _
    (b₀ : ℕ)
    (P : ℕ → Type₀)
    (base : ∀ n → n < suc b₀ → P n)
    (step : ∀ n → P n → P (suc b₀ + n))
  where
  open WFI (<-wellfounded)

  private
    dichotomy : ∀ b n → (n < b) ⊎ (Σ[ m ∈ ℕ ] n ≡ b + m)
    dichotomy b n
      = case n ≟ b return (λ _ → (n < b) ⊎ (Σ[ m ∈ ℕ ] n ≡ b + m)) of λ
      { (lt o) → inl o
      ; (eq p) → inr (0 , p ∙ sym (+-zero b))
      ; (gt (m , p)) → inr (suc m , sym p ∙ +-suc m b ∙ +-comm (suc m) b)
      }

    dichotomy<≡ : ∀ b n → (n<b : n < b) → dichotomy b n ≡ inl n<b
    dichotomy<≡ b n n<b
      = case dichotomy b n return (λ d → d ≡ inl n<b) of λ
      { (inl x) → cong inl (m≤n-isProp x n<b)
      ; (inr (m , p)) → ⊥.rec (<-asym n<b (m , sym (p ∙ +-comm b m)))
      }

    dichotomy+≡ : ∀ b m n → (p : n ≡ b + m) → dichotomy b n ≡ inr (m , p)
    dichotomy+≡ b m n p
      = case dichotomy b n return (λ d → d ≡ inr (m , p)) of λ
      { (inl n<b) → ⊥.rec (<-asym n<b (m , +-comm m b ∙ sym p))
      ; (inr (m' , q))
      → cong inr (Σ≡Prop (λ x → isSetℕ n (b + x)) (inj-m+ {m = b} (sym q ∙ p)))
      }

    b = suc b₀

    lemma₁ : ∀{x y z} → x ≡ suc z + y → y < x
    lemma₁ {y = y} {z} p = z , +-suc z y ∙ sym p

    subStep : (n : ℕ) → (∀ m → m < n → P m) → (n < b) ⊎ (Σ[ m ∈ ℕ ] n ≡ b + m) → P n
    subStep n _   (inl l) = base n l
    subStep n rec (inr (m , p))
      = transport (cong P (sym p)) (step m (rec m (lemma₁ p)))

    wfStep : (n : ℕ) → (∀ m → m < n → P m) → P n
    wfStep n rec = subStep n rec (dichotomy b n)

    wfStepLemma₀ : ∀ n (n<b : n < b) rec → wfStep n rec ≡ base n n<b
    wfStepLemma₀ n n<b rec = cong (subStep n rec) (dichotomy<≡ b n n<b)

    wfStepLemma₁ : ∀ n rec → wfStep (b + n) rec ≡ step n (rec n (lemma₁ refl))
    wfStepLemma₁ n rec
      = cong (subStep (b + n) rec) (dichotomy+≡ b n (b + n) refl)
      ∙ transportRefl _

  +induction : ∀ n → P n
  +induction = induction wfStep

  +inductionBase : ∀ n → (l : n < b) → +induction n ≡ base n l
  +inductionBase n l = induction-compute wfStep n ∙ wfStepLemma₀ n l _

  +inductionStep : ∀ n → +induction (b + n) ≡ step n (+induction n)
  +inductionStep n = induction-compute wfStep (b + n) ∙ wfStepLemma₁ n _

module <-Reasoning where
  -- TODO: would it be better to mirror the way it is done in the agda-stdlib?
  infixr 2 _<⟨_⟩_ _≤<⟨_⟩_ _≤⟨_⟩_ _<≤⟨_⟩_ _≡<⟨_⟩_ _≡≤⟨_⟩_ _<≡⟨_⟩_ _≤≡⟨_⟩_
  _<⟨_⟩_ : ∀ k → k < n → n < m → k < m
  _ <⟨ p ⟩ q = <-trans p q

  _≤<⟨_⟩_ : ∀ k → k ≤ n → n < m → k < m
  _ ≤<⟨ p ⟩ q = ≤<-trans p q

  _≤⟨_⟩_ : ∀ k → k ≤ n → n ≤ m → k ≤ m
  _ ≤⟨ p ⟩ q = ≤-trans p q

  _<≤⟨_⟩_ : ∀ k → k < n → n ≤ m → k < m
  _ <≤⟨ p ⟩ q = <≤-trans p q

  _≡≤⟨_⟩_ : ∀ k → k ≡ l → l ≤ m → k ≤ m
  _ ≡≤⟨ p ⟩ q = subst (λ k → k ≤ _) (sym p) q

  _≡<⟨_⟩_ : ∀ k → k ≡ l → l < m → k < m
  _ ≡<⟨ p ⟩ q = _ ≡≤⟨ cong suc p ⟩ q

  _≤≡⟨_⟩_ : ∀ k → k ≤ l → l ≡ m → k ≤ m
  _ ≤≡⟨ p ⟩ q = subst (λ l → _ ≤ l) q p

  _<≡⟨_⟩_ : ∀ k → k < l → l ≡ m → k < m
  _ <≡⟨ p ⟩ q = _ ≤≡⟨ p ⟩ q