module sum where

open import level
open import bool
open import eq
open import maybe
open import product

----------------------------------------------------------------------
-- datatypes
----------------------------------------------------------------------

data _⊎_ {ℓ ℓ'} (A : Set ℓ) (B : Set ℓ') : Set (ℓ ⊔ ℓ') where
  inj₁ : (x : A) → A ⊎ B
  inj₂ : (y : B) → A ⊎ B

_∨_ : ∀ {ℓ ℓ'} (A : Set ℓ) (B : Set ℓ') → Set (ℓ ⊔ ℓ')
_∨_ = _⊎_

----------------------------------------------------------------------
-- syntax
----------------------------------------------------------------------

infixr 0 _⊎_ _∨_

----------------------------------------------------------------------
-- operations
----------------------------------------------------------------------

_≫=⊎_ : ∀ {ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'}{C : Set (ℓ ⊔ ℓ')}  → A ⊎ B → (B → A ⊎ C) → A ⊎ C
inj₁ x ≫=⊎ f = inj₁ x
inj₂ x ≫=⊎ f = f x

return⊎ : ∀ {ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'} → B → A ⊎ B
return⊎ b = inj₂ b

infix 5 error⊎_

error⊎_ : ∀ {ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'} → A → A ⊎ B
error⊎_ a = inj₁ a

extract-inj₁≡ : ∀{ℓ}{ℓ'}{A : Set ℓ}{B : Set ℓ'}{a a' : A} → inj₁{B = B} a ≡ inj₁ a' → a ≡ a'
extract-inj₁≡ refl = refl

extract-inj₂≡ : ∀{ℓ}{ℓ'}{A : Set ℓ}{B : Set ℓ'}{b b' : B} → inj₂{A = A} b ≡ inj₂ b' → b ≡ b'
extract-inj₂≡ refl = refl

=⊎ : ∀{ℓ}{ℓ'}{A : Set ℓ}{B : Set ℓ'} → (A → A → 𝔹) → (B → B → 𝔹) → A ⊎ B → A ⊎ B → 𝔹
=⊎ eqa eqb (inj₁ a) (inj₁ a') = eqa a a'
=⊎ eqa eqb (inj₂ b) (inj₂ b') = eqb b b'
=⊎ _ _ _ _ = ff

=⊎-to-≡ : ∀{ℓ}{ℓ'}{A : Set ℓ}{B : Set ℓ'} → (_eqa_ : A → A → 𝔹) → (_eqb_ : B → B → 𝔹) → ((a a' : A) → (a eqa a' ≡ tt) → a ≡ a') → ((b b' : B) → (b eqb b' ≡ tt) → b ≡ b') →  (x y : A ⊎ B) → =⊎ _eqa_ _eqb_ x y  ≡ tt → x ≡ y
=⊎-to-≡ eqa eqb risea riseb (inj₁ a) (inj₁ a') p rewrite risea a a' p = refl
=⊎-to-≡ eqa eqb risea riseb (inj₂ b) (inj₂ b') p rewrite riseb b b' p = refl
=⊎-to-≡ eqa eqb risea riseb (inj₁ a) (inj₂ b) ()
=⊎-to-≡ eqa eqb risea riseb (inj₂ b) (inj₁ a) ()

≡⊎-to-= : ∀{ℓ}{ℓ'}{A : Set ℓ}{B : Set ℓ'} → (_eqa_ : A → A → 𝔹) → (_eqb_ : B → B → 𝔹) → ((a a' : A) → a ≡ a' → a eqa a' ≡ tt) → ((b b' : B) → b ≡ b' → b eqb b' ≡ tt) →  (x y : A ⊎ B) → x ≡ y → =⊎ _eqa_ _eqb_ x y  ≡ tt
≡⊎-to-= eqa eqb dropa dropb (inj₁ a) (inj₁ a') p = dropa a a' (extract-inj₁≡ p)
≡⊎-to-= eqa eqb dropa dropb (inj₂ b) (inj₂ b') p = dropb b b' (extract-inj₂≡ p)
≡⊎-to-= eqa eqb dropa dropb (inj₁ a) (inj₂ b) ()
≡⊎-to-= eqa eqb dropa dropb (inj₂ b) (inj₁ a) ()


-- Andreas, 2011-04-05
module EtaContractToMillerPattern where

data _==_ {A : Set}(a : A) : A -> Set where
  refl : a == a

record Prod (A B : Set) : Set where
  constructor _,_
  field fst : A
        snd : B
open Prod

postulate A B C : Set

test : let X : (Prod A B -> C) -> (Prod A B -> C)
           X = _
       in (x : Prod A B -> C) ->
            X (\ z -> x (fst z , snd z)) == x
test x = refl
-- eta contracts unification problem to  X x = x


module Structure.Relator.Function where

import      Lvl
open import Lang.Instance
open import Logic
open import Logic.Propositional
open import Logic.Predicate
open import Functional
open import Structure.Setoid
open import Structure.Setoid.Uniqueness
open import Structure.Relator
open import Type

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

module _ {A : Type{ℓₒ₁}}{B : Type{ℓₒ₂}} ⦃ equiv-B : Equiv{ℓₑ₂}(B) ⦄ (φ : A → B → Stmt{ℓₒ₃}) where
  module _ (f : A → B) where
    record Computable : Stmt{ℓₒ₁ Lvl.⊔ ℓₒ₂ Lvl.⊔ ℓₒ₃ Lvl.⊔ ℓₑ₂} where
      constructor intro
      field proof : ∀{x}{y} → (f(x) ≡ y) → φ(x)(y)
    computable = inst-fn Computable.proof

  -- A binary operation is total when every LHS have at least one RHS in which the relation holds.
  record Total : Stmt{ℓₒ₁ Lvl.⊔ ℓₒ₂ Lvl.⊔ ℓₒ₃} where
    constructor intro
    field proof : ∀{x} → ∃(y ↦ φ(x)(y))

    compute : A → B
    compute(x) = [∃]-witness(proof{x})

    computableFunction : ⦃ _ : ∀{x} → UnaryRelator(φ(x)) ⦄ → ∃(Computable)
    ∃.witness computableFunction = compute
    Computable.proof (∃.proof computableFunction) {x} eq = substitute₁(φ(x)) eq ([∃]-proof(proof{x}))
  total = inst-fn Total.proof

  -- A binary operation is a function when every LHS have at least one RHS in which the relation holds.
  record Function : Stmt{ℓₒ₁ Lvl.⊔ ℓₒ₂ Lvl.⊔ ℓₒ₃ Lvl.⊔ ℓₑ₂} where
    constructor intro
    field proof : ∀{x} → Unique(φ(x))
  function = inst-fn Function.proof
  -- (∀{x}{y₁ y₂} → φ(x)(y₁) → φ(x)(y₂) → (y₁ ≡ y₂))

  totalFunction : ⦃ _ : Total ⦄ → ⦃ _ : Function ⦄ → (∀{x} → ∃!(φ(x)))
  totalFunction = [∧]-intro total function


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

module Algebra.Construct.Free.Semilattice.Definition where

open import Prelude

infixr 5 _∷_
data 𝒦 (A : Type a) : Type a where
  []   : 𝒦 A
  _∷_  : A → 𝒦 A → 𝒦 A
  com   : ∀ x y xs → x ∷ y ∷ xs ≡ y ∷ x ∷ xs
  dup   : ∀ x xs → x ∷ x ∷ xs ≡ x ∷ xs
  trunc : isSet (𝒦 A)


--- Sample Sit file

{-# OPTIONS --experimental-irrelevance #-}
{-# OPTIONS --sized-types #-}

open import Base

--; --- Leibniz-equality

Eq : forall (A : Set) (a b : A) -> Set1 --;
Eq = \ A a b -> (P : A -> Set) -> (P a) -> P b

--; --- Reflexivity

refl : forall (A : Set) (a : A) -> Eq A a a --;
refl = \ A a P pa -> pa

--; --- Symmetry

sym : forall (A : Set) (a b : A) -> Eq A a b -> Eq A b a --;
sym = \ A a b eq P pb ->  eq (\ x -> P x -> P a) (\ pa -> pa) pb

--; --- Transitivity

trans : forall (A : Set) (a b c : A) -> Eq A a b -> Eq A b c -> Eq A a c --;
trans = \ A a b c p q P pa -> q P (p P pa)

--; --- Congruence

cong : forall (A B : Set) (f : A -> B) (a a' : A) -> Eq A a a' -> Eq B (f a) (f a') --;
cong = \ A B f a a' eq P pfa -> eq (\ x -> P (f x)) pfa

--; --- Addition

plus : forall .i -> Nat i -> Nat oo -> Nat oo --;
plus = \ i x y ->
  fix (\ i x -> Nat oo)
      (\ _ f -> \
              { (zero _)   -> y
              ; (suc _ x) -> suc oo (f x)
              })
      x

--; --- Unit tests for plus

inc : Nat oo -> Nat oo --;
inc = \ x -> suc oo x  --;

one : Nat oo        --;
one = inc (zero oo) --;

two : Nat oo  --;
two = inc one --;

three : Nat oo  --;
three = inc two --;

four : Nat oo  --;
four = inc three --;

five : Nat oo  --;
five = inc four --;

six : Nat oo  --;
six = inc five --;

plus_one_zero : Eq (Nat oo) (plus oo one (zero oo)) one --;
plus_one_zero = refl (Nat oo) one  --;

plus_one_one : Eq (Nat oo) (plus oo one one) two --;
plus_one_one = refl (Nat oo) two  --;

--; --- Reduction rules for plus

plus_red_zero : forall .i (y : Nat oo) -> Eq (Nat oo) (plus (i + 1) (zero i) y) y  --;
plus_red_zero = \ i y -> refl (Nat oo) y  --;

plus_red_suc : forall .i (x : Nat i) (y : Nat oo) -> Eq (Nat oo) (plus (i + 1) (suc i x) y) (suc oo (plus i x y))  --;
plus_red_suc = \ i x y -> refl (Nat oo) (suc oo (plus i x y))  --;

--; --- Law: x + 0 = x

plus_zero : forall .i (x : Nat i) -> Eq (Nat oo) (plus i x (zero oo)) x  --;
plus_zero = \ i x ->
  fix (\ i x -> Eq (Nat oo) (plus i x (zero oo)) x)
      (\ j f -> \
         { (zero _)  -> refl (Nat oo) (zero oo)
         ; (suc _ y) -> cong (Nat oo) (Nat oo) inc (plus j y (zero oo)) y (f y)
         })
      x

--; --- Law: x + suc y = suc x + y

plus_suc : forall .i (x : Nat i) (y : Nat oo) -> Eq (Nat oo) (plus i x (inc y)) (inc (plus i x y))  --;
plus_suc = \ i x y ->
  fix (\ i x -> Eq (Nat oo) (plus i x (inc y)) (inc (plus i x y)))
      (\ j f -> \
         { (zero _)  -> refl (Nat oo) (inc y)
         ; (suc _ x') -> cong (Nat oo) (Nat oo) inc (plus j x' (inc y)) (inc (plus j x' y)) (f x')
         })
      x

--; --- Another definition of addition

plus' : forall .i -> Nat i -> Nat oo -> Nat oo  --;
plus' = \ i x ->
  fix (\ i x -> Nat oo -> Nat oo)
      (\ _ f -> \
         { (zero _)  -> \ y -> y
         ; (suc _ x) -> \ y -> suc oo (f x y)
         })
      x

--; --- Predecessor

pred  : forall .i -> Nat i -> Nat i  --;
pred = \ i n ->
  fix (\ i _ -> Nat i)
      (\ i _ -> \{ (zero _) -> zero i ; (suc _ y) -> y })
      n

--; --- Subtraction

sub : forall .j -> Nat j -> forall .i -> Nat i -> Nat i  --;
sub = \ j y ->
  fix (\ _ _ -> forall .i -> Nat i -> Nat i)
      (\ _ f -> \
        { (zero _) -> \ i x -> x
        ; (suc _ y) -> \ i x -> f y i (pred i x)
        }) --- pred i (f y i x) })
      y

--; --- Lemma: x - x == 0

sub_diag : forall .i (x : Nat i) -> Eq (Nat oo) (sub i x i x) (zero oo)  --;
sub_diag = \ i x ->
  fix (\ i x -> Eq (Nat oo) (sub i x i x) (zero oo))
      (\ _ f -> \
        { (zero _) -> refl (Nat oo) (zero oo)
        ; (suc _ y) -> f y
        })
      x

--- Large eliminations

--; --- Varying arity

Fun : forall .i (n : Nat i) (A : Set) (B : Set) -> Set --;
Fun = \ i n A B ->
  fix (\ _ _ -> Set)
      (\ _ f -> \
         { (zero _) -> B
         ; (suc _ x) -> A -> f x
         })
      n

--; --- Type of n-ary Sum function

Sum : forall .i (n : Nat i) -> Set  --;
Sum = \ i n -> Nat oo -> Fun i n (Nat oo) (Nat oo)

--; --- n-ary summation function

sum : forall .i (n : Nat i) -> Sum i n --;
sum = \ _ n ->
  fix (\ i n -> Sum i n)
      (\ _ f -> \
        { (zero _) -> \ acc -> acc
        ; (suc _ x) -> \ acc -> \ k -> f x (plus oo k acc)
        })
      n

--; --- Testing sum

sum123 : Eq (Nat oo) (sum oo three (zero oo) one two three) six --;
sum123 = refl (Nat oo) six


module Formalization.LambdaCalculus.Semantics where

open import Data
open import Formalization.LambdaCalculus
open import Syntax.Number
open import Type

-- A value in the language of lambda calculus is a irreducible term by a standard reduction definition.
-- It can also be defined as terms that are lambda abstractions because an application of a lambda is supposed to be β-reducible.
data Value : Expression → Type{0} where
  instance abs : ∀{body : Term(1)} → Value(Abstract body)


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

open import lib.Basics
open import lib.types.Group
open import lib.types.CommutingSquare
open import lib.groups.Homomorphism
open import lib.groups.Isomorphism

module lib.groups.CommutingSquare where

-- A new type to keep the parameters.
record CommSquareᴳ {i₀ i₁ j₀ j₁}
  {G₀ : Group i₀} {G₁ : Group i₁} {H₀ : Group j₀} {H₁ : Group j₁}
  (φ₀ : G₀ →ᴳ H₀) (φ₁ : G₁ →ᴳ H₁) (ξG : G₀ →ᴳ G₁) (ξH : H₀ →ᴳ H₁)
  : Type (lmax (lmax i₀ i₁) (lmax j₀ j₁)) where
  constructor comm-sqrᴳ
  field
    commutesᴳ : ∀ g₀ → GroupHom.f (ξH ∘ᴳ φ₀) g₀ == GroupHom.f (φ₁ ∘ᴳ ξG) g₀

infix 0 _□$ᴳ_
_□$ᴳ_ = CommSquareᴳ.commutesᴳ

CommSquareᴳ-∘v : ∀ {i₀ i₁ i₂ j₀ j₁ j₂}
  {G₀ : Group i₀} {G₁ : Group i₁} {G₂ : Group i₂}
  {H₀ : Group j₀} {H₁ : Group j₁} {H₂ : Group j₂}
  {φ : G₀ →ᴳ H₀} {ψ : G₁ →ᴳ H₁} {χ : G₂ →ᴳ H₂}
  {ξG : G₀ →ᴳ G₁} {ξH : H₀ →ᴳ H₁}
  {μA : G₁ →ᴳ G₂} {μB : H₁ →ᴳ H₂}
  → CommSquareᴳ ψ χ μA μB
  → CommSquareᴳ φ ψ ξG ξH
  → CommSquareᴳ φ χ (μA ∘ᴳ ξG) (μB ∘ᴳ ξH)
CommSquareᴳ-∘v {ξG = ξG} {μB = μB} (comm-sqrᴳ □₁₂) (comm-sqrᴳ □₀₁) =
  comm-sqrᴳ λ g₀ → ap (GroupHom.f μB) (□₀₁ g₀) ∙ □₁₂ (GroupHom.f ξG g₀)

CommSquareᴳ-inverse-v : ∀ {i₀ i₁ j₀ j₁}
  {G₀ : Group i₀} {G₁ : Group i₁} {H₀ : Group j₀} {H₁ : Group j₁}
  {φ₀ : G₀ →ᴳ H₀} {φ₁ : G₁ →ᴳ H₁} {ξG : G₀ →ᴳ G₁} {ξH : H₀ →ᴳ H₁}
  → CommSquareᴳ φ₀ φ₁ ξG ξH
  → (ξG-ise : is-equiv (GroupHom.f ξG)) (ξH-ise : is-equiv (GroupHom.f ξH))
  → CommSquareᴳ φ₁ φ₀ (GroupIso.g-hom (ξG , ξG-ise)) (GroupIso.g-hom (ξH , ξH-ise))
CommSquareᴳ-inverse-v (comm-sqrᴳ □) ξG-ise ξH-ise =
  comm-sqrᴳ (commutes (CommSquare-inverse-v (comm-sqr □) ξG-ise ξH-ise))


------------------------------------------------------------------------
-- The Agda standard library
--
-- An inductive definition of the sublist relation with respect to a
-- setoid which is decidable. This is a generalisation of what is
-- commonly known as Order Preserving Embeddings (OPE).
------------------------------------------------------------------------

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

open import Relation.Binary

module Data.List.Relation.Binary.Sublist.DecSetoid
  {c ℓ} (S : DecSetoid c ℓ) where

import Data.List.Relation.Binary.Equality.DecSetoid as DecSetoidEquality
import Data.List.Relation.Binary.Sublist.Setoid as SetoidSublist
import Data.List.Relation.Binary.Sublist.Heterogeneous.Properties
  as HeterogeneousProperties
open import Level using (_⊔_)

open DecSetoid S
open DecSetoidEquality S

------------------------------------------------------------------------
-- Re-export core definitions

open SetoidSublist setoid public

------------------------------------------------------------------------
-- Additional relational properties

_⊆?_ : Decidable _⊆_
_⊆?_ = HeterogeneousProperties.sublist? _≟_

⊆-isDecPartialOrder : IsDecPartialOrder _≋_ _⊆_
⊆-isDecPartialOrder = record
  { isPartialOrder = ⊆-isPartialOrder
  ; _≟_            = _≋?_
  ; _≤?_           = _⊆?_
  }

⊆-decPoset : DecPoset c (c ⊔ ℓ) (c ⊔ ℓ)
⊆-decPoset = record
  { isDecPartialOrder = ⊆-isDecPartialOrder
  }


open import Logic
open import Structure.Setoid
open import Structure.Operator.Ring
open import Structure.OrderedField
open import Type

module Structure.OrderedField.AbsoluteValue
  {ℓ ℓₗ ℓₑ}
  {F : Type{ℓ}}
  ⦃ equiv : Equiv{ℓₑ}(F) ⦄
  (_+_ _⋅_ : F → F → F)
  (_≤_ : F → F → Stmt{ℓₗ})
  ⦃ ring : Ring(_+_)(_⋅_) ⦄ -- TODO: The definition does not require a ring, only some kind of total order compatible with an operation with an identity and an inverse
  -- ⦃ identity : Identity(_+_) ⦄
  -- ⦃ inverseFunction : InverseFunction(_+_)(−_) ⦄
  ⦃ ordered : Ordered(_+_)(_⋅_)(_≤_) ⦄
  where

open Ring(ring)
open Ordered(ordered)

import      Lvl
open import Data.Boolean
open import Data.Boolean.Proofs
import      Data.Either as Either
open import Functional
open import Logic.IntroInstances
open import Logic.Propositional
open import Structure.Function.Domain
open import Structure.Function.Ordering
open import Structure.Function
open import Structure.Operator
open import Structure.Operator.Proofs
open import Structure.Operator.Properties
open import Structure.Operator.Ring.Proofs
open import Structure.Relator.Properties
open import Syntax.Implication
open import Syntax.Transitivity

‖_‖ : F → F
‖ x ‖ = if Either.isRight(converseTotal(_≤_){𝟎}{x}) then (− x) else x

instance
  abs-function : Function(‖_‖)
  Function.congruence abs-function {x}{y} xy with converseTotal(_≤_){𝟎}{x} | converseTotal(_≤_){𝟎}{y}
  ... | Either.Left  p | Either.Left  q = xy
  ... | Either.Left  p | Either.Right q = antisymmetry(_≤_)(_≡_) (sub₂(_≡_)(_≤_) xy 🝖 q) p 🝖 antisymmetry(_≤_)(_≡_) ([↔]-to-[→] [≤]-flip-negative q) ([↔]-to-[→] [≤]-flip-positive(p 🝖 sub₂(_≡_)(_≤_) xy))
  ... | Either.Right p | Either.Left  q = antisymmetry(_≤_)(_≡_) ([↔]-to-[→] [≤]-flip-positive(q 🝖 sub₂(_≡_)(_≤_) (symmetry(_≡_) xy))) ([↔]-to-[→] [≤]-flip-negative p) 🝖 antisymmetry(_≤_)(_≡_) q (sub₂(_≡_)(_≤_) (symmetry(_≡_) xy) 🝖 p)
  ... | Either.Right p | Either.Right q = congruence₁(−_) xy

abs-positive : ∀{x} → (‖ x ‖ ≥ 𝟎)
abs-positive{x} = if-either-bool-intro {P = _≥ 𝟎} {x = x} {y = − x} id ([↔]-to-[→] [≤]-flip-negative) (converseTotal(_≤_){𝟎}{x})

abs-values : ∀{x} → (‖ x ‖ ≡ x) ∨ (‖ x ‖ ≡ − x)
abs-values{x} with converseTotal(_≤_){𝟎}{x}
... | [∨]-introₗ _ = [∨]-introₗ (reflexivity(_≡_))
... | [∨]-introᵣ _ = [∨]-introᵣ (reflexivity(_≡_))

abs-of-zero : (‖ 𝟎 ‖ ≡ 𝟎)
abs-of-zero with abs-values{𝟎}
... | Either.Left  p = p
... | Either.Right p = p 🝖 [−]-of-𝟎

abs-when-zero : ∀{x} → (‖ x ‖ ≡ 𝟎) ↔ (x ≡ 𝟎)
abs-when-zero{x} = [↔]-intro (p ↦ congruence₁(‖_‖) p 🝖 abs-of-zero) (p ↦ symmetry(_≡_) ([∨]-elim id (q ↦ p 🝖 symmetry(_≡_) ([↔]-to-[→] [−]-is-𝟎 (symmetry(_≡_) q 🝖 p))) abs-values) 🝖 p)

abs-of-negation : ∀{x} → (‖ − x ‖ ≡ ‖ x ‖)
abs-of-negation{x} with converseTotal(_≤_){𝟎}{x} | converseTotal(_≤_){𝟎}{− x}
... | [∨]-introₗ _   | [∨]-introᵣ _   = involution(−_)
... | [∨]-introᵣ _   | [∨]-introₗ _   = reflexivity(_≡_)
... | [∨]-introₗ zx  | [∨]-introₗ znx = antisymmetry(_≤_)(_≡_) (nxz 🝖 zx) (xz 🝖 znx) where
  nxz : (− x) ≤ 𝟎
  nxz = [↔]-to-[←] [≤]-flip-negative (zx 🝖 (sub₂(_≡_)(_≤_) $ symmetry(_≡_) $ involution(−_)))

  xz : x ≤ 𝟎
  xz = [↔]-to-[←] [≤]-flip-negative znx
... | [∨]-introᵣ xz | [∨]-introᵣ nxz  = antisymmetry(_≤_)(_≡_) (involution(−_) 🝖-subₗ (xz 🝖 znx)) (nxz 🝖 zx 🝖-subᵣ symmetry(_≡_) (involution(−_))) where
  znx : 𝟎 ≤ (− x)
  znx = [↔]-to-[→] [≤]-flip-negative xz

  zx : 𝟎 ≤ x
  zx = [↔]-to-[→] [≤]-flip-negative nxz 🝖 (sub₂(_≡_)(_≤_) $ involution(−_))

instance
  abs-idempotent : Idempotent(‖_‖)
  Idempotent.proof abs-idempotent {x} with abs-values{x}
  ... | Either.Left  p = congruence₁(‖_‖) p
  ... | Either.Right p = congruence₁(‖_‖) p 🝖 abs-of-negation

abs-order : ∀{x} → ((− ‖ x ‖) ≤ ‖ x ‖)
abs-order{x} = [↔]-to-[→] [≤]-flip-positive(abs-positive{x}) 🝖 abs-positive{x}

abs-order-pos : ∀{x} → (x ≤ ‖ x ‖)
abs-order-pos {x} with converseTotal(_≤_){𝟎}{x}
... | Either.Left  p = reflexivity(_≤_)
... | Either.Right p = p 🝖 [↔]-to-[→] [≤]-flip-negative p

abs-order-neg : ∀{x} → ((− x) ≤ ‖ x ‖)
abs-order-neg {x} with converseTotal(_≤_){𝟎}{x}
... | Either.Left  p = [↔]-to-[→] [≤]-flip-positive p 🝖 p
... | Either.Right p = reflexivity(_≤_)

abs-of-positive : ∀{x} → (𝟎 ≤ x) → (‖ x ‖ ≡ x)
abs-of-positive {x} ox = antisymmetry(_≤_)(_≡_) p abs-order-pos where
  p : ‖ x ‖ ≤ x
  p with converseTotal(_≤_){𝟎}{x}
  ... | Either.Left  _ = reflexivity(_≤_)
  ... | Either.Right _ = [↔]-to-[→] [≤]-flip-positive ox 🝖 ox
  -- Alternative 1:
  -- with abs-values{x}
  -- ... | Either.Left  p = p
  -- ... | Either.Right p = [↔]-to-[←] abs-when-zero xzero 🝖 symmetry(_≡_) xzero where
  --   xzero : (x ≡ 𝟎)
  --   xzero = antisymmetry(_≤_)(_≡_) ([↔]-to-[←] [≤]-flip-negative (abs-positive{x} 🝖 sub₂(_≡_)(_≤_) p)) ox
  -- Alternative 2: antisymmetry(_≤_)(_≡_) (sub₂(_≡_)(_≤_) p 🝖 [≤]-flip-positive ox 🝖 ox) (sub₂(_≡_)(_≤_) (symmetry(_≡_) (congruence₁(−_) p 🝖 [−−]-elim)) 🝖 abs-order{x})

abs-of-negative : ∀{x} → (x ≤ 𝟎) → (‖ x ‖ ≡ − x)
abs-of-negative {x} xo = antisymmetry(_≤_)(_≡_) p abs-order-neg where
  p : ‖ x ‖ ≤ (− x)
  p with converseTotal(_≤_){𝟎}{x}
  ... | Either.Left  _ = xo 🝖 [↔]-to-[→] [≤]-flip-negative xo
  ... | Either.Right _ = reflexivity(_≤_)
  -- Alternative 1:
  -- with abs-values{x}
  -- ... | Either.Right p = p
  -- ... | Either.Left  p = symmetry(_≡_) abs-of-negation 🝖 [↔]-to-[←] abs-when-zero xzero 🝖 symmetry(_≡_) xzero where
  --   xzero : (− x ≡ 𝟎)
  --   xzero = antisymmetry(_≤_)(_≡_) ([↔]-to-[←] [≤]-flip-negative (abs-positive{x} 🝖 sub₂(_≡_)(_≤_) p 🝖 sub₂(_≡_)(_≤_) (symmetry(_≡_) [−−]-elim))) ([↔]-to-[→] [≤]-flip-negative xo)

abs-triangle-inequality : ∀{x y} → (‖ x + y ‖ ≤ (‖ x ‖ + ‖ y ‖))
abs-triangle-inequality {x}{y} with converseTotal(_≤_){𝟎}{x + y}
... | Either.Left  p =
  (x + y)         🝖[ _≤_ ]-[ [≤][+]-preserve abs-order-pos abs-order-pos ]
  (‖ x ‖ + ‖ y ‖) 🝖-end
... | Either.Right p =
  −(x + y)        🝖[ _≡_ ]-[ [+]-negation-distribution ]-sub
  (− x) + (− y)   🝖[ _≤_ ]-[ [≤][+]-preserve abs-order-neg abs-order-neg ]
  (‖ x ‖ + ‖ y ‖) 🝖-end

-- TODO: True in rings? Only division rings? Maybe ≤ instead of ≡ is better because of zero divisors
-- abs-scaling : ∀{a x} → (‖ a ⋅ x ‖ ≡ (‖ a ‖ ⋅ ‖ x ‖))
-- abs-scaling{a}{x} with converseTotal(_≤_){𝟎}{a ⋅ x} | converseTotal(_≤_){𝟎}{a} | converseTotal(_≤_){𝟎}{x}
{-... | Either.Left  p =
  (a ⋅ x)         🝖[ _≡_ ]-[ {!!} ]
  (‖ a ‖ ⋅ ‖ x ‖) 🝖-end
... | Either.Right p = {!!}
-}

-- Distance
_𝄩_ : F → F → F
x 𝄩 y = ‖ x − y ‖

open import Structure.Function.Proofs
open import Structure.Operator.Proofs.Util

instance
  [𝄩]-binaryOperator : BinaryOperator(_𝄩_)
  [𝄩]-binaryOperator = [∘₂]-function {f = ‖_‖} ⦃ oper = [−]-binaryOperator ⦄

instance
  [𝄩]-commutativity : Commutativity(_𝄩_)
  Commutativity.proof [𝄩]-commutativity {x}{y} =
    ‖ x − y ‖    🝖-[ abs-of-negation ]-sym
    ‖ −(x − y) ‖ 🝖-[ congruence₁(‖_‖) [−]-negation-distribution ]
    ‖ y − x ‖    🝖-end

[𝄩]-triangle-inequality : ∀{x y z} → ((x 𝄩 z) ≤ ((x 𝄩 y) + (y 𝄩 z)))
[𝄩]-triangle-inequality {x}{y}{z} =
  x 𝄩 z                     🝖[ _≤_ ]-[]
  ‖ x − z ‖                 🝖[ _≡_ ]-[ congruence₁(‖_‖) (congruence₂ₗ(_−_) ⦃ [−]-binaryOperator ⦄ (z) (symmetry(_≡_) (identityᵣ(_+_)(𝟎)))) ]-sub
  ‖ (x + 𝟎) − z ‖           🝖[ _≡_ ]-[ congruence₁(‖_‖) (congruence₂ₗ(_−_) ⦃ [−]-binaryOperator ⦄ (z) (congruence₂ᵣ(_+_)(x) (symmetry(_≡_) (inverseFunctionₗ(_+_)(−_))))) ]-sub
  ‖ (x + ((− y) + y)) − z ‖ 🝖[ _≡_ ]-[ congruence₁(‖_‖) ((One.associate4-213-222 {_▫_ = _+_} {a = x}{− y}{y}{− z})) ]-sub
  ‖ (x + (− y)) + (y − z) ‖ 🝖[ _≤_ ]-[]
  ‖ (x − y) + (y − z) ‖     🝖[ _≤_ ]-[ abs-triangle-inequality ]
  (‖ x − y ‖) + (‖ y − z ‖) 🝖[ _≤_ ]-[]
  (x 𝄩 y) + (y 𝄩 z)          🝖-end

[𝄩]-self : ∀{x y} → (x 𝄩 y ≡ 𝟎) ↔ (x ≡ y)
[𝄩]-self {x}{y} = [↔]-intro l r where
  l =
    (x ≡ y)            ⇒-[ symmetry(_≡_) ∘ congruence₂ᵣ(_𝄩_)(x) ]
    (x 𝄩 y ≡ x 𝄩 x)     ⇒-[]
    (_     ≡ ‖ x − x ‖) ⇒-[ _🝖 congruence₁(‖_‖) (inverseFunctionᵣ(_+_)(−_)) ]
    (_     ≡ ‖ 𝟎 ‖)     ⇒-[ _🝖 abs-of-zero ]
    (_     ≡ 𝟎)         ⇒-end
  r =
    (x 𝄩 y ≡ 𝟎) ⇒-[ [↔]-to-[→] (abs-when-zero{x − y}) ]
    (x − y ≡ 𝟎) ⇒-[ [↔]-to-[→] [−]-difference-is-𝟎 ]
    (x ≡ y)     ⇒-end


------------------------------------------------------------------------
-- The Agda standard library
--
-- This module constructs the zero R-module, and similar for weaker
-- module-like structures.
-- The intended universal property is that, given any R-module M, there
-- is a unique map into and a unique map out of the zero R-module
-- from/to M.
------------------------------------------------------------------------

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

module Algebra.Module.Construct.Zero where

open import Algebra.Bundles
open import Algebra.Module.Bundles
open import Data.Unit
open import Level

private
  variable
    r s ℓr ℓs : Level

leftSemimodule : {R : Semiring r ℓr} → LeftSemimodule R 0ℓ 0ℓ
leftSemimodule = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }

rightSemimodule : {S : Semiring s ℓs} → RightSemimodule S 0ℓ 0ℓ
rightSemimodule = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }

bisemimodule :
  {R : Semiring r ℓr} {S : Semiring s ℓs} → Bisemimodule R S 0ℓ 0ℓ
bisemimodule = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }

semimodule : {R : CommutativeSemiring r ℓr} → Semimodule R 0ℓ 0ℓ
semimodule = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }

leftModule : {R : Ring r ℓr} → LeftModule R 0ℓ 0ℓ
leftModule = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }

rightModule : {S : Ring s ℓs} → RightModule S 0ℓ 0ℓ
rightModule = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }

bimodule : {R : Ring r ℓr} {S : Ring s ℓs} → Bimodule R S 0ℓ 0ℓ
bimodule = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }

⟨module⟩ : {R : CommutativeRing r ℓr} → Module R 0ℓ 0ℓ
⟨module⟩ = record
  { Carrierᴹ = ⊤
  ; _≈ᴹ_ = λ _ _ → ⊤
  }


------------------------------------------------------------------------
-- The partiality monad
------------------------------------------------------------------------

module Category.Monad.Partiality where

open import Coinduction
open import Category.Monad
open import Data.Nat
open import Data.Bool

-- The partiality monad.

data _⊥ (A : Set) : Set where
  now   : (x : A) → A ⊥
  later : (x : ∞ (A ⊥)) → A ⊥

monad : RawMonad _⊥
monad = record
  { return = now
  ; _>>=_  = _>>=_
  }
  where
  _>>=_ : ∀ {A B} → A ⊥ → (A → B ⊥) → B ⊥
  now x   >>= f = f x
  later x >>= f = later (♯ ♭ x >>= f)

-- run x for n steps peels off at most n "later" constructors from x.

run_for_steps : ∀ {A} → A ⊥ → ℕ → A ⊥
run now   x for n     steps = now x
run later x for zero  steps = later x
run later x for suc n steps = run ♭ x for n steps

-- Is the computation done?

isNow : ∀ {A} → A ⊥ → Bool
isNow (now x)   = true
isNow (later x) = false

------------------------------------------------------------------------
-- Productivity checker workaround

-- The monad can be awkward to use, due to the limitations of guarded
-- coinduction. The following code provides a (limited) workaround.

infixl 1 _>>=_

data _⊥-prog : Set → Set₁ where
  now   : ∀ {A} (x : A) → A ⊥-prog
  later : ∀ {A} (x : ∞₁ (A ⊥-prog)) → A ⊥-prog
  _>>=_ : ∀ {A B} (x : A ⊥-prog) (f : A → B ⊥-prog) → B ⊥-prog

data _⊥-whnf : Set → Set₁ where
  now   : ∀ {A} (x : A) → A ⊥-whnf
  later : ∀ {A} (x : A ⊥-prog) → A ⊥-whnf

whnf : ∀ {A} → A ⊥-prog → A ⊥-whnf
whnf (now   x) = now x
whnf (later x) = later (♭₁ x)
whnf (x >>= f) with whnf x
whnf (x >>= f) | now   x′ = whnf (f x′)
whnf (x >>= f) | later x′ = later (x′ >>= f)

mutual

  value : ∀ {A} → A ⊥-whnf → A ⊥
  value (now   x) = now x
  value (later x) = later (♯ run x)

  run : ∀ {A} → A ⊥-prog → A ⊥
  run x = value (whnf x)

------------------------------------------------------------------------
-- Examples

module Examples where

  open import Relation.Nullary

  -- McCarthy's f91:

  f91′ : ℕ → ℕ ⊥-prog
  f91′ n with n ≤? 100
  ... | yes _ = later (♯₁ (f91′ (11 + n) >>= f91′))
  ... | no  _ = now (n ∸ 10)

  f91 : ℕ → ℕ ⊥
  f91 n = run (f91′ n)


{-# OPTIONS --cubical-compatible #-}
module Common.Nat where

open import Agda.Builtin.Nat public
  using    ( Nat; zero; suc; _+_; _*_ )
  renaming ( _-_ to _∸_ )

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


------------------------------------------------------------------------------
-- Agda-Prop Library.
-- Theorems of ¬ connective.
------------------------------------------------------------------------------

open import Data.Nat using ( ℕ )

module Data.PropFormula.Theorems.Negation ( n : ℕ ) where

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

open import Data.PropFormula.Properties n using ( ¬-injective ; subst )
open import Data.PropFormula.Syntax n
open import Data.PropFormula.Theorems.Classical n
open import Data.PropFormula.Theorems.Implication n using ( subst⊢⊃₁ )

open import Function using ( _$_ ; _∘_ )
open import Relation.Binary.PropositionalEquality using ( _≡_ ; refl ; sym )

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

-- Theorem.
¬-equiv₁
  : ∀ {Γ} {φ}
  → Γ ⊢ ¬ φ
  → Γ ⊢ φ ⊃ ⊥
¬-to-⊃⊥ = ¬-equiv₁

-- Proof.
¬-equiv₁ {φ = φ} Γ⊢¬φ =
  ⊃-intro
    (¬-elim
      (weaken φ Γ⊢¬φ)
      (assume φ))
-------------------------------------------------------------------------- ∎

-- Theorem.
¬-equiv₂
  : ∀ {Γ} {φ}
  → Γ ⊢ φ ⊃ ⊥
  → Γ ⊢ ¬ φ
⊃⊥-to-¬ = ¬-equiv₂

-- Proof.
¬-equiv₂ {φ = φ} Γ⊢φ⊃⊥ =
  ¬-intro
    (⊃-elim
      (weaken φ Γ⊢φ⊃⊥)
      (assume φ))
-------------------------------------------------------------------------- ∎

-- Theorem.
¬¬-equiv₁
  : ∀ {Γ} {φ}
  → Γ ⊢ ¬ (¬ φ)
  → Γ ⊢ φ

-- Proof.
¬¬-equiv₁ {Γ}{φ} Γ⊢¬¬φ =
  (⊃-elim
    (⊃-intro $ RAA
      (¬-elim
        (weaken (¬ φ) $
          assume $ ¬ (¬ φ))
        (assume {Γ = Γ , ¬ (¬ φ)} $ ¬ φ)))
    Γ⊢¬¬φ)
-------------------------------------------------------------------------- ∎

-- Theorem.
¬¬-equiv₂
  : ∀ {Γ} {φ}
  → Γ ⊢ φ
  → Γ ⊢ ¬ (¬ φ)

-- Proof.
¬¬-equiv₂ {Γ}{φ} Γ⊢φ =
  ⊃⊥-to-¬
    (⊃-intro
      (¬-elim
        (assume (¬ φ))
        (weaken (¬ φ) Γ⊢φ)))
-------------------------------------------------------------------------- ∎

-- Theorem.
¬∨-to-⊃
  : ∀ {Γ} {φ ψ}
  → Γ ⊢ ¬ φ ∨ ψ
  → Γ ⊢ φ ⊃ ψ

-- Proof.
¬∨-to-⊃ {Γ}{φ}{ψ} =
  ⊃-elim $
    ⊃-intro $
      ∨-elim
        (⊃-intro $
          ⊥-elim {Γ = Γ , ¬ φ , φ} ψ
          (¬-elim
            (weaken φ $
              assume (¬ φ))
            (assume {Γ = Γ , ¬ φ} φ)))
        (⊃-intro $
          weaken φ $
            assume ψ)
-------------------------------------------------------------------------- ∎

-- Theorem.
¬⊤-to-⊥
  : ∀ {Γ}
  → Γ ⊢ ¬ ⊤
  → Γ ⊢ ⊥

-- Proof.
¬⊤-to-⊥ Γ⊢¬⊤ = ¬-elim Γ⊢¬⊤ ⊤-intro
-------------------------------------------------------------------------- ∎

-- Theorem.
⊤-to-¬⊥
  : ∀ {Γ}
  → Γ ⊢ ⊤
  → Γ ⊢ ¬ ⊥

-- Proof.
⊤-to-¬⊥ = λ _ → ¬-intro (assume ⊥)
-------------------------------------------------------------------------- ∎

-- Theorem.
¬⊥-to-⊤
  : ∀ {Γ}
  → Γ ⊢ ¬ ⊥
  → Γ ⊢ ⊤

-- Proof.
¬⊥-to-⊤ Γ⊢¬⊥ = ⊤-intro
-------------------------------------------------------------------------- ∎

-- Theorem.
⊥-to-¬⊤
  : ∀ {Γ}
  → Γ ⊢ ⊥
  → Γ ⊢ ¬ ⊤

-- Proof.
⊥-to-¬⊤ = ¬-intro ∘ weaken ⊤
-------------------------------------------------------------------------- ∎

-- Theorem.
¬-inside
  : ∀ {Γ} {φ ψ}
  → φ ≡ ψ
  → Γ ⊢ ¬ φ
  → Γ ⊢ ¬ ψ
≡-¬-to-¬ = ¬-inside

-- Proof.
¬-inside {φ = φ}{ψ} φ≡ψ Γ⊢¬φ =
  ¬-equiv₂
    (⊃-intro
      (⊃-elim
        (¬-equiv₁
          (weaken ψ Γ⊢¬φ))
        (subst
          (sym φ≡ψ)
          (assume ψ))))
-------------------------------------------------------------------------- ∎

-- Theorem.
subst⊢¬
  : ∀ {Γ} {φ γ}
  → Γ ⊢ γ ⊃ φ
  → Γ ⊢ ¬ φ
  → Γ ⊢ ¬ γ

-- Proof.
subst⊢¬ Γ⊢γ⊃φ Γ⊢¬φ = ⊃⊥-to-¬ (subst⊢⊃₁ Γ⊢γ⊃φ (¬-to-⊃⊥ Γ⊢¬φ))
-------------------------------------------------------------------------- ∎

-- Theorem.
¬⇔-to-⊃¬∧⊃¬
  : ∀ {Γ} {φ₁ φ₂}
  → Γ ⊢ ¬ (φ₁ ⇔ φ₂)
  → Γ ⊢ (φ₁ ⊃ ¬ φ₂) ∧ (φ₂ ⊃ ¬ φ₁)

-- Proof.
¬⇔-to-⊃¬∧⊃¬ {Γ}{φ₁}{φ₂} thm =
  ∧-intro
    (⊃-intro
      (¬-intro
        (¬-elim
          (weaken φ₂ $ weaken φ₁ thm)
          (⇔-intro
            (weaken φ₁ $ assume {Γ = Γ , φ₁} φ₂)
            (weaken φ₂ $ weaken φ₂ $ assume φ₁)))))
    (⊃-intro
      (¬-intro
        (¬-elim (weaken φ₁ $ weaken φ₂ thm)
          (⇔-intro
            (weaken φ₁ $ weaken φ₁ $ assume φ₂)
            (weaken φ₂ $ assume {Γ = Γ , φ₂} φ₁)))))
-------------------------------------------------------------------------- ∎


{-# OPTIONS --without-K #-}
open import HoTT.Base

module HoTT.Transport.Coproduct where

private
  variable
    i : Level
    X : 𝒰 i
    A B : X → 𝒰 i
    x₁ x₂ : X

transport-+ : (p : x₁ == x₂) →
              transport (λ x → A x + B x) p ~
              +-rec (inl ∘ transport A p) (inr ∘ transport B p)
transport-+ refl (inl a) = refl
transport-+ refl (inr b) = refl


module Logic.DiagonalProof {ℓ₁} {ℓ₂} where

import      Lvl
open import Logic.Propositional{ℓ₁ Lvl.⊔ ℓ₂}
open import Logic.Predicate{ℓ₁}{ℓ₂}
open import Functional
open import Relator.Equals{ℓ₁}{ℓ₂}
open import Relator.Equals.Proofs{ℓ₁}{ℓ₂}
open import Type{ℓ₂}

diagonal-proof : ∀{T₁ T₂ : Type}(diff-oper : T₂ → T₂) → (∀{x} → (x ≢ diff-oper(x))) → (ff : T₁ → T₁ → T₂) → ∃{T₁ → T₂}(f ↦ (∀{a : T₁} → ¬(ff(a)(a) ≡ f(a))))
diagonal-proof(diff-oper)(diff-proof)(ff) = [∃]-intro (a ↦ diff-oper(ff(a)(a))) ⦃ \{a} → diff-proof{ff(a)(a)} ⦄


module Type.Dependent.Functions where

import      Lvl
open import Functional.Dependent
open import Type
open import Type.Dependent
open import Syntax.Function

module _ {ℓ₁ ℓ₂ ℓ₃}
         {A : Type{ℓ₁}}
         {B : A → Type{ℓ₂}}
         {C : ∀{x} → B(x) → Type{ℓ₃}}
         where
  _[Π]-∘_ : (∀{x} → Π(B(x))(C)) → (g : Π(A)(B)) → Π(A)(\x → C(Π.apply g x))
  Π.apply (f [Π]-∘ g) x = Π.apply f (Π.apply g x)

  depCurry : (Π(Σ A B) (C ∘ Σ.right)) → (Π A (a ↦ (Π(B(a)) C)))
  Π.apply (Π.apply (depCurry f) a) b = Π.apply f (intro a b)

  depUncurry : (Π A (a ↦ Π(B(a)) C)) → (Π(Σ A B) (C ∘ Σ.right))
  Π.apply (depUncurry f) (intro a b) = Π.apply(Π.apply f a) b

module _ {ℓ₁ ℓ₂ ℓ₃ ℓ₄}
         {A₁ : Type{ℓ₁}}
         {B₁ : A₁ → Type{ℓ₂}}
         {A₂ : Type{ℓ₃}}
         {B₂ : A₂ → Type{ℓ₄}}
         where
  [Σ]-apply : (x : Σ(A₁)(B₁)) → (l : A₁ → A₂) → (r : B₁(Σ.left x) → B₂(l(Σ.left x))) → Σ(A₂)(B₂)
  [Σ]-apply x l r = intro(l(Σ.left x))(r(Σ.right x))

  [ℰ]-apply : (x : Σ(A₁)(B₁)) → {l : A₁ → A₂} → (r : B₁(Σ.left x) → B₂(l(Σ.left x))) → Σ(A₂)(B₂)
  [ℰ]-apply x {l} r = [Σ]-apply x l r

  [Σ]-map : (l : A₁ → A₂) → (∀{a} → B₁(a) → B₂(l(a))) → (Σ(A₁)(B₁) → Σ(A₂)(B₂))
  [Σ]-map l r (intro left right) = intro (l left) (r right)

  [ℰ]-map : ∀{l : A₁ → A₂} → (∀{a} → B₁(a) → B₂(l(a))) → (Σ(A₁)(B₁) → Σ(A₂)(B₂))
  [ℰ]-map {l} = [Σ]-map l

module _ {ℓ₁ ℓ₂ ℓ₃}
         {A : Type{ℓ₁}}
         {B₁ : A → Type{ℓ₂}}
         {B₂ : A → Type{ℓ₃}}
         where
  [Σ]-applyᵣ : (x : Σ(A)(B₁)) → (r : B₁(Σ.left x) → B₂(Σ.left x)) → Σ(A)(B₂)
  [Σ]-applyᵣ x r = intro(Σ.left x)(r(Σ.right x))

module _ {ℓ₁ ℓ₂ ℓ₃ ℓ₄ ℓ₅ ℓ₆}
         {A₁ : Type{ℓ₁}}
         {B₁ : A₁ → Type{ℓ₂}}
         {A₂ : Type{ℓ₃}}
         {B₂ : A₂ → Type{ℓ₄}}
         {A₃ : Type{ℓ₅}}
         {B₃ : A₃ → Type{ℓ₆}}
         where
  [Σ]-apply₂ : (x : Σ(A₁)(B₁)) → (y : Σ(A₂)(B₂)) → (l : A₁ → A₂ → A₃) → (r : B₁(Σ.left x) → B₂(Σ.left y) → B₃(l(Σ.left x)(Σ.left y))) → Σ(A₃)(B₃)
  [Σ]-apply₂ x y l r = intro(l(Σ.left x)(Σ.left y))(r(Σ.right x)(Σ.right y))

  [ℰ]-apply₂ : (x : Σ(A₁)(B₁)) → (y : Σ(A₂)(B₂)) → {l : A₁ → A₂ → A₃} → (r : B₁(Σ.left x) → B₂(Σ.left y) → B₃(l(Σ.left x)(Σ.left y))) → Σ(A₃)(B₃)
  [ℰ]-apply₂ x y {l} r = [Σ]-apply₂ x y l r

  [Σ]-map₂ : (l : A₁ → A₂ → A₃) → (∀{a₁}{a₂} → B₁(a₁) → B₂(a₂) → B₃(l a₁ a₂)) → (Σ(A₁)(B₁) → Σ(A₂)(B₂) → Σ(A₃)(B₃))
  [Σ]-map₂ l r (intro left₁ right₁) (intro left₂ right₂) = intro (l left₁ left₂) (r right₁ right₂)

  [ℰ]-map₂ : ∀{l : A₁ → A₂ → A₃} → (∀{a₁}{a₂} → B₁(a₁) → B₂(a₂) → B₃(l a₁ a₂)) → (Σ(A₁)(B₁) → Σ(A₂)(B₂) → Σ(A₃)(B₃))
  [ℰ]-map₂ {l} = [Σ]-map₂ l


import Relation.Binary.PropositionalEquality as PEq

module Relation.Binary.PropositionalEquality.Extensionality
  (funext : ∀ {ℓ₁ ℓ₂} → PEq.Extensionality ℓ₁ ℓ₂) where

funext² : ∀ {p q r}{P : Set p}{Q : P → Set q}
          {R : (p : P) → Q p → Set r} →
          {f g : ∀ (p : P)(q : Q p) → R p q} → (∀ p q → f p q PEq.≡ g p q) →
          f PEq.≡ g
funext² f = funext λ p → funext λ q → f p q

funext³ : ∀ {p q r s}{P : Set p}{Q : P → Set q}
          {R : (p : P) → Q p → Set r}{S : (p : P)(q : Q p) → R p q → Set s} →
          {f g : ∀ (p : P)(q : Q p)(r : R p q) → S p q r} → (∀ p q r → f p q r PEq.≡ g p q r) →
          f PEq.≡ g
funext³ f = funext λ p → funext λ q → funext λ r → f p q r


------------------------------------------------------------------------
-- The Agda standard library
--
-- An inductive definition of the sublist relation. This is commonly
-- known as Order Preserving Embeddings (OPE).
------------------------------------------------------------------------

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

module Data.List.Relation.Binary.Sublist.Propositional
  {a} {A : Set a} where

open import Data.List.Relation.Binary.Equality.Propositional using (≋⇒≡)
import Data.List.Relation.Binary.Sublist.Setoid as SetoidSublist
open import Data.List.Relation.Unary.Any using (Any)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Unary using (Pred)

------------------------------------------------------------------------
-- Re-export definition and operations from setoid sublists

open SetoidSublist (setoid A) public
  hiding
  (lookup; ⊆-reflexive; ⊆-antisym
  ; ⊆-isPreorder; ⊆-isPartialOrder
  ; ⊆-preorder; ⊆-poset
  )

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

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

  lookup : ∀ {xs ys} → xs ⊆ ys → Any P xs → Any P ys
  lookup = SetoidSublist.lookup (setoid A) (subst _)

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

⊆-reflexive : _≡_ ⇒ _⊆_
⊆-reflexive refl = ⊆-refl

⊆-antisym : Antisymmetric _≡_ _⊆_
⊆-antisym xs⊆ys ys⊆xs = ≋⇒≡ (SetoidSublist.⊆-antisym (setoid A) xs⊆ys ys⊆xs)

⊆-isPreorder : IsPreorder _≡_ _⊆_
⊆-isPreorder = record
  { isEquivalence = isEquivalence
  ; reflexive     = ⊆-reflexive
  ; trans         = ⊆-trans
  }

⊆-isPartialOrder : IsPartialOrder _≡_ _⊆_
⊆-isPartialOrder = record
  { isPreorder = ⊆-isPreorder
  ; antisym    = ⊆-antisym
  }

⊆-preorder : Preorder a a a
⊆-preorder = record
  { isPreorder = ⊆-isPreorder
  }

⊆-poset : Poset a a a
⊆-poset = record
  { isPartialOrder = ⊆-isPartialOrder
  }


------------------------------------------------------------------------
-- The Agda standard library
--
-- Implications of nullary relations
------------------------------------------------------------------------

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

module Relation.Nullary.Implication where

open import Data.Bool.Base
open import Data.Empty
open import Function.Base
open import Relation.Nullary
open import Level

private
  variable
    p q : Level
    P : Set p
    Q : Set q

------------------------------------------------------------------------
-- Some properties which are preserved by _→_.

infixr 2 _→-reflects_ _→-dec_

_→-reflects_ : ∀ {bp bq} → Reflects P bp → Reflects Q bq →
                           Reflects (P → Q) (not bp ∨ bq)
ofʸ  p →-reflects ofʸ  q = ofʸ (const q)
ofʸ  p →-reflects ofⁿ ¬q = ofⁿ (¬q ∘ (_$ p))
ofⁿ ¬p →-reflects _      = ofʸ (⊥-elim ∘ ¬p)

_→-dec_ : Dec P → Dec Q → Dec (P → Q)
does  (p? →-dec q?) = not (does p?) ∨ does q?
proof (p? →-dec q?) = proof p? →-reflects proof q?


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

module Categories.Adjoint.Instance.PosetCore where

-- The adjunction between the "forgetful" functor from Posets to
-- Setoids and the core functor for posets.

open import Level using (_⊔_)
import Function
open import Function.Equality using (Π; _⟶_)
open import Relation.Binary using (Setoid; Poset)
open import Relation.Binary.OrderMorphism using (_⇒-Poset_) renaming (_∘_ to _∙_)

open import Categories.Adjoint using (_⊣_)
import Categories.Adjoint.Instance.0-Truncation as Setd
import Categories.Adjoint.Instance.01-Truncation as Pos
open import Categories.Category using (Category)
open import Categories.Category.Construction.Thin
open import Categories.Category.Instance.Posets using (fun-resp-≈; Posets)
open import Categories.Category.Instance.Setoids using (Setoids)
open import Categories.Functor.Instance.Core using () renaming (Core to CatCore)
import Categories.Functor.Instance.Core as Cat
open import Categories.Functor using (Functor; _∘F_; id)
import Categories.Morphism as Morphism
open import Categories.Morphism.IsoEquiv using (⌞_⌟)
open import Categories.NaturalTransformation using (ntHelper)
open import Categories.NaturalTransformation.NaturalIsomorphism
  using (_≃_; niHelper)

open Π
open _⇒-Poset_

-- The "forgetful" functor from Setoids to Posets (forgetting symmetry).

Forgetful : ∀ {c ℓ} → Functor (Setoids c ℓ) (Posets c ℓ ℓ)
Forgetful = record
  { F₀           = Forgetful₀
  ; F₁           = λ f → record { fun = _⟨$⟩_ f ; monotone = cong f }
  ; identity     = λ {S}       → refl S
  ; homomorphism = λ {_ _ S}   → refl S
  ; F-resp-≈     = λ {S _} f≗g → f≗g (refl S)
  }
  where
    Forgetful₀ : ∀ {c ℓ} → Setoid c ℓ → Poset c ℓ ℓ
    Forgetful₀ S = record
      { _≈_               = _≈_
      ; _≤_               = _≈_
      ; isPartialOrder    = record
        { isPreorder      = record
          { isEquivalence = isEquivalence
          ; reflexive     = Function.id
          ; trans         = trans
          }
        ; antisym         = Function.const
        }
      }
      where open Setoid S

    open Setoid

-- The "core" functor from Posets to Setoids.
--
-- This functor simply forgets the _≤_ relation, mapping a Poset to
-- the Setoid over which it is defined.  This Setoid is the "core" of
-- the Poset in the sense that the "equality" _≈_ associated with the
-- Poset is really an equivalence, and antisymmetry ensures that this
-- equivalence is equivalent to the symmetric core of _≤_.

Core : ∀ {c ℓ₁ ℓ₂} → Functor (Posets c ℓ₁ ℓ₂) (Setoids c ℓ₁)
Core = record
  { F₀           = λ A → record { isEquivalence = isEquivalence A }
  ; F₁           = λ f → record { _⟨$⟩_ = fun f ; cong = fun-resp-≈ f }
  ; identity     = Function.id
  ; homomorphism = λ {_ _ _ f g} → fun-resp-≈ (g ∙ f)
  ; F-resp-≈     = λ {_ B} {f _} f≗g x≈y → Eq.trans B (fun-resp-≈ f x≈y) f≗g
  }
  where open Poset

-- Core is right-adjoint to the forgetful functor

CoreAdj : ∀ {o ℓ} → Forgetful ⊣ Core {o} {ℓ} {ℓ}
CoreAdj = record
  { unit   = ntHelper record { η = unit   ; commute = cong                  }
  ; counit = ntHelper record { η = counit ; commute = λ {_ B} _ → Eq.refl B }
  ; zig    = λ {S} → Setoid.refl S
  ; zag    = Function.id
  }
  where
    open Poset
    open Functor Core      using () renaming (F₀ to Core₀; F₁ to Core₁)
    open Functor Forgetful using () renaming (F₀ to U₀   ; F₁ to U₁)

    unit : ∀ S → S ⟶ Core₀ (U₀ S)
    unit S = record { _⟨$⟩_ = Function.id ; cong = Function.id }

    counit : ∀ A → U₀ (Core₀ A) ⇒-Poset A
    counit C = record { fun = Function.id ; monotone = reflexive C }

-- The core functor commutes with inclusion, i.e. the core of a thin
-- category is the 0-Groupoid generated by the associated equivalence.
--
-- Note that the core functor does not commute with truncation,
-- because the latter forgets too much (there are many more isos in
-- the (0,1)-truncated category).

Core-commutes : ∀ {c ℓ} e → Setd.Inclusion e ∘F Core ≃
                Cat.Core ∘F Pos.Inclusion {c} {ℓ ⊔ e} {ℓ} e
Core-commutes e = niHelper record
  { η   = λ A → record { F₀ = Function.id ; F₁ = EqIsIso.≈⇒≅ e A }
  ; η⁻¹ = λ A → record { F₀ = Function.id ; F₁ = EqIsIso.≅⇒≈ e A }
  ; commute = λ {A B} f →
    let open Morphism (Thin e B)
    in niHelper record { η   = λ _ → ≅.refl ; η⁻¹ = λ _ → ≅.refl }
  ; iso = λ A →
    let open Poset A
        open Morphism (Thin e A)
    in record
    { isoˡ = niHelper record { η = λ _ → Eq.refl ; η⁻¹ = λ _ → Eq.refl }
    ; isoʳ = niHelper record { η = λ _ → ≅.refl  ; η⁻¹ = λ _ → ≅.refl  }
    }
  }


------------------------------------------------------------------------
-- The Agda standard library
--
-- Symmetric closures of binary relations
------------------------------------------------------------------------

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

module Relation.Binary.Construct.Closure.Symmetric where

open import Data.Sum as Sum using (_⊎_)
open import Function using (id)
open import Relation.Binary

open Sum public using () renaming (inj₁ to fwd; inj₂ to bwd)

-- The symmetric closure of a relation.

SymClosure : ∀ {a ℓ} {A : Set a} → Rel A ℓ → Rel A ℓ
SymClosure _∼_ a b = a ∼ b ⊎ b ∼ a

module _ {a ℓ} {A : Set a} where

  -- Symmetric closures are symmetric.

  symmetric : (_∼_ : Rel A ℓ) → Symmetric (SymClosure _∼_)
  symmetric _ (fwd a∼b) = bwd a∼b
  symmetric _ (bwd b∼a) = fwd b∼a

  -- A generalised variant of map which allows the index type to change.

  gmap : ∀ {b ℓ₂} {B : Set b} {P : Rel A ℓ} {Q : Rel B ℓ₂} →
         (f : A → B) → P =[ f ]⇒ Q → SymClosure P =[ f ]⇒ SymClosure Q
  gmap _ g = Sum.map g g

  map : ∀ {ℓ₂} {P : Rel A ℓ} {Q : Rel A ℓ₂} →
        P ⇒ Q → SymClosure P ⇒ SymClosure Q
  map = gmap id


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

open import LogicalFormulae
open import Sets.EquivalenceRelations
open import Setoids.Setoids
open import Rings.Definition
open import Rings.PrincipalIdealDomains.Definition
open import Rings.IntegralDomains.Definition
open import Rings.Ideals.Maximal.Definition

module Rings.PrincipalIdealDomains.Lemmas {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ _*_ : A → A → A} {R : Ring S _+_ _*_} (intDom : IntegralDomain R) (pid : {c : _} → PrincipalIdealDomain intDom {c}) where

open import Rings.Ideals.Definition R
open import Rings.Irreducibles.Definition intDom
open import Rings.Ideals.Principal.Definition R
open import Rings.Divisible.Definition R
open import Rings.Associates.Lemmas intDom
open import Rings.Ideals.Lemmas R
open import Rings.Units.Definition R
open import Rings.Irreducibles.Lemmas intDom
open import Rings.Units.Lemmas R
open import Rings.Ideals.Prime.Definition {R = R}
open import Rings.Ideals.Prime.Lemmas {R = R}
open import Rings.Primes.Definition intDom
open import Rings.Primes.Lemmas intDom
open import Rings.Ideals.Principal.Lemmas R
open import Rings.Ideals.Maximal.Lemmas {R = R}

open Ring R
open Setoid S
open Equivalence eq

irreducibleImpliesMaximalIdeal : {r : A} → Irreducible r → {d : _} → MaximalIdeal (generatedIdeal r) {d}
MaximalIdeal.notContained (irreducibleImpliesMaximalIdeal {r} irred {d}) = 1R
MaximalIdeal.notContainedIsNotContained (irreducibleImpliesMaximalIdeal {r} irred {d}) = Irreducible.nonunit irred
MaximalIdeal.isMaximal (irreducibleImpliesMaximalIdeal {r} irred {d}) {biggerPred} bigger biggerContains (outsideR , (biggerContainsOutside ,, notInR)) {x} = biggerPrincipal' (unitImpliesGeneratedIdealEverything w {x})
  where
    biggerGen : A
    biggerGen = PrincipalIdeal.generator (pid bigger)
    biggerPrincipal : {x : A} → biggerPred x → biggerGen ∣ x
    biggerPrincipal = PrincipalIdeal.genGenerates (pid bigger)
    bp : biggerPred biggerGen
    bp = PrincipalIdeal.genIsInIdeal (pid bigger)
    biggerPrincipal' : {x : A} → biggerGen ∣ x → biggerPred x
    biggerPrincipal' {y} bg|y = memberDividesImpliesMember bigger bp bg|y
    u : biggerGen ∣ r
    u = biggerPrincipal (biggerContains (1R , transitive *Commutative identIsIdent))
    biggerGenNonzero : biggerGen ∼ 0R → False
    biggerGenNonzero bg=0 = notInR (Ideal.isSubset (generatedIdeal r) (symmetric t) (Ideal.containsIdentity (generatedIdeal r)))
      where
        t : outsideR ∼ 0R
        t with biggerPrincipal {outsideR} biggerContainsOutside
        ... | mult , pr = transitive (symmetric pr) (transitive (*WellDefined bg=0 reflexive) (transitive *Commutative timesZero))
    v : (r ∣ biggerGen) → False
    v r|bg with mutualDivisionImpliesAssociate r|bg u (Irreducible.nonzero irred)
    v r|bg | assoc = notInR (associateImpliesGeneratedIdealsEqual' assoc (PrincipalIdeal.genGenerates (pid bigger) biggerContainsOutside))
    w : Unit biggerGen
    w = dividesIrreducibleImpliesUnit irred u v

primeIdealIsMaximal : {c : _} {pred : A → Set c} → {i : Ideal pred} → (nonzero : Sg A (λ a → ((a ∼ 0R) → False) && pred a)) → PrimeIdeal i → {d : _} → MaximalIdeal i {d}
primeIdealIsMaximal {pred = pred} {i} (m , (m!=0 ,, predM)) prime {d = d} = maximalIdealWellDefined (generatedIdeal (PrincipalIdeal.generator princ)) i (memberDividesImpliesMember i (PrincipalIdeal.genIsInIdeal princ)) (PrincipalIdeal.genGenerates princ) isMaximal
  where
    princ : PrincipalIdeal i
    princ = pid i
    isPrime : Prime (PrincipalIdeal.generator princ)
    isPrime = primeIdealImpliesPrime (λ gen=0 → PrimeIdeal.notContainedIsNotContained prime (exFalso (m!=0 (generatorZeroImpliesAllZero princ gen=0 predM)))) (primeIdealWellDefined i (generatedIdeal (PrincipalIdeal.generator princ)) (PrincipalIdeal.genGenerates princ) (memberDividesImpliesMember i (PrincipalIdeal.genIsInIdeal princ)) prime)
    isIrreducible : Irreducible (PrincipalIdeal.generator princ)
    isIrreducible = primeIsIrreducible isPrime
    isMaximal : MaximalIdeal (generatedIdeal (PrincipalIdeal.generator princ)) {d}
    isMaximal = irreducibleImpliesMaximalIdeal isIrreducible {d}

irreducibleImpliesPrime : {x : A} → Irreducible x → Prime x
irreducibleImpliesPrime {x} irred = primeIdealImpliesPrime (Irreducible.nonzero irred) (idealMaximalImpliesIdealPrime (generatedIdeal x) (irreducibleImpliesMaximalIdeal irred))


------------------------------------------------------------------------
-- The Agda standard library
--
-- Heterogeneous equality
------------------------------------------------------------------------

-- This file contains some core definitions which are reexported by
-- Relation.Binary.HeterogeneousEquality.

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

module Relation.Binary.HeterogeneousEquality.Core where

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

------------------------------------------------------------------------
-- Heterogeneous equality

infix 4 _≅_

data _≅_ {ℓ} {A : Set ℓ} (x : A) : {B : Set ℓ} → B → Set ℓ where
   refl : x ≅ x

------------------------------------------------------------------------
-- Conversion

≅-to-≡ : ∀ {a} {A : Set a} {x y : A} → x ≅ y → x ≡ y
≅-to-≡ refl = refl

≡-to-≅ : ∀ {a} {A : Set a} {x y : A} → x ≡ y → x ≅ y
≡-to-≅ refl = refl


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.ZCohomology.Groups.Connected where

open import Cubical.ZCohomology.Base
open import Cubical.ZCohomology.Properties
open import Cubical.ZCohomology.Groups.Unit

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

open import Cubical.HITs.SetTruncation renaming (rec to sRec ; elim to sElim ; elim2 to sElim2)
open import Cubical.HITs.PropositionalTruncation renaming (rec to pRec ; ∥_∥ to ∥_∥₁ ; ∣_∣ to ∣_∣₁)
open import Cubical.HITs.Nullification

open import Cubical.Data.Sigma hiding (_×_)
open import Cubical.Data.Int renaming (_+_ to _+ℤ_; +-comm to +ℤ-comm ; +-assoc to +ℤ-assoc)
open import Cubical.Data.Nat
open import Cubical.HITs.Truncation renaming (rec to trRec)
open import Cubical.Algebra.Group

open import Cubical.Homotopy.Connected
open import Cubical.Foundations.Equiv

private
  H⁰-connected-type : ∀ {ℓ} {A : Type ℓ} (a : A) → isConnected 2 A → Iso (coHom 0 A) Int
  Iso.fun (H⁰-connected-type a con) = sRec isSetInt λ f → f a
  Iso.inv (H⁰-connected-type a con) b = ∣ (λ x → b) ∣₂
  Iso.rightInv (H⁰-connected-type a con) b = refl
  Iso.leftInv (H⁰-connected-type a con) =
    sElim (λ _ → isOfHLevelPath 2 setTruncIsSet _ _)
           λ f → cong ∣_∣₂ (funExt λ x → trRec (isSetInt _ _) (cong f) (isConnectedPath 1 con a x .fst))

H⁰-connected : ∀ {ℓ} {A : Type ℓ} (a : A) → ((x : A) → ∥ a ≡ x ∥₁) → GroupIso (coHomGr 0 A) intGroup
GroupHom.fun (GroupIso.map (H⁰-connected a con)) = sRec isSetInt (λ f → f a)
GroupHom.isHom (GroupIso.map (H⁰-connected a con)) =
  sElim2 (λ _ _ → isProp→isSet (isSetInt _ _)) λ x y → addLemma (x a) (y a)
GroupIso.inv (H⁰-connected a con) b = ∣ (λ _ → b) ∣₂
GroupIso.rightInv (H⁰-connected a con) _ = refl
GroupIso.leftInv (H⁰-connected a con) =
  sElim (λ _ → isProp→isSet (setTruncIsSet _ _))
        (λ f → cong ∣_∣₂ (funExt λ x → pRec (isSetInt _ _) (cong f) (con x)))


-- Andreas, issue reported by Matteo Acerbi, 2014-09-04.
-- Short summary: x = c x is not impossible for coinductive constructors c,
-- so x should not be considered a strictly rigid occurrence in (c x).

-- Matteo:

-- In the following I cannot understand what justifies the absurd pattern
-- in the definition of ¬id≡In: as νId is coinductive, elaboration of the
-- no-cycles check to eliminators should not be possible (as far as I know).

-- Any two inhabitants of νId are bisimilar, but it seems that current
-- pattern matching makes it inconsistent to assume that bisimilarity
-- implies equality for νId, which *might* upset some. :-)

{-# OPTIONS --copatterns #-}

-- False and equality.

⊥ = (X : Set) → X

data _≡_ {A : Set}(x : A) : A → Set where
  <> : x ≡ x

-- The cofixpoint of the identity functor.

record νId : Set where
  coinductive
  constructor In
  field       Out : νId
open νId

-- The "only" inhabitant of νId.

tt : νId
Out tt = tt

-- x ≡ In x is considered absurd.

¬id≡In : {x : νId} → x ≡ In x → ⊥
¬id≡In ()

-- _≈_ is bisimilarity for elements of νId.

record _≈νId_ (x y : νId) : Set where
  coinductive
  field step : Out x ≈νId Out y
open _≈νId_

-- Any two elements are bisimilar.

trivial-≈νId : ∀ {x y} → x ≈νId y
step trivial-≈νId = trivial-≈νId

-- For νId it is not consistent to assume that bisimilarity implies
-- equality.

problem? : (ext : ∀ {x y} → x ≈νId y → x ≡ y) → ⊥
problem? ext = ¬id≡In {tt} (ext trivial-≈νId)


module Numeral.Real where

open import Data.Tuple
open import Logic
import      Lvl
open import Numeral.Natural
open import Numeral.Natural.Oper
open import Numeral.Rational
open import Numeral.Rational.Oper
open import Relator.Equals
open import Type
open import Type.Quotient

-- TODO: This will not work, but it is the standard concept at least. Maybe there is a better way

record CauchySequence (a : ℕ → ℚ) : Stmt where
  field
    N : ℚ₊ → ℕ
    ∀{ε : ℚ₊}{m n : ℕ} → (m > N(ε)) → (n > N(ε)) → (‖ a(m) − a(n) ‖ < ε)

_converges-to-same_ : Σ(CauchySequence) → Σ(CauchySequence) → Stmt{Lvl.𝟎}
a converges-to-same b = lim(n ↦ Σ.left(a) − Σ.left(b)) ≡ 𝟎

ℝ : Type{Lvl.𝟎}
ℝ = Σ(CauchySequence) / (_converges-to-same_)

-- TODO: Here is another idea: https://github.com/dylanede/cubical-experiments/blob/master/scratch.agda
-- TODO: Also these: https://en.wikipedia.org/wiki/Construction_of_the_real_numbers#Construction_from_Cauchy_sequences


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

open import HoTT

{- Proof that if [A] and [B] are two propositions, then so is [A * B]. -}

module homotopy.PropJoinProp
  {i} {A : Type i} (pA : is-prop A)
  {j} {B : Type j} (pB : is-prop B) where

contr-left : (a : A) → is-contr (A * B)
contr-left a = left a , Pushout-elim
  (λ a' → ap left (prop-has-all-paths pA a a'))
  (λ b' → glue (a , b'))
  (λ {(a' , b') → ↓-cst=idf-in' $ ! $
    ↓-app=cst-out (apd (λ a → glue (a , b')) (prop-has-all-paths pA a a'))})

contr-right : (b : B) → is-contr (A * B)
contr-right b = right b , Pushout-elim
  (λ a' → ! (glue (a' , b)))
  (λ b' → ap right (prop-has-all-paths pB b b'))
  (λ {(a' , b') → ↓-cst=idf-in' $
    ! (glue (a' , b)) ∙ glue (a' , b')
      =⟨ ! (↓-cst=app-out' $ apd (λ b → glue (a' , b)) (prop-has-all-paths pB b b'))
        |in-ctx ! (glue (a' , b)) ∙_ ⟩
    ! (glue (a' , b)) ∙ glue (a' , b) ∙ ap right (prop-has-all-paths pB b b')
      =⟨ ! $ ∙-assoc (! (glue (a' , b))) (glue (a' , b)) (ap right (prop-has-all-paths pB b b')) ⟩
    (! (glue (a' , b)) ∙ glue (a' , b)) ∙ ap right (prop-has-all-paths pB b b')
      =⟨ !-inv-l (glue (a' , b)) |in-ctx _∙ ap right (prop-has-all-paths pB b b') ⟩
    ap right (prop-has-all-paths pB b b')
      =∎})

prop*prop-is-prop : is-prop (A * B)
prop*prop-is-prop = inhab-to-contr-is-prop $
  Pushout-rec contr-left contr-right (λ _ → prop-has-all-paths is-contr-is-prop _ _)


module Formalization.Polynomial where

import      Lvl
open import Data.ListSized
open import Numeral.Natural as ℕ using (ℕ)
open import Type

private variable ℓ ℓₑ : Lvl.Level
private variable T : Type{ℓ}
private variable n n₁ n₂ : ℕ

-- TODO: Some of the operations should work with arbitrary Rg structures, not just ℕ, and some other stuff should work with more assumptions. Currently, one of the function that needs to be modified is 𝐷 and normalize for this to work because their implementations depend on ℕ.
-- TODO: Composition of polynomials, power operation

module _ where
  -- A polynomial of a finite degree represented as a list of its coefficients.
  -- Examples:
  --   (a₀⋅x⁰ + a₁⋅x¹ + a₂⋅x² + a₃⋅x³ + a₄⋅x⁴) of degree 4 is [a₀,a₁,a₂,a₃,a₄]
  --   (5 + 7⋅x + x³) of maximal degree 3 is [5,7,0,1]
  Polynomial : ℕ → Type
  Polynomial(n) = List(ℕ)(ℕ.𝐒(n))

  open import Data.ListSized.Functions
  import      Functional as Fn
  open import Logic.Propositional
  open import Logic.Predicate
  import      Numeral.Natural.Function as ℕ
  open import Numeral.Natural.Function.Proofs
  import      Numeral.Natural.Oper as ℕ
  open import Numeral.Natural.Relation.Order
  open import Numeral.Natural.Relation.Order.Proofs
  open import Relator.Equals
  open import Relator.Equals.Proofs.Equiv{T = ℕ}

  -- Constant polynomial.
  -- Semantically, this corresponds to a constant.
  const : ℕ → Polynomial(n)
  const {n} a = a ⊰ repeat ℕ.𝟎 n

  -- Zero polynomial.
  -- Semantically, this corresponds to zero.
  𝟎 : Polynomial(n)
  𝟎 {n} = const{n} ℕ.𝟎

  -- Unit polynomial.
  -- Semantically, this corresponds to one.
  𝟏 : Polynomial(n)
  𝟏 {n} = const{n}(ℕ.𝐒(ℕ.𝟎))

  -- Increases the degree of the polynomial by adding a zero term at the beginning.
  -- Semantically, this corresponds to multiplying the whole polynomial by the variable.
  -- Example: (var⋅ [a₀,a₁,a₂] = [0,a₀,a₁,a₂])
  --   x ⋅ (a₀⋅x⁰ + a₁⋅x¹ + a₂⋅x²)
  --   = a₀⋅x¹ + a₁⋅x² + a₂⋅x³
  var⋅_ : Polynomial(n) → Polynomial(ℕ.𝐒(n))
  var⋅_ = ℕ.𝟎 ⊰_

  -- Single variable polynomial.
  var : Polynomial(ℕ.𝐒(n))
  var = var⋅ 𝟏

  -- Polynomial addition.
  -- Adds the powers component-wise.
  -- Examples: ([a₀,a₁,a₂] + [b₀,b₁,b₂] = [a₀b₀ , a₁+b₁ , a₂+b₂])
  --   (a₀⋅x⁰ + a₁⋅x¹ + a₂⋅x²) + (b₀⋅x⁰ + b₁⋅x¹ + b₂⋅x²)
  --   = (a₀+b₀)⋅x⁰ + (a₁+b₁)⋅x¹ + (a₂+b₂)⋅x²
  --   of maximal degree 2 is [a₀+b₀ , a₁+b₁ , a₂+b₂]
  _+_ : Polynomial(n₁) → Polynomial(n₂) → Polynomial(ℕ.max n₁ n₂)
  _+_ = map₂(ℕ._+_) Fn.id Fn.id

  -- Polymonial scalar multiplication.
  -- Multiplies every component by a factor.
  -- Example: (n ⋅ [a₀,a₁,a₂] = [n⋅a₀ , n⋅a₁ , n⋅a₂])
  --   n ⋅ (a₀⋅x⁰ + a₁⋅x¹ + a₂⋅x²)
  --   = (n⋅a₀)⋅x⁰ + (n⋅a₁)⋅x¹ + (n⋅a₂)⋅x²
  _⋅_ : ℕ → Polynomial(n) → Polynomial(n)
  n ⋅ as = map (n ℕ.⋅_) as

  -- Increases the degree of the polynomial by adding zero terms at the end.
  -- Semantically, this corresponds to adding terms multiplied by zero.
  -- Example: (pad [a₀,a₁,a₂] = [a₀,a₁,a₂,0,0])
  --   a₀⋅x⁰ + a₁⋅x¹ + a₂⋅x²
  --   = a₀⋅x⁰ + a₁⋅x¹ + a₂⋅x² + 0⋅x³ + 0⋅x⁴
  pad : ⦃ _ : (n₁ ≤ n₂)⦄ → Polynomial(n₁) → Polynomial(n₂)
  pad {n₁ = ℕ.𝟎}     {n₂ = ℕ.𝟎}     ⦃ min ⦄  (a ⊰ ∅)  = singleton a
  pad {n₁ = ℕ.𝟎}     {n₂ = ℕ.𝐒(n₂)} ⦃ min ⦄  (a ⊰ ∅)  = a ⊰ 𝟎
  pad {n₁ = ℕ.𝐒(n₁)} {n₂ = ℕ.𝐒(n₂)} ⦃ succ p ⦄ (a ⊰ as) = a ⊰ pad ⦃ p ⦄ as

  -- Polynomial multiplication.
  -- Proof of step:
  --   ∑(0‥𝐒(n₁))(i ↦ aᵢ⋅xⁱ) ⋅ ∑(0‥𝐒(n₂))(i ↦ bᵢ⋅xⁱ)
  --   = (a + ∑(1‥𝐒(n₁))(i ↦ aᵢ⋅xⁱ)) ⋅ (b + ∑(1‥𝐒(n₂))(i ↦ bᵢ⋅xⁱ))
  --   = (a ⋅ b) + (a ⋅ ∑(1‥𝐒(n₂))(i ↦ bᵢ⋅xⁱ)) + (∑(1‥𝐒(n₁))(i ↦ aᵢ⋅xⁱ) ⋅ b) + (∑(1‥𝐒(n₁))(i ↦ aᵢ⋅xⁱ) ⋅ ∑(1‥𝐒(n₂))(i ↦ bᵢ⋅xⁱ))
  --   = (a⋅b) + (a ⋅ ∑(1‥𝐒(n₂))(i ↦ bᵢ⋅xⁱ)) + (∑(1‥𝐒(n₁))(i ↦ aᵢ⋅xⁱ) ⋅ b⋅x) + (∑(1‥𝐒(n₁))(i ↦ aᵢ⋅xⁱ) ⋅ ∑(1‥𝐒(n₂))(i ↦ bᵢ⋅xⁱ))
  --   = (a⋅b) + (a ⋅ ∑(0‥n₂)(i ↦ bᵢ⋅xⁱ)⋅x) + (∑(0‥n₁)(i ↦ aᵢ⋅xⁱ)⋅x ⋅ b) + (∑(1‥𝐒(n₁))(i ↦ aᵢ⋅xⁱ) ⋅ ∑(1‥𝐒(n₂))(i ↦ bᵢ⋅xⁱ))
  --   = (a⋅b) + (a ⋅ ∑(0‥n₂)(i ↦ bᵢ⋅xⁱ))⋅x + (∑(0‥n₁)(i ↦ aᵢ⋅xⁱ) ⋅ b)⋅x + (∑(0‥n₁)(i ↦ aᵢ⋅xⁱ) ⋅ ∑(0‥n₂)(i ↦ bᵢ⋅xⁱ))⋅x²
  --   = (a⋅b) + ((a ⋅ ∑(0‥n₂)(i ↦ bᵢ⋅xⁱ)) + (∑(0‥n₁)(i ↦ aᵢ⋅xⁱ) ⋅ b) + (∑(0‥n₁)(i ↦ aᵢ⋅xⁱ) ⋅ ∑(0‥n₂)(i ↦ bᵢ⋅xⁱ))⋅x)⋅x
  --   Also see `eval-preserves-multiplication`.
  _⨯_ : Polynomial(n₁) → Polynomial(n₂) → Polynomial(n₁ ℕ.+ n₂)
  _⨯_                  as@(_ ⊰ _)       (b ⊰ ∅)          = b ⋅ as
  _⨯_                  (a ⊰ ∅)          bs@(_ ⊰ _ ⊰ _)   = a ⋅ bs
  _⨯_ {ℕ.𝐒 n₁}{ℕ.𝐒 n₂} (a ⊰ as@(_ ⊰ _)) (b ⊰ bs@(_ ⊰ _)) = (a ℕ.⋅ b) ⊰ lr where
    l : Polynomial(n₁ ℕ.+ n₂)
    l = pad ⦃ max-order-[+] ⦄ ((b ⋅ as) + (a ⋅ bs))

    r : Polynomial(ℕ.𝐒(n₁ ℕ.+ n₂))
    r = var⋅ (as ⨯ bs)

    lr : Polynomial(ℕ.𝐒(n₁ ℕ.+ n₂))
    lr = [≡]-substitutionᵣ ([↔]-to-[→] max-defᵣ [≤]-of-[𝐒]) {Polynomial} (l + r)

  normalize : Polynomial(n) → ∃(Polynomial)
  normalize {ℕ.𝟎}   (x ⊰ ∅)      = [∃]-intro ℕ.𝟎 ⦃ x ⊰ ∅ ⦄
  normalize {ℕ.𝐒 n} (ℕ.𝟎 ⊰ p) with normalize{n} p
  ... | [∃]-intro ℕ.𝟎 ⦃ singleton ℕ.𝟎 ⦄ = [∃]-intro ℕ.𝟎      ⦃ singleton ℕ.𝟎 ⦄
  {-# CATCHALL #-}
  ... | [∃]-intro m   ⦃ a ⦄             = [∃]-intro (ℕ.𝐒(m)) ⦃ ℕ.𝟎 ⊰ a ⦄
  normalize {ℕ.𝐒 n} (ℕ.𝐒(x) ⊰ p) = [∃]-map ℕ.𝐒 (ℕ.𝐒(x) ⊰_) (normalize{n} p)

  degree : Polynomial(n) → ℕ
  degree = [∃]-witness Fn.∘ normalize

  𝐷 : Polynomial(n) → Polynomial(ℕ.𝐏(n))
  𝐷 {ℕ.𝟎}   = Fn.id
  𝐷 {ℕ.𝐒 n} = map₂₌(ℕ._⋅_) (accumulateIterate n ℕ.𝐒(ℕ.𝐒(ℕ.𝟎))) Fn.∘ tail

  import Numeral.Natural.Oper.FlooredDivision as ℕ
  ∫ : Polynomial(n) → Polynomial(ℕ.𝐒(n))
  ∫ {n} p = var⋅(map₂₌(ℕ._⌊/⌋₀_) p (accumulateIterate n ℕ.𝐒(ℕ.𝐒(ℕ.𝟎))))

module Semantics where
  open import Data.ListSized.Functions
  open import Logic.Propositional
  open import Numeral.Finite as 𝕟 using (𝕟)
  import      Numeral.Natural.Oper as ℕ
  open import Numeral.Natural.Oper.Proofs
  open import Numeral.Natural.Relation.Order
  open import Relator.Equals.Proofs.Equiv{T = ℕ}
  open import Structure.Function.Multi
  open import Structure.Operator
  open import Structure.Operator.Proofs.Util
  open import Structure.Operator.Properties
  open import Structure.Relator.Properties
  open import Structure.Setoid
  open import Syntax.Function
  open import Syntax.Transitivity

  eval : Polynomial(n) → (ℕ → ℕ)
  eval (singleton a)    _ = a
  eval (a ⊰ al@(_ ⊰ _)) x = a ℕ.+ (x ℕ.⋅ (eval al x))

  module Proofs where
    eval-of-[⊰] : ∀{x}{a}{al : Polynomial(n)} → (eval (a ⊰ al) x ≡ a ℕ.+ (x ℕ.⋅ (eval al x)))
    eval-of-[⊰] {ℕ.𝟎}   {x} {a} {b ⊰ ∅}      = reflexivity(_≡_)
    eval-of-[⊰] {ℕ.𝐒 n} {x} {a} {b ⊰ c ⊰ al} = reflexivity(_≡_)

    eval-preserves-var⋅ : ∀{x}{a : Polynomial(n)} → (eval (var⋅ a) x ≡ x ℕ.⋅ (eval a x))
    eval-preserves-var⋅ {n}{x}{a} = eval-of-[⊰] {n}{x}{ℕ.𝟎}{a}

    eval-preserves-zero : ∀{x} → (eval{n} 𝟎 x ≡ ℕ.𝟎)
    eval-preserves-zero {ℕ.𝟎}   {x} = reflexivity(_≡_)
    eval-preserves-zero {ℕ.𝐒 n} {x} =
      eval(𝟎 {ℕ.𝐒 n}) x              🝖[ _≡_ ]-[]
      eval(ℕ.𝟎 ⊰ 𝟎 {n}) x            🝖[ _≡_ ]-[]
      ℕ.𝟎 ℕ.+ (x ℕ.⋅ eval (𝟎 {n}) x) 🝖[ _≡_ ]-[]
      x ℕ.⋅ eval (𝟎 {n}) x           🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._⋅_)(x) (eval-preserves-zero{n}{x}) ]
      x ℕ.⋅ ℕ.𝟎                      🝖[ _≡_ ]-[ absorberᵣ(ℕ._⋅_)(ℕ.𝟎) {x} ]
      ℕ.𝟎                            🝖-end

    eval-preserves-const : ∀{x}{a} → (eval{n} (const a) x ≡ a)
    eval-preserves-const {ℕ.𝟎}   {x}{a} = reflexivity(_≡_)
    eval-preserves-const {ℕ.𝐒 n} {x}{a} =
      eval{ℕ.𝐒 n} (const a) x                  🝖[ _≡_ ]-[]
      eval(a ⊰ repeat ℕ.𝟎 (ℕ.𝐒 n)) x           🝖[ _≡_ ]-[ eval-of-[⊰] {x = x}{a}{repeat ℕ.𝟎 (ℕ.𝐒 n)} ]
      a ℕ.+ (x ℕ.⋅ eval(repeat ℕ.𝟎 (ℕ.𝐒 n)) x) 🝖[ _≡_ ]-[]
      a ℕ.+ (x ℕ.⋅ eval{n} 𝟎 x)                🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a) (eval-preserves-zero{ℕ.𝐒 n}{x = x}) ]
      a ℕ.+ (x ℕ.⋅ ℕ.𝟎)                        🝖[ _≡_ ]-[]
      a ℕ.+ ℕ.𝟎                                🝖[ _≡_ ]-[ identityᵣ(ℕ._+_)(ℕ.𝟎) ]
      a                                        🝖-end

    eval-preserves-one : ∀{x} → (eval{n} 𝟏 x ≡ ℕ.𝐒(ℕ.𝟎))
    eval-preserves-one {n}{x} = eval-preserves-const {n}{x}{ℕ.𝐒(ℕ.𝟎)}

    eval-preserves-var : ∀{x}{a : Polynomial(n)} → (eval (var{n}) x ≡ x)
    eval-preserves-var {n}{x}{a} =
      eval (var{n}) x      🝖[ _≡_ ]-[ eval-preserves-var⋅{n}{x}{𝟏} ]
      x ℕ.⋅ eval (𝟏 {n}) x 🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._⋅_)(x) (eval-preserves-one {n}{x}) ]
      x ℕ.⋅ ℕ.𝐒(ℕ.𝟎)       🝖[ _≡_ ]-[ identityᵣ(ℕ._⋅_)(ℕ.𝐒(ℕ.𝟎)) {x} ]
      x                    🝖-end

    eval-preserves-addition : ∀{x}{a : Polynomial(n₁)}{b : Polynomial(n₂)} → (eval (a + b) x ≡ (eval a x) ℕ.+ (eval b x))
    eval-preserves-addition {x = x} {singleton a}    {singleton b}    = reflexivity(_≡_)
    eval-preserves-addition {x = x} {singleton a}    {b ⊰ bs@(_ ⊰ _)} = associativity(ℕ._+_) {a}{b}
    eval-preserves-addition {x = x} {a ⊰ as@(_ ⊰ _)} {singleton b}    =
      eval ((a ⊰ as) + (singleton b)) x            🝖[ _≡_ ]-[]
      (a ℕ.+ b) ℕ.+ (x ℕ.⋅ (eval as x))            🝖[ _≡_ ]-[ associativity(ℕ._+_) {a}{b} ]
      a ℕ.+ (b ℕ.+ (x ℕ.⋅ (eval as x)))            🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a) (commutativity(ℕ._+_) {x = b}) ]
      a ℕ.+ ((x ℕ.⋅ (eval as x)) ℕ.+ b)            🝖[ _≡_ ]-[ associativity(ℕ._+_) {a}{x ℕ.⋅ eval as x} ]-sym
      (a ℕ.+ (x ℕ.⋅ (eval as x))) ℕ.+ b            🝖[ _≡_ ]-[]
      (eval (a ⊰ as) x) ℕ.+ (eval (singleton b) x) 🝖-end
    eval-preserves-addition {x = x} {a ⊰ as@(_ ⊰ _)} {b ⊰ bs@(_ ⊰ _)} =
      eval ((a ⊰ as) + (b ⊰ bs)) x                                  🝖[ _≡_ ]-[]
      eval ((a ℕ.+ b) ⊰ (as + bs)) x                                🝖[ _≡_ ]-[]
      (a ℕ.+ b) ℕ.+ (x ℕ.⋅ (eval (as + bs) x))                      🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.+ b) (congruence₂ᵣ(ℕ._⋅_)(x) (eval-preserves-addition {x = x}{as}{bs})) ]
      (a ℕ.+ b) ℕ.+ (x ℕ.⋅ ((eval as x) ℕ.+ (eval bs x)))           🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.+ b) (distributivityₗ(ℕ._⋅_)(ℕ._+_) {x}{eval as x}{eval bs x}) ]
      (a ℕ.+ b) ℕ.+ ((x ℕ.⋅ (eval as x)) ℕ.+ (x ℕ.⋅ (eval bs x)))   🝖[ _≡_ ]-[ One.associate-commute4 {a = a}{b = b}{c = x ℕ.⋅ (eval as x)}{d = x ℕ.⋅ (eval bs x)} (commutativity(ℕ._+_) {b}) ]
      (a ℕ.+ (x ℕ.⋅ (eval as x))) ℕ.+ (b ℕ.+ (x ℕ.⋅ (eval bs x)))   🝖[ _≡_ ]-[]
      (eval (a ⊰ as) x) ℕ.+ (eval (b ⊰ bs) x)                       🝖-end

    eval-preserves-scalar-multiplication : ∀{x}{a}{b : Polynomial(n)} → (eval (a ⋅ b) x ≡ a ℕ.⋅ (eval b x))
    eval-preserves-scalar-multiplication {ℕ.𝟎}   {x} {a} {b ⊰ ∅} = reflexivity(_≡_)
    eval-preserves-scalar-multiplication {ℕ.𝐒 n} {x} {a} {b ⊰ bs@(_ ⊰ _)} =
      eval (a ⋅ (b ⊰ bs)) x                     🝖[ _≡_ ]-[]
      eval ((a ℕ.⋅ b) ⊰ (a ⋅ bs)) x             🝖[ _≡_ ]-[]
      (a ℕ.⋅ b) ℕ.+ (x ℕ.⋅ (eval (a ⋅ bs) x))   🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.⋅ b) (congruence₂ᵣ(ℕ._⋅_)(x) (eval-preserves-scalar-multiplication {n} {x}{a}{bs})) ]
      (a ℕ.⋅ b) ℕ.+ (x ℕ.⋅ (a ℕ.⋅ (eval bs x))) 🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.⋅ b) (One.commuteₗ-assocᵣ {a = x}{b = a}{c = eval bs x}) ]
      (a ℕ.⋅ b) ℕ.+ (a ℕ.⋅ (x ℕ.⋅ (eval bs x))) 🝖[ _≡_ ]-[ distributivityₗ(ℕ._⋅_)(ℕ._+_) {x = a}{y = b}{z = x ℕ.⋅ (eval bs x)} ]-sym
      a ℕ.⋅ (b ℕ.+ (x ℕ.⋅ (eval bs x)))         🝖[ _≡_ ]-[]
      a ℕ.⋅ eval (b ⊰ bs) x                     🝖-end

    eval-preserves-pad : ∀{x}{a : Polynomial(n₁)} ⦃ ord : (n₁ ≤ n₂) ⦄ → (eval (pad ⦃ ord ⦄ a) x ≡ eval a x)
    eval-preserves-pad {ℕ.𝟎}    {ℕ.𝟎}    {x} {a ⊰ ∅}          ⦃ ord@min ⦄  = reflexivity(_≡_)
    eval-preserves-pad {ℕ.𝟎}    {ℕ.𝐒 n₂} {x} {a ⊰ ∅}          ⦃ ord@min ⦄  =
      eval (pad ⦃ ord ⦄ (a ⊰ ∅)) x  🝖[ _≡_ ]-[]
      a ℕ.+ (x ℕ.⋅ eval (𝟎 {n₂}) x) 🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a) (congruence₂ᵣ(ℕ._⋅_)(x) (eval-preserves-zero{n₂}{x})) ]
      a ℕ.+ (x ℕ.⋅ ℕ.𝟎)             🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a) (absorberᵣ(ℕ._⋅_)(ℕ.𝟎) {x}) ]
      a ℕ.+ ℕ.𝟎                     🝖[ _≡_ ]-[ identityᵣ(ℕ._+_)(ℕ.𝟎) ]
      a                             🝖[ _≡_ ]-[]
      eval (a ⊰ ∅) x                🝖-end
    eval-preserves-pad {ℕ.𝐒 n₁} {ℕ.𝐒 n₂} {x} {a ⊰ as@(_ ⊰ _)} ⦃ ord@(succ p) ⦄ =
      eval (pad ⦃ ord ⦄ (a ⊰ as)) x       🝖[ _≡_ ]-[]
      eval (a ⊰ pad ⦃ _ ⦄ as) x           🝖[ _≡_ ]-[ eval-of-[⊰] {n₂}{x}{a}{pad ⦃ p ⦄ as} ]
      a ℕ.+ (x ℕ.⋅ eval (pad ⦃ _ ⦄ as) x) 🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a) (congruence₂ᵣ(ℕ._⋅_)(x) (eval-preserves-pad {n₁}{n₂}{x}{as} ⦃ p ⦄)) ]
      a ℕ.+ (x ℕ.⋅ eval as x)       🝖[ _≡_ ]-[ eval-of-[⊰] {n₁}{x}{a}{as} ]-sym
      eval (a ⊰ as) x               🝖-end

    eval-preserves-multiplication : ∀{x}{a : Polynomial(n₁)}{b : Polynomial(n₂)} → (eval (a ⨯ b) x ≡ (eval a x) ℕ.⋅ (eval b x))
    eval-preserves-multiplication {n₁}    {ℕ.𝟎}   {x} {a ⊰ as}         {b ⊰ ∅}          =
      eval ((a ⊰ as) ⨯ (b ⊰ ∅)) x          🝖[ _≡_ ]-[]
      eval (b ⋅ (a ⊰ as)) x                🝖[ _≡_ ]-[ eval-preserves-scalar-multiplication {x = x}{b}{a ⊰ as} ]
      b ℕ.⋅ eval (a ⊰ as) x                🝖[ _≡_ ]-[ commutativity(ℕ._⋅_) {b}{eval(a ⊰ as) x} ]
      eval (a ⊰ as) x ℕ.⋅ b                🝖[ _≡_ ]-[]
      (eval (a ⊰ as) x ℕ.⋅ eval (b ⊰ ∅) x) 🝖-end
    eval-preserves-multiplication {ℕ.𝟎}   {ℕ.𝐒 n₂}{x} {a ⊰ ∅}          {b ⊰ bs@(_ ⊰ _)} =
      eval ((a ⊰ ∅) ⨯ (b ⊰ bs)) x        🝖[ _≡_ ]-[]
      eval (a ⋅ (b ⊰ bs)) x              🝖[ _≡_ ]-[ eval-preserves-scalar-multiplication {x = x}{a}{b ⊰ bs} ]
      a ℕ.⋅ (b ℕ.+ (x ℕ.⋅ eval bs x))    🝖[ _≡_ ]-[]
      eval (a ⊰ ∅) x ℕ.⋅ eval (b ⊰ bs) x 🝖-end
    eval-preserves-multiplication {ℕ.𝐒 n₁}{ℕ.𝐒 n₂}{x} {a ⊰ as@(_ ⊰ _)} {b ⊰ bs@(_ ⊰ _)} =
      eval((a ℕ.⋅ b) ⊰ lr) x                                                                                🝖[ _≡_ ]-[ eval-of-[⊰] {x = x}{a = a ℕ.⋅ b}{al = lr} ]
      (a ℕ.⋅ b) ℕ.+ (x ℕ.⋅ eval lr x)                                                                                🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.⋅ b) (congruence₂ᵣ(ℕ._⋅_)(x) eval-lr) ]
      (a ℕ.⋅ b) ℕ.+ (x ℕ.⋅ (((b ℕ.⋅ eval as x) ℕ.+ (a ℕ.⋅ eval bs x)) ℕ.+ (x ℕ.⋅ (eval as x ℕ.⋅ eval bs x))))                   🝖[ _≡_ ]-[ alg{a}{b}{x}{eval as x}{eval bs x} ]
      (a ℕ.+ (x ℕ.⋅ eval as x)) ℕ.⋅ (b ℕ.+ (x ℕ.⋅ eval bs x))                                                                   🝖[ _≡_ ]-[ congruence₂(ℕ._⋅_) (eval-of-[⊰] {x = x}{a = a}{al = as}) (eval-of-[⊰] {x = x}{a = b}{al = bs}) ]
      (eval(a ⊰ as) x ℕ.⋅ eval(b ⊰ bs) x)                                                                                🝖-end
      where
        open import Numeral.Natural.Function
        open import Numeral.Natural.Function.Proofs
        open import Numeral.Natural.Relation.Order.Proofs
        open import Relator.Equals using ([≡]-intro)

        l : Polynomial(n₁ ℕ.+ n₂)
        l = pad ⦃ max-order-[+] ⦄ ((b ⋅ as) + (a ⋅ bs))

        r : Polynomial(ℕ.𝐒(n₁ ℕ.+ n₂))
        r = var⋅ (as ⨯ bs)

        lr : Polynomial(ℕ.𝐒(n₁ ℕ.+ n₂))
        lr = [≡]-substitutionᵣ ([↔]-to-[→] max-defᵣ [≤]-of-[𝐒]) {Polynomial} (l + r)

        eval-l : (eval l x ≡ (b ℕ.⋅ eval as x) ℕ.+ (a ℕ.⋅ eval bs x))
        eval-l =
          eval l x                                             🝖[ _≡_ ]-[]
          eval (pad ⦃ max-order-[+] ⦄ ((b ⋅ as) + (a ⋅ bs))) x 🝖[ _≡_ ]-[ eval-preserves-pad {x = x}{(b ⋅ as) + (a ⋅ bs)} ⦃ max-order-[+] ⦄ ]
          eval ((b ⋅ as) + (a ⋅ bs)) x                         🝖[ _≡_ ]-[ eval-preserves-addition {x = x}{b ⋅ as}{a ⋅ bs} ]
          eval (b ⋅ as) x ℕ.+ eval (a ⋅ bs) x                  🝖[ _≡_ ]-[ congruence₂(ℕ._+_) (eval-preserves-scalar-multiplication {x = x}{b}{as}) (eval-preserves-scalar-multiplication {x = x}{a}{bs}) ]
          (b ℕ.⋅ eval as x) ℕ.+ (a ℕ.⋅ eval bs x)              🝖-end

        eval-r : (eval r x ≡ x ℕ.⋅ (eval as x ℕ.⋅ eval bs x))
        eval-r =
          eval r x                        🝖[ _≡_ ]-[]
          eval (var⋅ (as ⨯ bs)) x         🝖[ _≡_ ]-[ eval-preserves-var⋅ {x = x}{as ⨯ bs} ]
          x ℕ.⋅ eval (as ⨯ bs) x          🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._⋅_)(x) (eval-preserves-multiplication {x = x}{as}{bs}) ]
          x ℕ.⋅ (eval as x ℕ.⋅ eval bs x) 🝖-end

        eval-substitution : ∀{m n}{a : Polynomial(m)}{eq : (m ≡ n)}{x} → (eval ([≡]-substitutionᵣ eq {Polynomial} a) x ≡ eval a x)
        eval-substitution {eq = [≡]-intro} = [≡]-intro

        eval-lr : (eval lr x ≡ ((b ℕ.⋅ eval as x) ℕ.+ (a ℕ.⋅ eval bs x)) ℕ.+ (x ℕ.⋅ (eval as x ℕ.⋅ eval bs x)))
        eval-lr =
          eval lr x                                                                       🝖[ _≡_ ]-[ eval-substitution{a = l + r}{[↔]-to-[→] max-defᵣ [≤]-of-[𝐒]}{x = x} ]
          eval (l + r) x                                                                  🝖[ _≡_ ]-[ eval-preserves-addition{x = x}{l}{r} ]
          eval l x ℕ.+ eval r x                                                           🝖[ _≡_ ]-[ congruence₂(ℕ._+_) eval-l eval-r ]
          ((b ℕ.⋅ eval as x) ℕ.+ (a ℕ.⋅ eval bs x)) ℕ.+ (x ℕ.⋅ (eval as x ℕ.⋅ eval bs x)) 🝖-end

        alg : ∀{a b x q r} → ((a ℕ.⋅ b) ℕ.+ (x ℕ.⋅ (((b ℕ.⋅ q) ℕ.+ (a ℕ.⋅ r)) ℕ.+ (x ℕ.⋅ (q ℕ.⋅ r)))) ≡ (a ℕ.+ (x ℕ.⋅ q)) ℕ.⋅ (b ℕ.+ (x ℕ.⋅ r)))
        alg {a}{b}{x}{q}{r} =
          (a ℕ.⋅ b) ℕ.+ (x ℕ.⋅ (((b ℕ.⋅ q) ℕ.+ (a ℕ.⋅ r)) ℕ.+ (x ℕ.⋅ (q ℕ.⋅ r))))                   🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.⋅ b) (distributivityₗ(ℕ._⋅_)(ℕ._+_) {x}{(b ℕ.⋅ q) ℕ.+ (a ℕ.⋅ r)}{x ℕ.⋅ (q ℕ.⋅ r)}) ]
          (a ℕ.⋅ b) ℕ.+ ((x ℕ.⋅ ((b ℕ.⋅ q) ℕ.+ (a ℕ.⋅ r))) ℕ.+ (x ℕ.⋅ (x ℕ.⋅ (q ℕ.⋅ r))))           🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.⋅ b) (congruence₂(ℕ._+_) (distributivityₗ(ℕ._⋅_)(ℕ._+_) {x}{b ℕ.⋅ q}{a ℕ.⋅ r}) (symmetry(_≡_) (associativity(ℕ._⋅_) {x}{x}{q ℕ.⋅ r}))) ]
          (a ℕ.⋅ b) ℕ.+ (((x ℕ.⋅ (b ℕ.⋅ q)) ℕ.+ (x ℕ.⋅ (a ℕ.⋅ r))) ℕ.+ ((x ℕ.⋅ x) ℕ.⋅ (q ℕ.⋅ r)))   🝖[ _≡_ ]-[ congruence₂ᵣ(ℕ._+_)(a ℕ.⋅ b) (congruence₂(ℕ._+_) (congruence₂(ℕ._+_) (One.commuteᵣ-assocᵣ {_▫_ = ℕ._⋅_}{a = x}{b}{q}) (One.commuteₗ-assocᵣ {_▫_ = ℕ._⋅_}{a = x}{a}{r})) (One.associate-commute4-c {_▫_ = ℕ._⋅_}{a = x}{x}{q}{r})) ]
          (a ℕ.⋅ b) ℕ.+ ((((x ℕ.⋅ q) ℕ.⋅ b) ℕ.+ (a ℕ.⋅ (x ℕ.⋅ r))) ℕ.+ ((x ℕ.⋅ q) ℕ.⋅ (x ℕ.⋅ r)))   🝖[ _≡_ ]-[ One.associate4-231-222 {_▫_ = ℕ._+_} {a = a ℕ.⋅ b}{(x ℕ.⋅ q) ℕ.⋅ b}{a ℕ.⋅ (x ℕ.⋅ r)}{(x ℕ.⋅ q) ℕ.⋅ (x ℕ.⋅ r)} ]
          ((a ℕ.⋅ b) ℕ.+ ((x ℕ.⋅ q) ℕ.⋅ b)) ℕ.+ ((a ℕ.⋅ (x ℕ.⋅ r)) ℕ.+ ((x ℕ.⋅ q) ℕ.⋅ (x ℕ.⋅ r)))   🝖[ _≡_ ]-[ OneTypeTwoOp.cross-distribute{a = a}{x ℕ.⋅ q}{b}{x ℕ.⋅ r} ]-sym
          (a ℕ.+ (x ℕ.⋅ q)) ℕ.⋅ (b ℕ.+ (x ℕ.⋅ r))                                                   🝖-end


module Issue690a where

data ℕ : Set where
  zero : ℕ
  succ : ℕ → ℕ

-- A negative type.
data T : Set → Set where
  c : T (T ℕ)

-- From Andreas (2012-09-07) message on Agda mailing list "Forget
-- Hurken's paradox ..."
--
-- Trying to make sense of T in terms of inductive types, explaining
-- indices via equalities, one arrives at
--
--  data T (X : Set) : Set where
--    c : (X ≡ T ℕ) → T X
--
-- which has a non-positive occurrence of T in (X ≡ T ℕ).
--
-- An argument for the existence of T would have to argue for the
-- existence this least fixed point:
--
--  lfp \lambda T X → (X ≡ T ℕ)

-- ASR (14 August 2014): In Coq'Art, § 14.1.2.1, the type T is
-- rejected due to the head type constrains.


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

module SetQuotientTest where

open import Cubical.Foundations.Everything renaming (_⁻¹ to _⁻¹ᵖ; assoc to ∙-assoc)
open import Cubical.Foundations.Logic renaming (inl to inlᵖ; inr to inrᵖ)
open import Cubical.Data.Empty renaming (elim to ⊥-elim; ⊥ to ⊥⊥)
open import Cubical.Relation.Nullary.Base renaming (¬_ to ¬ᵗ_)
open import Cubical.Data.Sigma.Base renaming (_×_ to infixr 4 _×_)
open import Cubical.Data.Sum.Base renaming (_⊎_ to infixr 4 _⊎_)
open import Cubical.Data.NatPlusOne using (HasFromNat; 1+_; ℕ₊₁; ℕ₊₁→ℕ)
open import Cubical.HITs.Ints.QuoInt using (HasFromNat; signed) renaming
  ( abs to absᶻ
  ; pos to pos
  ; neg to neg
  )
open import Cubical.HITs.Ints.QuoInt hiding (_+_; -_; +-assoc; +-comm)
open import Cubical.HITs.Rationals.QuoQ using
    ( ℚ
    ; onCommonDenom
    ; onCommonDenomSym
    ; eq/
    ; _//_
    ; _∼_
    ; isSetℚ
    )
    renaming
    ( [_] to [_]ᶠ
    ; ℕ₊₁→ℤ to [1+_ⁿ]ᶻ
    )
open import Cubical.HITs.SetQuotients as SetQuotient using () renaming (_/_ to _//_)

postulate
  _<ᶻ_ : ℤ → ℤ → hProp ℓ-zero

_<'_ : ℤ × ℕ₊₁ → ℤ × ℕ₊₁ → hProp ℓ-zero
(aᶻ , aⁿ) <' (bᶻ , bⁿ) =
  let aⁿᶻ = [1+ aⁿ ⁿ]ᶻ
      bⁿᶻ = [1+ bⁿ ⁿ]ᶻ
  in (aᶻ * bⁿᶻ) <ᶻ (bᶻ * aⁿᶻ)

postulate
  <'-respects-∼ˡ : ∀ a b x → a ∼ b → a <' x ≡ b <' x
  <'-respects-∼ʳ : ∀ x a b → a ∼ b → x <' a ≡ x <' b

_<_ : ℚ → ℚ → hProp ℓ-zero
a < b = SetQuotient.rec2 {R = _∼_} {B = hProp ℓ-zero} isSetHProp _<'_ <'-respects-∼ˡ <'-respects-∼ʳ a b

isProp⊎ˡ : ∀{ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → isProp A → isProp B → (A → ¬ᵗ B) → isProp (A ⊎ B)
isProp⊎ˡ pA pB A⇒¬B (inl x) (inl y) = cong inl (pA x y)
isProp⊎ˡ pA pB A⇒¬B (inr x) (inr y) = cong inr (pB x y)
isProp⊎ˡ pA pB A⇒¬B (inl x) (inr y) = ⊥-elim (A⇒¬B x y)
isProp⊎ˡ pA pB A⇒¬B (inr x) (inl y) = ⊥-elim (A⇒¬B y x)

⊎ᵖ-syntax : ∀{ℓ ℓ'} (P : hProp ℓ) (Q : hProp ℓ') → {[ P ] → [ ¬ Q ]} → hProp _
⊎ᵖ-syntax P Q {P⇒¬Q} = ([ P ] ⊎ [ Q ]) , isProp⊎ˡ (isProp[] P) (isProp[] Q) P⇒¬Q

syntax ⊎ᵖ-syntax P Q {P⇒¬Q} = [ P⇒¬Q ] P ⊎ᵖ Q

postulate
  <-asym : ∀ x y → [ x < y ] → [ ¬(y < x) ]

_#_ : ℚ → ℚ → hProp ℓ-zero
x # y = [ <-asym x y ] (x < y) ⊎ᵖ (y < x)

_⁻¹''' : (x : ℚ) → [ x # 0 ] → ℚ
_⁻¹''' = SetQuotient.elim {R = _∼_} {B = λ x → [ x # 0 ] → ℚ} φ _⁻¹'' ⁻¹''-respects-∼ where
  φ : ∀ x → isSet ([ x # 0 ] → ℚ)
  φ x = isSetΠ (λ _ → isSetℚ)
  _⁻¹''  : (a : ℤ × ℕ₊₁) → [ [ a ]ᶠ # 0 ] → ℚ
  x ⁻¹'' = {!!}
  ⁻¹''-respects-∼ : (a b : ℤ × ℕ₊₁) (r : a ∼ b)
                  → PathP (λ i → [ eq/ a b r i # 0 ] → ℚ) (a ⁻¹'') (b ⁻¹'')
  ⁻¹''-respects-∼ a b r = {!!}


------------------------------------------------------------------------
-- The Agda standard library
--
-- Almost commutative rings
------------------------------------------------------------------------

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

module Tactic.RingSolver.Core.AlmostCommutativeRing where

open import Level
open import Relation.Binary
open import Algebra.Core using (Op₁; Op₂)
open import Algebra.Structures using (IsCommutativeSemiring)
open import Algebra.Definitions
open import Algebra.Bundles using (RawRing; CommutativeRing; CommutativeSemiring)
import Algebra.Morphism as Morphism
open import Function
open import Level
open import Data.Maybe.Base as Maybe using (Maybe; just; nothing)

record IsAlmostCommutativeRing
         {a ℓ} {A : Set a} (_≈_ : Rel A ℓ)
         (_+_ _*_ : A → A → A) (-_ : A → A) (0# 1# : A) : Set (a ⊔ ℓ) where
  field
    isCommutativeSemiring : IsCommutativeSemiring _≈_ _+_ _*_ 0# 1#
    -‿cong                : -_ Preserves _≈_ ⟶ _≈_
    -‿*-distribˡ          : ∀ x y → ((- x) * y)     ≈ (- (x * y))
    -‿+-comm              : ∀ x y → ((- x) + (- y)) ≈ (- (x + y))

  open IsCommutativeSemiring isCommutativeSemiring public

import Algebra.Operations.Ring as Exp

record AlmostCommutativeRing c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 -_
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  infixr 8 _^_
  field
    Carrier                 : Set c
    _≈_                     : Rel Carrier ℓ
    _+_                     : Op₂ Carrier
    _*_                     : Op₂ Carrier
    -_                      : Op₁ Carrier
    0#                      : Carrier
    0≟_                     : (x : Carrier) → Maybe (0# ≈ x)
    1#                      : Carrier
    isAlmostCommutativeRing :
      IsAlmostCommutativeRing _≈_ _+_ _*_ -_ 0# 1#

  open IsAlmostCommutativeRing isAlmostCommutativeRing hiding (refl) public
  open import Data.Nat.Base as ℕ using (ℕ)

  commutativeSemiring : CommutativeSemiring _ _
  commutativeSemiring = record
    { isCommutativeSemiring = isCommutativeSemiring
    }

  open CommutativeSemiring commutativeSemiring public
    using ( +-semigroup; +-monoid; +-commutativeMonoid
          ; *-semigroup; *-monoid; *-commutativeMonoid
          ; semiring
          )

  rawRing : RawRing _ _
  rawRing = record
    { _≈_ = _≈_
    ; _+_ = _+_
    ; _*_ = _*_
    ; -_  = -_
    ; 0#  = 0#
    ; 1#  = 1#
    }

  _^_ : Carrier → ℕ → Carrier
  _^_ = Exp._^_ rawRing
  {-# NOINLINE _^_ #-}

  refl : ∀ {x} → x ≈ x
  refl = IsAlmostCommutativeRing.refl isAlmostCommutativeRing

record _-Raw-AlmostCommutative⟶_
         {r₁ r₂ r₃ r₄}
         (From : RawRing r₁ r₂)
         (To : AlmostCommutativeRing r₃ r₄) : Set (r₁ ⊔ r₂ ⊔ r₃ ⊔ r₄) where
  private
    module F = RawRing From
    module T = AlmostCommutativeRing To
  open Morphism.Definitions F.Carrier T.Carrier T._≈_
  field
    ⟦_⟧    : Morphism
    +-homo : Homomorphic₂ ⟦_⟧ F._+_ T._+_
    *-homo : Homomorphic₂ ⟦_⟧ F._*_ T._*_
    -‿homo : Homomorphic₁ ⟦_⟧ F.-_  T.-_
    0-homo : Homomorphic₀ ⟦_⟧ F.0#  T.0#
    1-homo : Homomorphic₀ ⟦_⟧ F.1#  T.1#

-raw-almostCommutative⟶
  : ∀ {r₁ r₂} (R : AlmostCommutativeRing r₁ r₂) →
    AlmostCommutativeRing.rawRing R -Raw-AlmostCommutative⟶ R
-raw-almostCommutative⟶ R = record
  { ⟦_⟧    = id
  ; +-homo = λ _ _ → refl
  ; *-homo = λ _ _ → refl
  ; -‿homo = λ _ → refl
  ; 0-homo = refl
  ; 1-homo = refl
  }
  where open AlmostCommutativeRing R

-- A homomorphism induces a notion of equivalence on the raw ring.

Induced-equivalence :
  ∀ {c₁ c₂ c₃ ℓ} {Coeff : RawRing c₁ c₂} {R : AlmostCommutativeRing c₃ ℓ} →
  Coeff -Raw-AlmostCommutative⟶ R → Rel (RawRing.Carrier Coeff) ℓ
Induced-equivalence {R = R} morphism a b = ⟦ a ⟧ ≈ ⟦ b ⟧
  where
  open AlmostCommutativeRing R
  open _-Raw-AlmostCommutative⟶_ morphism

------------------------------------------------------------------------
-- Conversions

-- Commutative rings are almost commutative rings.

fromCommutativeRing : ∀ {r₁ r₂} (CR : CommutativeRing r₁ r₂) →
                      (open CommutativeRing CR) →
                      (∀ x → Maybe (0# ≈ x)) →
                      AlmostCommutativeRing _ _
fromCommutativeRing CR 0≟_ = record
  { isAlmostCommutativeRing = record
      { isCommutativeSemiring = isCommutativeSemiring
      ; -‿cong                = -‿cong
      ; -‿*-distribˡ          = -‿*-distribˡ
      ; -‿+-comm              = ⁻¹-∙-comm
      }
  ; 0≟_ = 0≟_
  }
  where
  open CommutativeRing CR
  open import Algebra.Properties.Ring ring
  open import Algebra.Properties.AbelianGroup +-abelianGroup

fromCommutativeSemiring : ∀ {r₁ r₂} (CS : CommutativeSemiring r₁ r₂)
                          (open CommutativeSemiring CS) →
                          (∀ x → Maybe (0# ≈ x)) →
                          AlmostCommutativeRing _ _
fromCommutativeSemiring CS 0≟_ = record
  { -_                      = id
  ; isAlmostCommutativeRing = record
      { isCommutativeSemiring = isCommutativeSemiring
      ; -‿cong                = id
      ; -‿*-distribˡ          = λ _ _ → refl
      ; -‿+-comm              = λ _ _ → refl
      }
  ; 0≟_ = 0≟_
  }
  where open CommutativeSemiring CS


module Data.Star.Indexed where

open import Relation.Binary
open import Function
open import Level

infixr 10 _◅_
data Star {i a t}(I : Set i){A : I → Set a}
     (T : ∀ n m → REL (A n) (A m) t) : ∀ {n m : I} → REL (A n) (A m) (i ⊔ a ⊔ t) where
  ε   : ∀ {i}{x : A i} → Star I T x x
  _◅_ : ∀ {n m k : I}{x : A n}{y : A m}{z : A k} → T n m x y → Star I T y z → Star I T x z


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

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

module Categories.Functor.Definition where

record Functor {a b c d : _} (C : Category {a} {b}) (D : Category {c} {d}) : Set (a ⊔ b ⊔ c ⊔ d) where
  field
    onObj : Category.objects C → Category.objects D
    onArrow : {S T : Category.objects C} → Category.arrows C S T → Category.arrows D (onObj S) (onObj T)
    mapId : {T : Category.objects C} → onArrow (Category.id C T) ≡ Category.id D (onObj T)
    mapCompose : {X Y Z : Category.objects C} → (f : Category.arrows C X Y) (g : Category.arrows C Y Z) → onArrow (Category._∘_ C g f) ≡ Category._∘_ D (onArrow g) (onArrow f)


{-

This file contains basic theory about subgroups.

The definition is the same as the first definition of subgroups in:

https://www.cs.bham.ac.uk/~mhe/HoTT-UF-in-Agda-Lecture-Notes/HoTT-UF-Agda.html#subgroups-sip

-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.Group.Subgroup where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure
open import Cubical.Foundations.Powerset
open import Cubical.Foundations.GroupoidLaws hiding (assoc)
open import Cubical.Data.Sigma
open import Cubical.HITs.PropositionalTruncation

open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Group.Properties
open import Cubical.Algebra.Group.Morphisms
open import Cubical.Algebra.Group.MorphismProperties

private
  variable
    ℓ : Level

-- We assume an ambient group
module _ (G' : Group ℓ) where

  open GroupStr (snd G')
  private G = ⟨ G' ⟩

  record isSubgroup (H : ℙ G) : Type ℓ where
    field
      id-closed  : (1g ∈ H)
      op-closed  : {x y : G} → x ∈ H → y ∈ H → x · y ∈ H
      inv-closed : {x : G} → x ∈ H → inv x ∈ H

  open isSubgroup

  Subgroup : Type (ℓ-suc ℓ)
  Subgroup = Σ[ H ∈ ℙ G ] isSubgroup H

  isPropIsSubgroup : (H : ℙ G) → isProp (isSubgroup H)
  id-closed (isPropIsSubgroup H h1 h2 i) =
    ∈-isProp H 1g (h1 .id-closed) (h2 .id-closed) i
  op-closed (isPropIsSubgroup H h1 h2 i) Hx Hy =
    ∈-isProp H _ (h1 .op-closed Hx Hy) (h2 .op-closed Hx Hy) i
  inv-closed (isPropIsSubgroup H h1 h2 i) Hx =
    ∈-isProp H _ (h1 .inv-closed Hx) (h2 .inv-closed Hx) i

  isSetSubgroup : isSet Subgroup
  isSetSubgroup = isSetΣ isSetℙ λ x → isProp→isSet (isPropIsSubgroup x)

  Subgroup→Group : Subgroup → Group ℓ
  Subgroup→Group (H , Hh) = makeGroup-right 1HG _·HG_ invHG isSetHG assocHG ridHG invrHG
    where
    HG = Σ[ x ∈ G ] ⟨ H x ⟩
    isSetHG = isSetΣ is-set (λ x → isProp→isSet (H x .snd))

    1HG : HG
    1HG = (1g , (id-closed Hh))

    _·HG_ : HG → HG → HG
    (x , Hx) ·HG (y , Hy) = (x · y) , (op-closed Hh Hx Hy)

    invHG : HG → HG
    invHG (x , Hx) = inv x , inv-closed Hh Hx

    assocHG : (x y z : HG) → x ·HG (y ·HG z) ≡ (x ·HG y) ·HG z
    assocHG (x , Hx) (y , Hy) (z , Hz) =
      ΣPathP (·Assoc x y z , isProp→PathP (λ i → H (·Assoc x y z i) .snd) _ _)

    ridHG : (x : HG) → x ·HG 1HG ≡ x
    ridHG (x , Hx) = ΣPathP (·IdR x , isProp→PathP (λ i → H (·IdR x i) .snd) _ _)

    invrHG : (x : HG) → x ·HG invHG x ≡ 1HG
    invrHG (x , Hx) = ΣPathP (·InvR x , isProp→PathP (λ i → H (·InvR x i) .snd) _ _)

⟪_⟫ : {G' : Group ℓ} → Subgroup G' → ℙ (G' .fst)
⟪ H , _ ⟫ = H

module _ {G' : Group ℓ} where

  open GroupStr (snd G')
  open isSubgroup
  open GroupTheory G'
  private G = ⟨ G' ⟩

  isNormal : Subgroup G' → Type ℓ
  isNormal H = (g h : G) → h ∈ ⟪ H ⟫ → g · h · inv g ∈ ⟪ H ⟫

  isPropIsNormal : (H : Subgroup G') → isProp (isNormal H)
  isPropIsNormal H = isPropΠ3 λ g h _ → ∈-isProp ⟪ H ⟫ (g · h · inv g)

  ·CommNormalSubgroup : (H : Subgroup G') (Hnormal : isNormal H) {x y : G}
                      → x · y ∈ ⟪ H ⟫ → y · x ∈ ⟪ H ⟫
  ·CommNormalSubgroup H Hnormal {x = x} {y = y} Hxy =
    subst-∈ ⟪ H ⟫ rem (Hnormal (inv x) (x · y) Hxy)
      where
      rem : inv x · (x · y) · inv (inv x) ≡ y · x
      rem = inv x · (x · y) · inv (inv x) ≡⟨ ·Assoc _ _ _ ⟩
            (inv x · x · y) · inv (inv x) ≡⟨ (λ i → ·Assoc (inv x) x y i · invInv x i) ⟩
            ((inv x · x) · y) · x         ≡⟨ cong (λ z → (z · y) · x) (·InvL x) ⟩
            (1g · y) · x                  ≡⟨ cong (_· x) (·IdL y) ⟩
            y · x                         ∎

  -- Examples of subgroups

  -- We can view all of G as a subset of itself
  groupSubset : ℙ G
  groupSubset x = (x ≡ x) , is-set x x

  isSubgroupGroup : isSubgroup G' groupSubset
  id-closed isSubgroupGroup = refl
  op-closed isSubgroupGroup _ _ = refl
  inv-closed isSubgroupGroup _ = refl

  groupSubgroup : Subgroup G'
  groupSubgroup = groupSubset , isSubgroupGroup

  -- The trivial subgroup
  trivialSubset : ℙ G
  trivialSubset x = (x ≡ 1g) , is-set x 1g

  isSubgroupTrivialGroup : isSubgroup G' trivialSubset
  id-closed isSubgroupTrivialGroup = refl
  op-closed isSubgroupTrivialGroup hx hy = cong (_· _) hx ∙∙ ·IdL _ ∙∙ hy
  inv-closed isSubgroupTrivialGroup hx = cong inv hx ∙ inv1g

  trivialSubgroup : Subgroup G'
  trivialSubgroup = trivialSubset , isSubgroupTrivialGroup

  isNormalTrivialSubgroup : isNormal trivialSubgroup
  isNormalTrivialSubgroup g h h≡1 =
    (g · h · inv g)  ≡⟨ (λ i → g · h≡1 i · inv g) ⟩
    (g · 1g · inv g) ≡⟨ ·Assoc _ _ _ ∙ cong (_· inv g) (·IdR g) ⟩
    (g · inv g)      ≡⟨ ·InvR g ⟩
    1g ∎

NormalSubgroup : (G : Group ℓ) → Type _
NormalSubgroup G = Σ[ G ∈ Subgroup G ] isNormal G

-- Can one get this to work with different universes for G and H?
module _ {G H : Group ℓ} (ϕ : GroupHom G H) where

  open isSubgroup
  open GroupTheory

  private
    module G = GroupStr (snd G)
    module H = GroupStr (snd H)
    f = ϕ .fst
    module ϕ = IsGroupHom (ϕ .snd)

  imSubset : ℙ ⟨ H ⟩
  imSubset x = isInIm ϕ x , isPropIsInIm ϕ x

  isSubgroupIm : isSubgroup H imSubset
  id-closed isSubgroupIm = ∣ G.1g , ϕ.pres1 ∣₁
  op-closed isSubgroupIm =
    map2 λ { (x , hx) (y , hy) → x G.· y , ϕ.pres· x y ∙ λ i → hx i H.· hy i }
  inv-closed isSubgroupIm = map λ { (x , hx) → G.inv x , ϕ.presinv x ∙ cong H.inv hx }

  imSubgroup : Subgroup H
  imSubgroup = imSubset , isSubgroupIm

  imGroup : Group ℓ
  imGroup = Subgroup→Group _ imSubgroup

  isNormalIm : ((x y : ⟨ H ⟩) → x H.· y ≡ y H.· x)
            → isNormal imSubgroup
  isNormalIm comm x y =
    map λ {(g , p)
      → g ,
      (ϕ .fst g                  ≡⟨ p ⟩
      y                          ≡⟨ sym (H.·IdR y) ⟩
      (y H.· H.1g)               ≡⟨ cong (y H.·_) (sym (H.·InvR x)) ⟩
      (y H.· (x H.· H.inv x))    ≡⟨ H.·Assoc y x (H.inv x) ⟩
      ((y H.· x) H.· H.inv x)    ≡⟨ cong (H._· H.inv x) (comm y x) ⟩
      ((x H.· y) H.· H.inv x)    ≡⟨ sym (H.·Assoc x y (H.inv x)) ⟩
      x H.· y H.· H.inv x        ∎ )}

  kerSubset : ℙ ⟨ G ⟩
  kerSubset x = isInKer ϕ x , isPropIsInKer ϕ x

  isSubgroupKer : isSubgroup G kerSubset
  id-closed isSubgroupKer = ϕ.pres1
  op-closed isSubgroupKer {x} {y} hx hy =
    ϕ.pres· x y ∙∙ (λ i → hx i H.· hy i) ∙∙ H.·IdR _
  inv-closed isSubgroupKer hx = ϕ.presinv _ ∙∙ cong H.inv hx ∙∙ inv1g H

  kerSubgroup : Subgroup G
  kerSubgroup = kerSubset , isSubgroupKer

  isNormalKer : isNormal kerSubgroup
  isNormalKer x y hy =
    f (x G.· y G.· G.inv x)         ≡⟨ ϕ.pres· _ _ ⟩
    f x H.· f (y G.· G.inv x)       ≡⟨ cong (f x H.·_) (ϕ.pres· _ _) ⟩
    f x H.· f y H.· f (G.inv x)     ≡⟨ (λ i → f x H.· hy i H.· f (G.inv x)) ⟩
    f x H.· (H.1g H.· f (G.inv x))  ≡⟨ cong (f x H.·_) (H.·IdL _) ⟩
    f x H.· f (G.inv x)             ≡⟨ cong (f x H.·_) (ϕ.presinv x) ⟩
    f x H.· H.inv (f x)             ≡⟨ H.·InvR _ ⟩
    H.1g                            ∎


module bools where

open import lib

----------------------------------------------------------------------
-- these problems are about the nand operator, also known as the Scheffer stroke
----------------------------------------------------------------------
nand-not : ∀ (b : 𝔹) → ~ b ≡ b nand b
nand-not tt = refl
nand-not ff = refl

nand-or : ∀ (b1 b2 : 𝔹) → b1 || b2 ≡ (b1 nand b1) nand (b2 nand b2)
nand-or tt tt = refl
nand-or tt ff = refl
nand-or ff tt = refl
nand-or ff ff = refl

nand-and : ∀ (b1 b2 : 𝔹) → b1 && b2 ≡ (b1 nand b2) nand (b1 nand b2)
nand-and tt tt = refl
nand-and tt ff = refl
nand-and ff tt = refl
nand-and ff ff = refl

nand-imp : ∀ (b1 b2 : 𝔹) → b1 imp b2 ≡ b1 nand (b2 nand b2)
nand-imp tt tt = refl
nand-imp tt ff = refl
nand-imp ff tt = refl
nand-imp ff ff = refl

ite-not : ∀(A : Set)(x : 𝔹)(y : A)(z : A) → if x then y else z ≡ if ~ x then z else y
ite-not A tt y z = refl
ite-not A ff y z = refl

&&-distrib : ∀ x y z → x && (y || z) ≡ (x && y) || (x && z)
&&-distrib tt tt tt = refl
&&-distrib tt tt ff = refl
&&-distrib tt ff tt = refl
&&-distrib tt ff ff = refl
&&-distrib ff tt tt = refl
&&-distrib ff tt ff = refl
&&-distrib ff ff tt = refl
&&-distrib ff ff ff = refl

combK : ∀ x y → x imp (y imp x) ≡ tt
combK tt tt = refl
combK tt ff = refl
combK ff tt = refl
combK ff ff = refl

combS : ∀ x y z → (x imp (y imp z)) ≡ tt → (x imp y) ≡ tt → x ≡ tt → z ≡ tt
combS tt tt tt x₁ x₂ x₃ = refl


------------------------------------------------------------------------------
-- Properties of the Collatz function
------------------------------------------------------------------------------

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

module FOTC.Program.Collatz.PropertiesATP where

open import FOTC.Base
open import FOTC.Data.Nat
open import FOTC.Data.Nat.PropertiesATP using ( ∸-N )
open import FOTC.Data.Nat.UnaryNumbers
open import FOTC.Data.Nat.UnaryNumbers.TotalityATP using ( 2-N )
open import FOTC.Program.Collatz.Collatz
open import FOTC.Program.Collatz.Data.Nat
open import FOTC.Program.Collatz.Data.Nat.PropertiesATP

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

helper : ∀ {n} → N n → collatz (2' ^ succ₁ n) ≡ collatz (2' ^ n)
helper nzero = prf
  where postulate prf : collatz (2' ^ succ₁ zero) ≡ collatz (2' ^ zero)
        {-# ATP prove prf #-}
helper (nsucc {n} Nn) = prf
  where postulate prf : collatz (2' ^ succ₁ (succ₁ n)) ≡ collatz (2' ^ succ₁ n)
        {-# ATP prove prf +∸2 ^-N 2-N 2^x≢0 2^[x+1]≢1 div-2^[x+1]-2≡2^x
                      x-Even→SSx-Even ∸-N ∸-Even 2^[x+1]-Even 2-Even
        #-}

collatz-2^x : ∀ {n} → N n → collatz (2' ^ n) ≡ 1'
collatz-2^x nzero = prf
  where postulate prf : collatz (2' ^ 0') ≡ 1'
        {-# ATP prove prf #-}

collatz-2^x (nsucc {n} Nn) = prf (collatz-2^x Nn)
  where postulate prf : collatz (2' ^ n) ≡ 1' → collatz (2' ^ succ₁ n) ≡ 1'
        {-# ATP prove prf helper #-}