------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of functions, such as associativity and commutativity
------------------------------------------------------------------------

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

open import Level
open import Relation.Binary
open import Data.Sum

-- The properties are parameterised by the following "equality" relation

module Algebra.FunctionProperties
  {a ℓ} {A : Set a} (_≈_ : Rel A ℓ) where

open import Data.Product

------------------------------------------------------------------------
-- Unary and binary operations

open import Algebra.FunctionProperties.Core public

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

Associative : Op₂ A → Set _
Associative _∙_ = ∀ x y z → ((x ∙ y) ∙ z) ≈ (x ∙ (y ∙ z))

Commutative : Op₂ A → Set _
Commutative _∙_ = ∀ x y → (x ∙ y) ≈ (y ∙ x)

LeftIdentity : A → Op₂ A → Set _
LeftIdentity e _∙_ = ∀ x → (e ∙ x) ≈ x

RightIdentity : A → Op₂ A → Set _
RightIdentity e _∙_ = ∀ x → (x ∙ e) ≈ x

Identity : A → Op₂ A → Set _
Identity e ∙ = (LeftIdentity e ∙) × (RightIdentity e ∙)

LeftZero : A → Op₂ A → Set _
LeftZero z _∙_ = ∀ x → (z ∙ x) ≈ z

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

Zero : A → Op₂ A → Set _
Zero z ∙ = (LeftZero z ∙) × (RightZero z ∙)

LeftInverse : A → Op₁ A → Op₂ A → Set _
LeftInverse e _⁻¹ _∙_ = ∀ x → ((x ⁻¹) ∙ x) ≈ e

RightInverse : A → Op₁ A → Op₂ A → Set _
RightInverse e _⁻¹ _∙_ = ∀ x → (x ∙ (x ⁻¹)) ≈ e

Inverse : A → Op₁ A → Op₂ A → Set _
Inverse e ⁻¹ ∙ = (LeftInverse e ⁻¹) ∙ × (RightInverse e ⁻¹ ∙)

LeftConical : A → Op₂ A → Set _
LeftConical e _∙_ = ∀ x y → (x ∙ y) ≈ e → x ≈ e

RightConical : A → Op₂ A → Set _
RightConical e _∙_ = ∀ x y → (x ∙ y) ≈ e → y ≈ e

Conical : A → Op₂ A → Set _
Conical e ∙ = (LeftConical e ∙) × (RightConical e ∙)

_DistributesOverˡ_ : Op₂ A → Op₂ A → Set _
_*_ DistributesOverˡ _+_ =
  ∀ x y z → (x * (y + z)) ≈ ((x * y) + (x * z))

_DistributesOverʳ_ : Op₂ A → Op₂ A → Set _
_*_ DistributesOverʳ _+_ =
  ∀ x y z → ((y + z) * x) ≈ ((y * x) + (z * x))

_DistributesOver_ : Op₂ A → Op₂ A → Set _
* DistributesOver + = (* DistributesOverˡ +) × (* DistributesOverʳ +)

_IdempotentOn_ : Op₂ A → A → Set _
_∙_ IdempotentOn x = (x ∙ x) ≈ x

Idempotent : Op₂ A → Set _
Idempotent ∙ = ∀ x → ∙ IdempotentOn x

IdempotentFun : Op₁ A → Set _
IdempotentFun f = ∀ x → f (f x) ≈ f x

Selective : Op₂ A → Set _
Selective _∙_ = ∀ x y → (x ∙ y) ≈ x ⊎ (x ∙ y) ≈ y

_Absorbs_ : Op₂ A → Op₂ A → Set _
_∙_ Absorbs _∘_ = ∀ x y → (x ∙ (x ∘ y)) ≈ x

Absorptive : Op₂ A → Op₂ A → Set _
Absorptive ∙ ∘ = (∙ Absorbs ∘) × (∘ Absorbs ∙)

Involutive : Op₁ A → Set _
Involutive f = ∀ x → f (f x) ≈ x

LeftCancellative : Op₂ A → Set _
LeftCancellative _•_ = ∀ x {y z} → (x • y) ≈ (x • z) → y ≈ z

RightCancellative : Op₂ A → Set _
RightCancellative _•_ = ∀ {x} y z → (y • x) ≈ (z • x) → y ≈ z

Cancellative : Op₂ A → Set _
Cancellative _•_ = (LeftCancellative _•_) × (RightCancellative _•_)

Congruent₁ : Op₁ A → Set _
Congruent₁ f = f Preserves _≈_ ⟶ _≈_

Congruent₂ : Op₂ A → Set _
Congruent₂ ∙ = ∙ Preserves₂ _≈_ ⟶ _≈_ ⟶ _≈_

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

RightCongruent : Op₂ A → Set _
RightCongruent _∙_ = ∀ {x} → (_∙ x) Preserves _≈_ ⟶ _≈_


{-# OPTIONS --without-K --safe #-}
module Categories.Functor.Representable where

-- A Presheaf (into Setoids) is representation if it is naturally isomorphic to a Hom functor
--  over a particular object A of the base category.
open import Level

open import Categories.Category using (Category)
open import Categories.Category.Instance.Setoids
open import Categories.Functor using (Functor)
open import Categories.Functor.Hom
open import Categories.Functor.Presheaf
open import Categories.NaturalTransformation.NaturalIsomorphism

record Representable {o ℓ e} {C : Category o ℓ e} (F : Presheaf C (Setoids ℓ e)) : Set (o ⊔ suc ℓ ⊔ suc e ) where
  open Category C
  open Hom C
  field
    A : Obj
    Iso : NaturalIsomorphism F Hom[-, A ]


{-# OPTIONS --sized-types #-}
open import Relation.Binary.Core

module Quicksort.Correctness.Permutation {A : Set}
                  (_≤_ : A → A → Set)
                  (tot≤ : Total _≤_) where

open import Bound.Total A
open import Bound.Total.Order _≤_
open import Data.List
open import Data.Product
open import Data.Sum
open import List.Permutation.Base A
open import List.Permutation.Base.Concatenation A
open import List.Permutation.Base.Equivalence A
open import List.Permutation.Pair A
open import List.Permutation.Pair.Properties A
open import Quicksort _≤_ tot≤
open import SBList _≤_
open import SBList.Properties _≤_
open import Size
open import SOList.Total _≤_

lemma-deal : {ι : Size}{b t : Bound}{x : A} → (b≤x : LeB b (val x)) → (x≤t : LeB (val x) t) → (xs : SBList {ι} b t) → unbound xs ≈ unbound× (deal b≤x x≤t xs)
lemma-deal _ _ (nil _) = ≈[]r []
lemma-deal {x = x} b≤x x≤t (cons y b≤y y≤t ys)
    with tot≤ x y
... | inj₁ x≤y = ≈xr (lemma-deal b≤x x≤t ys)
... | inj₂ y≤x = ≈xl (lemma-deal b≤x x≤t ys)

lemma-quickSort : {ι : Size}{b t : Bound}(xs : SBList {ι} b t) → unbound xs ∼ forget (quickSort xs)
lemma-quickSort (nil _) = ∼[]
lemma-quickSort (cons x b≤x x≤t xs) =  trans∼ (lemma≈∼ (≈xr (lemma-deal b≤x x≤t xs))) (lemma++∼ (lemma-quickSort ys) (∼x /head /head (lemma-quickSort zs)))
                where yszs = deal b≤x x≤t xs
                      ys = proj₁ yszs
                      zs = proj₂ yszs

theorem-quickSort∼ : (xs : List A) → xs ∼ forget (quickSort (bound xs))
theorem-quickSort∼ xs = trans∼ (lemma-unbound-bound xs) (lemma-quickSort (bound xs))


-- imports
open import Data.Nat as ℕ     using (ℕ; suc; zero; _+_; _∸_)
open import Data.Vec as Vec   using (Vec; _∷_; []; tabulate; foldr)
open import Data.Fin as Fin   using (Fin; suc; zero)
open import Function          using (_∘_; const; id)
open import Data.List as List using (List; _∷_; [])
open import Data.Maybe        using (Maybe; just; nothing)

-- Without square cutoff optimization
module Simple where
  primes : ∀ n → List (Fin n)
  primes zero = []
  primes (suc zero) = []
  primes (suc (suc zero)) = []
  primes (suc (suc (suc m))) = sieve (tabulate (just ∘ suc))
    where
    sieve : ∀ {n} → Vec (Maybe (Fin (2 + m))) n → List (Fin (3 + m))
    sieve [] = []
    sieve (nothing ∷ xs) =         sieve xs
    sieve (just x  ∷ xs) = suc x ∷ sieve (foldr B remove (const []) xs x)
      where
      B = λ n → ∀ {i} → Fin i → Vec (Maybe (Fin (2 + m))) n

      remove : ∀ {n} → Maybe (Fin (2 + m)) → B n → B (suc n)
      remove _ ys zero    = nothing ∷ ys x
      remove y ys (suc z) = y       ∷ ys z

-- With square cutoff optimization
module SquareOpt where
  primes : ∀ n → List (Fin n)
  primes zero = []
  primes (suc zero) = []
  primes (suc (suc zero)) = []
  primes (suc (suc (suc m))) = sieve 1 m (Vec.tabulate (just ∘ Fin.suc ∘ Fin.suc))
    where
    sieve : ∀ {n} → ℕ → ℕ → Vec (Maybe (Fin (3 + m))) n → List (Fin (3 + m))
    sieve _ zero = List.mapMaybe id ∘ Vec.toList
    sieve _ (suc _) [] = []
    sieve i (suc l) (nothing ∷ xs) =     sieve (suc i) (l ∸ i ∸ i) xs
    sieve i (suc l) (just x  ∷ xs) = x ∷ sieve (suc i) (l ∸ i ∸ i) (Vec.foldr B remove (const []) xs i)
      where
      B = λ n → ℕ → Vec (Maybe (Fin (3 + m))) n

      remove : ∀ {i} → Maybe (Fin (3 + m)) → B i → B (suc i)
      remove _ ys zero    = nothing ∷ ys i
      remove y ys (suc j) = y       ∷ ys j


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

-- We can use a propositional equality parametrized on Set instead of
-- using two "different" equalities on D and M.

module LogicalFramework.SetEquality where

-- We add 3 to the fixities of the Agda standard library 0.8.1 (see
-- Relation/Binary/Core.agda).
infix 7 _≡D_ _≡M_

------------------------------------------------------------------------------
-- Domain universe D
postulate
  D : Set

-- Propositional equality on D.
data _≡D_ (x : D) : D → Set where
  refl : x ≡D x

≡D-thm : ∀ {d e} → d ≡D e → e ≡D d
≡D-thm refl = refl

------------------------------------------------------------------------------
-- Domain universe M

data M : Set where
  zero :     M
  succ : M → M

-- Propositional equality on M.
data _≡M_ (n : M) : M → Set where
  refl : n ≡M n

≡M-thm : ∀ {m n} → m ≡M n → n ≡M m
≡M-thm refl = refl

------------------------------------------------------------------------------
-- Propositional equality on Set.

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

≡-thm₁ : ∀ {d e : D} → d ≡ e → e ≡ d
≡-thm₁ refl = refl

≡-thm₂ : ∀ {m n : M} → m ≡ n → n ≡ m
≡-thm₂ refl = refl


module Numeral.Natural.TotalOper where

import Lvl
open import Logic.Propositional
open import Logic.Predicate
open import Numeral.Natural hiding (𝐏)
open import Numeral.Natural.Relation.Divisibility
open import Numeral.Natural.Relation.Divisibility.Proofs
open import Numeral.Natural.Relation
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals
open import Relator.Equals.Proofs

-- Total predecessor function (Truncated predecessor)
𝐏 : (n : ℕ) → ⦃ _ : Positive(n) ⦄ → ℕ
𝐏(𝐒(n)) = n

-- Total subtraction (Truncated subtraction)
_−_ : (a : ℕ) → (b : ℕ) → ⦃ _ : a ≥ b ⦄ → ℕ
_−_ a 𝟎 = a
_−_ 𝟎 (𝐒(b)) ⦃ 0≥𝐒b ⦄ with ([<]-to-[≱] ([<]-minimum{b})) (0≥𝐒b)
... | ()
_−_ (𝐒(a)) (𝐒(b)) ⦃ 𝐒b≤𝐒a ⦄ = _−_ a b ⦃ [≤]-without-[𝐒] {b} (𝐒b≤𝐒a) ⦄

-- Total division (Whole number division)
_/₀_ : (a : ℕ) → (b : ℕ) → ⦃ _ : (b ∣ a) ⦄ → ℕ
_/₀_ _ _ ⦃ div ⦄ = divides-quotient div


module Numeral.Sign.Oper where

open import Data.Boolean
open import Numeral.Sign

-- Negation
−_ : (+|−) → (+|−)
− (➕) = (➖)
− (➖) = (➕)

-- Addition
_+_ : (+|−) → (+|−) → (+|0|−)
(➕) + (➕) = (➕)
(➖) + (➖) = (➖)
(➕) + (➖) = (𝟎)
(➖) + (➕) = (𝟎)

-- Multiplication
_⨯_ : (+|−) → (+|−) → (+|−)
(➕) ⨯ (➕) = (➕)
(➖) ⨯ (➖) = (➕)
(➕) ⨯ (➖) = (➖)
(➖) ⨯ (➕) = (➖)

_⋚_ : (+|−) → (+|−) → (+|0|−)
➕ ⋚ ➕ = 𝟎
➕ ⋚ ➖ = ➕
➖ ⋚ ➕ = ➖
➖ ⋚ ➖ = 𝟎


module Dave.Isomorphism where
    open import Dave.Equality
    open import Dave.Functions

    infix 0 _≃_
    record _≃_ (A B : Set) : Set where
        field
            to : A → B
            from : B → A
            from∘to : ∀ (x : A) → from (to x) ≡ x
            to∘from : ∀ (x : B) → to (from x) ≡ x
    open _≃_

    {- Another way to define Isomporphism throug data -}
    data _≃′_ (A B : Set) : Set where
        mk-≃′ : ∀ (to : A → B) →
                ∀ (from : B → A) →
                ∀ (from∘to : (∀ (x : A) → from (to x) ≡ x)) →
                ∀ (to∘from : (∀ (y : B) → to (from y) ≡ y)) →
                A ≃′ B

    to′ : ∀ {A B : Set} → (A ≃′ B) → (A → B)
    to′ (mk-≃′ f g g∘f f∘g) = f

    from′ : ∀ {A B : Set} → (A ≃′ B) → (B → A)
    from′ (mk-≃′ f g g∘f f∘g) = g

    from∘to′ : ∀ {A B : Set} → (A≃B : A ≃′ B) → (∀ (x : A) → from′ A≃B (to′ A≃B x) ≡ x)
    from∘to′ (mk-≃′ f g g∘f f∘g) = g∘f

    to∘from′ : ∀ {A B : Set} → (A≃B : A ≃′ B) → (∀ (y : B) → to′ A≃B (from′ A≃B y) ≡ y)
    to∘from′ (mk-≃′ f g g∘f f∘g) = f∘g

    ≃-refl : ∀ {A : Set} → A ≃ A
    ≃-refl = record
        {
            to = λ x → x;
            from = λ y → y;
            from∘to = λ x → refl;
            to∘from = λ y → refl
        }

    ≃-sym : ∀ {A B : Set} → A ≃ B → B ≃ A
    ≃-sym A≃B = record
        {
            to = from A≃B ;
            from = to A≃B ;
            from∘to = to∘from A≃B ;
            to∘from = from∘to A≃B
        }

    ≃-trans : ∀ {A B C : Set} → A ≃ B → B ≃ C → A ≃ C
    ≃-trans A≃B B≃C = record
        {
            to = (to B≃C) ∘ (to A≃B);
            from = (from A≃B) ∘ (from B≃C);
            from∘to = λ x → begin
                (from A≃B ∘ from B≃C) ((to B≃C ∘ to A≃B) x) ≡⟨⟩
                from A≃B (from B≃C (to B≃C (to A≃B x))) ≡⟨ cong (from A≃B) (from∘to B≃C (to A≃B x)) ⟩
                from A≃B (to A≃B x) ≡⟨ from∘to A≃B x ⟩
                x ∎;
            to∘from = λ x → begin
                (to B≃C ∘ to A≃B) ((from A≃B ∘ from B≃C) x) ≡⟨⟩
                to B≃C (to A≃B (from A≃B (from B≃C x))) ≡⟨ cong (to B≃C) (to∘from A≃B (from B≃C x)) ⟩
                to B≃C (from B≃C x) ≡⟨ to∘from B≃C x ⟩
                x ∎
        }

    module ≃-Reasoning where

        infix  1 ≃-begin_
        infixr 2 _≃⟨_⟩_
        infix  3 _≃-∎

        ≃-begin_ : ∀ {A B : Set}
            → A ≃ B
            -----
            → A ≃ B
        ≃-begin A≃B = A≃B

        _≃⟨_⟩_ : ∀ (A : Set) {B C : Set}
            → A ≃ B
            → B ≃ C
            -----
            → A ≃ C
        A ≃⟨ A≃B ⟩ B≃C = ≃-trans A≃B B≃C

        _≃-∎ : ∀ (A : Set)
            -----
            → A ≃ A
        A ≃-∎ = ≃-refl

    open ≃-Reasoning public


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of the `Reflects` construct
------------------------------------------------------------------------

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

module Relation.Nullary.Reflects where

open import Agda.Builtin.Equality
open import Data.Bool.Base
open import Data.Empty
open import Level
open import Relation.Nullary

private
  variable
    p : Level
    P : Set p

------------------------------------------------------------------------
-- `Reflects P b` is equivalent to `if b then P else ¬ P`.

-- These lemmas are intended to be used mostly when `b` is a value, so
-- that the `if` expressions have already been evaluated away.
-- In this case, `of` works like the relevant constructor (`ofⁿ` or
-- `ofʸ`), and `invert` strips off the constructor to just give either
-- the proof of `P` or the proof of `¬ P`.

of : ∀ {b} → if b then P else ¬ P → Reflects P b
of {b = false} ¬p = ofⁿ ¬p
of {b = true }  p = ofʸ p

invert : ∀ {b} → Reflects P b → if b then P else ¬ P
invert (ofʸ  p) = p
invert (ofⁿ ¬p) = ¬p

------------------------------------------------------------------------
-- Other lemmas

-- `Reflects` is deterministic.
det : ∀ {b b′} → Reflects P b → Reflects P b′ → b ≡ b′
det (ofʸ  p) (ofʸ  p′) = refl
det (ofʸ  p) (ofⁿ ¬p′) = ⊥-elim (¬p′ p)
det (ofⁿ ¬p) (ofʸ  p′) = ⊥-elim (¬p p′)
det (ofⁿ ¬p) (ofⁿ ¬p′) = refl


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

module Test where

open import Level

infixl 4 _≡_
data _≡_ {a} {A : Set a} (x : A) : A → Set a where
  refl : x ≡ x

J : {a b : Level} (A : Set a) (C : (x y : A) → x ≡ y → Set b)
    → ((x : A) → C x x refl)
    → (x y : A) (P : x ≡ y)
    → C x y P
J A C b x .x refl = b x

-- K : (A : Set) (x : A) (C : x ≡ x → Set)
--   → C refl
--   → (loop : x ≡ x)
--   → C loop
-- K A x C b p = {! p  !}

-- Lemma 2.1.1 (inversion of paths)
infix 6 ¬_
¬_ : {a : Level} {A : Set a} {x y : A} → x ≡ y → y ≡ x
¬_ {a} {A} {x} {y} p = J A D d x y p

  where
    D : (x y : A) (p : x ≡ y) → Set a
    D x y p = y ≡ x

    d : (x : A) → D x x refl
    d x = refl

-- Lemma 2.1.2 (concatenation of paths)
infixl 5 _∙_
_∙_ : {a : Level} {A : Set a} {x y z : A} → x ≡ y → y ≡ z → x ≡ z
_∙_ {a} {A} {x} {y} {z} p q = J {a} {a} A D d x y p z q

  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set a
    D x y p = (z : A) (q : y ≡ z) → x ≡ z

    -- base case
    d : (x : A) → D x x refl
    d x z q = J A E e x z q
      where
        -- the predicate
        E : (x z : A) (q : x ≡ z) → Set a
        E x z q = x ≡ z

        -- base case
        e : (x : A) → E x x refl
        e x = refl

-- Lemma 2.1.4.i (identity of path concatenation)
∙-identityʳ : {a : Level} {A : Set a} {x y : A} (p : x ≡ y) → p ≡ p ∙ refl
∙-identityʳ {a} {A} {x} {y} p = J A D d x y p

  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set a
    D x y p = p ≡ p ∙ refl

    -- base case
    d : (x : A) → D x x refl
    d x = refl

∙-identityˡ : {a : Level} {A : Set a} {x y : A} (p : x ≡ y) → p ≡ refl ∙ p
∙-identityˡ {a} {A} {x} {y} p = J A D d x y p
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set a
    D x y p = p ≡ refl ∙ p

    -- base case
    d : (x : A) → D x x refl
    d x = refl

-- Lemma 2.1.4.ii (identity of path inversion)
¬-identityʳ : {a : Level} {A : Set a} {x y : A} (p : x ≡ y) → ¬ p ∙ p ≡ refl
¬-identityʳ {a} {A} {x} {y} p = J A D d x y p
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set a
    D x y p = ¬ p ∙ p ≡ refl

    -- base case
    d : (x : A) → D x x refl
    d x = refl

¬-identityˡ : {a : Level} {A : Set a} {x y : A} (p : x ≡ y) → p ∙ ¬ p ≡ refl
¬-identityˡ {a} {A} {x} {y} p = J A D d x y p
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set a
    D x y p = p ∙ ¬ p ≡ refl

    -- base case
    d : (x : A) → D x x refl
    d x = refl

-- Lemma 2.1.4.iii (involution of path inversion)
involution : {A : Set} {x y : A} (p : x ≡ y) → ¬ ¬ p ≡ p
involution {A} {x} {y} p = J A D d x y p
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set
    D x y p = ¬ ¬ p ≡ p

    -- base case
    d : (x : A) → D x x refl
    d x = refl

-- Lemma 2.1.4.iv (associativity of path concatenation)
∙-assoc : {a : Level} {A : Set a} {w x y z : A}
  → (p : w ≡ x) (q : x ≡ y) (r : y ≡ z)
  → p ∙ (q ∙ r) ≡ (p ∙ q) ∙ r
∙-assoc {a} {A} {w} {x} {y} {z} p q r = J A D d w x p y q z r
  where
    -- the predicate
    D : (w x : A) (p : w ≡ x) → Set a
    D w x p = (y : A) (q : x ≡ y)
            → (z : A) (r : y ≡ z)
            → p ∙ (q ∙ r) ≡ (p ∙ q) ∙ r

    -- base case
    d : (x : A) → D x x refl
    d x y q z r = J A E e x y q z r
      where
        -- the predicate
        E : (x y : A) (q : x ≡ y) → Set a
        E x y q = (z : A) (r : y ≡ z)
                → refl ∙ (q ∙ r) ≡ refl ∙ q ∙ r

        -- base case
        e : (x : A) → E x x refl
        e x z r = J A F f x z r
          where
            -- the predicate
            F : (y z : A) (r : y ≡ z) → Set a
            F y z r = refl ∙ (refl ∙ r) ≡ refl ∙ refl ∙ r

            -- base case
            f : (x : A) → F x x refl
            f x = {!   !}


------------------------------------------------------------------------
-- The Agda standard library
--
-- A definition for the permutation relation using setoid equality
------------------------------------------------------------------------

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

module Data.List.Relation.Binary.Permutation.Homogeneous where

open import Data.List.Base using (List; _∷_)
open import Data.List.Relation.Binary.Pointwise as Pointwise
  using (Pointwise)
open import Level using (Level; _⊔_)
open import Relation.Binary

private
  variable
    a r s : Level
    A : Set a

data Permutation {A : Set a} (R : Rel A r) : Rel (List A) (a ⊔ r) where
  refl  : ∀ {xs ys} → Pointwise R xs ys → Permutation R xs ys
  prep  : ∀ {xs ys x y} (eq : R x y) → Permutation R xs ys → Permutation R (x ∷ xs) (y ∷ ys)
  swap  : ∀ {xs ys x y x' y'} (eq₁ : R x x') (eq₂ : R y y') → Permutation R xs ys → Permutation R (x ∷ y ∷ xs) (y' ∷ x' ∷ ys)
  trans : ∀ {xs ys zs} → Permutation R xs ys → Permutation R ys zs → Permutation R xs zs

------------------------------------------------------------------------
-- The Permutation relation is an equivalence

module _ {R : Rel A r}  where

  sym : Symmetric R → Symmetric (Permutation R)
  sym R-sym (refl xs∼ys)           = refl (Pointwise.symmetric R-sym xs∼ys)
  sym R-sym (prep x∼x' xs↭ys)      = prep (R-sym x∼x') (sym R-sym xs↭ys)
  sym R-sym (swap x∼x' y∼y' xs↭ys) = swap (R-sym y∼y') (R-sym x∼x') (sym R-sym xs↭ys)
  sym R-sym (trans xs↭ys ys↭zs)    = trans (sym R-sym ys↭zs) (sym R-sym xs↭ys)

  isEquivalence : Reflexive R → Symmetric R → IsEquivalence (Permutation R)
  isEquivalence R-refl R-sym = record
    { refl  = refl (Pointwise.refl R-refl)
    ; sym   = sym R-sym
    ; trans = trans
    }

  setoid : Reflexive R → Symmetric R → Setoid _ _
  setoid R-refl R-sym = record
    { isEquivalence = isEquivalence R-refl R-sym
    }

map : ∀ {R : Rel A r} {S : Rel A s} →
      (R ⇒ S) → (Permutation R ⇒ Permutation S)
map R⇒S (refl xs∼ys)         = refl (Pointwise.map R⇒S xs∼ys)
map R⇒S (prep e xs∼ys)       = prep (R⇒S e) (map R⇒S xs∼ys)
map R⇒S (swap e₁ e₂ xs∼ys)   = swap (R⇒S e₁) (R⇒S e₂) (map R⇒S xs∼ys)
map R⇒S (trans xs∼ys ys∼zs)  = trans (map R⇒S xs∼ys) (map R⇒S ys∼zs)


module FMSB where

data Nat : Set where
  ze : Nat
  su : Nat -> Nat

data Lam (X : Nat -> Set)(n : Nat) : Set where
  var : X n -> Lam X n
  app : Lam X n -> Lam X n -> Lam X n
  lam : Lam X (su n) -> Lam X n

_->>_ : {I : Set}(X Y : I -> Set) -> Set
X ->> Y = {i : _} -> X i -> Y i

fmsub : {X Y : Nat -> Set} -> (X ->> Lam Y) -> Lam X ->> Lam Y
fmsub sb (var x)   = sb x
fmsub sb (app f s) = app (fmsub sb f) (fmsub sb s)
fmsub sb (lam b)   = lam (fmsub sb b)

data Fin : Nat -> Set where
  ze : {n : Nat} -> Fin (su n)
  su : {n : Nat} -> Fin n -> Fin (su n)

D : (Nat -> Set) -> Nat -> Set
D F n = F (su n)

weak : {F : Nat -> Set} -> (Fin ->> F) -> (F ->> D F) ->
       {m n : Nat}-> (Fin m -> F n) -> D Fin m -> D F n
weak v w f ze      = v ze
weak v w f (su x)  = w (f x)

_+_ : Nat -> Nat -> Nat
ze    + y = y
su x  + y = su (x + y)

_!+_ : (Nat -> Set) -> Nat -> (Nat -> Set)
F !+ n = \ m -> F (m + n)

weaks : {F : Nat -> Set} -> (Fin ->> F) -> (F ->> D F) ->
        {m n : Nat}-> (Fin m -> F n) -> (Fin !+ m) ->> (F !+ n)
weaks v w f {ze}    = f
weaks v w f {su i}  = weak v w (weaks v w f {i})

jing : {m n : Nat} -> Lam Fin (m + n) -> Lam (Fin !+ n) m
jing (var x) = var x
jing (app f s) = app (jing f) (jing s)
jing (lam t) = lam (jing t)

gnij : {m n : Nat} -> Lam (Fin !+ n) m -> Lam Fin (m + n)
gnij (var x) = var x
gnij (app f s) = app (gnij f) (gnij s)
gnij (lam t) = lam (gnij t)

ren : {m n : Nat} -> (Fin m -> Fin n) -> Lam Fin m -> Lam Fin n
ren f t = gnij (fmsub (\ {i} x -> var (weaks (\ z -> z) su f {i} x)) {ze} (jing t))

sub : {m n : Nat} -> (Fin m -> Lam Fin n) -> Lam Fin m -> Lam Fin n
sub {m}{n} f t = gnij {ze} (fmsub (\ {i} x -> jing {i} (weaks {Lam Fin} var (ren su) f {i} x)) (jing {ze} t))


{-

ℤ is a Commutative Ring (using QuoInt)

-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.CommRing.Instances.QuoInt where

open import Cubical.Foundations.Prelude

open import Cubical.Algebra.CommRing
open import Cubical.Data.Nat  using (ℕ ; zero ; suc)
open import Cubical.Data.Bool using (not)
open import Cubical.Data.Int.MoreInts.QuoInt
  renaming (ℤ to ℤType ; _+_ to _+ℤ_; _·_ to _·ℤ_; -_ to -ℤ_)

open CommRingStr

-- The missing additive inversion

+InvL' : ∀ n s → signed (not s) n +ℤ signed s n ≡ signed s zero
+InvL' zero _ = refl
+InvL' (suc n) spos = predℤ-+ʳ (neg n) (pos (suc n)) ∙ (λ i → neg n +ℤ predSucℤ (pos n) i) ∙ +InvL' n spos
+InvL' (suc n) sneg = sucℤ-+ʳ  (pos n) (neg (suc n)) ∙ (λ i → pos n +ℤ sucPredℤ (neg n) i) ∙ +InvL' n sneg

+InvL : (n : ℤType) → (-ℤ n) +ℤ n ≡ 0
+InvL (signed spos n) = +InvL' n spos
+InvL (signed sneg n) = +InvL' n sneg ∙ sym posneg
+InvL (posneg i) j =
  hcomp (λ k → λ
    { (i = i0) → 0
    ; (i = i1) → compPath-filler refl (sym posneg) k j
    ; (j = i0) → posneg i
    ; (j = i1) → posneg (i ∧ ~ k) })
  (posneg i)

+InvR : (n : ℤType) → n +ℤ (-ℤ n) ≡ 0
+InvR n = +-comm n (-ℤ n) ∙ +InvL n

ℤCommRing : CommRing ℓ-zero
ℤCommRing .fst = ℤType
ℤCommRing .snd .0r = 0
ℤCommRing .snd .1r = 1
ℤCommRing .snd ._+_ = _+ℤ_
ℤCommRing .snd ._·_ = _·ℤ_
ℤCommRing .snd .-_ = -ℤ_
ℤCommRing .snd .isCommRing = isCommRingℤ
  where
  abstract
    isCommRingℤ : IsCommRing 0 1 _+ℤ_ _·ℤ_ -ℤ_
    isCommRingℤ = makeIsCommRing
      isSetℤ +-assoc (+-zeroʳ _)
      +InvR +-comm ·-assoc
      ·-identityʳ (λ x y z → sym (·-distribˡ x y z)) ·-comm


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

open import Categories.Category

-- Biproducts, a-la Karvonen.
--
-- This definition has advantages over more traditional ones,
-- namely that that we don't require either enrichment in CMon/Ab, or Zero Objects.
--
-- See https://arxiv.org/abs/1801.06488
module Categories.Object.Biproduct {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level

open import Categories.Object.Coproduct 𝒞
open import Categories.Object.Product 𝒞

open import Categories.Morphism 𝒞

open Category 𝒞
open HomReasoning

private
  variable
    A B C D : Obj
    f g h : A ⇒ B

record IsBiproduct {A B A⊕B : Obj} (π₁ : A⊕B ⇒ A) (π₂ : A⊕B ⇒ B) (i₁ : A ⇒ A⊕B) (i₂ : B ⇒ A⊕B) : Set (o ⊔ ℓ ⊔ e) where
  field
    isCoproduct : IsCoproduct i₁ i₂
    isProduct : IsProduct π₁ π₂

    π₁∘i₁≈id : π₁ ∘ i₁ ≈ id
    π₂∘i₂≈id : π₂ ∘ i₂ ≈ id
    permute  : i₁ ∘ π₁ ∘ i₂ ∘ π₂ ≈ i₂ ∘ π₂ ∘ i₁ ∘ π₁

  open IsCoproduct isCoproduct public renaming (unique to []-unique)
  open IsProduct isProduct public renaming (unique to ⟨⟩-unique)

record Biproduct (A B : Obj) : Set (o ⊔ ℓ ⊔ e) where
  field
    A⊕B : Obj

    π₁    : A⊕B ⇒ A
    π₂    : A⊕B ⇒ B

    i₁    : A ⇒ A⊕B
    i₂    : B ⇒ A⊕B

    isBiproduct : IsBiproduct π₁ π₂ i₁ i₂

  open IsBiproduct isBiproduct public

IsBiproduct⇒Biproduct : {π₁ : C ⇒ A} {π₂ : C ⇒ B} {i₁ : A ⇒ C} {i₂ : B ⇒ C}  → IsBiproduct π₁ π₂ i₁ i₂ → Biproduct A B
IsBiproduct⇒Biproduct isBiproduct = record
  { isBiproduct = isBiproduct
  }

Biproduct⇒IsBiproduct : (b : Biproduct A B) → IsBiproduct (Biproduct.π₁ b) (Biproduct.π₂ b) (Biproduct.i₁ b) (Biproduct.i₂ b)
Biproduct⇒IsBiproduct biproduct = Biproduct.isBiproduct biproduct

Biproduct⇒Product : Biproduct A B → Product A B
Biproduct⇒Product b = record
  { ⟨_,_⟩ = ⟨_,_⟩
  ; project₁ = project₁
  ; project₂ = project₂
  ; unique = ⟨⟩-unique
  }
  where
    open Biproduct b

Biproduct⇒Coproduct : Biproduct A B → Coproduct A B
Biproduct⇒Coproduct b = record
  { [_,_] = [_,_]
  ; inject₁ = inject₁
  ; inject₂ = inject₂
  ; unique = []-unique
  }
  where
    open Biproduct b


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

module Lecture8 where

import Lecture7
open Lecture7 public

-- Section 8.1 Propositions

is-prop : {i : Level} (A : UU i) → UU i
is-prop A = (x y : A) → is-contr (Id x y)

is-prop-empty : is-prop empty
is-prop-empty ()

is-prop-unit : is-prop unit
is-prop-unit = is-prop-is-contr is-contr-unit

is-prop' : {i : Level} (A : UU i) → UU i
is-prop' A = (x y : A) → Id x y

is-prop-is-prop' : {i : Level} {A : UU i} → is-prop' A → is-prop A
is-prop-is-prop' {i} {A} H x y =
  dpair
    (concat _ (inv (H x x)) (H x y))
    (ind-Id
      (λ z p → Id (concat _ (inv (H x x)) (H x z)) p)
      (left-inv (H x x)) y)

is-prop'-is-prop : {i : Level} {A : UU i} → is-prop A → is-prop' A
is-prop'-is-prop H x y = pr1 (H x y)

is-contr-is-prop-inh : {i : Level} {A : UU i} → is-prop A → A → is-contr A
is-contr-is-prop-inh H a = dpair a (is-prop'-is-prop H a)

is-subtype : {i j : Level} {A : UU i} (B : A → UU j) → UU (i ⊔ j)
is-subtype B = (x : _) → is-prop (B x)

-- Section 8.2 Sets

is-set : {i : Level} → UU i → UU i
is-set A = (x y : A) → is-prop (Id x y)

axiom-K : {i : Level} → UU i → UU i
axiom-K A = (x : A) (p : Id x x) → Id refl p

is-set-axiom-K : {i : Level} (A : UU i) → axiom-K A → is-set A
is-set-axiom-K A H x y =
  is-prop-is-prop' (ind-Id (λ z p → (q : Id x z) → Id p q) (H x) y)

axiom-K-is-set : {i : Level} (A : UU i) → is-set A → axiom-K A
axiom-K-is-set A H x p =
  concat
    (center (is-contr-is-prop-inh (H x x) refl))
      (inv (contraction (is-contr-is-prop-inh (H x x) refl) refl))
      (contraction (is-contr-is-prop-inh (H x x) refl) p)

is-equiv-prop-in-id : {i j : Level} {A : UU i}
  (R : A → A → UU j)
  (p : (x y : A) → is-prop (R x y))
  (ρ : (x : A) → R x x)
  (i : (x y : A) → R x y → Id x y)
  → (x y : A) → is-equiv (i x y)
is-equiv-prop-in-id R p ρ i x =
  id-fundamental-retr x (i x)
    (λ y → dpair
      (ind-Id (λ z p → R x z) (ρ x) y)
      ((λ r → is-prop'-is-prop (p x y) _ r)))

is-prop-is-equiv : {i j : Level} {A : UU i} (B : UU j)
  (f : A → B) (E : is-equiv f) → is-prop B → is-prop A
is-prop-is-equiv B f E H x y =
  is-contr-is-equiv (ap f {x} {y}) (is-emb-is-equiv f E x y) (H (f x) (f y))

is-prop-is-equiv' : {i j : Level} (A : UU i) {B : UU j}
  (f : A → B) (E : is-equiv f) → is-prop A → is-prop B
is-prop-is-equiv' A f E H =
  is-prop-is-equiv _ (inv-is-equiv E) (is-equiv-inv-is-equiv E) H

is-set-prop-in-id : {i j : Level} {A : UU i}
  (R : A → A → UU j)
  (p : (x y : A) → is-prop (R x y))
  (ρ : (x : A) → R x x)
  (i : (x y : A) → R x y → Id x y)
  → is-set A
is-set-prop-in-id R p ρ i x y = is-prop-is-equiv' (R x y) (i x y) (is-equiv-prop-in-id R p ρ i x y) (p x y)

is-prop-EqN : (n m : ℕ) → is-prop (EqN n m)
is-prop-EqN Nzero Nzero = is-prop-unit
is-prop-EqN Nzero (Nsucc m) = is-prop-empty
is-prop-EqN (Nsucc n) Nzero = is-prop-empty
is-prop-EqN (Nsucc n) (Nsucc m) = is-prop-EqN n m

is-set-nat : is-set ℕ
is-set-nat =
  is-set-prop-in-id
    EqN
    is-prop-EqN
    reflexive-EqN
    (least-reflexive-EqN (λ n → refl))


module Nats.Add.Assoc where

open import Equality
open import Nats
open import Function

------------------------------------------------------------------------
-- internal stuffs

private

  a+/b+c/=/a+b/+c : ∀ a b c → a + b + c ≡ a + (b + c)
  a+/b+c/=/a+b/+c  zero   b c = refl
  a+/b+c/=/a+b/+c (suc a) b c = cong suc $ a+/b+c/=/a+b/+c a b c

------------------------------------------------------------------------
-- public aliases

nat-add-assoc : ∀ a b c → a + b + c ≡ a + (b + c)
nat-add-assoc = a+/b+c/=/a+b/+c


data Nat : Set where
  zero : Nat
  suc  : Nat → Nat

data Zero : Nat → Set where
  instance
    isZero : Zero zero

data NonZero : Nat → Set where
  instance
    isSuc : ∀ {n : Nat} → NonZero (suc n)

pred : ∀ t {{_ : NonZero t}} → Nat
pred ._ {{isSuc {n}}} = n

test : Nat
test = pred (suc zero)

data Test (x : Nat) : Set where
  here  : {{_ : Zero x}} → Test x
  there : {{nz : NonZero x}} → Test (pred x) → Test x

broken : Test (suc zero)
broken = there here


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

open import Algebra.Structures.Bundles.Field

module Algebra.Linear.Structures.FiniteDimensional
  {k ℓᵏ} (K : Field k ℓᵏ)
  where

open import Algebra.Linear.Core
open import Algebra.FunctionProperties
open import Relation.Binary using (Rel)

open import Algebra.Linear.Morphism.Bundles K

open import Algebra.Linear.Structures.VectorSpace K

open import Function.Equality

open import Level using (_⊔_; suc)
open import Data.Nat using (ℕ)
import Algebra.Linear.Construct.Vector K as Vec

private
  K' : Set k
  K' = Field.Carrier K

record IsFiniteDimensional
       {v ℓ} {V : Set v}
       (_≈_ : Rel V ℓ)
       (_+_ : Op₂ V) (_∙_ : K' → V → V) (-_ : Op₁ V) (0# : V)
       (n : ℕ) : Set (suc (v ⊔ k ⊔ ℓ ⊔ ℓᵏ))
    where
  field
    isVectorSpace : IsVectorSpace _≈_ _+_ _∙_ -_ 0#
    embed         : LinearIsomorphism (record { isVectorSpace = isVectorSpace })
                                      (record { isVectorSpace = Vec.isVectorSpace {n} })

  open IsVectorSpace isVectorSpace public

module Vector {n} where
  open Vec

  isFiniteDimensional : IsFiniteDimensional (Vec._≈_) (Vec._+_) (Vec._∙_) (Vec.-_) (Vec.0#) n
  isFiniteDimensional = record
    { isVectorSpace = Vec.isVectorSpace
    ; embed         = Vec.embed
    }


module Cat where

open import Agda.Builtin.Equality

{- A category is very much like a graph. It has vertices
   named objects and vertices named arrows. Each arrow goes
   from an object to an object (possibly the same!). -}
record Cat (obj : Set) (arr : obj -> obj -> Set) : Set where
  constructor MkCat
  field
    {- For each object, there is an arrow called `id` which
       goes from the object to itself. -}
    id : {o : obj} -> arr o o

    {- Given an arrow `f` from object `a` to `b` and an arrow
       `g` from `b` to `c`. We can compose these arrow. The
       result is an arrow from `a` to `c`. -}
    compose : {a b c : obj} -> arr a b -> arr b c -> arr a c

    -- Here comes some properties of `id` and `compose`

    {- For any arrow `f`, compose id f = f -}
    neutralLeft  : {a b : obj} -> (f : arr a b) -> compose id f ≡ f

    {- For any arrow `f`, compose f id = f  -}
    neutralRight : {a b : obj} -> (f : arr a b) -> compose f id ≡ f

    {- For any arrows `f`, `g` and `h`,
        composing f with g, and then the result with h
       gives exatctly the same result as
        composing f with the result of the composition of g and h

       Which means, like string concatenation than we can commpose
       the way we preserve the order of each element in the sequence.
    -}
    associativity : {a b c d : obj} ->
                    (f : arr a b) -> (g : arr b c) -> (h : arr c d) ->
                    compose f (compose g h) ≡ compose (compose f g) h

open import Agda.Builtin.Nat

{- `LE n m` encode the property that `n ≤ m`
    i.e. `n` is less or equal to `m` -}
data LE : Nat -> Nat -> Set where
  LERefl : {n : Nat} -> LE n n
  LENext : {n m : Nat} -> LE n m -> LE n (suc m)

{- Taking naturals as objects and `LE` as arrows,
   this actually forms a category! -}
natPoset : Cat Nat LE
natPoset = ???


------------------------------------------------------------------------
-- Indices
------------------------------------------------------------------------

module Parallel.Index where

open import Data.Product.Record
import Data.Product as Prod; open Prod using () renaming (_,_ to pair)

open import Data.Bool using (Bool; true; false; _∨_; _∧_; if_then_else_)
open import Data.Bool.Properties as Bool

open import Data.Nat using (ℕ; zero; suc; _⊔_)
open import Data.Nat.Properties

open import Algebra
import Algebra.Props.BooleanAlgebra as BAlg
import Algebra.Props.DistributiveLattice as DL
private
  module NR = CommutativeSemiringWithoutOne
                ⊔-⊓-0-commutativeSemiringWithoutOne
  module NL = DL distributiveLattice
  module BR = CommutativeSemiring Bool.commutativeSemiring-∨-∧
  module BA = BAlg Bool.booleanAlgebra

import Relation.Binary.PropositionalEquality as PropEq
open PropEq hiding (setoid)
open ≡-Reasoning
open import Data.Function
open import Relation.Nullary

------------------------------------------------------------------------
-- The index type

-- Does the parser accept the empty string?

Empty : Set
Empty = Bool

-- The maximum "distance" to the next parser which is guaranteed to
-- either consume a token or fail.

Distance : Set
Distance = ℕ

-- Parser indices. Note that it is important that the record type used
-- here has η-equality, since otherwise it would be harder to infer
-- the types.

Index : Set
Index = Empty × Distance

import Algebra.FunctionProperties as P; open P (PropEq.setoid Index)

------------------------------------------------------------------------
-- The basic operations on indices

infixl 50 _·I_
infixl 40 _∣I_

0I : Index
0I = (false , zero)

1I : Index
1I = (true , zero)

_·I_ : Index -> Index -> Index
i₁ ·I i₂ = ( proj₁ i₁ ∧ proj₁ i₂
           , (if proj₁ i₁ then proj₂ i₁ ⊔ proj₂ i₂
                          else proj₂ i₁)
           )

_∣I_ : Index -> Index -> Index
i₁ ∣I i₂ = (proj₁ i₁ ∨ proj₁ i₂ , proj₂ i₁ ⊔ proj₂ i₂)

------------------------------------------------------------------------
-- These operations satisfy some algebraic properties

private

  -- TODO: General code for taking the product of two commutative
  -- monoids. However, I don't want to define this operation for both
  -- Data.Product and Data.Product.Record. Hence I'll probably wait
  -- (at least) until pattern matching on records is possible, since I
  -- plan to merge Data.Product and Data.Product.Record then.

  ∣-assoc : Associative _∣I_
  ∣-assoc i₁ i₂ i₃ =
    cong₂ _,_ (BR.+-assoc (proj₁ i₁) (proj₁ i₂) (proj₁ i₃))
              (NR.+-assoc (proj₂ i₁) (proj₂ i₂) (proj₂ i₃))

  ∣-comm : Commutative _∣I_
  ∣-comm i₁ i₂ =
    cong₂ _,_ (BR.+-comm (proj₁ i₁) (proj₁ i₂))
              (NR.+-comm (proj₂ i₁) (proj₂ i₂))

  ∣-identity : Identity 0I _∣I_
  ∣-identity = pair
    (\i -> cong₂ _,_ (Prod.proj₁ BR.+-identity (proj₁ i))
                     (Prod.proj₁ NR.+-identity (proj₂ i)))
    (\i -> cong₂ _,_ (Prod.proj₂ BR.+-identity (proj₁ i))
                     (Prod.proj₂ NR.+-identity (proj₂ i)))

  ·-assoc : Associative _·I_
  ·-assoc i₁ i₂ i₃ with proj₁ i₁ | proj₁ i₂
  ·-assoc i₁ i₂ i₃ | false | e₂    = refl
  ·-assoc i₁ i₂ i₃ | true  | false = refl
  ·-assoc i₁ i₂ i₃ | true  | true  =
    cong (_,_ (proj₁ i₃)) (NR.+-assoc (proj₂ i₁) (proj₂ i₂) (proj₂ i₃))

  ·-identity : Identity 1I _·I_
  ·-identity = pair (\_ -> refl) (\x -> helper (proj₁ x) (proj₂ x))
    where
    helper : forall e d ->
             _≡_ {a = Index} (e ∧ true , (if e then d ⊔ zero else d))
                             (e        , d)
    helper false d = refl
    helper true  d = cong (_,_ true) (Prod.proj₂ NR.+-identity d)

  ·-∣-distrib : _·I_ DistributesOver _∣I_
  ·-∣-distrib = pair
    (\i₁ i₂ i₃ ->
        cong₂ _,_
              (Prod.proj₁ BR.distrib (proj₁ i₁) (proj₁ i₂) (proj₁ i₃))
              (distribˡ₂ (proj₂ i₁) (proj₂ i₂) (proj₂ i₃) (proj₁ i₁)))
    (\i₁ i₂ i₃ ->
        cong₂ _,_
              (Prod.proj₂ BR.distrib (proj₁ i₁) (proj₁ i₂) (proj₁ i₃))
              (distribʳ₂ (proj₂ i₁) (proj₂ i₂) (proj₂ i₃)
                                    (proj₁ i₂) (proj₁ i₃)))
    where
    lemma : forall d₁ d₂ d₃ -> d₁ ⊔ (d₂ ⊔ d₃) ≡ d₁ ⊔ d₂ ⊔ (d₁ ⊔ d₃)
    lemma d₁ d₂ d₃ = begin
      d₁       ⊔ (d₂ ⊔ d₃)   ≡⟨ sym (NL.∧-idempotent d₁)
                                  ⟨ NR.+-pres-≈ ⟩
                                byDef {x = d₂ ⊔ d₃} ⟩
      d₁ ⊔  d₁ ⊔ (d₂ ⊔ d₃)   ≡⟨ NR.+-assoc d₁ d₁ (d₂ ⊔ d₃) ⟩
      d₁ ⊔ (d₁ ⊔ (d₂ ⊔ d₃))  ≡⟨ byDef {x = d₁} ⟨ NR.+-pres-≈ ⟩
                                sym (NR.+-assoc d₁ d₂ d₃) ⟩
      d₁ ⊔ (d₁ ⊔  d₂ ⊔ d₃)   ≡⟨ byDef {x = d₁} ⟨ NR.+-pres-≈ ⟩
                                  (NR.+-comm d₁ d₂ ⟨ NR.+-pres-≈ ⟩
                                   byDef {x = d₃}) ⟩
      d₁ ⊔ (d₂ ⊔  d₁ ⊔ d₃)   ≡⟨ byDef {x = d₁} ⟨ NR.+-pres-≈ ⟩
                                NR.+-assoc d₂ d₁ d₃ ⟩
      d₁ ⊔ (d₂ ⊔ (d₁ ⊔ d₃))  ≡⟨ sym $ NR.+-assoc d₁ d₂ (d₁ ⊔ d₃) ⟩
      d₁ ⊔ d₂  ⊔ (d₁ ⊔ d₃)   ∎

    distribˡ₂ : forall d₁ d₂ d₃ e₁ ->
                (if e₁ then d₁ ⊔ (d₂ ⊔ d₃) else d₁) ≡
                (if e₁ then d₁ ⊔ d₂        else d₁) ⊔
                (if e₁ then d₁ ⊔ d₃        else d₁)
    distribˡ₂ d₁ d₂ d₃ true  = lemma d₁ d₂ d₃
    distribˡ₂ d₁ d₂ d₃ false = sym (NL.∧-idempotent d₁)

    distribʳ₂ : forall d₁ d₂ d₃ e₂ e₃ ->
                (if e₂ ∨ e₃ then d₂ ⊔ d₃ ⊔ d₁ else d₂ ⊔ d₃)
                ≡
                (if e₂ then d₂ ⊔ d₁ else d₂) ⊔
                (if e₃ then d₃ ⊔ d₁ else d₃)
    distribʳ₂ d₁ d₂ d₃ true true = begin
      d₂ ⊔ d₃ ⊔ d₁         ≡⟨ NR.+-comm (d₂ ⊔ d₃) d₁ ⟩
      d₁ ⊔ (d₂ ⊔ d₃)       ≡⟨ lemma d₁ d₂ d₃ ⟩
      d₁ ⊔ d₂ ⊔ (d₁ ⊔ d₃)  ≡⟨ NR.+-comm d₁ d₂ ⟨ NR.+-pres-≈ ⟩
                              NR.+-comm d₁ d₃ ⟩
      d₂ ⊔ d₁ ⊔ (d₃ ⊔ d₁)  ∎
    distribʳ₂ d₁ d₂ d₃ true false = begin
      d₂ ⊔  d₃ ⊔ d₁   ≡⟨ NR.+-assoc d₂ d₃ d₁ ⟩
      d₂ ⊔ (d₃ ⊔ d₁)  ≡⟨ byDef {x = d₂} ⟨ NR.+-pres-≈ ⟩
                         NR.+-comm d₃ d₁ ⟩
      d₂ ⊔ (d₁ ⊔ d₃)  ≡⟨ sym $ NR.+-assoc d₂ d₁ d₃ ⟩
      d₂ ⊔  d₁ ⊔ d₃   ∎
    distribʳ₂ d₁ d₂ d₃ false true  = NR.+-assoc d₂ d₃ d₁
    distribʳ₂ d₁ d₂ d₃ false false = refl

·-idempotent : Idempotent _·I_
·-idempotent i = cong₂ _,_ (BA.∧-idempotent (proj₁ i))
                           (lemma (proj₁ i) (proj₂ i))
  where
  lemma : forall b x -> (if b then x ⊔ x else x) ≡ x
  lemma true  x = NL.∧-idempotent x
  lemma false x = refl

∣-idempotent : Idempotent _∣I_
∣-idempotent i = cong₂ _,_ (BA.∨-idempotent (proj₁ i))
                           (NL.∧-idempotent (proj₂ i))

-- Not quite a semiring, but the proper name is too long...

indexSemiring : SemiringWithoutAnnihilatingZero
indexSemiring = record
  { setoid = PropEq.setoid Index
  ; _+_    = _∣I_
  ; _*_    = _·I_
  ; 0#     = 0I
  ; 1#     = 1I
  ; isSemiringWithoutAnnihilatingZero = record
    { +-isCommutativeMonoid = record
      { isMonoid = record
        { isSemigroup = record
          { assoc    = ∣-assoc
          ; ∙-pres-≈ = cong₂ _∣I_
          }
        ; identity = ∣-identity
        }
      ; comm = ∣-comm
      }
    ; *-isMonoid = record
      { isSemigroup = record
        { assoc    = ·-assoc
        ; ∙-pres-≈ = cong₂ _·I_
        }
      ; identity = ·-identity
      }
    ; distrib = ·-∣-distrib
    }
  }

module IndexSemiring =
  SemiringWithoutAnnihilatingZero indexSemiring

nearSemiring : NearSemiring
nearSemiring = record
  { setoid = setoid
  ; _+_    = _+_
  ; _*_    = _*_
  ; 0#     = 0#
  ; isNearSemiring = record
    { +-isMonoid    = +-isMonoid
    ; *-isSemigroup = *-isSemigroup
    ; distribʳ      = Prod.proj₂ distrib
    ; zeroˡ         = \_ -> PropEq.refl
    }
  }
  where open IndexSemiring

private

  lemma : suc zero ≢ zero
  lemma ()

  -- The indices very nearly form a semiring (∣I, ·I, 0I, 1I). The
  -- only missing piece is that 0I is not a right zero for ·I:

  notRightZero : ¬ RightZero 0I _·I_
  notRightZero zeroʳ = lemma $ cong proj₂ $
    zeroʳ (false , suc zero)

  -- It might also be worth noting that ·I is not commutative:

  notCommutative : ¬ Commutative _·I_
  notCommutative comm = lemma $ cong proj₂ $
    comm (true , suc zero) (false , zero)

  -- Note that we don't want these properties to be true. The second
  -- one implies the first, and the first implies that
  --   p = p ⊛> symbol
  -- is an OK definition, even though it is left recursive.


{-# OPTIONS --safe #-}
module Cubical.Algebra.AbGroup.Properties where

open import Cubical.Foundations.Prelude

open import Cubical.Algebra.AbGroup.Base

private variable
  ℓ : Level

module AbGroupTheory (A'@(A , Ar) : AbGroup ℓ) where

  open AbGroupStr Ar

  comm-4 : (a b c d : A) → ((a + b) + (c + d) ≡ (a + c) + (b + d))
  comm-4 a b c d = ((a + b) + (c + d)  ≡⟨ +Assoc (a + b) c d ⟩
                   (((a + b) + c) + d) ≡⟨ cong (λ X → X + d) (sym (+Assoc a b c)) ⟩
                   ((a + (b + c)) + d) ≡⟨ cong (λ X → (a + X) + d) (+Comm b c) ⟩
                   ((a + (c + b)) + d) ≡⟨ cong (λ X → X + d) (+Assoc a c b) ⟩
                   (((a + c) + b) + d) ≡⟨ sym (+Assoc (a + c) b d) ⟩
                   ((a + c) + (b + d)) ∎)


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

module Data.Binary.Isomorphism where

open import Data.Binary.Definition
open import Data.Binary.Conversion
open import Data.Binary.Increment
open import Prelude
import Data.Nat as ℕ

inc-suc : ∀ x → ⟦ inc x ⇓⟧ ≡ suc ⟦ x ⇓⟧
inc-suc 0ᵇ     i = 1
inc-suc (1ᵇ x) i = 2 ℕ.+ ⟦ x ⇓⟧ ℕ.* 2
inc-suc (2ᵇ x) i = suc (inc-suc x i ℕ.* 2)

inc-2*-1ᵇ : ∀ n → inc ⟦ n ℕ.* 2 ⇑⟧ ≡ 1ᵇ ⟦ n ⇑⟧
inc-2*-1ᵇ zero    i = 1ᵇ 0ᵇ
inc-2*-1ᵇ (suc n) i = inc (inc (inc-2*-1ᵇ n i))

𝔹-rightInv : ∀ x → ⟦ ⟦ x ⇑⟧ ⇓⟧ ≡ x
𝔹-rightInv zero    = refl
𝔹-rightInv (suc x) = inc-suc ⟦ x ⇑⟧ ; cong suc (𝔹-rightInv x)

𝔹-leftInv : ∀ x → ⟦ ⟦ x ⇓⟧ ⇑⟧ ≡ x
𝔹-leftInv 0ᵇ = refl
𝔹-leftInv (1ᵇ x) =           inc-2*-1ᵇ ⟦ x ⇓⟧  ; cong 1ᵇ_ (𝔹-leftInv x)
𝔹-leftInv (2ᵇ x) = cong inc (inc-2*-1ᵇ ⟦ x ⇓⟧) ; cong 2ᵇ_ (𝔹-leftInv x)

𝔹⇔ℕ : 𝔹 ⇔ ℕ
𝔹⇔ℕ .fun = ⟦_⇓⟧
𝔹⇔ℕ .inv = ⟦_⇑⟧
𝔹⇔ℕ .rightInv = 𝔹-rightInv
𝔹⇔ℕ .leftInv  = 𝔹-leftInv


module Cats.Category.Mon where

open import Data.Unit using (⊤)
open import Relation.Binary using (Setoid ; _Preserves₂_⟶_⟶_ ; IsEquivalence)
open import Level

open import Cats.Category
open import Cats.Category.Setoids using (Setoids)
open import Cats.Util.Conv

import Cats.Util.Function as Fun

record Monoid l l≈ : Set (suc (l ⊔ l≈)) where
  infixr 9 _⊕_

  field
    Universe : Setoid l l≈

  open Setoid Universe public

  field
    _⊕_ : Carrier → Carrier → Carrier
    unit : Carrier

    ⊕-resp : _⊕_ Preserves₂ _≈_ ⟶ _≈_ ⟶ _≈_
    assoc : ∀ {a b c} → (a ⊕ b) ⊕ c ≈ a ⊕ (b ⊕ c)
    id-l : ∀ {a} → unit ⊕ a ≈ a
    id-r : ∀ {a} → a ⊕ unit ≈ a

  module ≈ = IsEquivalence isEquivalence

module _ (l l≈ : Level) where

  infixr 9 _∘_
  infixr 4 _≈_

  module Setoids = Category (Setoids l l≈)

  Obj : Set (suc (l ⊔ l≈))
  Obj = Monoid l l≈

  record _⇒_ (M N : Obj) : Set (l ⊔ l≈) where
    private
      module M = Monoid M
      module N = Monoid N

    field
      arr : M.Universe Setoids.⇒ N.Universe
      unit : (arr ⃗) M.unit N.≈ N.unit
      commute : ∀ {n m} → (arr ⃗) (n M.⊕ m) N.≈ (arr ⃗) n N.⊕ (arr ⃗) m

    open Cats.Category.Setoids._⇒_ arr public using (resp)

  open _⇒_ using (unit ; commute ; resp)

  instance
    HasArrow-⇒ : ∀ M N → HasArrow (M ⇒ N) _ _ _
    HasArrow-⇒ M N = record { Cat = Setoids l l≈ ; _⃗ = _⇒_.arr }

  id : ∀ {M} → M ⇒ M
  id {M} = record
      { arr = Setoids.id
      ; unit = refl
      ; commute = refl
      }
    where
      open Monoid M using (refl)

  _≈_ : ∀ {M N} (f g : M ⇒ N) → Set (l≈ ⊔ l)
  _≈_ = Setoids._≈_ Fun.on _⃗

  _∘_ : ∀ {M N O} → (N ⇒ O) → (M ⇒ N) → (M ⇒ O)
  _∘_ {M} {N} {O} f g = record
      { arr = f ⃗ Setoids.∘ g ⃗
      ; unit = trans (resp f (unit g)) (unit f)
      ; commute = trans (resp f (commute g)) (commute f)
      }
    where
      open Monoid O using (trans)

  Mon : Category (suc (l≈ ⊔ l)) (l≈ ⊔ l) (l≈ ⊔ l)
  Mon = record
      { Obj = Obj
      ; _⇒_ = _⇒_
      ; _≈_ = _≈_
      ; id = id
      ; _∘_ = _∘_
      ; equiv = Fun.on-isEquivalence _⃗ Setoids.equiv
      ; ∘-resp = Setoids.∘-resp
      ; id-r = Setoids.id-r
      ; id-l = Setoids.id-l
      ; assoc = λ { {f = f} {g} {h} → Setoids.assoc {f = f ⃗} {g ⃗} {h ⃗} }
      }

monoidAsCategory : ∀ {l l≈} → Monoid l l≈ → Category zero l l≈
monoidAsCategory M = record
    { Obj = ⊤
    ; _⇒_ = λ _ _ → M.Carrier
    ; _≈_ = M._≈_
    ; id = M.unit
    ; _∘_ = M._⊕_
    ; equiv = M.isEquivalence
    ; ∘-resp = M.⊕-resp
    ; id-r = M.id-r
    ; id-l = M.id-l
    ; assoc = M.assoc
    }
  where
    module M = Monoid M


------------------------------------------------------------------------------
-- Group theory congruence proofs using pattern matching
------------------------------------------------------------------------------

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

module LogicalFramework.GroupCongruence where

open import GroupTheory.Base

·-cong : ∀ {a b c d} → a ≡ b → c ≡ d → a · c ≡ b · d
·-cong refl refl = refl

·-leftCong : ∀ {a b c} → a ≡ b → a · c ≡ b · c
·-leftCong refl = refl

·-rightCong : ∀ {a b c} → b ≡ c → a · b ≡ a · c
·-rightCong refl = refl

⁻¹-cong : ∀ {a b} → a ≡ b → a ⁻¹ ≡ b ⁻¹
⁻¹-cong refl = refl


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

-- Define Strong Monad; use the Wikipedia definition
-- https://en.wikipedia.org/wiki/Strong_monad
-- At the nLab, https://ncatlab.org/nlab/show/strong+monad
-- there are two further definitions; the 2-categorical version is too complicated
-- and the Moggi definition is a special case of the one here

module Categories.Monad.Strong  where

open import Level
open import Data.Product using (_,_)

open import Categories.Category
open import Categories.Functor renaming (id to idF)
open import Categories.Category.Monoidal
open import Categories.Category.Product
open import Categories.NaturalTransformation hiding (id)
-- open import Categories.NaturalTransformation.NaturalIsomorphism
open import Categories.Monad

private
  variable
    o ℓ e : Level

record Strength {C : Category o ℓ e} (V : Monoidal C) (m : Monad C) : Set (o ⊔ ℓ ⊔ e) where
  open Category C
  open Monoidal V
  open Monad m using (F)
  module M = Monad m
  open NaturalTransformation M.η using (η)
  open NaturalTransformation M.μ renaming (η to μ)
  open Functor F
  field
    strengthen : NaturalTransformation (⊗ ∘F (idF ⁂ F)) (F ∘F ⊗)

  private
    module t = NaturalTransformation strengthen

  field
    -- strengthening with 1 is irrelevant
    identityˡ : {A : Obj} → F₁ (unitorˡ.from) ∘ t.η (unit , A) ≈ unitorˡ.from
    -- commutes with unit (of monad)
    η-comm : {A B : Obj} → t.η (A , B) ∘ (id ⊗₁ η B) ≈  η (A ⊗₀ B)
    -- strength commutes with multiplication
    μ-η-comm : {A B : Obj} → μ (A ⊗₀ B) ∘ F₁ (t.η (A , B)) ∘ t.η (A , F₀ B)
      ≈ t.η (A , B) ∘ id ⊗₁ μ B
    -- consecutive applications of strength commute (i.e. strength is associative)
    strength-assoc :  {A B C : Obj} → F₁ associator.from ∘ t.η (A ⊗₀ B , C)
      ≈ t.η (A , B ⊗₀ C) ∘ id ⊗₁ t.η (B , C) ∘ associator.from

record StrongMonad {C : Category o ℓ e} (V : Monoidal C) : Set (o ⊔ ℓ ⊔ e) where
  field
    m : Monad C
    strength : Strength V m


------------------------------------------------------------------------------
-- Mendelson's substitution
------------------------------------------------------------------------------

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

module FOT.FOL.MendelsonSubstI where

-- First-order logic with equality.
open import Common.FOL.FOL-Eq public

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

-- Mendelson's [2015] substitution (p. 93).

--   (A7) x = y ⇒ (A(x,x) ⇒ B(x,y)) (substitutivity of equality)

-- Using pattern matching.
mendelsonSubst : (A : D → D → Set) → ∀ {x y} → x ≡ y → A x x → A x y
mendelsonSubst A refl Axx = Axx

-- From `subst` to Mendelson substitution.
subst→mendelsonSubst : (A : D → D → Set) → ∀ {x y} → x ≡ y → A x x → A x y
subst→mendelsonSubst A {x} = subst (λ z → A x z)

-- From Mendelson substitution to `subst`.
mendelsonSubst→subst : (A : D → Set) → ∀ {x y} → x ≡ y → A x → A y
mendelsonSubst→subst A = mendelsonSubst (λ _ → A)

------------------------------------------------------------------------------
-- References

-- Mendelson, Elliott (2015). Introduction to Mathematical Logic. CRC
-- Press, 6th edition.


{-# OPTIONS --cubical --safe #-}
module Label where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude using (isProp; transport)

open import Cubical.Data.Nat using (ℕ; zero; suc; isSetℕ)
open import Cubical.Data.Nat.Order using (_<_; _≤_; ≤-refl; <-weaken; ≤<-trans; m≤n-isProp; <-asym)
open import Cubical.Data.Maybe using (Maybe; nothing; just)
open import Cubical.Data.Empty using () renaming (rec to ⊥-elim)

Label : Set
Label = ℕ

data Record (A : Set) : Label -> Set where
  nil : forall {l} -> Record A l
  cons : forall {l} -> Record A l -> (l' : Label) -> A -> .(l < l') -> Record A l'

data _∈_ {A : Set} (l₁ : Label) {l : Label} : Record A l -> Set where
  here : forall {l'} {r : Record A l'} {x lt} -> l₁ ≡ l -> l₁ ∈ cons r l x lt
  there : forall {l'} {r : Record A l'} {x lt} -> l₁ ∈ r -> l₁ ∈ cons r l x lt

find : forall {A} {l} -> (l₁ : Label) -> (r : Record A l) -> l₁ ∈ r -> A
find l₁ (cons _ _ x _) (here e) = x
find l₁ (cons r _ _ _) (there l₁∈r) = find l₁ r l₁∈r

∈-implies-≤ : forall {A} {l l'} {r : Record A l'} -> l ∈ r -> l ≤ l'
∈-implies-≤ {l = l} (here e) = transport (λ i -> l ≤ e i) ≤-refl
∈-implies-≤ (there {lt = lt} l∈r) = <-weaken (≤<-trans (∈-implies-≤ l∈r) lt)

l∈r-isProp : forall {A} l {l'} (r : Record A l') -> isProp (l ∈ r)
l∈r-isProp l {l'} (cons _ _ _ _) (here {lt = a} e1) (here {lt = b} e2) = λ i -> here {lt = m≤n-isProp a b i} (isSetℕ l l' e1 e2 i)
l∈r-isProp l (cons {l = l₁} r _ _ _) (here {lt = k} e) (there y) = ⊥-elim (<-asym k (transport (λ i -> e i ≤ l₁) (∈-implies-≤ y)))
l∈r-isProp l (cons {l = l₁} r _ _ _) (there {lt = k} x) (here e) = ⊥-elim (<-asym k (transport (λ i -> e i ≤ l₁) (∈-implies-≤ x)))
l∈r-isProp l (cons r _ _ _) (there {lt = k1} x) (there {lt = k2} y) = let a = l∈r-isProp l r x y in λ i → there {lt = m≤n-isProp k1 k2 i} (a i)


----------------------------------------------------------------
-- This file contains the definition natural transformations. --
----------------------------------------------------------------
module Category.NatTrans where

open import Level

open import Category.Category public
open import Category.Funct public
open import Category.CatEq public

record NatTrans {l₁ l₂ : Level}
                {ℂ₁ : Cat {l₁}}
                {ℂ₂ : Cat {l₂}}
                (F G : Functor ℂ₁ ℂ₂) : Set (l₁ ⊔ l₂) where
  field
    -- The family of components.
    η : (A : Obj ℂ₁) → el (Hom ℂ₂ (omap F A) (omap G A))

    -- The natural transformation law.
    η-ax : ∀{A B}{f : el (Hom ℂ₁ A B)} → comm-square {ℂ = ℂ₂} (appT (fmap F) f) (η B) (η A) (appT (fmap G) f)

open NatTrans public


-- Agda program using the Iowa Agda library

open import bool

module TO-PROVE-evendoublecoin
  (Choice : Set)
  (choose : Choice → 𝔹)
  (lchoice : Choice → Choice)
  (rchoice : Choice → Choice)
  where

open import eq
open import nat
open import list
open import maybe

---------------------------------------------------------------------------
-- Translated Curry operations:

add : ℕ → ℕ → ℕ
add zero x = x
add (suc y) z = suc (add y z)

coin : Choice → ℕ → ℕ
coin c1 x = if choose c1 then x else suc x

double : ℕ → ℕ
double x = add x x

even : ℕ → 𝔹
even zero = tt
even (suc zero) = ff
even (suc (suc x)) = even x

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

evendoublecoin : (c1 : Choice) → (x : ℕ) → (even (double (coin c1 x))) ≡ tt
evendoublecoin c1 x = ?

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


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

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

record Stream (A : Set) : Set where
  constructor stream
  field
    start : A
    next : A → A

open Stream

ℕ-stream : Stream ℕ
start ℕ-stream = zero
next ℕ-stream n = succ n

0th : {A : Set} → Stream A → A
0th s = start s

3rd : {A : Set} → Stream A → A
3rd s = next s (next s (next s (start s)))

_ : 0th ℕ-stream ≡ zero
_ = refl

_ : 3rd ℕ-stream ≡ succ (succ (succ zero))
_ = refl


open import Agda.Builtin.Bool
open import Agda.Builtin.Equality
open import Agda.Builtin.Sigma
open import Agda.Primitive

infixr 2 _×_

_×_ : ∀ {a b} → Set a → Set b → Set (a ⊔ b)
A × B = Σ A λ _ → B

∃-notation exists-notation :
  ∀ {a b} {A : Set a} → (A → Set b) → Set (a ⊔ b)
∃-notation      = Σ _
exists-notation = Σ _

Σ-notation : ∀ {a b} (A : Set a) → (A → Set b) → Set (a ⊔ b)
Σ-notation = Σ

infixr 2 ∃-notation exists-notation Σ-notation

syntax ∃-notation (λ x → B)      = ∃ x × B
syntax exists-notation (λ x → B) = exists x × B
syntax Σ-notation A (λ x → B)    = [ x ∶ A ] × B

_ : ∃ b × b ≡ true × Bool
_ = true , refl , false

_ : exists b × b ≡ true
_ = true , refl

_ : [ b ∶ Bool ] × b ≡ true
_ = true , refl

_ : [ b₁ ∶ Bool ] × [ b₂ ∶ Bool ] × b₁ ≡ b₂
_ = true , true , refl

_ : [ b₁ ∶ Bool ] × ∃ b₂ × b₁ ≡ b₂
_ = true , true , refl

_ : [ f ∶ (Bool → Bool) ] × f ≡ λ x → x
_ = (λ x → x) , refl

data List (A : Set) : Set where
  []   : List A
  cons : A → List A → List A

infixr 5 cons

syntax []        = [ ]
syntax cons x xs = x consed to xs

_ : List Bool
_ = true consed to false consed to [ ]

f : List Bool → Bool
f [ ]                               = true
f (true consed to [ ])              = false
f (false consed to x consed to [ ]) = x
f _                                 = true


module Acme.Data.Nat where

open import Acme.Type

ℕ   : Type
isZ : Type
isS : Type

ℕ cs = isZ cs || isS cs

isZ [] = false
isZ (c ∷ cs) = c == 'Z' && isNil cs

isS [] = false
isS (c ∷ cs) = c == 'S' && ℕ cs

zero = ℕ ∋ "Z"

suc : Elt ℕ → Elt ℕ
suc [ n ] = [ 'S' ∷ n ]

one    = ℕ ∋ "SZ"
two    = suc (suc zero)
three  = ℕ ∋ "SSSZ"
four   = suc three

module _ (P : Elt ℕ → Set)
         (P0 : P zero)
         (PS : ∀ n → P n → P (suc n))
         where

  induction : ∀ n → P n
  induction [ ccs@(c ∷ cs) ] = checkZ (c ≟ 'Z') cs refl where

    checkS : ∀ {b} → Reflects c 'S' b → ∀ cs →
             {{@0 _ : IsTrue (b && ℕ cs)}} →
             ∀ {ccs} → c ∷ cs ≡ ccs .value → P ccs
    checkS true cs refl = PS [ cs ] (induction [ cs ])

    checkZ : ∀ {b} → Reflects c 'Z' b → ∀ cs →
             {{@0 _ : IsTrue (b && isNil cs || isS (c ∷ cs))}} →
             ∀ {ccs} → c ∷ cs ≡ ccs .value → P ccs
    checkZ true  [] refl = P0
    checkZ false cs eq   = checkS (c ≟ 'S') cs eq

_ : ∀ {P P0 PS} → induction P P0 PS zero ≡ P0
_ = refl

_ : ∀ {P P0 PS n} →
    induction P P0 PS (suc n) ≡ PS n (induction P P0 PS n)
_ = refl

_+_ : Elt ℕ → Elt ℕ → Elt ℕ
m + n = induction (λ _ → Elt ℕ) n (λ _ → suc) m

_ : three + one ≡ four
_ = refl

_*_ : Elt ℕ → Elt ℕ → Elt ℕ
m * n = induction (λ _ → Elt ℕ) zero (λ _ → n +_) m

_ : two * three ≡ four + two
_ = refl

zero-+ : ∀ m → zero + m ≡ m
zero-+ m = refl

+-zero : ∀ m → m + zero ≡ m
+-zero =
  induction
    (λ m → m + zero ≡ m)
    refl
    (λ n → cong suc)

suc-+ : ∀ m n → suc m + n ≡ suc (m + n)
suc-+ m n = refl

+-suc : ∀ m n → m + suc n ≡ suc (m + n)
+-suc m n =
  induction
    (λ m → (m + suc n) ≡ suc (m + n))
    refl
    (λ n → cong suc)
    m

+-comm : ∀ m n → m + n ≡ n + m
+-comm m n =
  induction
    (λ m → m + n ≡ n + m)
    (sym (+-zero n))
    (λ m ih → trans (cong suc ih) (sym (+-suc n m)))
    m

+-assoc : ∀ m n p → (m + n) + p ≡ m + (n + p)
+-assoc m n p =
  induction
    (λ m → ((m + n) + p) ≡ (m + (n + p)))
    refl
    (λ m → cong suc)
    m


module Oscar.Property.Associativity where

open import Oscar.Level

record Associativity
  {𝔬} {⋆ : Set 𝔬}
  {𝔪} {_⇒_ : ⋆ → ⋆ → Set 𝔪}
  (_∙_ : ∀ {y z} → y ⇒ z → ∀ {x} → x ⇒ y → x ⇒ z)
  {𝔮} (_≤_ : ∀ {x y} → x ⇒ y → x ⇒ y → Set 𝔮)
  : Set (𝔬 ⊔ 𝔪 ⊔ 𝔮) where
  field
    associativity : ∀ {w x} (f : w ⇒ x) {y} (g : x ⇒ y) {z} (h : y ⇒ z) → ((h ∙ g) ∙ f) ≤ (h ∙ (g ∙ f))

open Associativity ⦃ … ⦄ public

association : ∀
  {𝔬} {⋆ : Set 𝔬}
  {𝔪} {_⇒_ : ⋆ → ⋆ → Set 𝔪}
  (_∙_ : ∀ {y z} → y ⇒ z → ∀ {x} → x ⇒ y → x ⇒ z)
  {𝔮} (_≤_ : ∀ {x y} → x ⇒ y → x ⇒ y → Set 𝔮)
  ⦃ _ : Associativity _∙_ _≤_ ⦄
  → ∀ {w x} (f : w ⇒ x) {y} (g : x ⇒ y) {z} (h : y ⇒ z) → ((h ∙ g) ∙ f) ≤ (h ∙ (g ∙ f))
association _∙_ _≤_ = associativity {_∙_ = _∙_} {_≤_ = _≤_}


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

open import LogicalFormulae
open import Groups.Homomorphisms.Definition
open import Groups.Definition
open import Groups.Lemmas
open import Setoids.Setoids
open import Sets.EquivalenceRelations
open import Rings.Definition
open import Rings.Homomorphisms.Definition
open import Groups.Homomorphisms.Lemmas
open import Rings.Subrings.Definition
open import Rings.Cosets
open import Rings.Isomorphisms.Definition
open import Groups.Isomorphisms.Definition

module Rings.Ideals.FirstIsomorphismTheorem {a b c d : _} {A : Set a} {B : Set c} {S : Setoid {a} {b} A} {T : Setoid {c} {d} B} {_+A_ _*A_ : A → A → A} {_+B_ _*B_ : B → B → B} {R1 : Ring S _+A_ _*A_} {R2 : Ring T _+B_ _*B_} {f : A → B} (hom : RingHom R1 R2 f) where

open import Rings.Quotients.Definition R1 R2 hom
open import Rings.Homomorphisms.Image hom
open import Rings.Homomorphisms.Kernel hom
open Setoid T
open Equivalence eq
open import Groups.FirstIsomorphismTheorem (RingHom.groupHom hom)

ringFirstIsomorphismTheorem : RingsIsomorphic (cosetRing R1 ringKernelIsIdeal) (subringIsRing R2 imageGroupSubring)
RingsIsomorphic.f ringFirstIsomorphismTheorem = GroupsIsomorphic.isomorphism groupFirstIsomorphismTheorem
RingHom.preserves1 (RingIso.ringHom (RingsIsomorphic.iso ringFirstIsomorphismTheorem)) = RingHom.preserves1 hom
RingHom.ringHom (RingIso.ringHom (RingsIsomorphic.iso ringFirstIsomorphismTheorem)) = RingHom.ringHom hom
GroupHom.groupHom (RingHom.groupHom (RingIso.ringHom (RingsIsomorphic.iso ringFirstIsomorphismTheorem))) = GroupHom.groupHom (RingHom.groupHom hom)
GroupHom.wellDefined (RingHom.groupHom (RingIso.ringHom (RingsIsomorphic.iso ringFirstIsomorphismTheorem))) {x} {y} x=y = transferToRight (Ring.additiveGroup R2) t
  where
    t : f x +B Group.inverse (Ring.additiveGroup R2) (f y) ∼ Ring.0R R2
    t = transitive (Ring.groupIsAbelian R2) (transitive (Group.+WellDefined (Ring.additiveGroup R2) (symmetric (homRespectsInverse (RingHom.groupHom hom))) reflexive) (transitive (symmetric (GroupHom.groupHom (RingHom.groupHom hom))) x=y))
RingIso.bijective (RingsIsomorphic.iso ringFirstIsomorphismTheorem) = GroupIso.bij (GroupsIsomorphic.proof groupFirstIsomorphismTheorem)

ringFirstIsomorphismTheorem' : RingsIsomorphic quotientByRingHom (subringIsRing R2 imageGroupSubring)
RingsIsomorphic.f ringFirstIsomorphismTheorem' a = f a , (a , reflexive)
RingHom.preserves1 (RingIso.ringHom (RingsIsomorphic.iso ringFirstIsomorphismTheorem')) = RingHom.preserves1 hom
RingHom.ringHom (RingIso.ringHom (RingsIsomorphic.iso ringFirstIsomorphismTheorem')) {r} {s} = RingHom.ringHom hom
RingHom.groupHom (RingIso.ringHom (RingsIsomorphic.iso ringFirstIsomorphismTheorem')) = GroupIso.groupHom (GroupsIsomorphic.proof (groupFirstIsomorphismTheorem'))
RingIso.bijective (RingsIsomorphic.iso ringFirstIsomorphismTheorem') = GroupIso.bij (GroupsIsomorphic.proof groupFirstIsomorphismTheorem')


module Function.Domains.Id where

import      Lvl
open import Functional using (_∘_)
open import Type
open import Type.Dependent

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

module _ {X : Type{ℓₒ₁}} {Y : Type{ℓₒ₂}} where
  data Image (f : X → Y) : Y → Type{ℓₒ₁ Lvl.⊔ ℓₒ₂} where
    intro : (x : X) → Image f (f(x))

  -- The image/range of a function.
  -- Represents the "set" of values of a function.
  -- Note: An element of Y and a proof that this element is the value of the function f is included so that (⊶ f) does not become injective when f is not.
  -- Note: A construction of this implies that X is non-empty.
  ⊶ : (X → Y) → Type{ℓₒ₁ Lvl.⊔ ℓₒ₂}
  ⊶ = Σ(Y) ∘ Image

  -- Represents the "set" of objects pointing to the value y of the function f.
  -- ∃(Fiber f(y)) is also called "the fiber of the element y under the map f".
  -- Fiber(f) is similar to the inverse image or the preimage of f when their argument is a singleton set.
  data Fiber (f : X → Y) : Y → X → Type{ℓₒ₁ Lvl.⊔ ℓₒ₂} where
    intro : (x : X) → Fiber f (f(x)) x


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

open import Algebra
open import Relation.Unary
open import Relation.Binary hiding (Decidable)

module Data.FingerTree.Split.StoredPredicate
  {r m}
  (ℳ : Monoid r m)
  {s}
  {ℙ : Pred (Monoid.Carrier ℳ) s}
  (ℙ-resp : ℙ Respects (Monoid._≈_ ℳ))
  (ℙ? : Decidable ℙ)
  where

open Monoid ℳ renaming (Carrier to 𝓡)
open import Level using (_⊔_)
open import Relation.Nullary

infixl 2 _≈ℙ_[_]
record ⟪ℙ⟫ (x : 𝓡) : Set (s ⊔ r ⊔ m) where
  constructor _≈ℙ_[_]
  field
    result : Dec (ℙ x)
    stored : 𝓡
    equiv  : stored ≈ x
open ⟪ℙ⟫ public

⟪ℙ?⟫ : ∀ x → ⟪ℙ⟫ x
result (⟪ℙ?⟫ x) = ℙ? x
stored (⟪ℙ?⟫ x) = x
equiv  (⟪ℙ?⟫ x) = refl


{- small library for MGS 2021 -}

{- products and sums -}

infix 10 _×_
record _×_ (A B : Set) : Set where
  constructor _,_
  field
    proj₁ : A
    proj₂ : B

open _×_ public

variable
  A B C M : Set

curry : (A × B → C) → (A → B → C)
curry f a b = f (a , b) -- C-c C-,
uncurry : (A → B → C) → (A × B → C)
uncurry f (a , b) = f a b

infix 5 _⊎_
data _⊎_(A B : Set) : Set where
  inj₁ : A → A ⊎ B
  inj₂ : B → A ⊎ B

case : (A → C) → (B → C) → (A ⊎ B → C)
case f g (inj₁ a) = f a
case f g (inj₂ b) = g b

uncase : (A ⊎ B → C) → (A → C) × (B → C)
uncase f = (λ a → f (inj₁ a)) , λ b → f (inj₂ b)

--case' : (A → C) × (B → C) → (A ⊎ B → C)
--case' = uncurry case

record ⊤ : Set where
  constructor tt

open ⊤ public

data ⊥ : Set where

case⊥ : ⊥ → A
case⊥ ()

data Bool : Set where
  true : Bool
  false : Bool

if_then_else_ : Bool → A → A → A
if true then x else y = x
if false then x else y = y

{- bool logic -}

_&_ : Bool → Bool → Bool
true & y = y
false & y = false

{- ∣ = \mid -}

_∣_ : Bool → Bool → Bool
true ∣ y = true
false ∣ y = y

!_ : Bool → Bool
! true = false
! false = true

_⇒b_ : Bool → Bool → Bool
true ⇒b y = y
false ⇒b y = true

{- prop logic -}

prop = Set

variable
  P Q R : prop

infix 3 _∧_
_∧_ : prop → prop → prop
P ∧ Q = P × Q

infix 2 _∨_
_∨_ : prop → prop → prop
P ∨ Q = P ⊎ Q

infixr 1 _⇒_
_⇒_ : prop → prop → prop
P ⇒ Q = P → Q

False : prop
False = ⊥

True : prop
True = ⊤

¬_ : prop → prop
¬ P = P ⇒ False

infix 0 _⇔_
_⇔_ : prop → prop → prop
P ⇔ Q = (P ⇒ Q) ∧ (Q ⇒ P)

efq : False ⇒ P
efq = case⊥

{- classical principles -}

TND : prop → prop
TND P = P ∨ ¬ P

RAA : prop → prop
RAA P = ¬ ¬ P ⇒ P

tnd⇒raa : TND P ⇒ RAA P
tnd⇒raa (inj₁ p) nnp = p
tnd⇒raa (inj₂ np) nnp = efq (nnp np)

nnpnp : ¬ ¬ (P ∨ ¬ P)
nnpnp h = h (inj₂ (λ p → h (inj₁ p)))

raa⇒tnd : RAA (P ∨ ¬ P) ⇒ TND P
raa⇒tnd raa = raa nnpnp

{- natural numbers -}

data ℕ : Set where
  zero : ℕ
  suc : ℕ → ℕ

{-# BUILTIN NATURAL ℕ #-}

infixl 6 _+_

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

infixl 7 _*_

_*_ : ℕ → ℕ → ℕ
zero * n = zero
suc m * n = n + m * n

{- Lists -}

infixr 5 _∷_

data List (A : Set) : Set where
  [] : List A
  _∷_ : A → List A → List A -- \::

_++_ : List A → List A → List A
[] ++ ys = ys
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)

{- Streams -}

record Stream (A : Set) : Set where
  constructor _∷_
  coinductive
  field
    head : A
    tail : Stream A

open Stream public

mapS : (A → B) → Stream A → Stream B
head (mapS f as) = f (head as)
tail (mapS f as) = mapS f (tail as)

{- conatural numbers -}

data Maybe (A : Set) : Set where
  nothing : Maybe A
  just : A → Maybe A

record ℕ∞ : Set where
  coinductive
  field
    pred∞ : Maybe ℕ∞

open ℕ∞ public

zero∞ : ℕ∞
pred∞ zero∞ = nothing

suc∞ : ℕ∞ → ℕ∞
pred∞ (suc∞ n) = just n

∞ : ℕ∞
pred∞ ∞ = just ∞

_+∞_ : ℕ∞ → ℕ∞ → ℕ∞
pred∞ (m +∞ n) with pred∞ m
... | nothing = pred∞ n
... | just m' = just (m' +∞ n)

{- Vectors and Fin -}

variable i j k m n : ℕ

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

_++v_ : Vec A m → Vec A n → Vec A (m + n)
[] ++v ys = ys
(x ∷ xs) ++v ys = x ∷ (xs ++v ys)

data Fin : ℕ → Set where
  zero : Fin (suc n)
  suc : Fin n → Fin (suc n)

_!!v_ : Vec A n → Fin n → A
(x ∷ xs) !!v zero = x
(x ∷ xs) !!v suc i = xs !!v i


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

open import HoTT
open import homotopy.SuspProduct
open import homotopy.SuspSmash
open import homotopy.JoinSusp
open import cohomology.Theory

module cohomology.SphereProduct {i} (CT : CohomologyTheory i)
  (n : ℤ) (m : ℕ) (X : Ptd i) where

  open CohomologyTheory CT
  open import cohomology.Wedge CT

  private
    space-eq : ⊙Susp (⊙Sphere m ⊙× X)
            ⊙≃ ⊙Sphere (S m) ⊙∨ (⊙Susp X ⊙∨ ⊙Susp^ (S m) X)
    space-eq =
      ⊙∨-emap (⊙ide (⊙Sphere (S m)))
        (⊙∨-emap (⊙ide (⊙Susp X))
          (⊙*-Sphere-l m X ⊙∘e SuspSmash.⊙eq (⊙Sphere m) X))
      ⊙∘e SuspProduct.⊙eq (⊙Sphere m) X

  C-Sphere× : C n (⊙Sphere m ⊙× X)
           ≃ᴳ C n (⊙Lift (⊙Sphere m)) ×ᴳ (C n X ×ᴳ C n (⊙Susp^ m X))
  C-Sphere× =
    C n (⊙Sphere m ⊙× X)
      ≃ᴳ⟨ C-Susp n (⊙Sphere m ⊙× X) ⁻¹ᴳ ⟩
    C (succ n) (⊙Susp (⊙Sphere m ⊙× X))
      ≃ᴳ⟨ C-emap (succ n) (space-eq ⊙⁻¹) ⟩
    C (succ n) (⊙Sphere (S m) ⊙∨ (⊙Susp X ⊙∨ ⊙Susp^ (S m) X))
      ≃ᴳ⟨ C-emap (succ n) (⊙∨-emap (⊙Susp-emap (⊙lower-equiv {X = ⊙Sphere m})) (⊙ide _)) ⟩
    C (succ n) (⊙Susp (⊙Lift {j = i} (⊙Sphere m)) ⊙∨ (⊙Susp X ⊙∨ ⊙Susp^ (S m) X))
      ≃ᴳ⟨ C-Wedge (succ n) (⊙Susp (⊙Lift (⊙Sphere m))) (⊙Susp X ⊙∨ ⊙Susp^ (S m) X) ⟩
    C (succ n) (⊙Susp (⊙Lift (⊙Sphere m))) ×ᴳ C (succ n) (⊙Susp X ⊙∨ ⊙Susp^ (S m) X)
      ≃ᴳ⟨ ×ᴳ-emap (C-Susp n (⊙Lift (⊙Sphere m)))
              ( ×ᴳ-emap (C-Susp n X) (C-Susp n (⊙Susp^ m X))
            ∘eᴳ C-Wedge (succ n) (⊙Susp X) (⊙Susp^ (S m) X)) ⟩
    C n (⊙Lift (⊙Sphere m)) ×ᴳ (C n X ×ᴳ C n (⊙Susp^ m X))
      ≃ᴳ∎


module PLRTree.Heap.Correctness {A : Set}(_≤_ : A → A → Set) where

open import BTree.Heap _≤_
open import PLRTree {A}
open import PLRTree.Heap _≤_ renaming (Heap to Heap')

lemma-heap'-heap : {t : PLRTree} → Heap' t → Heap (forget t)
lemma-heap'-heap leaf = leaf
lemma-heap'-heap (node {t} {x} (lf≤* .x) (lf≤* .x) _ _) = single x
lemma-heap'-heap (node {t} {x} (lf≤* .x) (nd≤* x≤y  _ _) _ h'r) = right x≤y (lemma-heap'-heap h'r)
lemma-heap'-heap (node {t} {x} (nd≤* x≤y _ _) (lf≤* .x) h'l _) = left x≤y (lemma-heap'-heap h'l)
lemma-heap'-heap (node (nd≤* x≤y _ _) (nd≤* x≤y' _ _) h'l h'r) = both x≤y x≤y' (lemma-heap'-heap h'l) (lemma-heap'-heap h'r)


open import Level
open import Data.Product
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality using (_≡_; refl; cong)

module AlgProg where

-- 1.1 Datatypes

private
 variable
  l : Level

data Bool : Set where
 false : Bool
 true : Bool

data Char : Set where
 ca : Char
 cb : Char
 cc : Char

data Either : Set where
 bool : Bool → Either
 char : Char → Either

data Both : Set where
 tuple : Bool × Char → Both

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

switch : Both → Both
switch (tuple (b , c)) = tuple (not b , c)

and : (Bool × Bool) → Bool
and (false , _) = false
and (true , b) = b

cand : Bool → Bool → Bool
cand false _ = false
cand true b = b

curry' : {A B C : Set} → (B → (C → A)) → ((B × C) → A)
curry' f (b , c) = f b c

data maybe (A : Set l) : Set l where
 nothing : maybe A
 just : (x : A) → maybe A

-- 1.2 Natural Numbers

data Nat : Set where
 zero' : Nat
 1+ : Nat → Nat

{-# BUILTIN NATURAL Nat #-}

{-
plus : Nat × Nat → Nat
plus (n , zero') = n
plus (n , succ m) = succ (plus (n , m))

mult : Nat × Nat → Nat
mult (n , zero') = zero'
mult (n , succ m) = plus (n , mult (n , m))

-}
_+_ : Nat → Nat → Nat
n + 0 = n
n + (1+ m) = 1+ (n + m)

_*_ : Nat → Nat → Nat
n * 0 = 0
n * (1+ m) = n + (n * m)

fact : Nat → Nat
fact 0 = 1
fact (1+ n) = (1+ n) * (fact n)

fib : Nat → Nat
fib 0 = 0
fib (1+ 0) = 1
fib (1+ (1+ n)) = (fib n) + (fib (1+ n))

foldn : {A : Set} → A → (A → A) → (Nat → A)
foldn c h 0 = c
foldn c h (1+ n) = h (foldn c h n)

foldn1+is+ : (m n : Nat) → (m + n) ≡ ((foldn m 1+) n)
foldn1+is+ m 0 = refl
foldn1+is+ m (1+ n) = cong 1+ (foldn1+is+ m n)

foldn+is* : (m n : Nat) → m * n ≡ (foldn 0 (λ x → m + x)) n
foldn+is* m 0 = refl
foldn+is* m (1+ n) = cong (λ x → m + x) (foldn+is* m n)

expn : Nat → Nat → Nat
expn m = foldn 1 (λ n →  m * n)

outl : {A B : Set} → (A × B) → A
outl (fst , snd) = fst

outr : {A B : Set} → (A × B) → B
outr (fst , snd) = snd

f1 : (Nat × Nat) → Nat × Nat
f1 (m , n) = (1+ m , (1+ m) * n)

rec-× : {A B C D : Set} → (f : A → B) → (g : C → D) → ((A × C) -> (B × D))
rec-× f g (a , c) = (f a , g c)

outrFoldnIsFact : (n : Nat) → (foldn (0 , 1) f1 n) ≡ (n , fact n)
outrFoldnIsFact zero' = refl
outrFoldnIsFact (1+ n) rewrite (outrFoldnIsFact n) = refl

-- 1.3 Lists

data listr (A : Set l) : Set l where
 nil : listr A
 cons : A → listr A → listr A

data listl (A : Set l) : Set l where
 nil : listl A
 snoc : listl A → A → listl A

snocr : {A : Set} → listr A → A → listr A
snocr nil a = cons a nil
snocr (cons a0 as) a1 = cons a0 (snocr as a1)

convert : {A : Set} → listl A → listr A
convert nil = nil
convert (snoc xs x) = snocr (convert xs) x

_++_ : {A : Set} → listl A → listl A → listl A
xs ++ nil = xs
xs ++ snoc ys x = snoc (xs ++ ys) x

++-assoc : {A : Set} → (xs ys zs : listl A) → (xs ++ (ys ++ zs)) ≡ ((xs ++ ys) ++ zs)
++-assoc xs ys nil = refl
++-assoc xs ys (snoc zs x) = cong (λ y → snoc y x) (++-assoc xs ys zs)

listrF : {A B : Set} → (A → B) → listr A → listr B
listrF f nil = nil
listrF f (cons x as) = cons (f x) (listrF f as)

foldr : {A B : Set} → B → (A → B → B) → (listr A → B)
foldr c h nil = c
foldr c h (cons a as) = h a (foldr c h as)


-- Andreas, 2014-01-24, Issue 1411
-- First split might not succeed in the unifier,
-- so try later splits also.

-- {-# OPTIONS -v tc.lhs:10 #-}

open import Common.Prelude
open import Common.Equality

data Fin : Nat → Set where
  fzero : (n : Nat) → Fin (suc n)
  fsuc  : (n : Nat) → (i : Fin n) → Fin (suc n)

data _≅_ {A : Set} (a : A) : {B : Set} (b : B) → Set where
  refl : a ≅ a

works : ∀ n m (i : Fin n) (j : Fin m) → n ≡ m → fsuc n i ≅ fsuc m j → i ≅ j
works n .n i .i refl refl = refl

fails : ∀ n m (i : Fin n) (j : Fin m) → fsuc n i ≅ fsuc m j → n ≡ m → i ≅ j
fails n .n i .i refl refl = refl

-- Refuse to solve heterogeneous constraint i : Fin n =?= j : Fin m
-- when checking that the pattern refl has type fsuc n i ≅ fsuc m j

-- Should work now.


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

open import Groups.Definition
open import Groups.Lemmas
open import Groups.Abelian.Definition
open import Setoids.Setoids
open import Sets.EquivalenceRelations
open import Rings.Definition
open import Modules.Definition

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

open Group G'
open Ring R
open Setoid T
open Equivalence eq
open Module mod

moduleTimesZero : {x : M} → (0R · x) ∼ 0G
moduleTimesZero {x} = equalsDoubleImpliesZero G' (symmetric x=2x)
  where
    x=2x : (0R · x) ∼ (0R · x) + (0R · x)
    x=2x = transitive (dotWellDefined (Equivalence.symmetric (Setoid.eq S) (Group.identLeft additiveGroup)) reflexive) dotDistributesRight

moduleTimes-1 : {x : M} → ((Group.inverse additiveGroup 1R) · x) ∼ inverse x
moduleTimes-1 {x} = transitive (transferToRight' G' j) (inverseWellDefined G' dotIdentity)
  where
    i : ((1R · x) + ((Group.inverse additiveGroup 1R) · x)) ∼ 0G
    i = transitive (symmetric (transitive (dotWellDefined (Equivalence.symmetric (Setoid.eq S) (Group.invRight additiveGroup {1R})) reflexive) dotDistributesRight)) (moduleTimesZero)
    j : (((Group.inverse additiveGroup 1R) · x) + (1R · x)) ∼ 0G
    j = transitive (AbelianGroup.commutative G) i


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

module Fragment.Algebra.Free.Atoms where

open import Level using (Level; _⊔_)

open import Data.Nat using (ℕ)
open import Data.Fin using (Fin)

open import Relation.Binary using (Setoid; IsEquivalence)
open import Relation.Binary.PropositionalEquality as PE using (_≡_)

private
  variable
    a ℓ : Level

module _ (A : Set a) where

  data BT (n : ℕ) : Set a where
    sta : A → BT n
    dyn : Fin n → BT n

module _ (S : Setoid a ℓ) (n : ℕ) where

  open Setoid S renaming (Carrier to A)

  data _≍_ : BT A n → BT A n → Set (a ⊔ ℓ) where
    sta : ∀ {x y} → x ≈ y → sta x ≍ sta y
    dyn : ∀ {x y} → x ≡ y → dyn x ≍ dyn y

  private

    ≍-refl : ∀ {x} → x ≍ x
    ≍-refl {sta _} = sta refl
    ≍-refl {dyn _} = dyn PE.refl

    ≍-sym : ∀ {x y} → x ≍ y → y ≍ x
    ≍-sym (sta x≈y) = sta (sym x≈y)
    ≍-sym (dyn x≡y) = dyn (PE.sym x≡y)

    ≍-trans : ∀ {x y z} → x ≍ y → y ≍ z → x ≍ z
    ≍-trans (sta x≈y) (sta y≈z) = sta (trans x≈y y≈z)
    ≍-trans (dyn x≡y) (dyn y≡z) = dyn (PE.trans x≡y y≡z)

    ≍-isEquivalence : IsEquivalence _≍_
    ≍-isEquivalence = record { refl  = ≍-refl
                             ; sym   = ≍-sym
                             ; trans = ≍-trans
                             }

  Atoms : Setoid a (a ⊔ ℓ)
  Atoms = record { Carrier       = BT (Setoid.Carrier S) n
                 ; _≈_           = _≍_
                 ; isEquivalence = ≍-isEquivalence
                 }


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

module T where

open import Level
open import Relation.Binary.PropositionalEquality
  using (_≡_; refl; sym; trans; cong; subst; module ≡-Reasoning)
open import Data.Nat using (ℕ; _+_)
open import Data.Fin using (Fin)

data Exp : Set where
  ONE   : Exp
  PLUS  : Exp → Exp → Exp

val : Exp → ℕ
val ONE           = 1
val (PLUS e₁ e₂)  = val e₁ + val e₂

data eqExp : Exp → Exp → Set where
  idExp    : {e : Exp} → eqExp e e
  transExp : {e₁ e₂ e₃ : Exp} → (eqExp e₁ e₂) → (eqExp e₂ e₃) → (eqExp e₁ e₃)

val≡ : {e₁ e₂ : Exp} → (eqExp e₁ e₂) → (val e₁ ≡ val e₂)
val≡ idExp = refl
val≡ (transExp α₁ α₂) = trans (val≡ α₁) (val≡ α₂)

trans-assoc : {A : Set} {x y z w : A} → (p : x ≡ y) (q : y ≡ z) (r : z ≡ w) →
  trans (trans p q) r ≡ trans p (trans q r)
trans-assoc refl refl refl = refl

subst-trans : (P : ℕ → Set) (p : (n : ℕ) → P n) {e₁ e₂ e₃ : Exp} →
              (α : eqExp e₁ e₂) (β : eqExp e₂ e₃) (v : P (val e₁)) →
              subst P (trans (val≡ α) (val≡ β)) v ≡
              subst P (val≡ β) (subst P (val≡ α) v)
subst-trans P p idExp β v = refl
subst-trans P p (transExp α₁ α₂) β v =
  begin (subst P (trans (trans (val≡ α₁) (val≡ α₂)) (val≡ β)) v
         ≡⟨ cong (λ x → subst P x v)
                 (trans-assoc (val≡ α₁) (val≡ α₂) (val≡ β))  ⟩
         subst P (trans (val≡ α₁) (trans (val≡ α₂) (val≡ β))) v
         ≡⟨ refl ⟩
         subst P (trans (val≡ α₁) (val≡ (transExp α₂ β))) v
         ≡⟨  subst-trans P p α₁ (transExp α₂ β) v ⟩
         subst P (val≡ (transExp α₂ β)) (subst P (val≡ α₁) v)
         ≡⟨ refl ⟩
         subst P (trans (val≡ α₂) (val≡ β)) (subst P (val≡ α₁) v)
         ≡⟨ subst-trans P p α₂ β (subst P (val≡ α₁) v) ⟩
         subst P (val≡ β) (subst P (val≡ α₂) (subst P (val≡ α₁) v))
         ≡⟨ cong (λ x → subst P (val≡ β) x) (sym (subst-trans P p α₁ α₂ v)) ⟩
         subst P (val≡ β) (subst P (trans (val≡ α₁) (val≡ α₂)) v)
         ≡⟨ refl ⟩
         subst P (val≡ β) (subst P (val≡ (transExp α₁ α₂)) v) ∎)
  where open ≡-Reasoning

pr : {P : ℕ → Set} {p : (n : ℕ) → P n} {e₁ e₂ : Exp} {α : eqExp e₁ e₂} →
    subst P (val≡ α) (p (val e₁)) ≡ p (val e₂)
pr {P} {p} {e} {.e} {idExp} = refl
pr {P} {p} {e₁} {e₃} {transExp {e₂ = e₂} α β} =
  begin (subst P (val≡ (transExp α β)) (p (val e₁))
           ≡⟨ refl ⟩
         subst P (trans (val≡ α) (val≡ β)) (p (val e₁))
           ≡⟨ subst-trans P p α β (p (val e₁)) ⟩
         subst P (val≡ β) (subst P (val≡ α) (p (val e₁)))
           ≡⟨ cong (λ x → subst P (val≡ β) x) (pr {P} {p} {e₁} {e₂} {α}) ⟩
         subst P (val≡ β) (p (val e₂))
           ≡⟨ pr {P} {p} {e₂} {e₃} {β} ⟩
         p (val e₃) ∎)
  where open ≡-Reasoning


------------------------------------------------------------------------------
-- Agda-Prop Library.
------------------------------------------------------------------------------

open import Data.Nat using ( ℕ )

module Data.PropFormula.Dec ( n : ℕ ) where

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

open import Data.PropFormula.Syntax n

open import Data.Bool.Base using  ( Bool; false; true; not; T )
open import Data.Fin       using  ( Fin; suc; zero )
open import Data.Empty     hiding (⊥)

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

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

data ⊥₂ : Set where

⊥₂-elim : ∀ {Whatever : Set} → ⊥₂ → Whatever
⊥₂-elim ()

infix 3 ¬₂_

¬₂_ : Set → Set
¬₂ P = P → ⊥₂

-- Decidable relations.

data Dec (P : Set) : Set where
  yes : ( p :    P) → Dec P
  no  : (¬p : ¬₂ P) → Dec P

⌊_⌋ : {P : Set} → Dec P → Bool
⌊ yes _ ⌋ = true
⌊ no  _ ⌋ = false

REL : Set → Set → Set₁
REL A B = A → B → Set

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


module Adjoint where

import Category
import Functor

open Category
open Functor using (Functor)

module Adj where

  open Functor.Projections using (Map; map)

  data _⊢_ {ℂ ⅅ : Cat}(F : Functor ℂ ⅅ)(G : Functor ⅅ ℂ) : Set1 where
    adjunction :
      (_*   : {X : Obj ℂ}{Y : Obj ⅅ} -> Map F X ─→ Y -> X ─→ Map G Y)
      (_#   : {X : Obj ℂ}{Y : Obj ⅅ} -> X ─→ Map G Y -> Map F X ─→ Y)
      (inv₁ : {X : Obj ℂ}{Y : Obj ⅅ}(g : X ─→ Map G Y) -> g # * == g)
      (inv₂ : {X : Obj ℂ}{Y : Obj ⅅ}(f : Map F X ─→ Y) -> f * # == f)
      (nat₁ : {X₁ X₂ : Obj ℂ}{Y₁ Y₂ : Obj ⅅ}
	      (f : Y₁ ─→ Y₂)(g : X₂ ─→ X₁)(h : Map F X₁ ─→ Y₁) ->
	      (f ∘ h ∘ map F g) * == map G f ∘ (h *) ∘ g
      )
      (nat₂ : {X₁ X₂ : Obj ℂ}{Y₁ Y₂ : Obj ⅅ}
	      (f : Y₁ ─→ Y₂)(g : X₂ ─→ X₁)(h : X₁ ─→ Map G Y₁) ->
	      (map G f ∘ h ∘ g) # == f ∘ (h #) ∘ map F g
      )
      -> F ⊢ G

open Adj public


------------------------------------------------------------------------------
-- Proving properties without using pattern matching on refl
------------------------------------------------------------------------------

{-# OPTIONS --no-pattern-matching #-}
{-# OPTIONS --exact-split              #-}
{-# OPTIONS --no-sized-types           #-}
{-# OPTIONS --no-universe-polymorphism #-}

module FOT.GroupTheory.NoPatternMatchingOnRefl where

open import GroupTheory.Base

------------------------------------------------------------------------------
-- From GroupTheory.PropertiesI

-- Congruence properties

-- The propositional equality is compatible with the binary operation.

·-leftCong : ∀ {a b c} → a ≡ b → a · c ≡ b · c
·-leftCong {a} {c = c} h = subst (λ t → a · c ≡ t · c) h refl

·-rightCong : ∀ {a b c} → b ≡ c → a · b ≡ a · c
·-rightCong {a} {b} h = subst (λ t → a · b ≡ a · t) h refl

-- The propositional equality is compatible with the inverse function.
⁻¹-cong : ∀ {a b} → a ≡ b → a ⁻¹ ≡ b ⁻¹
⁻¹-cong {a} h = subst (λ t → a ⁻¹ ≡ t ⁻¹) h refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Lists made up entirely of unique elements (setoid equality)
------------------------------------------------------------------------

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

open import Relation.Binary using (Rel; Setoid)

module Data.List.Relation.Unary.Unique.Setoid {a ℓ} (S : Setoid a ℓ) where

open Setoid S renaming (Carrier to A)

open import Data.List.Base
import Data.List.Relation.Unary.AllPairs as AllPairsM
open import Level using (_⊔_)
open import Relation.Unary using (Pred)
open import Relation.Nullary using (¬_)

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

private

  Distinct : Rel A ℓ
  Distinct x y = ¬ (x ≈ y)

open import Data.List.Relation.Unary.AllPairs.Core Distinct
     renaming (AllPairs to Unique)
     public

open import Data.List.Relation.Unary.AllPairs {R = Distinct}
     using (head; tail)
     public


------------------------------------------------------------------------
-- The Agda standard library
--
-- Some derivable properties
------------------------------------------------------------------------

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

open import Algebra

module Algebra.Properties.Ring {r₁ r₂} (R : Ring r₁ r₂) where

import Algebra.Properties.AbelianGroup as AGP
open import Function
import Relation.Binary.Reasoning.Setoid as EqR

open Ring R
open EqR setoid

open AGP +-abelianGroup public
  renaming ( ⁻¹-involutive to -‿involutive
           ; left-identity-unique to +-left-identity-unique
           ; right-identity-unique to +-right-identity-unique
           ; identity-unique to +-identity-unique
           ; left-inverse-unique to +-left-inverse-unique
           ; right-inverse-unique to +-right-inverse-unique
           ; ⁻¹-∙-comm to -‿+-comm
           )

-‿*-distribˡ : ∀ x y → - x * y ≈ - (x * y)
-‿*-distribˡ x y = begin
  - x * y                        ≈⟨ sym $ +-identityʳ _ ⟩
  - x * y + 0#                   ≈⟨ +-congˡ $ sym (-‿inverseʳ _) ⟩
  - x * y + (x * y + - (x * y))  ≈⟨ sym $ +-assoc _ _ _  ⟩
  - x * y + x * y + - (x * y)    ≈⟨ +-congʳ $ sym (distribʳ _ _ _) ⟩
  (- x + x) * y + - (x * y)      ≈⟨ +-congʳ $ *-congʳ $ -‿inverseˡ _ ⟩
  0# * y + - (x * y)             ≈⟨ +-congʳ $ zeroˡ _ ⟩
  0# + - (x * y)                 ≈⟨ +-identityˡ _ ⟩
  - (x * y)                      ∎

-‿*-distribʳ : ∀ x y → x * - y ≈ - (x * y)
-‿*-distribʳ x y = begin
  x * - y                        ≈⟨ sym $ +-identityˡ _ ⟩
  0# + x * - y                   ≈⟨ +-congʳ $ sym (-‿inverseˡ _) ⟩
  - (x * y) + x * y + x * - y    ≈⟨ +-assoc _ _ _  ⟩
  - (x * y) + (x * y + x * - y)  ≈⟨ +-congˡ $ sym (distribˡ _ _ _)  ⟩
  - (x * y) + x * (y + - y)      ≈⟨ +-congˡ $ *-congˡ $ -‿inverseʳ _ ⟩
  - (x * y) + x * 0#             ≈⟨ +-congˡ $ zeroʳ _ ⟩
  - (x * y) + 0#                 ≈⟨ +-identityʳ _ ⟩
  - (x * y)                      ∎


{-# OPTIONS --safe --experimental-lossy-unification #-}
module Cubical.Algebra.CommRing.Instances.MultivariatePoly-notationZ where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Nat
open import Cubical.Data.FinData

open import Cubical.Relation.Nullary

open import Cubical.Algebra.Ring
open import Cubical.Algebra.CommRing
open import Cubical.Algebra.CommRing.FGIdeal
open import Cubical.Algebra.CommRing.QuotientRing
open import Cubical.Algebra.CommRing.Instances.Int

open import Cubical.Algebra.Polynomials.Multivariate.Base
open import Cubical.Algebra.CommRing.Instances.MultivariatePoly
open import Cubical.Algebra.CommRing.Instances.MultivariatePoly-Quotient

-- Notations for ℤ polynomial rings

ℤ[X] : CommRing ℓ-zero
ℤ[X] = PolyCommRing ℤCommRing 1

ℤ[x] : Type ℓ-zero
ℤ[x] = fst ℤ[X]

ℤ[X,Y] : CommRing ℓ-zero
ℤ[X,Y] = PolyCommRing ℤCommRing 2

ℤ[x,y] : Type ℓ-zero
ℤ[x,y] = fst ℤ[X,Y]

ℤ[X,Y,Z] : CommRing ℓ-zero
ℤ[X,Y,Z] = PolyCommRing ℤCommRing 3

ℤ[x,y,z] : Type ℓ-zero
ℤ[x,y,z] = fst ℤ[X,Y,Z]

ℤ[X1,···,Xn] : (n : ℕ) → CommRing ℓ-zero
ℤ[X1,···,Xn] n = A[X1,···,Xn] ℤCommRing n

ℤ[x1,···,xn] : (n : ℕ) → Type ℓ-zero
ℤ[x1,···,xn] n = fst (ℤ[X1,···,Xn] n)

-- Notation for quotiented ℤ polynomial ring

<X> : FinVec ℤ[x] 1
<X> = <Xkʲ> ℤCommRing 1 0 1

<X²> : FinVec ℤ[x] 1
<X²> = <Xkʲ> ℤCommRing 1 0 2

<X³> : FinVec ℤ[x] 1
<X³> = <Xkʲ> ℤCommRing 1 0 3

<Xᵏ> : (k  : ℕ) → FinVec ℤ[x] 1
<Xᵏ> k = <Xkʲ> ℤCommRing 1 0 k

ℤ[X]/X : CommRing ℓ-zero
ℤ[X]/X = A[X1,···,Xn]/<Xkʲ> ℤCommRing 1 0 1

ℤ[x]/x : Type ℓ-zero
ℤ[x]/x = fst ℤ[X]/X

ℤ[X]/X² : CommRing ℓ-zero
ℤ[X]/X² = A[X1,···,Xn]/<Xkʲ> ℤCommRing 1 0 2

ℤ[x]/x² : Type ℓ-zero
ℤ[x]/x² = fst ℤ[X]/X²

ℤ[X]/X³ : CommRing ℓ-zero
ℤ[X]/X³ = A[X1,···,Xn]/<Xkʲ> ℤCommRing 1 0 3

ℤ[x]/x³ : Type ℓ-zero
ℤ[x]/x³ = fst ℤ[X]/X³

ℤ[X1,···,Xn]/<X1,···,Xn> : (n : ℕ) → CommRing ℓ-zero
ℤ[X1,···,Xn]/<X1,···,Xn> n = A[X1,···,Xn]/<X1,···,Xn> ℤCommRing n

ℤ[x1,···,xn]/<x1,···,xn> : (n : ℕ) → Type ℓ-zero
ℤ[x1,···,xn]/<x1,···,xn> n = fst (ℤ[X1,···,Xn]/<X1,···,Xn> n)

-- Warning there is two possible definitions of ℤ[X]
-- they only holds up to a path

ℤ'[X]/X : CommRing ℓ-zero
ℤ'[X]/X = A[X1,···,Xn]/<X1,···,Xn> ℤCommRing 1

equivℤ[X] : ℤ'[X]/X ≡ ℤ[X]/X
equivℤ[X] = cong (λ X → (A[X1,···,Xn] ℤCommRing 1) / (genIdeal ((A[X1,···,Xn] ℤCommRing 1)) X))
                   (funExt (λ {zero → refl }))


------------------------------------------------------------------------------
-- Propositional equality
------------------------------------------------------------------------------

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

-- This module is re-exported by (some) "base" modules.

module Common.FOL.Relation.Binary.PropositionalEquality where

open import Common.FOL.FOL using ( D )

infix 4 _≡_

------------------------------------------------------------------------------
-- The identity type on the universe of discourse.
data _≡_ (x : D) : D → Set where
  refl : x ≡ x

-- Elimination rule.
subst : (A : D → Set) → ∀ {x y} → x ≡ y → A x → A y
subst A refl Ax = Ax

-- Identity properties

sym : ∀ {x y} → x ≡ y → y ≡ x
sym refl = refl

trans : ∀ {x y z} → x ≡ y → y ≡ z → x ≡ z
trans refl h = h

trans₂ : ∀ {w x y z} → w ≡ x → x ≡ y → y ≡ z → w ≡ z
trans₂ refl refl h = h

subst₂ : (A : D → D → Set) → ∀ {x x' y y'} →
         x ≡ y → x' ≡ y' →
         A x x' →
         A y y'
subst₂ A refl refl Axs = Axs

subst₃ : (A : D → D → D → Set) → ∀ {x₁ x₂ x₃ y₁ y₂ y₃} →
         x₁ ≡ y₁ → x₂ ≡ y₂ → x₃ ≡ y₃ →
         A x₁ x₂ x₃ →
         A y₁ y₂ y₃
subst₃ A refl refl refl Axs = Axs

subst₄ : (A : D → D → D → D → Set) → ∀ {x₁ x₂ x₃ x₄ y₁ y₂ y₃ y₄} →
         x₁ ≡ y₁ → x₂ ≡ y₂ → x₃ ≡ y₃ → x₄ ≡ y₄ →
         A x₁ x₂ x₃ x₄ →
         A y₁ y₂ y₃ y₄
subst₄ A refl refl refl refl Axs = Axs