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

module Data.Binary.Operations.Multiplication where

open import Data.Binary.Definitions
open import Data.Binary.Operations.Addition

mul : 𝔹⁺ → 𝔹⁺ → 𝔹⁺
mul 1ᵇ ys = ys
mul (O ∷ xs) ys = O ∷ (mul xs ys)
mul (I ∷ xs) ys = add O (O ∷ mul ys xs) ys

_*_ :  𝔹 → 𝔹 → 𝔹
0ᵇ * ys = 0ᵇ
(0< _) * 0ᵇ = 0ᵇ
(0< xs) * (0< ys) = 0< mul xs ys
{-# INLINE _*_ #-}


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

module Codiscrete where

open import Level using (Level; 0ℓ; lift; lower)
open import Data.Nat using (ℕ; suc)
open import Data.Fin hiding (lift)
open import Data.Unit
open import Function renaming (id to idf)
open import Relation.Binary.PropositionalEquality
  using (_≡_; refl; sym; trans)

open import Categories.Category.Groupoid
open import Categories.Category.Instance.One
open import Categories.Category.Equivalence using (StrongEquivalence; WeakInverse)
open import Categories.Functor using (Functor; _∘F_) renaming (id to idF)
open import Categories.Category using (Category)
open import Categories.NaturalTransformation using (NaturalTransformation)
open import Categories.NaturalTransformation.NaturalIsomorphism using (_≃_)

-- Codiscrete Groupoid on (n+1) points
CodiscreteGroupoid : (n : ℕ) → Groupoid 0ℓ 0ℓ 0ℓ
CodiscreteGroupoid n = record
  { category = record
    { Obj = Fin (suc n)
    ; _⇒_ = λ _ _ → ⊤
    ; _≈_ = _≡_
    ; assoc = refl
    ; sym-assoc = refl
    ; identityˡ = refl
    ; identityʳ = refl
    ; equiv = record { refl = refl ; sym = sym ; trans = trans }
    ; ∘-resp-≈ = λ _ _ → refl
    }
  ; isGroupoid = record
    { _⁻¹ = idf
    ; iso = record { isoˡ = refl ; isoʳ = refl }
    }
  }

open Groupoid

Contractible : (n : ℕ) → (k : Fin (suc n)) →
  StrongEquivalence (category (CodiscreteGroupoid n)) (One {0ℓ} {0ℓ} {0ℓ})
Contractible n k = record
  { F = F
  ; G = G
  ; weak-inverse = record
    { F∘G≈id = F∘G≃id
    ; G∘F≈id = G∘F≃id
    }
  }
  where
  C : Category _ _ _
  C = category (CodiscreteGroupoid n)
  O : Category 0ℓ 0ℓ 0ℓ
  O = One
  F : Functor C O
  F = record
    { F₀ = λ _ → lift tt -- This is our 'GC' function
    ; F₁ = lift
    ; identity = lift tt
    ; homomorphism = lift tt
    ; F-resp-≈ = λ _ → lift tt
    }
  -- This is where 'k' is used:
  G : Functor O C
  G = record
    { F₀ = λ _ → k
    ; F₁ = lower
    ; identity = refl
    ; homomorphism = refl
    ; F-resp-≈ = λ _ → refl
    }
  F∘G≃id : F ∘F G ≃ idF
  F∘G≃id = record
    { F⇒G = record { η = idf ; commute = idf }
    ; F⇐G = record { η = idf ; commute = idf }
    }
  G∘F≃id : G ∘F F ≃ idF
  G∘F≃id = record
    { F⇒G = record { η = λ _ → tt ; commute = λ _ → refl }
    ; F⇐G = record { η = λ _ → tt ; commute = λ _ → refl }
    ; iso = λ X → record { isoˡ = refl ; isoʳ = refl }
    }


{-# OPTIONS --universe-polymorphism #-}
module Categories.Category.Construction.F-Algebras where

open import Level
open import Data.Product using (proj₁; proj₂)

open import Categories.Category
open import Categories.Functor hiding (id)
open import Categories.Functor.Algebra
open import Categories.Object.Initial
import Categories.Morphism.Reasoning as MR
import Categories.Morphism as Mor using (_≅_)

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

F-Algebras : {𝒞 : Category o ℓ e} → Endofunctor 𝒞 → Category (ℓ ⊔ o) (e ⊔ ℓ) e
F-Algebras {𝒞 = 𝒞} F = record
  { Obj       = F-Algebra F
  ; _⇒_       = F-Algebra-Morphism
  ; _≈_       = λ α₁ α₂ → f α₁ ≈ f α₂
  ; _∘_       = λ α₁ α₂ → record { f = f α₁ ∘ f α₂ ; commutes = commut α₁ α₂ }
  ; id        = record { f = id ; commutes = identityˡ ○ ⟺ identityʳ ○ ⟺ (∘-resp-≈ʳ identity) }
  ; assoc     = assoc
  ; sym-assoc = sym-assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; identity² = identity²
  ; equiv     = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }
  ; ∘-resp-≈  = ∘-resp-≈
  }
  where
    open Category 𝒞
    open Equiv
    open HomReasoning using (⟺; _○_; begin_; _≈⟨_⟩_; _∎)
    open Functor F
    open F-Algebra-Morphism
    open F-Algebra
    commut : {A B C : F-Algebra F} (α₁ : F-Algebra-Morphism B C) (α₂ : F-Algebra-Morphism A B) →
      (f α₁ ∘ f α₂) ∘ α A ≈ α C ∘ F₁ (f α₁ ∘ f α₂)
    commut {A} {B} {C} α₁ α₂ = begin
      (f α₁ ∘ f α₂) ∘ α A            ≈⟨ assoc ○ ∘-resp-≈ʳ (commutes α₂) ⟩
      f α₁ ∘ (α B ∘ F₁ (f α₂))       ≈⟨ ⟺ assoc ○ ∘-resp-≈ˡ (commutes α₁) ⟩
      (α C ∘ F₁ (f α₁)) ∘ F₁ (f α₂)  ≈⟨ assoc ○ ∘-resp-≈ʳ (⟺ homomorphism) ⟩
      α C ∘ F₁ (f α₁ ∘ f α₂)   ∎

module Lambek {𝒞 : Category o ℓ e} {F : Endofunctor 𝒞} (I : Initial (F-Algebras F)) where
  open Category 𝒞
  open Functor F
  open F-Algebra using (α)

  open MR 𝒞 using (glue)
  open Mor 𝒞
  open Initial I -- so ⊥ is an F-Algebra, which is initial

  -- While an expert might be able to decipher the proof at the nLab
  --   (https://ncatlab.org/nlab/show/initial+algebra+of+an+endofunctor)
  -- I (JC) have found that the notes at
  --   http://www.cs.ru.nl/~jrot/coalgebra/ak-algebras.pdf
  -- are easier to follow, and lead to the full proof below.
  private
    module ⊥ = F-Algebra ⊥
    A = ⊥.A
    a : F₀ A ⇒ A
    a = ⊥.α

    -- The F-Algebra structure that will make things work
    F⊥ : F-Algebra F
    F⊥ = iterate ⊥

    -- By initiality, we get the following morphism
    f : F-Algebra-Morphism ⊥ F⊥
    f = !

    module FAM = F-Algebra-Morphism f

    i : A ⇒ F₀ A
    i = FAM.f

    a∘f : F-Algebra-Morphism ⊥ ⊥
    a∘f = record
      { f = a ∘ i
      ; commutes = glue triv FAM.commutes ○ ∘-resp-≈ʳ (⟺ homomorphism)
      }
      where
        open HomReasoning using (_○_; ⟺)
        triv : CommutativeSquare (α F⊥) (α F⊥) a a
        triv = Equiv.refl

  lambek : A ≅ F₀ A
  lambek = record
    { from = i
    ; to = a
    ; iso = record
      { isoˡ = ⊥-id a∘f
      ; isoʳ = begin
        i ∘ a       ≈⟨ F-Algebra-Morphism.commutes f ⟩
        F₁ a ∘ F₁ i ≈˘⟨ homomorphism ⟩
        F₁ (a ∘ i)  ≈⟨ F-resp-≈ (⊥-id a∘f) ⟩
        F₁ id       ≈⟨ identity ⟩
        id ∎
      }
    }
    where
      open HomReasoning


module Issue2845 where

open import Agda.Builtin.Nat
open import Agda.Primitive.Cubical
open import Agda.Builtin.Equality

Ex1 : Nat
Ex1 = primComp (λ i → Nat) i0 (λ i → isOneEmpty) zero

test1 : Ex1 ≡ zero
test1 = refl

Ex2 : (i : I) → Nat
Ex2 i = primComp (λ i → Nat) i (λ { _ (i = i1) → zero}) zero

test2 : ∀ i → Ex2 i ≡ zero
test2 i = refl

Ex3 : (i : I) (p : I → Nat) → Nat
Ex3 i p = primComp (λ i → Nat) i (λ { k (i = i1) → suc (p k)}) (suc (p i0))

test3 : ∀ i p → Ex3 i p ≡ suc _
test3 i p = refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Closures of a unary relation with respect to a strict partial order
------------------------------------------------------------------------

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

open import Relation.Binary

module Relation.Unary.Closure.StrictPartialOrder
       {a r e} (P : StrictPartialOrder a e r) where

open StrictPartialOrder P renaming (_<_ to _∼_)
open import Relation.Unary using (Pred)

-- Specialising the results proven generically in `Base`.
import Relation.Unary.Closure.Base _∼_ as Base
open Base public using (□; map; Closed)

module _ {t} {T : Pred Carrier t} where

  reindex : ∀ {x y} → x ∼ y → □ T x → □ T y
  reindex = Base.reindex trans

  duplicate : ∀ {x} → □ T x → □ (□ T) x
  duplicate = Base.duplicate trans

□-closed : ∀ {t} {T : Pred Carrier t} → Closed (□ T)
□-closed = Base.□-closed trans


------------------------------------------------------------------------
-- Some boring lemmas used by the ring solver
------------------------------------------------------------------------

-- Note that these proofs use all "almost commutative ring" properties
-- except for zero and -‿pres-≈.

open import Algebra
open import Algebra.RingSolver.AlmostCommutativeRing

module Algebra.RingSolver.Lemmas
  (coeff : RawRing)
  (r : AlmostCommutativeRing)
  (morphism : coeff -Raw-AlmostCommutative⟶ r)
  where

private
  module C = RawRing coeff
open AlmostCommutativeRing r
open import Algebra.Morphism
open _-RawRing⟶_ morphism
import Relation.Binary.EqReasoning as EqR; open EqR setoid
open import Data.Function
open import Data.Product

lemma₀ : ∀ x → x + ⟦ C.0# ⟧ ≈ x
lemma₀ x = begin
  x + ⟦ C.0# ⟧  ≈⟨ refl ⟨ +-pres-≈ ⟩ 0-homo ⟩
  x + 0#        ≈⟨ proj₂ +-identity _ ⟩
  x             ∎

lemma₁ : ∀ a b c d x →
         (a + b) * x + (c + d) ≈ (a * x + c) + (b * x + d)
lemma₁ a b c d x = begin
  (a + b) * x + (c + d)      ≈⟨ proj₂ distrib _ _ _ ⟨ +-pres-≈ ⟩ refl ⟩
  (a * x + b * x) + (c + d)  ≈⟨ +-assoc _ _ _ ⟩
  a * x + (b * x + (c + d))  ≈⟨ refl ⟨ +-pres-≈ ⟩ sym (+-assoc _ _ _) ⟩
  a * x + ((b * x + c) + d)  ≈⟨ refl ⟨ +-pres-≈ ⟩ (+-comm _ _ ⟨ +-pres-≈ ⟩ refl) ⟩
  a * x + ((c + b * x) + d)  ≈⟨ refl ⟨ +-pres-≈ ⟩ +-assoc _ _ _ ⟩
  a * x + (c + (b * x + d))  ≈⟨ sym $ +-assoc _ _ _ ⟩
  (a * x + c) + (b * x + d)  ∎

lemma₂ : ∀ x y z → x + (y + z) ≈ y + (x + z)
lemma₂ x y z = begin
  x + (y + z)  ≈⟨ sym $ +-assoc _ _ _ ⟩
  (x + y) + z  ≈⟨ +-comm _ _ ⟨ +-pres-≈ ⟩ refl ⟩
  (y + x) + z  ≈⟨ +-assoc _ _ _ ⟩
  y + (x + z)  ∎

lemma₃ : ∀ a b c x → a * c * x + b * c ≈ (a * x + b) * c
lemma₃ a b c x = begin
  a * c * x + b * c  ≈⟨ lem ⟨ +-pres-≈ ⟩ refl ⟩
  a * x * c + b * c  ≈⟨ sym $ proj₂ distrib _ _ _ ⟩
  (a * x + b) * c    ∎
  where
  lem = begin
    a * c * x    ≈⟨ *-assoc _ _ _ ⟩
    a * (c * x)  ≈⟨ refl ⟨ *-pres-≈ ⟩ *-comm _ _ ⟩
    a * (x * c)  ≈⟨ sym $ *-assoc _ _ _ ⟩
    a * x * c    ∎

lemma₄ : ∀ a b c x → a * b * x + a * c ≈ a * (b * x + c)
lemma₄ a b c x = begin
  a * b * x + a * c    ≈⟨ *-assoc _ _ _ ⟨ +-pres-≈ ⟩ refl ⟩
  a * (b * x) + a * c  ≈⟨ sym $ proj₁ distrib _ _ _ ⟩
  a * (b * x + c)      ∎

lemma₅ : ∀ a b c d x →
         a * c * x * x + ((a * d + b * c) * x + b * d) ≈
         (a * x + b) * (c * x + d)
lemma₅ a b c d x = begin
  a * c * x * x +
  ((a * d + b * c) * x + b * d)          ≈⟨ lem₁ ⟨ +-pres-≈ ⟩
                                            (lem₂ ⟨ +-pres-≈ ⟩ refl) ⟩
  a * x * (c * x) +
  (a * x * d + b * (c * x) + b * d)      ≈⟨ refl ⟨ +-pres-≈ ⟩ +-assoc _ _ _ ⟩
  a * x * (c * x) +
  (a * x * d + (b * (c * x) + b * d))    ≈⟨ sym $ +-assoc _ _ _ ⟩
  a * x * (c * x) + a * x * d +
  (b * (c * x) + b * d)                  ≈⟨ sym $ proj₁ distrib _ _ _
                                                  ⟨ +-pres-≈ ⟩
                                                proj₁ distrib _ _ _ ⟩
  a * x * (c * x + d) + b * (c * x + d)  ≈⟨ sym $ proj₂ distrib _ _ _ ⟩
  (a * x + b) * (c * x + d)              ∎
  where
  lem₁' = begin
    a * c * x    ≈⟨ *-assoc _ _ _ ⟩
    a * (c * x)  ≈⟨ refl ⟨ *-pres-≈ ⟩ *-comm _ _ ⟩
    a * (x * c)  ≈⟨ sym $ *-assoc _ _ _ ⟩
    a * x * c    ∎

  lem₁ = begin
    a * c * x * x    ≈⟨ lem₁' ⟨ *-pres-≈ ⟩ refl ⟩
    a * x * c * x    ≈⟨ *-assoc _ _ _ ⟩
    a * x * (c * x)  ∎

  lem₂ = begin
    (a * d + b * c) * x        ≈⟨ proj₂ distrib _ _ _ ⟩
    a * d * x + b * c * x      ≈⟨ *-assoc _ _ _ ⟨ +-pres-≈ ⟩ *-assoc _ _ _ ⟩
    a * (d * x) + b * (c * x)  ≈⟨ (refl ⟨ *-pres-≈ ⟩ *-comm _ _)
                                    ⟨ +-pres-≈ ⟩ refl ⟩
    a * (x * d) + b * (c * x)  ≈⟨ sym $ *-assoc _ _ _ ⟨ +-pres-≈ ⟩ refl ⟩
    a * x * d + b * (c * x)    ∎

lemma₆ : ∀ a b x → - a * x + - b ≈ - (a * x + b)
lemma₆ a b x = begin
  - a * x + - b    ≈⟨ -‿*-distribˡ _ _ ⟨ +-pres-≈ ⟩ refl ⟩
  - (a * x) + - b  ≈⟨ -‿+-comm _ _ ⟩
  - (a * x + b)    ∎

lemma₇ : ∀ x → ⟦ C.1# ⟧ * x + ⟦ C.0# ⟧ ≈ x
lemma₇ x = begin
  ⟦ C.1# ⟧ * x + ⟦ C.0# ⟧  ≈⟨ (1-homo ⟨ *-pres-≈ ⟩ refl) ⟨ +-pres-≈ ⟩ 0-homo ⟩
  1# * x + 0#              ≈⟨ proj₂ +-identity _ ⟩
  1# * x                   ≈⟨ proj₁ *-identity _ ⟩
  x                        ∎


module Numeral.Natural.LinearSearchDecidable where -- TODO: Maybe move and rename to Numeral.Natural.Sequence.BoundedSearch
-- TODO: Maybe more natural to use 𝕟 (finite naturals) instead of ℕ (naturals)?

open import Data.Boolean
open import Data.Boolean.Stmt
open import Data.List
import      Data.List.Functions as List
open import Data.List.Relation.Membership using (_∈_)
open import Data.List.Relation.Membership.Proofs
open import Data.List.Relation.Quantification
open import Data.List.Relation.Quantification.Proofs
open import Data.List.Sorting
open import Data.Option
import      Data.Option.Functions as Option
open import Functional
open import Logic.Propositional
open import Numeral.Finite
import      Numeral.Finite.LinearSearch as 𝕟
open import Numeral.Natural
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Comparisons
open import Numeral.Natural.Oper.Proofs.Order
open import Numeral.Natural.Relation.Order
open import Relator.Equals
open import Relator.Equals.Proofs.Equiv
open import Structure.Function

private variable a b n i j : ℕ
private variable f : ℕ → Bool

{-
open import Data.Boolean
open import Data.Boolean.Stmt
open import Data.Option
import      Data.Option.Functions as Option
open import Functional
open import Logic
open import Numeral.Natural
open import Numeral.Natural.Oper
open import Numeral.Natural.Relation.Order
open import Structure.Relator.Ordering

-- Finds the maximal argument satisfying the given argument within the given search upper bound by searching linearly.
-- Examples:
--   findUpperBoundedMax(10 ∣?_) 5   = None
--   findUpperBoundedMax(10 ∣?_) 20  = Some 20
--   findUpperBoundedMax(10 ∣?_) 22  = Some 20
--   findUpperBoundedMax(10 ∣?_) 100 = Some 100
--   findUpperBoundedMax(10 ∣?_) 102 = Some 100
findUpperBoundedMax : (ℕ → Bool) → ℕ → Option(ℕ)
findUpperBoundedMax f(i) with f(i)
findUpperBoundedMax f(i)    | 𝑇 = Some i
findUpperBoundedMax f(𝟎)    | 𝐹 = None
findUpperBoundedMax f(𝐒(i)) | 𝐹 = findUpperBoundedMax f(i)

findMaxIndexInRange : (ℕ → Bool) → ℕ → ℕ → Option(ℕ)
findMaxIndexInRange f min max = Option.map (_+ min) (findUpperBoundedMax (f ∘ (_+ min)) (max −₀ min))

-- Finds the minimal argument satisfying the given argument within the given search upper bound by searching linearly.
-- Examples:
--   findUpperBoundedMin(10 ∣?_) 5   = None
--   findUpperBoundedMin(10 ∣?_) 20  = Some 10
--   findUpperBoundedMin(10 ∣?_) 22  = Some 10
--   findUpperBoundedMin(10 ∣?_) 100 = Some 10
--   findUpperBoundedMax(10 ∣?_) 102 = Some 10
findUpperBoundedMin : (ℕ → Bool) → ℕ → Option(ℕ)
findUpperBoundedMin f(i) with f(𝟎)
findUpperBoundedMin f(i)    | 𝑇 = Some 𝟎
findUpperBoundedMin f(𝟎)    | 𝐹 = None
findUpperBoundedMin f(𝐒(i)) | 𝐹 = Option.map 𝐒 (findUpperBoundedMin (f ∘ 𝐒)(i))

open import Data
open import Data.Boolean.Stmt.Proofs
open import Data.Option.Equiv.Id
open import Lang.Inspect
open import Logic.Predicate
open import Logic.Propositional
open import Numeral.Natural.Oper.Proofs
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals
open import Relator.Equals.Proofs.Equiv
open import Structure.Function.Domain
open import Structure.Relator.Properties
open import Structure.Relator

findUpperBoundedMax-correctness : ∀{f}{max i} → (findUpperBoundedMax f(max) ≡ Some(i)) → ((i ≤ max) ∧ IsTrue(f(i)))
findUpperBoundedMax-correctness {f} {max}    {i} p with f(max) | inspect f(max)
findUpperBoundedMax-correctness {f} {max}    {.max} [≡]-intro | 𝑇 | intro eq = [∧]-intro (reflexivity(_≤_)) (substitute₁ₗ(IsTrue) eq <>)
findUpperBoundedMax-correctness {f} {𝟎}      {i}    ()        | 𝐹 | _
findUpperBoundedMax-correctness {f} {𝐒(max)} {i}    p         | 𝐹 | intro eq with findUpperBoundedMax-correctness {f} {max} {i} p
... | [∧]-intro a b = [∧]-intro ([≤]-successor a) b

findUpperBoundedMin-correctness : ∀{f}{max i} → (findUpperBoundedMin f(max) ≡ Some(i)) → ((i ≤ max) ∧ IsTrue(f(i)))
findUpperBoundedMin-correctness {f} {max}   {i}   p with f(𝟎) | inspect f(𝟎)
findUpperBoundedMin-correctness {f} {max}   {.𝟎}  [≡]-intro | 𝑇 | intro eq = [∧]-intro [≤]-minimum ([↔]-to-[←] IsTrue.is-𝑇 eq)
findUpperBoundedMin-correctness {f} {𝐒 max} {𝟎}   p         | 𝐹 | intro eq with findUpperBoundedMin (f ∘ 𝐒) max
findUpperBoundedMin-correctness {f} {𝐒 max} {𝟎}   ()        | 𝐹 | intro eq | None
findUpperBoundedMin-correctness {f} {𝐒 max} {𝟎}   ()        | 𝐹 | intro eq | Some _
findUpperBoundedMin-correctness {f} {𝐒 max} {𝐒 i} p         | 𝐹 | intro eq = [∧]-map (\p → [≤]-with-[𝐒] ⦃ p ⦄) id (findUpperBoundedMin-correctness {f ∘ 𝐒} {max} {i} (injective(Option.map 𝐒) ⦃ map-injectivity ⦄ p))

findUpperBoundedMin-minimal : ∀{f}{max i j} → (findUpperBoundedMin f(max) ≡ Some(i)) → IsTrue(f(j)) → (i ≤ j)
findUpperBoundedMin-minimal {i = 𝟎} {_} p q = [≤]-minimum
findUpperBoundedMin-minimal {i = 𝐒 i} {𝟎} p q = {!!}
findUpperBoundedMin-minimal {i = 𝐒 i} {𝐒 j} p q = [≤]-with-[𝐒] ⦃ findUpperBoundedMin-minimal {i = i}{j} {!!} q ⦄

-- foldRange : ()

{-
searchUntilUpperBound : (f : ℕ → Bool) → ∃(IsTrue ∘ f) → ℕ
searchUntilUpperBound f ([∃]-intro upperBound ⦃ proof ⦄) = {!fold!}

searchUntilUpperBoundProof : ∀{f}{upperBound} → (IsTrue ∘ f)(searchUntilUpperBound f upperBound)
searchUntilUpperBoundProof = {!!}

bruteforceMinExistence : ∀{ℓ} → (P : ℕ → Stmt{ℓ}) → ⦃ ComputablyDecidable(P) ⦄ → ∃(P) → ∃(Weak.Properties.MinimumOf(_≤_)(P))
∃.witness (bruteforceMinExistence P upperBound) = {!!}
∃.proof   (bruteforceMinExistence P upperBound) = {!!}
-}
-}


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

open import LogicalFormulae
open import Numbers.Naturals.Definition

module Numbers.Integers.Definition where

data ℤ : Set where
  nonneg : ℕ → ℤ
  negSucc : ℕ → ℤ
{-# BUILTIN INTEGER       ℤ       #-}
{-# BUILTIN INTEGERPOS    nonneg  #-}
{-# BUILTIN INTEGERNEGSUC negSucc #-}

nonnegInjective : {a b : ℕ} → nonneg a ≡ nonneg b → a ≡ b
nonnegInjective refl = refl

negSuccInjective : {a b : ℕ} → negSucc a ≡ negSucc b → a ≡ b
negSuccInjective refl = refl

ℤDecideEquality : (a b : ℤ) → ((a ≡ b) || ((a ≡ b) → False))
ℤDecideEquality (nonneg x) (nonneg y) with ℕDecideEquality x y
ℤDecideEquality (nonneg x) (nonneg y) | inl eq = inl (applyEquality nonneg eq)
ℤDecideEquality (nonneg x) (nonneg y) | inr non = inr λ i → non (nonnegInjective i)
ℤDecideEquality (nonneg x) (negSucc y) = inr λ ()
ℤDecideEquality (negSucc x) (nonneg x₁) = inr λ ()
ℤDecideEquality (negSucc x) (negSucc y) with ℕDecideEquality x y
ℤDecideEquality (negSucc x) (negSucc y) | inl eq = inl (applyEquality negSucc eq)
ℤDecideEquality (negSucc x) (negSucc y) | inr non = inr λ i → non (negSuccInjective i)


{-# OPTIONS --allow-unsolved-metas --warning=error --without-K --guardedness #-}

open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Setoids.Setoids
open import Rings.Definition
open import Rings.Lemmas
open import Rings.Orders.Partial.Definition
open import Rings.Orders.Total.Definition
open import Groups.Definition
open import Groups.Groups
open import Fields.Fields
open import Sets.EquivalenceRelations
open import Sequences
open import Setoids.Orders.Partial.Definition
open import Setoids.Orders.Total.Definition
open import Functions.Definition
open import LogicalFormulae
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order

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

open Setoid S
open PartiallyOrderedRing pRing
open SetoidPartialOrder pOrder
open Equivalence eq
open SetoidTotalOrder (TotallyOrderedRing.total order)
open Field F
open Group (Ring.additiveGroup R)

open import Rings.Orders.Total.Cauchy order
open import Rings.Orders.Total.Lemmas order
open import Rings.Orders.Total.AbsoluteValue order
open import Fields.CauchyCompletion.Definition order F
open import Fields.CauchyCompletion.Multiplication order F
open import Fields.CauchyCompletion.Addition order F
open import Fields.CauchyCompletion.Setoid order F
open import Fields.CauchyCompletion.Group order F
open import Fields.CauchyCompletion.Ring order F
open import Fields.CauchyCompletion.Comparison order F

Cnontrivial : (pr : Setoid._∼_ cauchyCompletionSetoid (injection (Ring.0R R)) (injection (Ring.1R R))) → False
Cnontrivial pr with pr (Ring.1R R) (0<1 nontrivial)
Cnontrivial pr | N , b with b {succ N} (le 0 refl)
... | bl rewrite indexAndApply (constSequence 0G) (map inverse (constSequence (Ring.1R R))) _+_ {N} | indexAndConst 0G N | equalityCommutative (mapAndIndex (constSequence (Ring.1R R)) inverse N) | indexAndConst (Ring.1R R) N = irreflexive {Ring.1R R} (<WellDefined (Equivalence.transitive eq (absWellDefined _ _ identLeft) (Equivalence.transitive eq (Equivalence.symmetric eq (absNegation (Ring.1R R))) abs1Is1)) (Equivalence.reflexive eq) bl)

boundedMap : A → A
boundedMap a with totality 0G a
boundedMap a | inl (inl x) = underlying (allInvertible a λ pr → irreflexive (<WellDefined (Equivalence.reflexive eq) pr x))
boundedMap a | inl (inr x) = underlying (allInvertible a λ pr → irreflexive (<WellDefined pr (Equivalence.reflexive eq) x))
boundedMap a | inr x = Ring.1R R

-- TODO: make a real which is equivalent by approximating from above;
-- make a real which is equivalent by approximating from below.
-- Use not-zero to show that one of those sequences must pass 0 at some point.
aNonzeroImpliesBounded : (a : CauchyCompletion) → (Setoid._∼_ cauchyCompletionSetoid a (injection 0G) → False) → (a <Cr 0G) || 0G r<C a
aNonzeroImpliesBounded a a!=0 = {!!}

1/aConverges : (a : CauchyCompletion) → (Setoid._∼_ cauchyCompletionSetoid a (injection 0G) → False) → cauchy (map boundedMap (CauchyCompletion.elts a))
1/aConverges a a!=0 e 0<e = {!!}

1/a : (a : CauchyCompletion) → (Setoid._∼_ cauchyCompletionSetoid a (injection 0G) → False) → CauchyCompletion
1/a a a!=0 = record { elts = map boundedMap (CauchyCompletion.elts a) ; converges = 1/aConverges a a!=0 }

1/a*a=1 : (a : CauchyCompletion) (pr : Setoid._∼_ cauchyCompletionSetoid a (injection 0G) → False) → Setoid._∼_ cauchyCompletionSetoid ((1/a a pr) *C a) (injection (Ring.1R R))
1/a*a=1 a a!=0 e 0<e = {!!}

CField : Field CRing
Field.allInvertible CField a a!=0 = (1/a a a!=0) , 1/a*a=1 a a!=0
Field.nontrivial CField = Cnontrivial


{-# OPTIONS --safe #-}
module Cubical.Algebra.CommMonoid.CommMonoidProd where

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

open import Cubical.Data.Sigma

open import Cubical.Algebra.CommMonoid.Base

open CommMonoidStr

private
  variable
    ℓ ℓ' : Level

CommMonoidProd : CommMonoid ℓ → CommMonoid ℓ' → CommMonoid (ℓ-max ℓ ℓ')
CommMonoidProd M N = makeCommMonoid ε× _·×_ is-set× assoc× ·IdR× comm×
  where
  ε× : (fst M) × (fst N)
  ε× = (ε (snd M)) , (ε (snd N))

  _·×_ : (fst M) × (fst N) → (fst M) × (fst N) → (fst M) × (fst N)
  (x₁ , x₂) ·× (y₁ , y₂) = (_·_ (snd M) x₁ y₁) , (_·_ (snd N) x₂ y₂)

  is-set× : isSet ((fst M) × (fst N))
  is-set× = isSet× (is-set (snd M)) (is-set (snd N))

  assoc× : ∀ x y z → x ·× (y ·× z) ≡ (x ·× y) ·× z
  assoc× _ _ _ = cong₂ (_,_) (·Assoc (snd M) _ _ _) (·Assoc (snd N) _ _ _)

  ·IdR× : ∀ x → x ·× ε× ≡ x
  ·IdR× _ =  cong₂ (_,_) (·IdR (snd M) _) (·IdR (snd N) _)

  comm× : ∀ x y → x ·× y ≡ y ·× x
  comm× _ _ = cong₂ (_,_) (·Comm (snd M) _ _) (·Comm (snd N) _ _)


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

open import Algebra

module Algebra.SemiringLiterals {r} (rng : Semiring r) where

open Semiring rng

open import Literals.Number
open import Data.Nat.Literals
open import Data.Unit
import Data.Unit.UniversePolymorphic as Poly
open import Data.Nat.DivMod
open import Data.Nat using (ℕ; suc; zero)
open import Data.Nat.Properties
open import Data.Bool
open import Strict

2# : 𝑅
2# = 1# + 1#

sringFromNatRec : ℕ → ℕ → 𝑅
sringFromNatRec zero    _       = 0#
sringFromNatRec (suc 0) _       = 1#
sringFromNatRec (suc 1) _       = 2#
sringFromNatRec (suc 2) _       = 1# + 2#
sringFromNatRec (suc n) (suc w) =
  let! r =! sringFromNatRec (n ÷ 2) w in!
  if even n
    then 1# + (r * 2#)
    else (1# + r) * 2#
sringFromNatRec _ zero = 0# -- will not happen

sringFromNat : ℕ → 𝑅
sringFromNat n = sringFromNatRec n n

instance
  numberRng : Number 𝑅
  Number.Constraint numberRng _ = Poly.⊤
  Number.fromNat numberRng n = sringFromNat n


data _≡_ {X : Set} : X → X → Set where
  refl : {x : X} → x ≡ x

ap : {X Y : Set} (f : X → Y) {x x' : X} → x ≡ x' → f x ≡ f x'
ap f refl = refl

_∙_ : {X : Set} {x y z : X} → x ≡ y → y ≡ z → x ≡ z
p ∙ refl = p

f : {X : Set} {x : X} {A : X → Set} (η θ : (y : X) → x ≡ y → A y)
  → η x refl ≡ θ x refl → ∀ y p → η y p ≡ θ y p
f η θ q y refl = ap (λ a → a) q

succeeds : (X : Set) (z t : X) (r : z ≡ t)
         → (λ (x y : X) (p : x ≡ y) (q : y ≡ z) → (p ∙ q) ∙ r)
         ≡ (λ (x y : X) (p : x ≡ y) (q : y ≡ z) → p ∙ (q ∙ r))
succeeds X z = f -- {A = λ - → (x y : X) (p : x ≡ y) (q : y ≡ z) → x ≡ - }
                (λ z r x y p q → (p ∙ q) ∙ r)
                (λ z r x y p q → p ∙ (q ∙ r))
                refl

fails : (X : Set) (z t : X) (r : z ≡ t)
      → (λ (x y : X) (p : x ≡ y) (q : y ≡ z) → (p ∙ q) ∙ r)
      ≡ (λ (x y : X) (p : x ≡ y) (q : y ≡ z) → p ∙ (q ∙ r))
fails X z t = f -- {A = λ - → (x y : X) (p : x ≡ y) (q : y ≡ z) → x ≡ - }
               (λ z r x y p q → (p ∙ q) ∙ r)
               (λ z r x y p q → p ∙ (q ∙ r))
               refl
               t


module Common.PredicateBasedContext where

open import Common.Predicate public

-- Predicate-based context membership.

module _ {U : Set} where
  infix 3 _∈_
  _∈_ : U → Pred (Cx U)
  A ∈ Γ = Any (_≡ A) Γ

  infix 3 _∉_
  _∉_ : U → Pred (Cx U)
  A ∉ Γ = Not (A ∈ Γ)

  lookup : ∀ {Γ P} → All P Γ → (∀ {A} → A ∈ Γ → P A)
  -- Alternatively:
  -- lookup : ∀ {Γ P} → All P Γ → (_∈ Γ) ⊆ᴾ P
  lookup ∅       ()
  lookup (γ , a) (top refl) = a
  lookup (γ , a) (pop i)    = lookup γ i

  tabulate : ∀ {Γ P} → (∀ {A} → A ∈ Γ → P A) → All P Γ
  -- Alternatively:
  -- tabulate : ∀ {Γ P} → (_∈ Γ) ⊆ᴾ P → All P Γ
  tabulate {∅}     f = ∅
  tabulate {Γ , A} f = tabulate (f ∘ pop) , f (top refl)

  bot∈ : ∀ {A} → A ∉ ∅
  bot∈ ()

  [_]ᴵˣ : ∀ {A Γ} → A ∈ Γ → ℕ
  [ top refl ]ᴵˣ = zero
  [ pop i ]ᴵˣ    = suc [ i ]ᴵˣ

  i₀ : ∀ {A Γ} → A ∈ Γ , A
  i₀ = top refl

  i₁ : ∀ {A B Γ} → A ∈ Γ , A , B
  i₁ = pop i₀

  i₂ : ∀ {A B C Γ} → A ∈ Γ , A , B , C
  i₂ = pop i₁

-- Predicate-based context inclusion.

module _ {U : Set} where
  -- NOTE: This is similar to Ren from Conor’s fish-and-chips development.
  infix 3 _⊆_
  _⊆_ : Cx U → Pred (Cx U)
  Γ ⊆ Γ′ = ∀ {A} → A ∈ Γ → A ∈ Γ′
  -- Alternatively:
  -- Γ ⊆ Γ′ = (_∈ Γ) ⊆ᴾ (_∈ Γ′)

  infix 3 _⊈_
  _⊈_ : Cx U → Pred (Cx U)
  Γ ⊈ Γ′ = Not (Γ ⊆ Γ′)

  skip⊆ : ∀ {A Γ Γ′} → Γ ⊆ Γ′ → Γ ⊆ Γ′ , A
  skip⊆ η = pop ∘ η

  -- NOTE: This is similar to wkr from Conor’s fish-and-chips development.
  keep⊆ : ∀ {A Γ Γ′} → Γ ⊆ Γ′ → Γ , A ⊆ Γ′ , A
  keep⊆ η (top refl) = top refl
  keep⊆ η (pop i)    = pop (η i)

  refl⊆ : ∀ {Γ} → Γ ⊆ Γ
  refl⊆ {Γ} = refl⊆ᴾ {P = _∈ Γ}

  trans⊆ : ∀ {Γ Γ′ Γ″} → Γ ⊆ Γ′ → Γ′ ⊆ Γ″ → Γ ⊆ Γ″
  trans⊆ {Γ} η η′ = trans⊆ᴾ {P = _∈ Γ} η η′

  unskip⊆ : ∀ {A Γ Γ′} → Γ , A ⊆ Γ′ → Γ ⊆ Γ′
  unskip⊆ η = η ∘ pop

  -- NOTE: This doesn’t seem possible.
  -- unkeep⊆ : ∀ {A Γ Γ′} → Γ , A ⊆ Γ′ , A → Γ ⊆ Γ′

  weak⊆ : ∀ {A Γ} → Γ ⊆ Γ , A
  weak⊆ = pop

  bot⊆ : ∀ {Γ} → ∅  ⊆ Γ
  bot⊆ ()

-- Predicate-based context equality.

module _ {U : Set} where
  infix 3 _⫗_
  _⫗_ : Cx U → Pred (Cx U)
  Γ ⫗ Γ′ = (Γ ⊆ Γ′) × (Γ′ ⊆ Γ)

  infix 3 _⫘_
  _⫘_ : Cx U → Pred (Cx U)
  Γ ⫘ Γ′ = Not (Γ ⫗ Γ′)

  refl⫗ : ∀ {Γ} → Γ ⫗ Γ
  refl⫗ {Γ} = refl⫗ᴾ {P = _∈ Γ}

  trans⫗ : ∀ {Γ Γ′ Γ″} → Γ ⫗ Γ′ → Γ′ ⫗ Γ″ → Γ ⫗ Γ″
  trans⫗ {Γ} σ σ′ = trans⫗ᴾ {P = _∈ Γ} σ σ′

  sym⫗ : ∀ {Γ Γ′} → Γ ⫗ Γ′ → Γ′ ⫗ Γ
  sym⫗ {Γ} σ = sym⫗ᴾ {P = _∈ Γ} σ

  antisym⊆ : ∀ {Γ Γ′} → ((Γ ⊆ Γ′) × (Γ′ ⊆ Γ)) ≡ (Γ ⫗ Γ′)
  antisym⊆ {Γ} = antisym⊆ᴾ {P = _∈ Γ}

-- Monotonicity with respect to predicate-based context inclusion.

module _ {U : Set} where
  mono∈ : ∀ {A : U} {Γ Γ′} → Γ ⊆ Γ′ → A ∈ Γ → A ∈ Γ′
  mono∈ η i = η i

  reflmono∈ : ∀ {A Γ} → (i : A ∈ Γ) → i ≡ mono∈ refl⊆ i
  reflmono∈ i = refl

  transmono∈ : ∀ {A Γ Γ′ Γ″} → (η : Γ ⊆ Γ′) (η′ : Γ′ ⊆ Γ″) (i : A ∈ Γ)
               → mono∈ η′ (mono∈ η i) ≡ mono∈ (trans⊆ η η′) i
  transmono∈ η η′ i = refl

-- Predicate-based context concatenation.

module _ {U : Set} where
  _⧺_ : Cx U → Cx U → Cx U
  Γ ⧺ ∅        = Γ
  Γ ⧺ (Γ′ , A) = (Γ ⧺ Γ′) , A

  id⧺₁ : ∀ {Γ} → Γ ⧺ ∅ ≡ Γ
  id⧺₁ = refl

  id⧺₂ : ∀ {Γ} → ∅  ⧺ Γ ≡ Γ
  id⧺₂ {∅}     = refl
  id⧺₂ {Γ , A} = cong² _,_ id⧺₂ refl

  weak⊆⧺₁ : ∀ {Γ} Γ′ → Γ ⊆ Γ ⧺ Γ′
  weak⊆⧺₁ ∅        = refl⊆
  weak⊆⧺₁ (Γ′ , A) = skip⊆ (weak⊆⧺₁ Γ′)

  weak⊆⧺₂ : ∀ {Γ Γ′} → Γ′ ⊆ Γ ⧺ Γ′
  weak⊆⧺₂ {Γ} {∅}      = bot⊆
  weak⊆⧺₂ {Γ} {Γ′ , A} = keep⊆ weak⊆⧺₂

-- Predicate-based context thinning.

module _ {U : Set} where
  _-_ : ∀ {A} → (Γ : Cx U) → A ∈ Γ → Cx U
  ∅       - ()
  (Γ , A) - top refl = Γ
  (Γ , B) - pop i    = (Γ - i) , B

  thin⊆ : ∀ {A Γ} → (i : A ∈ Γ) → Γ - i ⊆ Γ
  thin⊆ (top refl) = pop
  thin⊆ (pop i)    = keep⊆ (thin⊆ i)

-- Decidable predicate-based context membership equality.

module _ {U : Set} where
  data _=∈_ {A : U} {Γ} (i : A ∈ Γ) : ∀ {C} → Pred (C ∈ Γ) where
    same : i =∈ i
    diff : ∀ {C} → (j : C ∈ Γ - i) → i =∈ mono∈ (thin⊆ i) j

  _≟∈_ : ∀ {A C Γ} → (i : A ∈ Γ) (j : C ∈ Γ) → i =∈ j
  top refl ≟∈ top refl = same
  top refl ≟∈ pop j    = diff j
  pop i    ≟∈ top refl = diff (top refl)
  pop i    ≟∈ pop j    with i ≟∈ j
  pop i ≟∈ pop .i      | same = same
  pop i ≟∈ pop ._      | diff j = diff (pop j)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Integer division
------------------------------------------------------------------------

module Data.Nat.DM where

open import Data.Fin as Fin using (Fin; toℕ)
import Data.Fin.Properties as FinP
open import Data.Nat as Nat
open import Data.Nat.Properties as NatP
open import Data.Nat.Properties.Simple
open import Relation.Nullary.Decidable
open import Relation.Binary.PropositionalEquality as P using (_≡_)
import Relation.Binary.PropositionalEquality.TrustMe as TrustMe
  using (erase)

open NatP.SemiringSolver
open P.≡-Reasoning
open Nat.≤-Reasoning
  renaming (begin_ to start_; _∎ to _□; _≡⟨_⟩_ to _≡⟨_⟩′_)

infixl 7 _div_ _mod_ _divMod_

-- Integer division.

private

  div-helper : ℕ → ℕ → ℕ → ℕ → ℕ
  div-helper acc s zero    n       = acc
  div-helper acc s (suc d) zero    = div-helper (suc acc) s d s
  div-helper acc s (suc d) (suc n) = div-helper acc       s d n

  -- {-# BUILTIN NATDIVSUCAUX div-helper #-}

_div_ : (dividend divisor : ℕ) {≢0 : False (divisor ≟ 0)} → ℕ
(d div 0) {}
(d div suc s) = div-helper 0 s d s

-- The remainder after integer division.

private

  mod-helper : ℕ → ℕ → ℕ → ℕ → ℕ
  mod-helper acc s zero    n       = acc
  mod-helper acc s (suc d) zero    = mod-helper zero      s d s
  mod-helper acc s (suc d) (suc n) = mod-helper (suc acc) s d n

  -- {-# BUILTIN NATMODSUCAUX mod-helper #-}

  -- The remainder is not too large.

  mod-lemma : (acc d n : ℕ) →
              let s = acc + n in
              mod-helper acc s d n ≤ s

  mod-lemma acc zero n = start
    acc      ≤⟨ m≤m+n acc n ⟩
    acc + n  □

  mod-lemma acc (suc d) zero = start
    mod-helper zero (acc + 0) d (acc + 0)  ≤⟨ mod-lemma zero d (acc + 0) ⟩
    acc + 0                                □

  mod-lemma acc (suc d) (suc n) =
    P.subst (λ x → mod-helper (suc acc) x d n ≤ x)
            (P.sym (+-suc acc n))
            (mod-lemma (suc acc) d n)

_mod_ : (dividend divisor : ℕ) {≢0 : False (divisor ≟ 0)} → Fin divisor
(d mod 0) {}
(d mod suc s) =
  Fin.fromℕ≤″ (mod-helper 0 s d s)
              (Nat.erase (≤⇒≤″ (s≤s (mod-lemma 0 d s))))

-- Integer division with remainder.

private

  -- The quotient and remainder are related to the dividend and
  -- divisor in the right way.

  division-lemma :
    (mod-acc div-acc d n : ℕ) →
    let s = mod-acc + n in
    mod-acc + div-acc * suc s + d
      ≡
    mod-helper mod-acc s d n + div-helper div-acc s d n * suc s

  division-lemma mod-acc div-acc zero n = begin

    mod-acc + div-acc * suc s + zero  ≡⟨ +-right-identity _ ⟩

    mod-acc + div-acc * suc s         ∎

    where s = mod-acc + n

  division-lemma mod-acc div-acc (suc d) zero = begin

    mod-acc + div-acc * suc s + suc d                ≡⟨ solve 3
                                                              (λ mod-acc div-acc d →
                                                                   let s = mod-acc :+ con 0 in
                                                                   mod-acc :+ div-acc :* (con 1 :+ s) :+ (con 1 :+ d)
                                                                     :=
                                                                   (con 1 :+ div-acc) :* (con 1 :+ s) :+ d)
                                                              P.refl mod-acc div-acc d ⟩
    suc div-acc * suc s + d                          ≡⟨ division-lemma zero (suc div-acc) d s ⟩

    mod-helper zero          s      d  s    +
    div-helper (suc div-acc) s      d  s    * suc s  ≡⟨⟩

    mod-helper      mod-acc  s (suc d) zero +
    div-helper      div-acc  s (suc d) zero * suc s  ∎

    where s = mod-acc + 0

  division-lemma mod-acc div-acc (suc d) (suc n) = begin

    mod-acc + div-acc * suc s + suc d                   ≡⟨ solve 4
                                                                 (λ mod-acc div-acc n d →
                                                                      mod-acc :+ div-acc :* (con 1 :+ (mod-acc :+ (con 1 :+ n))) :+ (con 1 :+ d)
                                                                        :=
                                                                      con 1 :+ mod-acc :+ div-acc :* (con 2 :+ mod-acc :+ n) :+ d)
                                                                 P.refl mod-acc div-acc n d ⟩
    suc mod-acc + div-acc * suc s′ + d                  ≡⟨ division-lemma (suc mod-acc) div-acc d n ⟩

    mod-helper (suc mod-acc) s′ d n +
    div-helper      div-acc  s′ d n * suc s′            ≡⟨ P.cong (λ s → mod-helper (suc mod-acc) s d n +
                                                                         div-helper div-acc s d n * suc s)
                                                                  (P.sym (+-suc mod-acc n)) ⟩

    mod-helper (suc mod-acc) s d n +
    div-helper      div-acc  s d n * suc s              ≡⟨⟩

    mod-helper      mod-acc  s (suc d) (suc n) +
    div-helper      div-acc  s (suc d) (suc n) * suc s  ∎

    where
    s  = mod-acc + suc n
    s′ = suc mod-acc + n

-- A specification of integer division.

record DivMod (dividend divisor : ℕ) {≢0 : False (divisor ≟ 0)} : Set where
  constructor result
  field
    quotient  : ℕ
    remainder : Fin divisor
    property  : dividend ≡ toℕ remainder + quotient * divisor
    div-eq : _div_ dividend divisor {≢0} ≡ quotient
    mod-eq : _mod_ dividend divisor {≢0} ≡ remainder

_divMod_ : (dividend divisor : ℕ) {≢0 : False (divisor ≟ 0)} →
           DivMod dividend divisor {≢0}
(d divMod 0) {}
(d divMod suc s) =
  result
    (d div suc s)
    (d mod suc s)
    (TrustMe.erase (begin
            d
        ≡⟨ division-lemma 0 0 d s ⟩
            mod-helper 0 s d s         + div-helper 0 s d s * suc s
        ≡⟨ P.cong₂ _+_ (P.sym (FinP.toℕ-fromℕ≤ lemma)) P.refl ⟩
            toℕ (Fin.fromℕ≤    lemma)  + div-helper 0 s d s * suc s
        ≡⟨ P.cong (λ n → toℕ n + div-helper 0 s d s * suc s) (FinP.fromℕ≤≡fromℕ≤″ lemma _) ⟩
            toℕ (Fin.fromℕ≤″ _ lemma′) + div-helper 0 s d s * suc s
        ∎))
    _≡_.refl
    _≡_.refl
  where
  lemma  = s≤s (mod-lemma 0 d s)
  lemma′ = Nat.erase (≤⇒≤″ lemma)


open import Agda.Builtin.Nat
open import Agda.Builtin.Equality
open import Agda.Builtin.String
open import Agda.Builtin.List

Id : (A : Set) → A → A → Set
Id _ = _≡_

pattern suc² n = suc (suc n)
pattern suc³ n = suc (suc² n)

_ : (n : Nat) → Id Nat (suc³ n) (suc (suc n))
_ = {!!}

data Vec {a} (A : Set a) : Nat → Set a where
  []  : Vec A 0
  _∷_ : ∀ {n} → A → Vec A n → Vec A (suc n)

pattern [_] x = x ∷ []

foo : List Nat → List Nat
foo [] = {!!}
foo (x ∷ xs) = {!!}

bar : Nat → Nat
bar zero = {!!}
bar (suc zero) = {!!}
bar (suc² n) = {!!}

_ : ∀ x → Id (Vec Nat _) [ x ] [ x ]
_ = {!!}


module Data.Num.Standard where
-- Standard positional notations

open import Data.Nat
open ≤-Reasoning
    renaming (begin_ to start_; _∎ to _□)
 -- using (≰⇒>; +-∸-assoc; ∸-mono)
open import Data.Nat.Properties
open import Data.Fin using (Fin)
    renaming (zero to Fzero; suc to Fsuc; toℕ to F→N; fromℕ≤ to N→F)
open import Data.Fin.Properties using (bounded)
open import Function
open import Relation.Nullary
-- open import Relation.Nullary.Decidable using (True; False; toWitness; toWitnessFalse; fromWitness; fromWitnessFalse)

open import Relation.Binary.PropositionalEquality as PropEq
    using (_≡_; _≢_; refl; cong; sym; trans; inspect)
open PropEq.≡-Reasoning
open import Relation.Binary

ℕ-isDecTotalOrder   = DecTotalOrder.isDecTotalOrder decTotalOrder
ℕ-isTotalOrder      = IsDecTotalOrder.isTotalOrder ℕ-isDecTotalOrder
ℕ-isPartialOrder    = IsTotalOrder.isPartialOrder ℕ-isTotalOrder
ℕ-isPreorder        = IsPartialOrder.isPreorder ℕ-isPartialOrder
≤-refl      = IsPreorder.reflexive ℕ-isPreorder
≤-antisym   = IsPartialOrder.antisym ℕ-isPartialOrder
≤-total     = IsTotalOrder.total ℕ-isTotalOrder

data Digit : (base : ℕ) → Set where
    D : ∀ {base} → Fin base → Digit base

infixl 6 _D+_

_D+_ : ∀ {b} → Digit b → Digit b → Digit b
D x D+ D {b} y with b ≤? (F→N x + F→N y)
D x D+ D {b} y | yes p = D $ N→F {F→N x + F→N y ∸ b} $
    start
        suc (F→N x + F→N y ∸ b)
    ≤⟨ ≤-refl (sym (+-∸-assoc 1 p)) ⟩
        (suc (F→N x) + F→N y) ∸ b
    ≤⟨ ∸-mono {suc (F→N x) + F→N y} {b + b} {b} {b} (bounded x +-mono (
            start
                F→N y
            ≤⟨ n≤1+n (F→N y) ⟩
                suc (F→N y)
            ≤⟨ bounded y ⟩
                b
            □
        )) (≤-refl refl) ⟩
        b + b ∸ b
    ≤⟨ ≤-refl (m+n∸n≡m b b) ⟩
        b
    □
D x D+ D {b} y | no ¬p = D $ N→F (≰⇒> ¬p)

-- start
--     {!   !}
-- ≤⟨ {!    !} ⟩
--     {!    !}
-- ≤⟨ {!    !} ⟩
--     {!   !}
-- ≤⟨ {!    !} ⟩
--     {!   !}
-- ≤⟨ {!    !} ⟩
--     {!   !}
-- □

-- begin
--     {!   !}
-- ≡⟨ {!   !} ⟩
--     {!   !}
-- ≡⟨ {!   !} ⟩
--     {!   !}
-- ≡⟨ {!   !} ⟩
--     {!   !}
-- ≡⟨ {!   !} ⟩
--     {!   !}
-- ∎


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

module GGT.Structures
  {a b ℓ₁ ℓ₂}
  {G : Set a}      -- The underlying group carrier
  {Ω : Set b}      -- The underlying set space
  (_≈_ : Rel G ℓ₁) -- The underlying group equality
  (_≋_ : Rel Ω ℓ₂) -- The underlying space equality
  where

open import Level using (_⊔_)
open import Algebra.Core
open import Algebra.Structures {a} {ℓ₁} {G} using (IsGroup)
open import GGT.Definitions

record IsAction
  (· : Opᵣ G Ω)
  (∙ : Op₂ G)
  (ε : G)
  (⁻¹ : Op₁ G)
  : Set (a ⊔ b ⊔ ℓ₁ ⊔ ℓ₂)
  where

  field
    isEquivalence : IsEquivalence _≋_
    isGroup       : IsGroup _≈_ ∙ ε ⁻¹
    actAssoc      : ActAssoc _≈_ _≋_ · ∙
    actId         : ActLeftIdentity _≈_ _≋_ ε ·
    ·-cong        : ·-≋-Congruence _≈_ _≋_ ·
    G-ext         : ≈-Ext _≈_ _≋_ ·

  setoid : Setoid b ℓ₂
  setoid = record
    { Carrier = Ω;
      _≈_ = _≋_;
      isEquivalence = isEquivalence }


------------------------------------------------------------------------
-- The Agda standard library
--
-- Container combinators
------------------------------------------------------------------------

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

module Data.Container.Combinator where

open import Level using (Level; _⊔_; Lift)
open import Data.Empty using (⊥)
open import Data.Product as P using (_,_; proj₁; proj₂; ∃)
open import Data.Sum.Base as S using ([_,_]′)
open import Data.Unit.Base using (⊤)
import Function as F

open import Data.Container.Core
open import Data.Container.Relation.Unary.Any

------------------------------------------------------------------------
-- Combinators

module _ {s p : Level} where

-- Identity.

  id : Container s p
  id .Shape    = Lift s ⊤
  id .Position = F.const (Lift p ⊤)

-- Constant.

  const : Set s → Container s p
  const X .Shape    = X
  const X .Position = F.const (Lift p ⊥)

-- Composition.

infixr 9 _∘_

_∘_ : ∀ {s₁ s₂ p₁ p₂} → Container s₁ p₁ → Container s₂ p₂ →
      Container (s₁ ⊔ s₂ ⊔ p₁) (p₁ ⊔ p₂)
(C₁ ∘ C₂) .Shape    = ⟦ C₁ ⟧ (Shape C₂)
(C₁ ∘ C₂) .Position = ◇ C₁ (Position C₂)

-- Product. (Note that, up to isomorphism, this is a special case of
-- indexed product.)

infixr 2 _×_

_×_ : ∀ {s₁ s₂ p₁ p₂} → Container s₁ p₁ → Container s₂ p₂ →
      Container (s₁ ⊔ s₂) (p₁ ⊔ p₂)
(C₁ × C₂) .Shape    = Shape C₁ P.× Shape C₂
(C₁ × C₂) .Position = P.uncurry λ s₁ s₂ → (Position C₁ s₁) S.⊎ (Position C₂ s₂)

-- Indexed product.

Π : ∀ {i s p} (I : Set i) → (I → Container s p) → Container (i ⊔ s) (i ⊔ p)
Π I C .Shape    = ∀ i → Shape (C i)
Π I C .Position = λ s → ∃ λ i → Position (C i) (s i)

-- Constant exponentiation. (Note that this is a special case of
-- indexed product.)

infix 0 const[_]⟶_

const[_]⟶_ : ∀ {i s p} → Set i → Container s p → Container (i ⊔ s) (i ⊔ p)
const[ X ]⟶ C = Π X (F.const C)

-- Sum. (Note that, up to isomorphism, this is a special case of
-- indexed sum.)

infixr 1 _⊎_

_⊎_ : ∀ {s₁ s₂ p} → Container s₁ p → Container s₂ p → Container (s₁ ⊔ s₂) p
(C₁ ⊎ C₂) .Shape    = (Shape C₁ S.⊎ Shape C₂)
(C₁ ⊎ C₂) .Position = [ Position C₁ , Position C₂ ]′

-- Indexed sum.

Σ : ∀ {i s p} (I : Set i) → (I → Container s p) → Container (i ⊔ s) p
Σ I C .Shape    = ∃ λ i → Shape (C i)
Σ I C .Position = λ s → Position (C (proj₁ s)) (proj₂ s)


{-# OPTIONS --without-K #-}
-- Two equivalent approached to define the advantage in
-- a (bit) guessing game
open import Data.Two
open import Data.Nat.NP hiding (_==_)
open import Data.Nat.Distance
open import Data.Product.NP

open import Function

open import Explore.Core
open import Explore.Properties
open import Explore.Summable
open import Explore.Sum
open import Explore.Product
open import Explore.Two

open import Relation.Binary.PropositionalEquality.NP

module Explore.GuessingGameFlipping
                 (R : Set)(sum : Sum R)(sum-ind : SumInd sum)(⅁ : 𝟚 → R → 𝟚) where
  open Operators
  X Y : R → 𝟚
  X = ⅁ 0₂
  Y = ⅁ 1₂
  R' = 𝟚 × R
  sum' : Sum R'
  sum' = 𝟚ˢ ×ˢ sum

  open FromSum    sum'    renaming (count to #'_)
  open FromSumInd sum-ind renaming (count to #_)

  G : R' → 𝟚
  G (b , r) = b == ⅁ b r

  1/2 : R' → 𝟚
  1/2 = fst

  -- TODO use the library
  lemma : ∀ X → sum (const 1) ≡ #(not ∘ X) + # X
  lemma X = sum-ind P refl (λ {a}{b} → part1 {a}{b}) part2
    where
      count = FromSum.count

      P = λ s → s (const 1) ≡ count s (not ∘ X) + count s X

      part1 : ∀ {s₀ s₁} → P s₀ → P s₁ → P (λ f → s₀ f + s₁ f)
      part1 {s₀} {s₁} Ps₀ Ps₁ rewrite Ps₀ | Ps₁ = +-interchange (count s₀ (not ∘ X)) (count s₀ X) (count s₁ (not ∘ X)) (count s₁ X)

      part2 : ∀ x → P (λ f → f x)
      part2 x with X x
      part2 x | 0₂ = refl
      part2 x | 1₂ = refl

  thm : dist (#' G) (#' 1/2) ≡ dist (# Y) (# X)
  thm = dist (#' G) (#' 1/2)
      ≡⟨ cong (dist (#' G)) helper ⟩
        dist (#' G) (#(not ∘ X) + # X)
      ≡⟨ refl ⟩ -- #' definition
        dist (# (_==_ 0₂ ∘ X) + # (_==_ 1₂ ∘ Y)) (# (not ∘ X) + # X)
      ≡⟨ refl ⟩ -- #' definition
        dist (# (not ∘ X) + # Y) (# (not ∘ X) + # X)
      ≡⟨ dist-x+ (# (not ∘ X)) (# Y) (# X) ⟩
        dist (# Y) (# X)
      ∎
    where
      open ≡-Reasoning

      helper = #' 1/2
             ≡⟨ refl ⟩
               sum (const 0) + sum (const 1)
             ≡⟨ cong (λ p → p + sum (const 1)) sum-zero ⟩
               sum (const 1)
             ≡⟨ lemma X ⟩
               # (not ∘ X) + # X
             ∎


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

open import Cubical.Core.Primitives

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

predℕ : ℕ → ℕ
predℕ zero    = 0
predℕ (suc n) = n

caseNat : ∀ {ℓ} → {A : Type ℓ} → (a0 aS : A) → ℕ → A
caseNat a0 aS 0       = a0
caseNat a0 aS (suc n) = aS

doubleℕ : ℕ → ℕ
doubleℕ 0 = 0
doubleℕ (suc x) = suc (suc (doubleℕ x))

-- doublesℕ n m = 2^n * m
doublesℕ : ℕ → ℕ → ℕ
doublesℕ 0 m = m
doublesℕ (suc n) m = doublesℕ n (doubleℕ m)

-- iterate
iter : ∀ {ℓ} {A : Type ℓ} → ℕ → (A → A) → A → A
iter zero f z    = z
iter (suc n) f z = f (iter n f z)


------------------------------------------------------------------------------
-- From ListP as the least fixed-point to ListP using data
------------------------------------------------------------------------------

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

-- We want to represent the polymorphic total lists data type
--
-- data ListP (A : D → Set) : D → Set where
--   lnil  : ListP A []
--   lcons : ∀ {x xs} → A x → ListP A xs → ListP A (x ∷ xs)
--
-- using the representation of ListP as the least fixed-point.

module LFPs.ListP where

open import FOTC.Base
open import FOTC.Base.List
open import FOTC.Data.Nat.Type
open import FOTC.Data.Nat.UnaryNumbers

------------------------------------------------------------------------------
-- ListP is a least fixed-point of a functor

-- The functor.
-- ListPF : (D → Set) → (D → Set) → D → Set
-- ListPF A B xs = xs ≡ [] ∨ (∃[ x' ] ∃[ xs' ] A x' ∧ xs ≡ x' ∷ xs' ∧ B xs')

-- ListP is the least fixed-point of ListPF.
postulate
  ListP : (D → Set) → D → Set

  -- ListP is a pre-fixed point of ListPF.
  --
  -- Peter: It corresponds to the introduction rules.
  ListP-in :
    (A : D → Set) →
    ∀ {xs} → xs ≡ [] ∨ (∃[ x' ] ∃[ xs' ] A x' ∧ xs ≡ x' ∷ xs' ∧ ListP A xs') →
    ListP A xs

  -- ListP is the least pre-fixed point of ListPF.
  --
  -- Peter: It corresponds to the elimination rule of an inductively
  -- defined predicate.
  ListP-ind :
    (A B : D → Set) →
    (∀ {xs} → xs ≡ [] ∨ (∃[ x' ] ∃[ xs' ] A x' ∧ xs ≡ x' ∷ xs' ∧ B xs') → B xs) →
    ∀ {xs} → ListP A xs → B xs

------------------------------------------------------------------------------
-- The data constructors of ListP.
lnil  : (A : D → Set) → ListP A []
lnil A = ListP-in A (inj₁ refl)

lcons : (A : D → Set) → ∀ {x xs} → A x → ListP A xs → ListP A (x ∷ xs)
lcons A {n} {ns} An LPns = ListP-in A (inj₂ (n , ns , An , refl , LPns))

------------------------------------------------------------------------------
-- The induction principle for ListP.
ListP-ind' : (A B : D → Set) →
             B [] →
             (∀ x {xs} → A x → B xs → B (x ∷ xs)) →
             ∀ {xs} → ListP A xs → B xs
ListP-ind' A B B[] is = ListP-ind A B prf
  where
  prf : ∀ {xs} →
        xs ≡ [] ∨ (∃[ x' ] ∃[ xs' ] A x' ∧ xs ≡ x' ∷ xs' ∧ B xs') →
        B xs
  prf (inj₁ xs≡[])                        = subst B (sym xs≡[]) B[]
  prf (inj₂ (x' , xs' , Ax' , h₁ , Bxs')) = subst B (sym h₁) (is x' Ax' Bxs')

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

-- "Heterogeneous" total lists
xs : D
xs = 0' ∷ true ∷ 1' ∷ false ∷ []

List : D → Set
List = ListP (λ d → d ≡ d)

xs-ListP : List xs
xs-ListP =
  lcons A refl (lcons A refl (lcons A refl (lcons A refl (lnil A))))
  where
  A : D → Set
  A d = d ≡ d

-- Total lists of total natural numbers
ys : D
ys = 0' ∷ 1' ∷ 2' ∷ []

ListN : D → Set
ListN = ListP N

ys-ListP : ListN ys
ys-ListP =
  lcons N nzero (lcons N (nsucc nzero) (lcons N (nsucc (nsucc nzero)) (lnil N)))


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

open import Tutorials.Monday-Complete
open import Tutorials.Tuesday
open List using (List; []; _∷_; _++_)
open Vec using (Vec; []; _∷_; _!_)
open Fin using (Fin; zero; suc)
module Tutorials.Wednesday where

-----------
-- Interfaces, isomorphisms
-----------

module Isomorphism where
  -- Why can we import _,_ from both modules without resulting in a nameclash?
  open Simple using (_⊎_; _×_; _,_; inl; inr)
  open Product using (Σ-syntax; Σ-⊎; Σ-×; Π-×; Π-→; _,_)

  infix 2 _≅_
  record _≅_ (A B : Set) : Set where
    constructor Mk≅
    field
      to      : A → B
      from    : B → A
      from∘to : ∀ a → from (to a) ≡ a
      to∘from : ∀ b → to (from b) ≡ b

  open _≅_

  -- We can use copattern matching to construct a record by defining how to construct each of its fields
  Σ-⊎-≅ : Σ-⊎ A B ≅ A ⊎ B
  Σ-⊎-≅ = {!!}

  Σ-×-≅ : Σ-× A B ≅ A × B
  Σ-×-≅ = {!!}

  Π-→-≅ : Π-→ A B ≅ (A → B)
  to Π-→-≅ = {!!}
  from Π-→-≅ = {!!}
  -- Needs η laws for functions (∀ x → f x) ≡ f
  from∘to Π-→-≅ = {!!}
  to∘from Π-→-≅ = {!!}

  -- The following isomorphism needs of function extensionality
  -- Function extensionality claims that if two functions give the same output on the same input, then they are equal
  -- This does not hold internally in Agda and we therefore need to postulate it as an axiom
  postulate
    extensionality : {P : A → Set} {f g : (a : A) → P a} → (∀ x → f x ≡ g x) → f ≡ g

  Π-×-≅ : Π-× A B ≅ A × B
  Π-×-≅ = {!!}

  curry : Π-→ A (Π-→ B C) → Π-→ (Σ-× A B) C
  curry f (a , b) = f a b

  uncurry : Π-→ (Σ-× A B) C → Π-→ A (Π-→ B C)
  uncurry f a b = f (a , b)

  curry-uncurry : Π-→ A (Π-→ B C) ≅ Π-→ (Σ-× A B) C
  curry-uncurry = {!!}

  Fin-≤-≅ : Fin m ≅ Σ[ n ∈ ℕ ] n < m
  Fin-≤-≅ = {!!}

  _iso-∘_ : B ≅ C → A ≅ B → A ≅ C
  x iso-∘ y = {!!}

-----------
-- Decidability
-----------

module Dec where
  open Product using (_×_; _,_; fst; snd)
  open Simple using (¬_)

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

  DecEq : Set → Set
  DecEq A = (x y : A) → Dec (x ≡ y)

  map : (A → B) → (¬ A → B) → Dec A → B
  map f g (yes x) = f x
  map f g (no x) = g x

  infix 5 _×-dec_
  _×-dec_ : Dec A → Dec B → Dec (A × B)
  yes x ×-dec yes y = yes (x , y)
  yes x ×-dec no ¬y = no (¬y ∘ snd)
  no ¬x ×-dec B? = no (¬x ∘ fst)

  _ℕ-≟_ : (n m : ℕ) → Dec (n ≡ m)
  n ℕ-≟ m = {!!}

  suc-injective : {i j : Fin n} → _≡_ {A = Fin (suc n)} (suc i) (suc j) → i ≡ j
  suc-injective refl = refl

  _Fin-≟_ : (i j : Fin n) → Dec (i ≡ j)
  zero Fin-≟ zero = yes refl
  zero Fin-≟ suc j = no λ ()
  suc i Fin-≟ zero = no λ ()
  suc i Fin-≟ suc j = map
    (yes ∘ cong suc)
    (no ∘ (λ neq → neq ∘ suc-injective))
    (i Fin-≟ j)

  ∷-injective : {x y : A} {xs ys : List A} → _≡_ {A = List A} (x ∷ xs) (y ∷ ys) → x ≡ y × xs ≡ ys
  ∷-injective refl = refl , refl

  List-≟ : (_A-≟_ : (x y : A) → Dec (x ≡ y)) → (xs ys : List A) → Dec (xs ≡ ys)
  List-≟ _A-≟_ [] [] = yes refl
  List-≟ _A-≟_ [] (y ∷ ys) = no λ ()
  List-≟ _A-≟_ (x ∷ xs) [] = no λ ()
  List-≟ _A-≟_ (x ∷ xs) (y ∷ ys) = map
    (yes ∘ Isomorphism.curry (cong₂ _∷_))
    (no ∘ (λ neq → neq ∘ ∷-injective))
    (x A-≟ y ×-dec List-≟ _A-≟_ xs ys)

-----------
-- Interfaces
-----------

-- We define what it is to be a monoid on a carrier set C
record Monoid (C : Set) : Set where
  constructor MkMonoid
  field
    ε   : C
    _∙_ : C → C → C
    -- Including the algebraic laws
    idˡ : (x : C) → ε ∙ x ≡ x
    idʳ : (x : C) → x ∙ ε ≡ x
    assoc : (x y z : C) → (x ∙ y) ∙ z ≡ x ∙ (y ∙ z)

module MonoidSolver (Symbol : Set) (symbol-≟ : Dec.DecEq Symbol) where
  -- The syntax for an expression tree of symbolic monoidal operations
  infixl 20 _‵∙_
  infix 25 ‵_
  data Expr : Set where
    ‵ε   : Expr
    ‵_   : Symbol → Expr
    _‵∙_ : Expr → Expr → Expr

  -- And define equations on monoids
  infix 10 _‵≡_
  record Eqn : Set where
    constructor _‵≡_
    field
      lhs : Expr
      rhs : Expr

  -- The canonical normal form for expression trees
  NormalForm : Set
  NormalForm = List Symbol

  normalise : Expr → NormalForm
  normalise ‵ε = []
  normalise (‵ x) = x ∷ []
  normalise (xs ‵∙ ys) = normalise xs ++ normalise ys

  module Eval (M : Monoid C) where
    open Monoid M

    -- An environment maps symbols to values in the carrier set
    Env : Set
    Env = Symbol → C

    -- Evaluate the syntax in a given environment
    ⟦_⟧ : Expr → Env → C
    ⟦ ‵ε ⟧ Γ = ε
    ⟦ ‵ x ⟧ Γ = Γ x
    ⟦ x ‵∙ y ⟧ Γ = ⟦ x ⟧ Γ ∙ ⟦ y ⟧ Γ

    -- Evaluate the normal form in a given environment
    ⟦_⟧⇓ : NormalForm → Env → C
    ⟦ [] ⟧⇓ Γ = ε
    ⟦ x ∷ xs ⟧⇓ Γ = Γ x ∙ ⟦ xs ⟧⇓ Γ

    -- The evaluation of normal forms distributes over list concatenation
    ++-homo : ∀ Γ (xs ys : NormalForm) → ⟦ xs ++ ys ⟧⇓ Γ ≡ ⟦ xs ⟧⇓ Γ ∙ ⟦ ys ⟧⇓ Γ
    ++-homo Γ [] ys = sym (idˡ _)
    ++-homo Γ (x ∷ xs) ys = begin
      Γ x ∙ ⟦ xs ++ ys ⟧⇓ Γ
        ≡⟨ cong (_ ∙_) (++-homo Γ xs ys) ⟩
      Γ x ∙ (⟦ xs ⟧⇓ Γ ∙ ⟦ ys ⟧⇓ Γ)
        ≡⟨ sym (assoc _ _ _) ⟩
      (Γ x ∙ ⟦ xs ⟧⇓ Γ) ∙ ⟦ ys ⟧⇓ Γ
        ∎

    -- Normalising and then evaluating the normal form is equal to evaluating the original expression
    correct : ∀ Γ (expr : Expr) → ⟦ normalise expr ⟧⇓ Γ ≡ ⟦ expr ⟧ Γ
    correct Γ ‵ε = refl
    correct Γ (‵ x) = idʳ _
    correct Γ (le ‵∙ re) = begin
      ⟦ normalise le      ++  normalise re ⟧⇓ Γ ≡⟨ ++-homo Γ (normalise le) (normalise re) ⟩
      ⟦ normalise le ⟧⇓ Γ ∙ ⟦ normalise re ⟧⇓ Γ ≡⟨ cong₂ _∙_ (correct Γ le) (correct Γ re) ⟩
      ⟦ le ⟧            Γ ∙ ⟦ re ⟧            Γ ∎

    -- We describe what it is to be a solution to an equation
    -- If both sides normalise to the same symbols in the same order,
    -- we claim that the monoid laws make the equations hold in any environment
    Solution : Eqn → Set
    Solution (lhs ‵≡ rhs) =
      Dec.map
        -- Both sides normalise to a common list of symbols, we must now show that the equation holds under any environment
        (λ _ → ∀ (Γ : Env) → ⟦ lhs ⟧ Γ ≡ ⟦ rhs ⟧ Γ)
        -- Both sides do *not* normalise to a common list of symbols, we claim only the trivial
        (λ _ → ⊤)
        (Dec.List-≟ symbol-≟ (normalise lhs) (normalise rhs))

    -- Now that we have described what a solution is, we show that we can provide one
    solve : (eqn : Eqn) → Solution eqn
    -- Pattern matching using with makes the goal type compute
    solve (lhs ‵≡ rhs) with Dec.List-≟ symbol-≟ (normalise lhs) (normalise rhs)
    solve (lhs ‵≡ rhs) | Dec.no _ = tt
    solve (lhs ‵≡ rhs) | Dec.yes lhs⇓≡rhs⇓ = λ Γ → begin
      ⟦ lhs ⟧ Γ            ≡⟨ sym (correct Γ lhs) ⟩
      ⟦ normalise lhs ⟧⇓ Γ ≡⟨ cong (λ ● → ⟦ ● ⟧⇓ Γ) lhs⇓≡rhs⇓ ⟩
      ⟦ normalise rhs ⟧⇓ Γ ≡⟨ correct Γ rhs ⟩
      ⟦ rhs ⟧ Γ            ∎

open MonoidSolver

-- An example instance of a monoid: natural numbers with addition
NAT-MONOID : Monoid ℕ
Monoid.ε NAT-MONOID = zero
Monoid._∙_ NAT-MONOID = _+_
Monoid.idˡ NAT-MONOID = +-idˡ
Monoid.idʳ NAT-MONOID = +-idʳ
Monoid.assoc NAT-MONOID = +-assoc

-- An example usage of the monoid solver
-- We first need to "quote" the goal, i.e. describe it in terms of the expression language / syntax
-- NAT-MONOID describes how to interpret the syntax back and evaluate the expression into a value of the carrier set
eqn₁-auto : (x y z : ℕ) → (0 + x) + y + (y + z) ≡ x + (0 + y + 0) + (y + z + 0)
eqn₁-auto x y z =
  let
    ‵x = zero
    ‵y = suc zero
    ‵z = suc (suc zero)
    lhs = (‵ε ‵∙ ‵ ‵x) ‵∙ ‵ ‵y ‵∙ (‵ ‵y ‵∙ ‵ ‵z)
    rhs = ‵ ‵x ‵∙ (‵ε ‵∙ ‵ ‵y ‵∙ ‵ε) ‵∙ (‵ ‵y ‵∙ ‵ ‵z ‵∙ ‵ε)
  in
  Eval.solve (Fin 3) Dec._Fin-≟_ NAT-MONOID (lhs ‵≡ rhs) λ where
    zero → x
    (suc zero) → y
    (suc (suc zero)) → z


open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.List using (List; []; _∷_; [_]; _++_)
open import Data.List.Any using (Any; here; there)
open import Data.List.Any.Membership.Propositional using (_∈_)
open import Data.Nat using (ℕ)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
-- open import Data.List.Any.Membership.Propositional.Properties using (∈-++⁺ˡ; ∈-++⁺ʳ; ∈-++⁻)

Id = ℕ

_⊆_ : List Id → List Id → Set
xs ⊆ ys = ∀ {w} → w ∈ xs → w ∈ ys

lemma : ∀ {x : Id} → x ∈ [ x ]
lemma = here refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- An explanation about how to use the solver in Tactic.MonoidSolver.
------------------------------------------------------------------------

open import Algebra

module README.Tactic.MonoidSolver {a ℓ} (M : Monoid a ℓ) where

open Monoid M

open import Data.Nat as Nat using (ℕ; suc; zero; _+_)
open import Data.Nat.Properties as Properties using (+-0-monoid; +-comm)
open import Relation.Binary.Reasoning.Setoid setoid

open import Tactic.MonoidSolver using (solve; solve-macro)

-- The monoid solver is capable to of solving equations without having
-- to specify the equation itself in the proof.

example₁ : ∀ x y z → (x ∙ y) ∙ z ≈ x ∙ (y ∙ z) ∙ ε
example₁ x y z = solve M

-- The solver can also be used in equational reasoning.

example₂ : ∀ w x y z → w ≈ x → (w ∙ y) ∙ z ≈ x ∙ (y ∙ z) ∙ ε
example₂ w x y z w≈x = begin
  (w ∙ y) ∙ z      ≈⟨ ∙-congʳ (∙-congʳ w≈x) ⟩
  (x ∙ y) ∙ z      ≈⟨ solve M ⟩
  x ∙ (y ∙ z) ∙ ε  ∎


{-# OPTIONS --safe #-}
module Cubical.Categories.Instances.TypePrecategory where

open import Cubical.Foundations.Prelude

open import Cubical.Categories.Category.Precategory

open Precategory

-- TYPE precategory has types as objects
module _ ℓ where
  TYPE : Precategory (ℓ-suc ℓ) ℓ
  TYPE .ob           = Type ℓ
  TYPE .Hom[_,_] A B = A → B
  TYPE .id           = λ x → x
  TYPE ._⋆_ f g      = λ x → g (f x)
  TYPE .⋆IdL f       = refl
  TYPE .⋆IdR f       = refl
  TYPE .⋆Assoc f g h = refl


module Numeric.Nat.Divide.Properties where

open import Prelude
open import Numeric.Nat.Properties
open import Numeric.Nat.DivMod
open import Numeric.Nat.Divide
open import Tactic.Nat

divides-add : ∀ {a b d} → d Divides a → d Divides b → d Divides (a + b)
divides-add (factor! q) (factor! q₁) = factor (q + q₁) auto

divides-mul-r : ∀ a {b d} → d Divides b → d Divides (a * b)
divides-mul-r a (factor! q) = factor (a * q) auto

divides-mul-l : ∀ {a} b {d} → d Divides a → d Divides (a * b)
divides-mul-l b (factor! q) = factor (b * q) auto

divides-mul : ∀ {a b c d} → c Divides a → d Divides b → (c * d) Divides (a * b)
divides-mul (factor! q) (factor! r) = factor (q * r) auto

mul-divides-l : (a b c : Nat) → (a * b) Divides c → a Divides c
mul-divides-l a b c (factor! q) = factor (q * b) auto

mul-divides-r : (a b c : Nat) → (a * b) Divides c → b Divides c
mul-divides-r a b c (factor! q) = factor (q * a) auto

divides-flip-mul : ∀ {a b c d} → c Divides b → d Divides a → (c * d) Divides (a * b)
divides-flip-mul {a} {b} {c} {d} c|b d|a =
  transport ((c * d) Divides_) (mul-commute b a) (divides-mul c|b d|a)

divides-sub-l : ∀ {a b d} → d Divides (a + b) → d Divides a → d Divides b
divides-sub-l {b = b} {d} (factor q₁ eq) (factor! q) = factor (q₁ - q) $ by eq

divides-sub-r : ∀ {a b d} → d Divides (a + b) → d Divides b → d Divides a
divides-sub-r {a} {b} d|ab d|b rewrite add-commute a b = divides-sub-l d|ab d|b

divides-mul-cong-l : ∀ {a b} c → a Divides b → (c * a) Divides (c * b)
divides-mul-cong-l {a} {b} c (factor q eq) = factor q (by (c *_ $≡ eq))

divides-mul-cong-r : ∀ {a b} c → a Divides b → (a * c) Divides (b * c)
divides-mul-cong-r {a} {b} c (factor q eq) = factor q (by (c *_ $≡ eq))

divides-nonzero : ∀ {a b} {{_ : NonZero b}} → a Divides b → NonZero a
divides-nonzero {zero} {{nzb}} (factor! b) = transport NonZero (mul-zero-r b) nzb
divides-nonzero {suc _} _ = _

divides-refl : ∀ {a} → a Divides a
divides-refl = factor 1 auto

divides-antisym : ∀ {a b} → a Divides b → b Divides a → a ≡ b
divides-antisym         (factor! q)       (factor! 0)                = auto
divides-antisym         (factor! q)       (factor 1 eq)              = by eq
divides-antisym {zero}  (factor! q)       (factor (suc (suc q₁)) eq) = auto
divides-antisym {suc a} (factor! 0)       (factor (suc (suc q₁)) eq) = by eq
divides-antisym {suc a} (factor! (suc q)) (factor (suc (suc q₁)) eq) = refute eq

divides-trans : ∀ {a b c} → a Divides b → b Divides c → a Divides c
divides-trans (factor! q) (factor! q′) = factor (q′ * q) auto

divides-zero : ∀ {a} → 0 Divides a → a ≡ 0
divides-zero (factor! q) = auto

one-divides : ∀ {a} → 1 Divides a
one-divides {a} = factor a auto

divides-one : ∀ {a} → a Divides 1 → a ≡ 1
divides-one {0} (factor k eq) = refute eq
divides-one {1} _ = refl
divides-one {suc (suc a)} (factor zero ())
divides-one {suc (suc a)} (factor (suc k) eq) = refute eq

mul=1-l : (a b : Nat) → a * b ≡ 1 → a ≡ 1
mul=1-l a b eq =
  divides-one (transport (a Divides_) eq (divides-mul-l b divides-refl))

mul=1-r : (a b : Nat) → a * b ≡ 1 → b ≡ 1
mul=1-r a b eq = mul=1-l b a (by eq)

divides-less : ∀ {a b} {{_ : NonZero b}} → a Divides b → a ≤ b
divides-less {{}} (factor! 0)
divides-less {a} (factor! (suc q)) = auto

nonzero-factor : ∀ {a b} ⦃ nzb : NonZero b ⦄ (a|b : a Divides b) → NonZero (get-factor a|b)
nonzero-factor ⦃ () ⦄ (factor! zero)
nonzero-factor (factor! (suc _)) = _

cancel-mul-divides-r : ∀ a b c ⦃ _ : NonZero c ⦄ → (a * c) Divides (b * c) → a Divides b
cancel-mul-divides-r a b c (factor q qac=bc) =
  factor q (mul-inj₁ (q * a) b c (by qac=bc))

cancel-mul-divides-l : ∀ a b c ⦃ _ : NonZero a ⦄ → (a * b) Divides (a * c) → b Divides c
cancel-mul-divides-l a b c rewrite mul-commute a b | mul-commute a c = cancel-mul-divides-r b c a


open import Data.Product

open import Relation.Binary.PropositionalEquality hiding ([_] ; Extensionality)
open import Relation.Nullary
open import Relation.Nullary.Negation

open import EffectAnnotations

module Types where

-- BASE AND GROUND TYPES

postulate BType : Set -- set of base types

postulate dec-bty : (B B' : BType) → Dec (B ≡ B')

GType = BType

-- VALUE AND COMPUTATION TYPES

mutual

  data VType : Set where
    ``  : GType → VType
    _⇒_ : VType → CType → VType
    ⟨_⟩ : VType → VType

  data CType : Set where
    _!_ : VType → O × I → CType

infix 30 _⇒_
infix 30 _!_

-- PROCESS TYPES

data PTypeShape : Set where
  _!_ : VType → I → PTypeShape
  _∥_ : PTypeShape → PTypeShape → PTypeShape

data PType : O → Set where

  _‼_,_ : (X : VType) →
          (o : O) →
          (i : I) →
          ---------------
          PType o

  _∥_   : {o o' : O} →
          (PP : PType o) →
          (QQ : PType o') →
          ---------------------------
          PType (o ∪ₒ o')

-- ACTION OF INTERRUPTS ON PROCESS TYPES

_↓ₚₚ_ : (op : Σₛ) → {o : O} →
        PType o → Σ[ o' ∈ O ] PType o'
op ↓ₚₚ (X ‼ o , i) with op ↓ₑ (o , i)
... | (o' , i') =
  o' , (X ‼ o' , i')
op ↓ₚₚ (PP ∥ QQ) with op ↓ₚₚ PP | op ↓ₚₚ QQ
... | (o'' , PP') | (o''' , QQ') =
  (o'' ∪ₒ o''') , (PP' ∥ QQ')

_↓ₚ_ : (op : Σₛ) → {o : O} →
       (PP : PType o) → PType (proj₁ (op ↓ₚₚ PP))

op ↓ₚ PP = proj₂ (op ↓ₚₚ PP)

-- ACTION OF INTERRUPTS ON PROCESS TYPES PRESERVES SIGNAL ANNOTATIONS

{- LEMMA 4.1 -}

↓ₚₚ-⊑ₒ : {op : Σₛ}
        {o : O} →
        (PP : PType o) →
        ----------------------
        o ⊑ₒ proj₁ (op ↓ₚₚ PP)

↓ₚₚ-⊑ₒ (X ‼ o , i) =
  ↓ₑ-⊑ₒ
↓ₚₚ-⊑ₒ (PP ∥ QQ) =
  ∪ₒ-fun (↓ₚₚ-⊑ₒ PP) (↓ₚₚ-⊑ₒ QQ)


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

open import Cubical.Core.Everything
open import Cubical.Foundations.HLevels

module Cubical.Algebra.Group.Construct.Free {ℓ} (Aˢ : hSet ℓ) where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Univalence
open import Cubical.Foundations.Path
open import Cubical.Algebra.Group

open import Cubical.Data.Empty.Polymorphic
open import Cubical.Data.Prod

open import Cubical.Relation.Binary.Reasoning.Equality

A = ⟨ Aˢ ⟩
isSetA = Aˢ .snd

data FreeG : Type ℓ where
  inj : A → FreeG
  _•_ : Op₂ FreeG
  ε   : FreeG
  _⁻¹ : Op₁ FreeG

  •-assoc     : Associative _•_
  •-identityˡ : LeftIdentity ε _•_
  •-identityʳ : RightIdentity ε _•_
  •-inverseˡ  : LeftInverse ε _⁻¹ _•_
  •-inverseʳ  : RightInverse ε _⁻¹ _•_

  squash : isSet FreeG

•-identity : Identity ε _•_
•-identity = •-identityˡ , •-identityʳ

•-inverse : Inverse ε _⁻¹ _•_
•-inverse = •-inverseˡ , •-inverseʳ

elim : ∀ {ℓ′} {B : FreeG → Type ℓ′} →
        (∀ x → isSet (B x)) →
        (∀ x → B (inj x)) →
        (op : ∀ {x y} → B x → B y → B (x • y)) →
        (e : B ε) →
        (inv : ∀ {x} → B x → B (x ⁻¹)) →
        (∀ {x y z} (a : B x) (b : B y) (c : B z) → PathP (λ i → B (•-assoc x y z i)) (op (op a b) c) (op a (op b c))) →
        (∀ {x} (a : B x) → PathP (λ i → B (•-identityˡ x i)) (op e a) a) →
        (∀ {x} (a : B x) → PathP (λ i → B (•-identityʳ x i)) (op a e) a) →
        (∀ {x} (a : B x) → PathP (λ i → B (•-inverseˡ x i)) (op (inv a) a) e) →
        (∀ {x} (a : B x) → PathP (λ i → B (•-inverseʳ x i)) (op a (inv a)) e) →
        (x : FreeG) → B x
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (inj x) = f x
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (x • y) = op (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x)
                                                            (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ y)
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ ε = e
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (x ⁻¹) = inv (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x)
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (•-assoc x y z i) = assc (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x)
                                                                        (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ y)
                                                                        (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ z) i
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (•-identityˡ x i) = idˡ (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x) i
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (•-identityʳ x i) = idʳ (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x) i
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (•-inverseˡ x i) = invˡ (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x) i
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (•-inverseʳ x i) = invʳ (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x) i
elim isSetB f op e inv assc idˡ idʳ invˡ invʳ (squash x y p q i j) =
  isOfHLevel→isOfHLevelDep 2 isSetB
    (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ x) (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ y)
    (cong (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ) p) (cong (elim isSetB f op e inv assc idˡ idʳ invˡ invʳ) q) (squash x y p q) i j

FreeG-isGroup : IsGroup FreeG _•_ ε _⁻¹
FreeG-isGroup = record
  { isMonoid = record
      { isSemigroup = record
          { isMagma = record { is-set = squash }
          ; assoc   = •-assoc
          }
      ; identity    = •-identity
      }
  ; inverse  = •-inverse
  }

FreeGroup : Group ℓ
FreeGroup = record { isGroup = FreeG-isGroup }


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

open import Agda.Builtin.Bool
open import Data.Maybe.Base using (Maybe; just; nothing)
open import Relation.Nullary
open import Data.Rational.Unnormalised.Base using (ℚᵘ; 0ℚᵘ; _≃_)
open import Data.Rational.Unnormalised.Properties using (+-*-commutativeRing; _≃?_)

isZero? : ∀ (p : ℚᵘ) -> Maybe (0ℚᵘ ≃ p)
isZero? p with 0ℚᵘ ≃? p
... | .true because ofʸ p₁ = just p₁
... | .false because ofⁿ ¬p = nothing

open import Tactic.RingSolver.Core.AlmostCommutativeRing using (fromCommutativeRing)
open import Tactic.RingSolver.NonReflective (fromCommutativeRing +-*-commutativeRing isZero?) public


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

open import Cubical.Foundations.Prelude
open import Cubical.Data.Nat
open import Cubical.Relation.Nullary

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

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)

¬Fin0 : ¬ Fin 0
¬Fin0 ()


module Example where

open import Data.List

-- reverse
rev : ∀ {a} {A : Set a} → List A → List A
rev [] = []
rev (x ∷ xs) = rev xs ++ [ x ]

-- https://code.google.com/p/agda/issues/detail?id=1252 暫定対策
rev' = rev
{-# COMPILED_EXPORT rev' rev' #-}

private
  open import Relation.Binary.PropositionalEquality

  -- reverse2回で元に戻る証明
  lemma : ∀ {a} {A : Set a} (x : A) (xs : List A) → rev (xs ∷ʳ x) ≡ x ∷ rev xs
  lemma x [] = refl
  lemma x (_ ∷ xs)
    rewrite lemma x xs
          = refl

  revrev-is-id : ∀ {a} {A : Set a} (xs : List A) → rev (rev xs) ≡ xs
  revrev-is-id [] = refl
  revrev-is-id (x ∷ xs)
    rewrite lemma x (rev xs)
          | revrev-is-id xs
          = refl

open import Data.Empty

head : ∀ {a} {A : Set a} (xs : List A) → {xs≢[] : xs ≢ []} → A
head [] {xs≠[]} = ⊥-elim (xs≠[] refl)
head (x ∷ xs) = x
{-
{-# COMPILED_EXPORT head safeHead' #-}
-- エラーになる
-- The type _≡_ cannot be translated to a Haskell type.
-- when checking the pragma COMPILED_EXPORT head' safeHead
--
-- つまり，証明オブジェクトを取るような関数は，
-- そのままではCOMPILED_EXPORTできないことが多い
-}

open import Data.Maybe

head' : ∀ {a} {A : Set a} (xs : List A) → Maybe A
head' = go where
  go : ∀ {a} {A : Set a} (xs : List A) → Maybe A
  go [] = nothing
  go (x ∷ xs) = just (head (x ∷ xs) {λ ()})
{-# COMPILED_EXPORT head' safeHead' #-}
-- つまり，安全なheadを使うには，
-- 安全なものだけ渡せるようにしてjustで結果が得られ，
-- それ以外についてはnothingになるように，
-- 適切にラップしないとCOMPILED_EXPORTできない．


module Class.Listable where

open import Class.Equality

open import Data.List
open import Data.List.Relation.Unary.Any
open import Data.List.Relation.Unary.All.Properties
open import Data.List.Relation.Unary.Unique.Propositional
open import Data.List.Membership.Propositional
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary

record Listable (A : Set) : Set where
  field
    listing  : List A
    unique   : Unique listing
    complete : (a : A) → a ∈ listing

  Listable→Eq : Eq A
  Listable→Eq ._≟_ a b = helper (complete a) (complete b) unique
    where
      helper : ∀ {a b} {l : List A} → (a ∈ l) → (b ∈ l) → Unique l → Dec (a ≡ b)
      helper {a} {b} {l} h h' u with l | h | h' | u
      ... | ._ | here refl | here refl | _      = yes refl
      ... | ._ | here refl | there h   | h' ∷ _ = no λ where refl → All¬⇒¬Any h' h
      ... | ._ | there h   | here refl | h' ∷ _ = no λ where refl → All¬⇒¬Any h' h
      ... | ._ | there h   | there h'  | _  ∷ u = helper h h' u


------------------------------------------------------------------------
-- The Agda standard library
--
-- Environments (heterogeneous collections)
------------------------------------------------------------------------

module Data.Star.Environment (Ty : Set) where

open import Data.Star
open import Data.Star.List
open import Data.Star.Decoration
open import Data.Star.Pointer as Pointer hiding (lookup)
open import Data.Unit
open import Relation.Binary.PropositionalEquality

-- Contexts, listing the types of all the elements in an environment.

Ctxt : Set
Ctxt = List Ty

-- Variables (de Bruijn indices); pointers into environments.

infix 4 _∋_

_∋_ : Ctxt → Ty → Set
Γ ∋ σ = Any (λ _ → ⊤) (_≡_ σ) Γ

vz : ∀ {Γ σ} → Γ ▻ σ ∋ σ
vz = this refl

vs : ∀ {Γ σ τ} → Γ ∋ τ → Γ ▻ σ ∋ τ
vs = that tt

-- Environments. The T function maps types to element types.

Env : (Ty → Set) → Ctxt → Set
Env T Γ = All T Γ

-- A safe lookup function for environments.

lookup : ∀ {Γ σ} {T : Ty → Set} → Γ ∋ σ → Env T Γ → T σ
lookup i ρ with Pointer.lookup i ρ
... | result refl x = x


{-# OPTIONS --cubical #-}

module Equality where

import Algebra.FunctionProperties
import Algebra.Structures
open import Cubical.Core.Everything public hiding (module Σ)
open import Data.Empty
open import Data.Nat as ℕ
open import Data.Nat.Properties
open import Data.Product as Σ
open import Data.Unit
open import Function
open import Quotient
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as ♥ public using () renaming (refl to ♥)

open module FunctionProperties {a} {A : Set a} =
  Algebra.FunctionProperties {A = A} _≡_

open module Structures {a} {A : Set a} =
  Algebra.Structures {A = A} _≡_

coe : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → A → B
coe = subst id

infix 1 _$⃗_
_$⃗_ : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → A → B
_$⃗_ = coe

infix 1 _$⃖_
_$⃖_ : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → B → A
p $⃖ x = sym p $⃗ x

≡-isEquivalence : ∀ {ℓ} {A : Set ℓ} → IsEquivalence {A = A} _≡_
≡-isEquivalence = record
  { refl = refl
  ; sym = sym
  ; trans = compPath
  }

≡-isPreorder : ∀ {ℓ} {A : Set ℓ} → IsPreorder {A = A} _≡_ _≡_
≡-isPreorder = record
  { isEquivalence = ≡-isEquivalence
  ; reflexive = id
  ; trans = compPath
  }

module _ {ℓ} {A : Set ℓ} {a b : A} where
  ⟨_⟩ : a ♥.≡ b → a ≡ b
  ⟨ ♥ ⟩ = refl

  ⟪_⟫ : a ≡ b → a ♥.≡ b
  ⟪_⟫ = J (λ x _ → _ ♥.≡ x) ♥

infixl 5 _≫_
_≫_ : ∀ {ℓ} {A : Set ℓ} {a b c : A} → a ≡ b → b ≡ c → a ≡ c
_≫_ = compPath

module _ {ℓ₁ ℓ₂} {A : Set ℓ₁} {B : Set ℓ₂} {f f′ : A → B} where
  happly : ∀ a → f ≡ f′ → f a ≡ f′ a
  happly a = cong λ g → g a

  congApp : ∀ {a a′} → f ≡ f′ → a ≡ a′ → f a ≡ f′ a′
  congApp p q = compPath (happly _ p) (cong f′ q)

cong₂ : ∀
  {ℓ₁ ℓ₂ ℓ₃} {A : Set ℓ₁} {B : Set ℓ₂} {C : Set ℓ₃}
  {a a′} {b b′}
  (f : A → B → C) →
  a ≡ a′ → b ≡ b′ →
  f a b ≡ f a′ b′
cong₂ f p q = congApp (cong f p) q


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

-- Common cost monoids.

module Calf.CostMonoids where

open import Calf.CostMonoid
open import Data.Product
open import Relation.Binary.PropositionalEquality

ℕ-CostMonoid : CostMonoid
ℕ-CostMonoid = record
  { ℂ = ℕ
  ; _+_ = _+_
  ; zero = zero
  ; _≤_ = _≤_
  ; isCostMonoid = record
    { isMonoid = +-0-isMonoid
    ; isCancellative = record { ∙-cancel-≡ = +-cancel-≡ }
    ; isPreorder = ≤-isPreorder
    ; isMonotone = record { ∙-mono-≤ = +-mono-≤ }
    }
  }
  where
    open import Data.Nat
    open import Data.Nat.Properties

ℕ-Work-ParCostMonoid : ParCostMonoid
ℕ-Work-ParCostMonoid = record
  { ℂ = ℕ
  ; _⊕_ = _+_
  ; 𝟘 = 0
  ; _⊗_ = _+_
  ; 𝟙 = 0
  ; _≤_ = _≤_
  ; isParCostMonoid = record
    { isMonoid = +-0-isMonoid
    ; isCommutativeMonoid = +-0-isCommutativeMonoid
    ; isCancellative = record { ∙-cancel-≡ = +-cancel-≡ }
    ; isPreorder = ≤-isPreorder
    ; isMonotone-⊕ = record { ∙-mono-≤ = +-mono-≤ }
    ; isMonotone-⊗ = record { ∙-mono-≤ = +-mono-≤ }
    }
  }
  where
    open import Data.Nat
    open import Data.Nat.Properties

ℕ-Span-ParCostMonoid : ParCostMonoid
ℕ-Span-ParCostMonoid = record
  { ℂ = ℕ
  ; _⊕_ = _+_
  ; 𝟘 = 0
  ; _⊗_ = _⊔_
  ; 𝟙 = 0
  ; _≤_ = _≤_
  ; isParCostMonoid = record
    { isMonoid = +-0-isMonoid
    ; isCommutativeMonoid = ⊔-0-isCommutativeMonoid
    ; isPreorder = ≤-isPreorder
    ; isCancellative = record { ∙-cancel-≡ = +-cancel-≡ }
    ; isMonotone-⊕ = record { ∙-mono-≤ = +-mono-≤ }
    ; isMonotone-⊗ = record { ∙-mono-≤ = ⊔-mono-≤ }
    }
  }
  where
    open import Data.Nat
    open import Data.Nat.Properties

combineParCostMonoids : ParCostMonoid → ParCostMonoid → ParCostMonoid
combineParCostMonoids pcm₁ pcm₂ = record
  { ℂ = ℂ pcm₁ × ℂ pcm₂
  ; _⊕_ = λ (a₁ , a₂) (b₁ , b₂) → _⊕_ pcm₁ a₁ b₁ , _⊕_ pcm₂ a₂ b₂
  ; 𝟘 = 𝟘 pcm₁ , 𝟘 pcm₂
  ; _⊗_ = λ (a₁ , a₂) (b₁ , b₂) → _⊗_ pcm₁ a₁ b₁ , _⊗_ pcm₂ a₂ b₂
  ; 𝟙 = 𝟙 pcm₁ , 𝟙 pcm₂
  ; _≤_ = λ (a₁ , a₂) (b₁ , b₂) → _≤_ pcm₁ a₁ b₁ × _≤_ pcm₂ a₂ b₂
  ; isParCostMonoid = record
    { isMonoid = record
      { isSemigroup = record
        { isMagma = record
          { isEquivalence = isEquivalence
          ; ∙-cong = λ h₁ h₂ →
              cong₂ _,_
                (cong₂ (_⊕_ pcm₁) (cong proj₁ h₁) (cong proj₁ h₂))
                (cong₂ (_⊕_ pcm₂) (cong proj₂ h₁) (cong proj₂ h₂))
          }
        ; assoc = λ (a₁ , a₂) (b₁ , b₂) (c₁ , c₂) → cong₂ _,_ (⊕-assoc pcm₁ a₁ b₁ c₁) (⊕-assoc pcm₂ a₂ b₂ c₂)
        }
      ; identity =
        (λ (a₁ , a₂) → cong₂ _,_ (⊕-identityˡ pcm₁ a₁) (⊕-identityˡ pcm₂ a₂)) ,
        (λ (a₁ , a₂) → cong₂ _,_ (⊕-identityʳ pcm₁ a₁) (⊕-identityʳ pcm₂ a₂))
      }
    ; isCommutativeMonoid = record
      { isMonoid = record
        { isSemigroup = record
          { isMagma = record
            { isEquivalence = isEquivalence
            ; ∙-cong = λ h₁ h₂ →
                cong₂ _,_
                  (cong₂ (_⊗_ pcm₁) (cong proj₁ h₁) (cong proj₁ h₂))
                  (cong₂ (_⊗_ pcm₂) (cong proj₂ h₁) (cong proj₂ h₂))
            }
          ; assoc = λ (a₁ , a₂) (b₁ , b₂) (c₁ , c₂) → cong₂ _,_ (⊗-assoc pcm₁ a₁ b₁ c₁) (⊗-assoc pcm₂ a₂ b₂ c₂)
          }
        ; identity =
          (λ (a₁ , a₂) → cong₂ _,_ (⊗-identityˡ pcm₁ a₁) (⊗-identityˡ pcm₂ a₂)) ,
          (λ (a₁ , a₂) → cong₂ _,_ (⊗-identityʳ pcm₁ a₁) (⊗-identityʳ pcm₂ a₂))
        }
      ; comm = λ (a₁ , a₂) (b₁ , b₂) → cong₂ _,_ (⊗-comm pcm₁ a₁ b₁) (⊗-comm pcm₂ a₂ b₂)
      }
    ; isCancellative = record
      { ∙-cancel-≡ =
        (λ (x₁ , x₂)           h → cong₂ _,_ (⊕-cancelˡ-≡ pcm₁ x₁    (cong proj₁ h)) (⊕-cancelˡ-≡ pcm₂ x₂    (cong proj₂ h))) ,
        (λ (y₁ , y₂) (z₁ , z₂) h → cong₂ _,_ (⊕-cancelʳ-≡ pcm₁ y₁ z₁ (cong proj₁ h)) (⊕-cancelʳ-≡ pcm₂ y₂ z₂ (cong proj₂ h)))
      }
    ; isPreorder = record
      { isEquivalence = isEquivalence
      ; reflexive = λ { refl → ≤-refl pcm₁ , ≤-refl pcm₂ }
      ; trans = λ (h₁ , h₂) (h₁' , h₂') → ≤-trans pcm₁ h₁ h₁' , ≤-trans pcm₂ h₂ h₂'
      }
    ; isMonotone-⊕ = record
      { ∙-mono-≤ = λ (h₁ , h₂) (h₁' , h₂') → ⊕-mono-≤ pcm₁ h₁ h₁' , ⊕-mono-≤ pcm₂ h₂ h₂'
      }
    ; isMonotone-⊗ = record
      { ∙-mono-≤ = λ (h₁ , h₂) (h₁' , h₂') → ⊗-mono-≤ pcm₁ h₁ h₁' , ⊗-mono-≤ pcm₂ h₂ h₂'
      }
    }
  }
  where open ParCostMonoid

ℕ²-ParCostMonoid : ParCostMonoid
ℕ²-ParCostMonoid = combineParCostMonoids ℕ-Work-ParCostMonoid ℕ-Span-ParCostMonoid


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

module Categories.Category.Finite where

open import Level
open import Data.Product using (Σ; _,_; ∃₂)
open import Function.Equality using (Π; _⟶_)
open import Function.Inverse
open import Data.Nat as ℕ hiding (_⊔_)
import Data.Fin as Fin
open import Data.Vec as Vec
open import Relation.Binary using (Setoid)
import Relation.Binary.PropositionalEquality as ≡

open import Categories.Category
open Π

FiniteSetoid : ∀ {c ℓ} n (S : Setoid c ℓ) → Set _
FiniteSetoid n S = Inverse (≡.setoid (Fin.Fin n)) S

record Finite {o ℓ e} (C : Category o ℓ e) : Set (o ⊔ ℓ ⊔ e) where
  open Category C

  field
    ∣Obj∣ : ℕ
    ∣_⇒_∣ : Obj → Obj → ℕ

    Obj-finite : FiniteSetoid ∣Obj∣ (≡.setoid Obj)
    ⇒-finite   : ∀ A B → FiniteSetoid ∣ A ⇒ B ∣ (hom-setoid {A} {B})

  module Obj-finite   = Inverse Obj-finite
  module ⇒-finite A B = Inverse (⇒-finite A B)

  private
    Fins : ∀ n → Vec (Fin.Fin n) n
    Fins ℕ.zero    = []
    Fins (ℕ.suc n) = Fin.fromℕ n ∷ Vec.map (Fin.raise 1) (Fins n)

  -- enumeration of all objects
  Objs : Vec Obj ∣Obj∣
  Objs = Vec.map (Obj-finite.to ⟨$⟩_) (Fins ∣Obj∣)

  private
    ObjPairs : ∀ {a} {A : Set a} → (Obj → Obj → A) → Vec A (∣Obj∣ * ∣Obj∣)
    ObjPairs {_} {A} f = Objs >>= ap
      where ap : Obj → Vec A ∣Obj∣
            ap X = Vec.map (f X) Objs

  -- enumeration of all morphisms of a given pair of objects
  ⟦_⇒_⟧ : ∀ A B → Vec (A ⇒ B) ∣ A ⇒ B ∣
  ⟦ A ⇒ B ⟧ = Vec.map (⇒-finite.to A B ⟨$⟩_) (Fins ∣ A ⇒ B ∣)

  -- number of all morphisms
  ∣-⇒-| : ℕ
  ∣-⇒-| = foldr (λ _ → ℕ) _+_ 0 (ObjPairs ∣_⇒_∣)


module Data.Bool.Instance where

open import Class.Equality
open import Class.Show
open import Data.Bool
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary

instance
  Bool-Eq : Eq Bool
  Bool-Eq = record { _≟_ = helper }
    where
      helper : ∀ (x y : Bool) → Dec (x ≡ y)
      helper false false = yes refl
      helper false true = no (λ ())
      helper true false = no (λ ())
      helper true true = yes refl

  Bool-Show : Show Bool
  Bool-Show = record { show = λ { false → "false" ; true → "true" } }


{-# OPTIONS --prop --rewriting #-}

open import Calf.CostMonoid
open import Data.Nat using (ℕ)

module Examples.Sorting.Comparable
  (costMonoid : CostMonoid) (fromℕ : ℕ → CostMonoid.ℂ costMonoid) where

open CostMonoid costMonoid using (ℂ)

open import Calf costMonoid
open import Calf.Types.Bool
open import Calf.Types.Bounded costMonoid

open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl; module ≡-Reasoning)
open import Data.Product using (_×_; _,_; proj₁; proj₂; ∃)
open import Function

record Comparable : Set₁ where
  field
    A : tp pos
    _≤_ : val A → val A → Set
    _≤ᵇ_ : val A → val A → cmp (F bool)
    ≤ᵇ-reflects-≤ : ∀ {x y b} → ◯ ((x ≤ᵇ y) ≡ ret b → Reflects (x ≤ y) b)
    ≤-refl : Reflexive _≤_
    ≤-trans : Transitive _≤_
    ≤-total : Total _≤_
    ≤-antisym : Antisymmetric _≡_ _≤_
    h-cost : (x y : val A) → IsBounded bool (x ≤ᵇ y) (fromℕ 1)

NatComparable : Comparable
NatComparable = record
  { A = nat
  ; _≤_ = _≤_
  ; _≤ᵇ_ = λ x y → step (F bool) (fromℕ 1) (ret (x ≤ᵇ y))
  ; ≤ᵇ-reflects-≤ = reflects
  ; ≤-refl = ≤-refl
  ; ≤-trans = ≤-trans
  ; ≤-total = ≤-total
  ; ≤-antisym = ≤-antisym
  ; h-cost = λ _ _ →
      bound/relax
        (λ u → CostMonoid.≤-reflexive costMonoid (CostMonoid.+-identityʳ costMonoid (fromℕ 1)))
        (bound/step (fromℕ 1) (CostMonoid.zero costMonoid) bound/ret)
  }
  where
    open import Calf.Types.Nat

    open import Data.Nat
    open import Data.Nat.Properties

    ret-injective : ∀ {𝕊 v₁ v₂} → ret {U (meta 𝕊)} v₁ ≡ ret {U (meta 𝕊)} v₂ → v₁ ≡ v₂
    ret-injective {𝕊} = Eq.cong (λ e → bind {U (meta 𝕊)} (meta 𝕊) e id)

    reflects : ∀ {m n b} → ◯ (step (F bool) (fromℕ 1) (ret (m ≤ᵇ n)) ≡ ret {bool} b → Reflects (m ≤ n) b)
    reflects {m} {n} {b} u h with ret-injective (Eq.subst (_≡ ret b) (step/ext (F bool) (ret (m ≤ᵇ n)) (fromℕ 1) u) h)
    ... | refl = ≤ᵇ-reflects-≤ m n


module FamilyPattern where

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

postulate C : {A : Set} -> A -> Set

-- We can't solve unify x = y since the type is a meta variable.
subst : {A : Set}{x y : A} -> x == y -> C y -> C x
subst refl cx = cx
-- subst {A}          refl cx = cx -- works
-- subst {x = x} .{x} refl cx = cx -- works


{-# OPTIONS --cubical #-}

module Type.Cubical.InductiveInterval where

open import Functional
import      Lvl
open import Type
import      Type.Cubical             as Cubical
import      Type.Cubical.Path        as Cubical
import      Type.Cubical.Path.Proofs as Cubical

private variable ℓ ℓ₁ ℓ₂ : Lvl.Level
private variable A B P : Type{ℓ}

data Interval : Type{Lvl.𝟎} where
  𝟎 : Interval
  𝟏 : Interval
  segment : Cubical.Path 𝟎 𝟏

elim : (P : Interval → Type{ℓ}) → (p0 : P(𝟎)) → (p1 : P(𝟏)) → (Cubical.PathP(\i → P(segment i)) p0 p1) → ((i : Interval) → P(i))
elim(P) p0 _  _  𝟎           = p0
elim(P) _  p1 _  𝟏           = p1
elim(P) _  _  ps (segment i) = ps(i)

flip : Interval → Interval
flip 𝟎 = 𝟏
flip 𝟏 = 𝟎
flip (segment i) = segment(Cubical.Interval.flip i)

min : Interval → Interval → Interval
min 𝟎 𝟎 = 𝟎
min 𝟎 𝟏 = 𝟎
min 𝟏 𝟎 = 𝟎
min 𝟏 𝟏 = 𝟏
min 𝟎           (segment i) = 𝟎
min 𝟏           (segment i) = segment i
min (segment i) 𝟎           = 𝟎
min (segment i) 𝟏           = segment i
min (segment i) (segment j) = segment(Cubical.Interval.min i j)

max : Interval → Interval → Interval
max = flip ∘₂ (min on₂ flip)

open import Structure.Relator.Properties
open import Type.Cubical.Path.Equality
open import Type.Properties.Singleton

instance
  Interval-unit : IsUnit(Interval)
  IsUnit.unit Interval-unit = 𝟏
  IsUnit.uniqueness Interval-unit {𝟎} = segment
  IsUnit.uniqueness Interval-unit {𝟏} = reflexivity(Cubical.Path)
  IsUnit.uniqueness Interval-unit {segment i} j = segment(Cubical.Interval.max i j)

transp : (P : Interval → Type{ℓ}) → P(𝟎) → P(𝟏)
transp(P) = sub₂(Cubical.Path)(_→ᶠ_) (Cubical.map P(segment))


open import Oscar.Prelude
open import Oscar.Class.IsCategory
open import Oscar.Class.IsPrefunctor
open import Oscar.Class.Reflexivity
open import Oscar.Class.Smap
open import Oscar.Class.Surjection
open import Oscar.Class.Surjidentity
open import Oscar.Class.Transitivity

module Oscar.Class.IsFunctor where

module _
  {𝔬₁} {𝔒₁ : Ø 𝔬₁}
  {𝔯₁} (_∼₁_ : 𝔒₁ → 𝔒₁ → Ø 𝔯₁)
  {ℓ₁} (_∼̇₁_ : ∀ {x y} → x ∼₁ y → x ∼₁ y → Ø ℓ₁)
  (ε₁ : Reflexivity.type _∼₁_)
  (_↦₁_ : Transitivity.type _∼₁_)
  {𝔬₂} {𝔒₂ : Ø 𝔬₂}
  {𝔯₂} (_∼₂_ : 𝔒₂ → 𝔒₂ → Ø 𝔯₂)
  {ℓ₂} (_∼̇₂_ : ∀ {x y} → x ∼₂ y → x ∼₂ y → Ø ℓ₂)
  (ε₂ : Reflexivity.type _∼₂_)
  (_↦₂_ : Transitivity.type _∼₂_)
  {surjection : Surjection.type 𝔒₁ 𝔒₂}
  (smap : Smap.type _∼₁_ _∼₂_ surjection surjection)
  where
  record IsFunctor : Ø 𝔬₁ ∙̂ 𝔯₁ ∙̂ ℓ₁ ∙̂ 𝔬₂ ∙̂ 𝔯₂ ∙̂ ℓ₂ where
    constructor ∁
    field
      ⦃ `IsPrefunctor ⦄ : IsPrefunctor _∼₁_ _∼̇₁_ _↦₁_ _∼₂_ _∼̇₂_ _↦₂_ smap
      overlap ⦃ `IsCategory₁ ⦄ : IsCategory _∼₁_ _∼̇₁_ ε₁ _↦₁_
      overlap ⦃ `IsCategory₂ ⦄ : IsCategory _∼₂_ _∼̇₂_ ε₂ _↦₂_
      overlap ⦃ `𝒮urjidentity ⦄ : Surjidentity.class _∼₁_ _∼₂_ _∼̇₂_ smap ε₁ ε₂


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

open import HoTT
open import homotopy.CircleHSpace
open import homotopy.LoopSpaceCircle
open import homotopy.Pi2HSusp
open import homotopy.IterSuspensionStable

-- This summerizes all [πₙ Sⁿ]
module homotopy.PinSn where

  private
    π1S¹-iso-ℤ : πS 0 ⊙S¹ ≃ᴳ ℤ-group
    π1S¹-iso-ℤ = ΩS¹-iso-ℤ ∘eᴳ unTrunc-iso ΩS¹-group-structure ΩS¹-is-set

  private
    πS-SphereS'-iso-ℤ : ∀ n → πS n (⊙Susp^ n ⊙S¹) ≃ᴳ ℤ-group
    πS-SphereS'-iso-ℤ 0 = π1S¹-iso-ℤ
    πS-SphereS'-iso-ℤ 1 =
      πS 1 ⊙S²
        ≃ᴳ⟨ Pi2HSusp.π₂-Susp S¹-level S¹-conn ⊙S¹-hSpace ⟩
      πS 0 ⊙S¹
        ≃ᴳ⟨ πS-SphereS'-iso-ℤ O ⟩
      ℤ-group
        ≃ᴳ∎
    πS-SphereS'-iso-ℤ (S (S n)) =
      πS (S (S n)) (⊙Susp^ (S (S n)) ⊙S¹)
        ≃ᴳ⟨ Susp^StableSucc.stable ⊙S¹ S¹-conn
             (S n) (S n) (≤-ap-S $ ≤-ap-S $ *2-increasing n) ⟩
      πS (S n) (⊙Susp^ (S n) ⊙S¹)
        ≃ᴳ⟨ πS-SphereS'-iso-ℤ (S n) ⟩
      ℤ-group
        ≃ᴳ∎

  πS-SphereS-iso-ℤ : ∀ n → πS n (⊙Sphere (S n)) ≃ᴳ ℤ-group
  πS-SphereS-iso-ℤ n = πS-SphereS'-iso-ℤ n
                   ∘eᴳ πS-emap n (⊙Susp^-Susp-split-iso n ⊙S⁰)


{-# OPTIONS --without-K #-}
module hott.level.closure.core where

open import level
open import decidable
open import equality
open import function.isomorphism.core
-- open import function.isomorphism.properties
open import sum
open import hott.level.core
open import hott.equivalence.core
open import hott.univalence
open import sets.nat.core
-- open import sets.nat.ordering.leq.core
-- open import sets.nat.ordering.leq.decide
open import sets.empty
open import sets.unit

Σ-contr : ∀ {i j}{X : Set i}{Y : X → Set j}
        → contr X → ((x : X) → contr (Y x))
        → contr (Σ X Y)
Σ-contr {X = X}{Y = Y} (x₀ , cx) hY
  = (x₀ , proj₁ (hY x₀)) , λ { (x , y) → c x y }
    where
      c : (x : X)(y : Y x) → (x₀ , proj₁ (hY x₀)) ≡ (x , y)
      c x y = ap (λ x → (x , proj₁ (hY x))) (cx x)
            · ap (_,_ x) (proj₂ (hY x) y)

×-contr : ∀ {i j}{X : Set i}{Y : Set j}
        → contr X → contr Y
        → contr (X × Y)
×-contr hX hY = Σ-contr hX (λ _ → hY)

unique-contr : ∀ {i}{A B : Set i}
             → contr A
             → contr B
             → A ≡ B
unique-contr {i}{A}{B} hA hB = ≈⇒≡ (f , f-we)
  where
    f : A → B
    f _ = proj₁ hB

    f-we : weak-equiv f
    f-we b = ×-contr hA (h↑ hB _ _)

-- h-≤ : ∀ {i n m}{X : Set i}
--     → n ≤ m → h n X → h m X
-- h-≤ {m = 0} z≤n hX = hX
-- h-≤ {m = suc m} z≤n hX = λ x y
--   → h-≤ {m = m} z≤n (h↑ hX x y)
-- h-≤ (s≤s p) hX = λ x y
--   → h-≤ p (hX x y)
--
-- h! : ∀ {i n m}{X : Set i}
--    → {p : True (n ≤? m)}
--    → h n X → h m X
-- h! {p = p} = h-≤ (witness p)

abstract
  -- retractions preserve levels
  retract-level : ∀ {i j n} {X : Set i}{Y : Set j}
                 → (f : X → Y)(g : Y → X)
                 → ((y : Y) → f (g y) ≡ y)
                 → h n X → h n Y
  retract-level {n = 0}{X}{Y} f g r (x , c) = (f x , c')
    where
      c' : (y : Y) → f x ≡ y
      c' y = ap f (c (g y)) · r y
  retract-level {n = suc n}{X}{Y} f g r hX = λ y y'
    → retract-level f' g' r' (hX (g y) (g y'))
    where
      f' : {y y' : Y} → g y ≡ g y' → y ≡ y'
      f' {y}{y'} p = sym (r y) · ap f p · r y'

      g' : {y y' : Y} → y ≡ y' → g y ≡ g y'
      g' = ap g

      r' : {y y' : Y}(p : y ≡ y') → f' (g' p) ≡ p
      r' {y}{.y} refl = ap (λ α → α · r y) (left-unit (sym (r y)))
                      · right-inverse (r y)

  iso-level : ∀ {i j n}{X : Set i}{Y : Set j}
             → X ≅ Y → h n X → h n Y
  iso-level (iso f g H K) = retract-level f g K


{-# OPTIONS --cubical --safe #-}
module Cubical.Structures.Semigroup where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma

open import Cubical.Foundations.SIP renaming (SNS-PathP to SNS)
open import Cubical.Structures.NAryOp

private
  variable
    ℓ ℓ' : Level

raw-semigroup-structure : Type ℓ → Type ℓ
raw-semigroup-structure X = X → X → X

raw-semigroup-is-SNS : SNS {ℓ} raw-semigroup-structure _
raw-semigroup-is-SNS = nAryFunSNS 2

semigroup-axioms : (X : Type ℓ) → raw-semigroup-structure X → Type ℓ
semigroup-axioms X _·_ = isSet X ×
                         ((x y z : X) → (x · (y · z)) ≡ ((x · y) · z))

semigroup-structure : Type ℓ → Type ℓ
semigroup-structure = add-to-structure (raw-semigroup-structure) semigroup-axioms

Semigroup : Type (ℓ-suc ℓ)
Semigroup {ℓ} = TypeWithStr ℓ semigroup-structure

-- Operations for extracting components

⟨_⟩ : Semigroup → Type ℓ
⟨ G , _ ⟩ = G

semigroup-operation : (G : Semigroup {ℓ}) → ⟨ G ⟩ → ⟨ G ⟩ → ⟨ G ⟩
semigroup-operation (_ , f , _) = f

module semigroup-operation-syntax where

  semigroup-operation-syntax : (G : Semigroup {ℓ}) → ⟨ G ⟩ → ⟨ G ⟩ → ⟨ G ⟩
  semigroup-operation-syntax = semigroup-operation

  infixl 20 semigroup-operation-syntax
  syntax semigroup-operation-syntax G x y = x ·⟨ G ⟩ y

open semigroup-operation-syntax

semigroup-isSet : (G : Semigroup {ℓ}) → isSet ⟨ G ⟩
semigroup-isSet (_ , _ , P , _) = P

semigroup-assoc : (G : Semigroup {ℓ})
                → (x y z : ⟨ G ⟩) → (x ·⟨ G ⟩ (y ·⟨ G ⟩ z)) ≡ ((x ·⟨ G ⟩ y) ·⟨ G ⟩ z)
semigroup-assoc (_ , _ , _ , P) = P

-- Semigroup equivalences

semigroup-iso : StrIso semigroup-structure ℓ
semigroup-iso = add-to-iso (nAryFunIso 2) semigroup-axioms

semigroup-axiom-isProp : (X : Type ℓ)
                       → (s : raw-semigroup-structure X)
                       → isProp (semigroup-axioms X s)
semigroup-axiom-isProp X _·_ = isPropΣ isPropIsSet
                               λ isSetX →  isPropΠ (λ x → isPropΠ (λ y → isPropΠ (λ z → isSetX _ _)))

semigroup-is-SNS : SNS {ℓ} semigroup-structure semigroup-iso
semigroup-is-SNS = add-axioms-SNS _ semigroup-axiom-isProp (nAryFunSNS 2)

SemigroupPath : (M N : Semigroup {ℓ}) → (M ≃[ semigroup-iso ] N) ≃ (M ≡ N)
SemigroupPath = SIP semigroup-is-SNS

-- Semigroup ·syntax

module semigroup-·syntax (G : Semigroup {ℓ}) where

  infixr 18 _·_

  _·_ : ⟨ G ⟩ → ⟨ G ⟩ → ⟨ G ⟩
  _·_ = semigroup-operation G