module Ag03 where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; sym)
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)
open import Data.Nat.Properties using (+-comm; *-comm; +-suc)

data _≤_ : ℕ → ℕ → Set where

  z≤n : ∀ {n : ℕ} → zero ≤ n
  s≤s : ∀ {m n : ℕ} → m ≤ n → suc m ≤ suc n

infix 4 _≤_

inv-s≤s : ∀ {m n : ℕ}
  → suc m ≤ suc n
  → m ≤ n

inv-s≤s (s≤s m≤n) = m≤n

inv-z≤n : ∀ {m : ℕ}
  → m ≤ zero
  → m ≡ zero

inv-z≤n z≤n = refl

≤-refl : ∀ {n : ℕ} → n ≤ n
≤-refl {0} = z≤n
≤-refl {suc n} = s≤s ≤-refl

≤-trans : ∀ {m n p : ℕ } → m ≤ n → n ≤ p → m ≤ p
≤-trans z≤n _ = z≤n
≤-trans (s≤s m≤n) (s≤s n≤p) = s≤s (≤-trans m≤n n≤p)

≤-antisym : ∀ {m n : ℕ} → m ≤ n → n ≤ m → m ≡ n
≤-antisym z≤n z≤n = refl
≤-antisym (s≤s m≤n) (s≤s n≤m) = cong suc (≤-antisym m≤n n≤m)

data Total (m n : ℕ) : Set where
  forward :
    m ≤ n → Total m n
  flipped :
    n ≤ m → Total m n

+-monoʳ-≤ : ∀ (n p q : ℕ)
  → p ≤ q
    -------------
  → n + p ≤ n + q
+-monoʳ-≤ zero    p q p≤q  =  p≤q
+-monoʳ-≤ (suc n) p q p≤q  =  s≤s (+-monoʳ-≤ n p q p≤q)

+-monoˡ-≤ : ∀ (m n p : ℕ)
  → m ≤ n
    -------------
  → m + p ≤ n + p
+-monoˡ-≤ m n p m≤n  rewrite +-comm m p | +-comm n p  = +-monoʳ-≤ p m n m≤n

+-mono-≤ : ∀ (m n p q : ℕ)
  → m ≤ n
  → p ≤ q
    -------------
  → m + p ≤ n + q
+-mono-≤ m n p q m≤n p≤q  =  ≤-trans (+-monoˡ-≤ m n p m≤n) (+-monoʳ-≤ n p q p≤q)

*-mono-ʳ : ∀ (n p q : ℕ) → p ≤ q → n * p ≤ n * q
*-mono-ʳ 0 _ _ p≤q = z≤n
*-mono-ʳ (suc n) p q p≤q = +-mono-≤ p q (n * p) (n * q) p≤q (*-mono-ʳ n p q p≤q)

*-mono-ˡ : ∀ (m n p : ℕ) → m ≤ n → m * p ≤ n * p
*-mono-ˡ m n p m≤n rewrite *-comm m p | *-comm n p = *-mono-ʳ p m n m≤n

*-mono : ∀ (m n p q : ℕ) → m ≤ n → p ≤ q → m * p ≤ n * q
*-mono m n p q m≤n p≤q = ≤-trans (*-mono-ˡ m n p m≤n) (*-mono-ʳ n p q p≤q)

infix 4 _⟨_

data _⟨_ : ℕ → ℕ → Set where
  z⟨s : ∀ {n : ℕ} → 0 ⟨ suc n
  s⟨s : ∀ {m n : ℕ} → m ⟨ n → suc m ⟨ suc n

⟨-trans : ∀ {m n p : ℕ} → m ⟨ n → n ⟨ p → m ⟨ p
⟨-trans z⟨s (s⟨s n⟨p) = z⟨s
⟨-trans (s⟨s m⟨n) (s⟨s n⟨p) = s⟨s (⟨-trans m⟨n n⟨p)

data Total-trichotomy (m n : ℕ) : Set where
  lt : m ⟨ n → Total-trichotomy m n
  eq : m ≡ n → Total-trichotomy m n
  gt : n ⟨ m → Total-trichotomy m n

trichotomy : ∀ (m n : ℕ) → Total-trichotomy m n
trichotomy zero zero = eq refl
trichotomy zero (suc n) = lt z⟨s
trichotomy (suc m) zero = gt z⟨s
trichotomy (suc m) (suc n) with trichotomy m n
...                          | lt m⟨n = lt (s⟨s m⟨n)
...                          | eq m≡n = eq (cong suc m≡n)
...                          | gt n⟨m = gt (s⟨s n⟨m)

+-monoʳ-⟨ : ∀ (n p q : ℕ) → p ⟨ q → n + p ⟨ n + q
+-monoʳ-⟨ 0 _ _ p⟨q = p⟨q
+-monoʳ-⟨ (suc n) p q p⟨q = s⟨s (+-monoʳ-⟨ n p q p⟨q)

+-monoˡ-⟨ : ∀ (m n p : ℕ) → m ⟨ n → m + p ⟨ n + p
+-monoˡ-⟨ m n p m⟨n rewrite +-comm m p | +-comm n p = +-monoʳ-⟨ p m n m⟨n

+-mono-⟨ : ∀ (m n p q : ℕ) → m ⟨ n → p ⟨ q → m + p ⟨ n + q
+-mono-⟨ m n p q m⟨n p⟨q = ⟨-trans (+-monoˡ-⟨ m n p m⟨n) (+-monoʳ-⟨ n p q p⟨q)

≤-iffˡ-⟨ : ∀ (m n : ℕ) → suc m ≤ n → m ⟨ n
≤-iffˡ-⟨ 0 _ (s≤s z≤n) = z⟨s
≤-iffˡ-⟨ (suc m) (suc n) (s≤s sm≤n) = s⟨s (≤-iffˡ-⟨ m n sm≤n)

≤-iffʳ-⟨ : ∀ (m n : ℕ) → m ⟨ n → suc m ≤ n
≤-iffʳ-⟨ .0 .(suc _) z⟨s = s≤s z≤n
≤-iffʳ-⟨ .(suc _) .(suc _) (s⟨s m⟨n) = s≤s (≤-iffʳ-⟨ _ _ m⟨n)

data Even : ℕ → Set
data Odd  : ℕ → Set

data Even where

  zero :
      ---------
      Even zero

  suc  : ∀ {n : ℕ}
    → Odd n
      ------------
    → Even (suc n)

data Odd where

  suc   : ∀ {n : ℕ}
    → Even n
      -----------
    → Odd (suc n)

e+e≡e : ∀ {m n : ℕ}
  → Even m
  → Even n
    ------------
  → Even (m + n)

o+e≡o : ∀ {m n : ℕ}
  → Odd m
  → Even n
    -----------
  → Odd (m + n)

e+e≡e zero     en  =  en
e+e≡e (suc om) en  =  suc (o+e≡o om en)

o+e≡o (suc em) en  =  suc (e+e≡e em en)

o+o≡e : ∀ {m n : ℕ} → Odd m → Odd n → Even (m + n)
o+o≡e {m} {suc n} om (suc en) rewrite +-suc m n = suc (o+e≡o om en)

e+o≡o : ∀ (m n : ℕ) → Even m → Odd n → Odd(m + n)
e+o≡o .0 .(suc _) zero (suc x) = suc x
e+o≡o (suc m) (suc n) (suc x) (suc x₁) rewrite +-suc m n = suc (suc (o+e≡o x x₁))

infixl 7 _e*e_ _o*e_ _o*o_ _e*o_
_e*e_ : ∀ {m n : ℕ} → Even m → Even n → Even (m * n)
_o*e_ : ∀ {m n : ℕ} → Odd  m → Even n → Even (m * n)
_o*o_ : ∀ {m n : ℕ} → Odd  m → Odd  n → Odd  (m * n)
_e*o_ : ∀ {m n : ℕ} → Even m → Odd  n → Even (m * n)

zero e*e en  = zero
suc x e*e en = e+e≡e en (x o*e en)

suc x o*e en = e+e≡e en (x e*e en)

suc x o*o on = o+e≡o on (x e*o on)

zero e*o on  = zero
suc x e*o on = o+o≡e on (x o*o on)


module Logics.Or where

open import Function
open import Logics.And

------------------------------------------------------------------------
-- definitions

infixl 4 _∨_

data _∨_ (P Q : Set) : Set where
  ∨-intro₀ : P → P ∨ Q
  ∨-intro₁ : Q → P ∨ Q

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

private

  p→r+q→r+p∨q=r : ∀ {P Q n} {R : Set n} → (P → R) → (Q → R) → (P ∨ Q) → R
  p→r+q→r+p∨q=r pr _ (∨-intro₀ p) = pr p
  p→r+q→r+p∨q=r _ qr (∨-intro₁ q) = qr q

  ∨-comm′ : ∀ {P Q} → (P ∨ Q) → (Q ∨ P)
  ∨-comm′ (∨-intro₀ p) = ∨-intro₁ p
  ∨-comm′ (∨-intro₁ q) = ∨-intro₀ q

  ∨-assoc₀ : ∀ {P Q R} → ((P ∨ Q) ∨ R) → (P ∨ (Q ∨ R))
  ∨-assoc₀ (∨-intro₀ (∨-intro₀ x)) = ∨-intro₀ x
  ∨-assoc₀ (∨-intro₀ (∨-intro₁ x)) = ∨-intro₁ $ ∨-intro₀ x
  ∨-assoc₀ (∨-intro₁ x) = ∨-intro₁ $ ∨-intro₁ x

  ∨-assoc₁ : ∀ {P Q R} → (P ∨ (Q ∨ R)) → ((P ∨ Q) ∨ R)
  ∨-assoc₁ (∨-intro₀ x) = ∨-intro₀ $ ∨-intro₀ x
  ∨-assoc₁ (∨-intro₁ (∨-intro₀ x)) = ∨-intro₀ $ ∨-intro₁ x
  ∨-assoc₁ (∨-intro₁ (∨-intro₁ x)) = ∨-intro₁ x

  ∨-elim : ∀ {P Q n} {R : Set n} → (P → R) → (Q → R) → (P ∨ Q) → R
  ∨-elim = p→r+q→r+p∨q=r

  ∨-comm : ∀ {P Q} → (P ∨ Q) ⇔ (Q ∨ P)
  ∨-comm = ∧-intro ∨-comm′ ∨-comm′

  ∨-assoc : ∀ {P Q R} → (P ∨ (Q ∨ R)) ⇔ ((P ∨ Q) ∨ R)
  ∨-assoc = ∧-intro ∨-assoc₁ ∨-assoc₀

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

or-elim : ∀ {P Q n} {R : Set n} → (P → R) → (Q → R) → (P ∨ Q) → R
or-elim = ∨-elim

or-comm : ∀ {P Q} → (P ∨ Q) ⇔ (Q ∨ P)
or-comm = ∨-comm

or-assoc : ∀ {P Q R} → (P ∨ (Q ∨ R)) ⇔ ((P ∨ Q) ∨ R)
or-assoc = ∨-assoc


------------------------------------------------------------------------
-- The Agda standard library
--
-- Lists where every pair of elements are related (symmetrically)
------------------------------------------------------------------------

-- Core modules are not meant to be used directly outside of the
-- standard library.

-- This module should be removable if and when Agda issue
-- https://github.com/agda/agda/issues/3210 is fixed

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

open import Relation.Binary using (Rel)

module Data.List.Relation.Unary.AllPairs.Core
       {a ℓ} {A : Set a} (R : Rel A ℓ) where

open import Level
open import Data.List.Base
open import Data.List.Relation.Unary.All

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

-- AllPairs R xs means that every pair of elements (x , y) in xs is a
-- member of relation R (as long as x comes before y in the list).

infixr 5 _∷_

data AllPairs : List A → Set (a ⊔ ℓ) where
  []  : AllPairs []
  _∷_ : ∀ {x xs} → All (R x) xs → AllPairs xs → AllPairs (x ∷ xs)


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

open import HoTT
open import homotopy.OneSkeleton

module homotopy.ConstantToSetFactorization
  {i j} {A : Type i} {B : Type j} (B-is-set : is-set B)
  (f : A → B) (f-is-const : ∀ a₁ a₂ → f a₁ == f a₂) where

  private
    Skel : Type i
    Skel = Trunc ⟨0⟩ (OneSkeleton f)

    abstract
      Skel-has-all-paths : has-all-paths Skel
      Skel-has-all-paths =
        Trunc-elim (λ _ → Π-is-set λ _ → =-preserves-set Trunc-level)
          (OneSkeleton-elim {P = λ s₁ → ∀ [s₂] → [ s₁ ] == [s₂]}
            (λ a₁ → Trunc-elim (λ _ → =-preserves-set Trunc-level)
              (OneSkeleton-elim {P = λ s₂ → [ point a₁ ] == [ s₂ ]}
                (λ a₂ → ap [_] $ link a₁ a₂ $ f-is-const a₁ a₂)
                (λ _ _ _ → prop-has-all-paths-↓ (Trunc-level {n = ⟨0⟩} _ _))))
            (λ a₁ a₂ p → ↓-cst→app-in λ s₂ →
              prop-has-all-paths-↓ (Trunc-level {n = ⟨0⟩} _ _)))

    Skel-is-prop : is-prop Skel
    Skel-is-prop = all-paths-is-prop Skel-has-all-paths

  cst-extend : Trunc ⟨-1⟩ A → B
  cst-extend = Trunc-rec B-is-set OneSkeleton-lift
             ∘ Trunc-rec Skel-is-prop ([_] ∘ point)

  -- The beta rule.
  -- This is definitionally true, so you don't need it.
  cst-extend-β : cst-extend ∘ [_] == f
  cst-extend-β = idp


import      Lvl
open import Data.Boolean
open import Type

module Data.List.Sorting.MergeSort {ℓ} {T : Type{ℓ}} (_≤?_ : T → T → Bool) where

open import Data.List
open import Data.List.Functions as List
open import Data.List.Relation.Membership as Membership using (_∈_ ; use ; skip)
open import Data.List.Relation.Membership.Proofs
open import Data.List.Sorting.Functions(_≤?_)
open import Relator.Equals.Proofs
open import Structure.Relator.Ordering

module _
  (split : List(T) → List(List(T)))
  (_<_ : _)
  ⦃ well-founded : Strict.Properties.WellFounded{ℓ₂ = ℓ}(_<_) ⦄
  ⦃ shrinking-proof : ∀{l}{ll} → ⦃ _ : (ll ∈ split(l)) ⦄ → (ll < l) ⦄
  where

  import Data.List.FunctionsProven as Listₚ

  -- Definition without using well-founded recursion:
  --   merge-sort = Sorted.concat ∘ List.map merge-sort ∘ split
  -- TODO: Correctness requires proof of split(l) being a partition of l
  merge-sort : List(T) → List(T)
  merge-sort = Strict.Properties.wellfounded-recursion(_<_) f where
    f : (l : List(T)) → ((prev : List(T)) → ⦃ _ : prev < l ⦄ → List(T)) → List(T)
    f(l) rec = mergeAll(Listₚ.map (\ll p → rec ll ⦃ shrinking-proof ⦃ p ⦄ ⦄) (split l) [∈]-self)

module Proofs where
  open import Data.Boolean.Stmt
  open import Data.List.Relation.Permutation
  open import Data.List.Sorting(_≤?_)
  open import Data.List.Sorting.Proofs(_≤?_)
  open import Functional using (_∘₂_)
  open import Logic.Propositional
  open import Relator.Equals
  open import Structure.Relator.Properties
  open import Syntax.Transitivity

  module _ (asym : ∀{x y} → (x ≤? y ≡ not(y ≤? x))) where -- TODO: Use Structure.Relator.Properties.Asymmetry by the relation (IsTrue ∘₂ (_≤?_))
  -- module _ (asym : ∀{x y} → (x ≤? y ≡ not(y ≤? x))) (trans : ∀{x y z} → IsTrue(x ≤? y) → IsTrue(y ≤? z) → IsTrue(x ≤? z)) where
    {-
    merge-sort-sorted-proof : ∀{l} → Sorted(merge-sort l)
    merge-sort-sorted-proof {∅}         = Sorted.empty
    merge-sort-sorted-proof {a ⊰ ∅}     = single
    merge-sort-sorted-proof l@{_ ⊰ _ ⊰ _} with Tuple.map1 merge-sort (split2 l)
    ... | (a , b) = Sorted.merge-sorted-proof asym trans (merge-sort-sorted-proof{l = ∅}) (merge-sort-sorted-proof{l = l})
    -}


open import Type

-- The relation (_⟶_) should be interpreted as "a term reduces/rewritten to another term".
-- Also called: Abstract reduction system, abstract rewriting system, rewriting system.
module ReductionSystem {ℓ₁ ℓ₂} {Term : Type{ℓ₁}} (_⟶_ : Term → Term → Type{ℓ₂}) where

open import Functional
open import Graph.Properties
open import Graph.Walk
open import Graph.Walk.Proofs
open import Lang.Instance
import      Lvl
open import Logic
open import Logic.Propositional
open import Logic.Predicate
open import Relator.Converse
open import Relator.Equals
open import Relator.Equals.Proofs.Equiv
open import Relator.ReflexiveTransitiveClosure
open import Structure.Setoid.Uniqueness
open import Structure.Relator.Equivalence
open import Structure.Relator.Ordering
open import Structure.Relator.Properties
open import Syntax.Function
open import Syntax.Transitivity

open Graph.Properties using (intro) public

-- The relation (_⟶_) is a function on the left argument.
-- In terms of paths, it means that there are no forks on any paths.
Deterministic = ∀{a} → Unique(a ⟶_)

-- A term is reducible when there is a term it can reduce to.
-- In terms of paths, it means that one can go somewhere else from this point.
Reducible : Term → Stmt
Reducible(a) = ∃(a ⟶_)

-- A term is in normal form when it is irreducible (cannot be reduced any further).
-- Also called: Irreducible term
-- In terms of paths, it means that this point is a dead-end.
NormalForm : Term → Stmt
NormalForm = FinalVertex(_⟶_)
module NormalForm = FinalVertex

-- "a normalizes to b" means that "a" reduces to the normal form "b".
-- In terms of paths, this means that the dead end of one path from "a" is "b".
record _normalizes-to_ (a : Term) (b : Term) : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
  constructor intro
  field
    reduction : Walk(_⟶_) a b
    ⦃ normalForm ⦄ : NormalForm(b)

-- In terms of paths, this means that there is a path which leads to a dead-end.
WeaklyNormalizes : Term → Stmt
WeaklyNormalizes a = ∃(a normalizes-to_)

-- A reduction system is weakly normalizing when all terms in the language have a normal form.
-- In terms of paths, this means that all points have a path whch eventually lead to a dead-end.
WeaklyNormalizing = ∀ₗ(WeaklyNormalizes)

StronglyNormalizes : Term → Stmt
StronglyNormalizes = Strict.Properties.Accessibleₗ(Converse(_⟶_))

-- Every term reduces to a normal form.
-- Also called: Terminating.
StronglyNormalizing : Stmt
StronglyNormalizing = Strict.Properties.WellFounded(Converse(_⟶_))

-- Both a and b reduce to c in zero or more steps.
-- Also called: _⟶*_*⟵_
CommonReduct : Term → Term → Term → Stmt
CommonReduct c a b = (Walk(_⟶_) a c) ∧ (Walk(_⟶_) b c)

-- Both a and b reduce to the same term in zero or more steps.
-- In terms of paths, this means that paths starting from the two points are able to eventually meet.
-- Also called: Joinable, _⟶*_*⟵_ _↓_.
Joinable : Term → Term → Stmt
Joinable a b = ∃(c ↦ CommonReduct c a b)

module Names where
  import Structure.Relator.Names as Names

  EverywhereCommonReduct = Names.Subrelation (Walk(_⟶_)) Joinable

  module _ (a : Term) where
    Confluent         = ∀{b c} → (Walk(_⟶_) a b) → (Walk(_⟶_) a c) → Joinable b c
    Semiconfluent     = ∀{b c} → (a ⟶ b)         → (Walk(_⟶_) a c) → Joinable b c
    LocallyConfluent  = ∀{b c} → (a ⟶ b)         → (a ⟶ c)         → Joinable b c
    StronglyConfluent = ∀{b c} → (a ⟶ b)         → (a ⟶ c)         → ∃(d ↦ (ReflexiveClosure(_⟶_) b d) ∧ (Walk(_⟶_) c d))
    DiamondProperty   = ∀{b c} → (a ⟶ b)         → (a ⟶ c)         → ∃(d ↦ (b ⟶ d) ∧ (c ⟶ d))

  Confluence = ∀ₗ(Confluent)

-- Also called: The Church-Rosser property
EverywhereCommonReduct = (Walk(_⟶_)) ⊆₂ Joinable

module _ (a : Term) where
  -- A term is confluent when all its reducts have a common reduct.
  -- In terms of paths, this means that paths starting from this point will always eventually meet.
  record Confluent : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : Names.Confluent(a)
  confluent = inst-fn Confluent.proof

  record Semiconfluent : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : Names.Semiconfluent(a)
  semiconfluent = inst-fn Semiconfluent.proof

  record LocallyConfluent : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : Names.LocallyConfluent(a)
  locally-confluent = inst-fn LocallyConfluent.proof

  record StronglyConfluent : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : Names.StronglyConfluent(a)
  strongly-confluent = inst-fn StronglyConfluent.proof

  record DiamondProperty : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : Names.DiamondProperty(a)
  diamond-property = inst-fn DiamondProperty.proof

-- All terms are confluent.
-- In terms of paths, this means that parts starting from the same point can always eventually meet.
Confluence = ∀ₗ(Confluent)

Semiconfluence = ∀ₗ(Semiconfluent)

LocalConfluence = ∀ₗ(LocallyConfluent)

StrongConfluence = ∀ₗ(StronglyConfluent)

record Convergent : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
  constructor intro
  field
    ⦃ confluence ⦄ : Confluence
    ⦃ strongly-normalizing ⦄ : StronglyNormalizing

-- Evaluable = ∃(f ↦ )

-- All paths from a dead-end results in going nowhere.
Normal-unique-Path : ∀{a} → ⦃ _ : NormalForm(a) ⦄ → ∀{b} → Walk(_⟶_) a b → (a ≡ b)
Normal-unique-Path              at                 = [≡]-intro
Normal-unique-Path ⦃ intro na ⦄ (prepend ab1 sb1b) = [⊥]-elim(na ab1)

instance
  -- A term reduces to itself in zero steps.
  -- In terms of paths, this means that two paths starting from the same point can reach this same point.
  Joinable-reflexivity : Reflexivity(Joinable)
  ∃.witness (Reflexivity.proof Joinable-reflexivity {x}) = x
  ∃.proof   (Reflexivity.proof Joinable-reflexivity {x}) = [∧]-intro Walk.at Walk.at

instance
  -- When one reduces to the same term as the other, the other also reduces to the same term as the first one.
  Joinable-symmetry : Symmetry(Joinable)
  ∃.witness (Symmetry.proof Joinable-symmetry {x} {y} xy) = [∃]-witness xy
  ∃.proof   (Symmetry.proof Joinable-symmetry {x} {y} xy) = [∧]-intro ([∧]-elimᵣ(∃.proof xy)) (([∧]-elimₗ(∃.proof xy)))

instance
  -- When one reduces to the same term as the other, the other also reduces to the same term as the first one.
  Walk-Joinable-subrelation : Walk(_⟶_) ⊆₂ Joinable
  ∃.witness (_⊆₂_.proof Walk-Joinable-subrelation {y = y} ab) = y
  ∃.proof   (_⊆₂_.proof Walk-Joinable-subrelation ab) = [∧]-intro ab (reflexivity(Walk(_⟶_)))

module _ ⦃ confl : Confluence ⦄ where
  import      Structure.Relator.Names as Names

  instance
    Confluence-to-Joinable-transitivity : Transitivity(Joinable)
    Confluence-to-Joinable-transitivity = intro proof where
      proof : Names.Transitivity(Joinable)
      proof {x}{y}{z} ([∃]-intro obj-xy ⦃ [∧]-intro pxxy pyxy ⦄) ([∃]-intro obj-yz ⦃ [∧]-intro pyyz pzyz ⦄) = [∃]-intro obj ⦃ [∧]-intro l r ⦄ where
        objxy-objyz-common-reduct : Joinable obj-xy obj-yz
        objxy-objyz-common-reduct = confluent(y) pyxy pyyz

        obj : Term
        obj = [∃]-witness objxy-objyz-common-reduct

        l : Walk(_⟶_) x obj
        l = transitivity(Walk(_⟶_)) pxxy ([∧]-elimₗ ([∃]-proof objxy-objyz-common-reduct))

        r : Walk(_⟶_) z obj
        r = transitivity(Walk(_⟶_)) pzyz ([∧]-elimᵣ ([∃]-proof objxy-objyz-common-reduct))

  instance
    Confluence-to-Joinable-equivalence : Equivalence(Joinable)
    Confluence-to-Joinable-equivalence = intro

module _ (det : Deterministic) where
  -- Frege thing
  deterministic-dichotomy : ∀{a b c} → (Walk(_⟶_) a b) → (Walk(_⟶_) a c) → (Walk(_⟶_) b c) ∨ (Walk(_⟶_) c b)
  deterministic-dichotomy at ac = [∨]-introₗ ac
  deterministic-dichotomy (ab @ (prepend _ _)) at = [∨]-introᵣ ab
  deterministic-dichotomy (prepend ab2 b) (prepend ab3 ac) with det ab2 ab3
  ... | [≡]-intro = deterministic-dichotomy b ac

  deterministic-step : ∀{a b c} → (a ⟶ b) → (Walk(_⟶_) a c) → ((a ≡ c) ∨ (Walk(_⟶_) b c))
  deterministic-step ab at = [∨]-introₗ [≡]-intro
  deterministic-step ab (prepend ab₁ ac) rewrite det ab ab₁ = [∨]-introᵣ ac

  instance
    deterministic-confluence : Confluence
    deterministic-confluence = intro proof where
      proof : Names.Confluence
      proof {c = c} at ac = [∃]-intro c ⦃ [∧]-intro ac at ⦄
      {-# CATCHALL #-}
      proof {b = b} ab at = [∃]-intro b ⦃ [∧]-intro at ab ⦄
      proof (prepend ab1 ab) (prepend ab2 ac) rewrite det ab1 ab2 = proof ab ac

  deterministic-unique-normalizes-to : ∀{a} → Unique(a normalizes-to_)
  deterministic-unique-normalizes-to (intro ax) (intro ay) = proof ax ay where
    proof : ∀{a b c} → ⦃ _ : NormalForm(b) ⦄ → ⦃ _ : NormalForm(c) ⦄ → Walk(_⟶_) a b → Walk(_⟶_) a c → (b ≡ c)
    proof                          at              at              = [≡]-intro
    proof ⦃ intro normal-x ⦄ ⦃ _ ⦄ at              (prepend ab by) = [⊥]-elim(normal-x ab)
    proof ⦃ _ ⦄ ⦃ intro normal-y ⦄ (prepend ab bx) at              = [⊥]-elim(normal-y ab)
    proof (prepend ab₁ b₁x) (prepend ab₂ b₂y) rewrite det ab₁ ab₂ = proof b₁x b₂y

confluence-semiconfluence : Confluence ↔ Semiconfluence
confluence-semiconfluence = [↔]-intro (semiconfl ↦ intro(l(semiconfl))) r where
  l : Names.Confluence ← Semiconfluence
  l semiconfl at                xc = sub₂(Walk(_⟶_))(Joinable) xc
  l semiconfl (prepend xb₁ b₁b) xc with Semiconfluent.proof semiconfl xb₁ xc
  ... | [∃]-intro d ⦃ [∧]-intro b₁d c₁d ⦄ with l semiconfl b₁b b₁d
  ... | [∃]-intro e ⦃ [∧]-intro be de ⦄ = [∃]-intro e ⦃ [∧]-intro be (transitivity(Walk(_⟶_)) c₁d de) ⦄

  r : Confluence → Semiconfluence
  Semiconfluent.proof (r confl) xb xc = Confluent.proof confl (sub₂(_⟶_)(Walk(_⟶_)) xb) xc

-- TODO: Not sure, but maybe?
{-# TERMINATING #-}
strong-confluence-confluence : StrongConfluence → Confluence
strong-confluence-confluence strconfl = intro(proof strconfl) where
  proof : StrongConfluence → Names.Confluence
  proof strconfl {x} at at = reflexivity(Joinable)
  proof strconfl {x} at (prepend xb bc) = sub₂(Walk(_⟶_))(Joinable) (prepend xb bc)
  proof strconfl {x} (prepend xb₁ b₁b) at = symmetry(Joinable) (sub₂(Walk(_⟶_))(Joinable) (prepend xb₁ b₁b))
  proof strconfl {x} {b}{c} (prepend xb₁ b₁b) (prepend xb₂ b₂c) with StronglyConfluent.proof strconfl xb₁ xb₂
  proof strconfl {x} {b}{c} (prepend xd db) (prepend xb₁ b₁c) | [∃]-intro d ⦃ [∧]-intro refl b₁d ⦄ with proof strconfl b₁c b₁d
  ... | [∃]-intro e ⦃ [∧]-intro ce de ⦄ with proof strconfl db de
  ... | [∃]-intro f ⦃ [∧]-intro bf ef ⦄ = [∃]-intro f ⦃ [∧]-intro bf (transitivity(Walk(_⟶_)) ce ef) ⦄
  proof strconfl {x} {b}{c} (prepend xb₁ b₁b) (prepend xb₂ b₂c) | [∃]-intro d ⦃ [∧]-intro (super b₁d) b₂d ⦄ with proof strconfl b₁b (sub₂(_⟶_)(Walk(_⟶_)) b₁d)
  ... | [∃]-intro e ⦃ [∧]-intro be de ⦄ with proof strconfl b₂c b₂d
  ... | [∃]-intro f ⦃ [∧]-intro cf df ⦄ with proof strconfl de df
  ... | [∃]-intro g ⦃ [∧]-intro eg fg ⦄ = [∃]-intro g ⦃ [∧]-intro (transitivity(Walk(_⟶_)) be eg) (transitivity(Walk(_⟶_)) cf fg) ⦄

semiconfluence-everywhere-common-reduct : ⦃ _ : Semiconfluence ⦄ → EverywhereCommonReduct
semiconfluence-everywhere-common-reduct ⦃ semiconfl ⦄ = intro proof where
  instance
    confl : Confluence
    confl = [↔]-to-[←] confluence-semiconfluence semiconfl

  proof : Names.EverywhereCommonReduct
  proof at = reflexivity(Joinable)
  proof {a}{c} (prepend {b = b} ab bc) = transitivity(Joinable) (sub₂(Walk(_⟶_))(Joinable) (sub₂(_⟶_)(Walk(_⟶_)) ab)) (proof bc)

diamond-property-locally-confluent : ⦃ _ : ∀ₗ(DiamondProperty) ⦄ → LocalConfluence
LocallyConfluent.proof (diamond-property-locally-confluent {x}) xb xc = [∃]-map-proof ([∧]-map (sub₂(_⟶_)(Walk(_⟶_))) (sub₂(_⟶_)(Walk(_⟶_)))) (diamond-property _ xb xc)

-- locally-confluent-diamond-property : ⦃ LocalConfluence ⦄ → ∀ₗ(DiamondProperty)
-- DiamondProperty.proof locally-confluent-diamond-property xb xc = {!locally-confluent _ xb xc!}

-- Terminating ↔ LocalConfluence (TODO: See Newman's lemma)
-- Convergent → ∀{a} → Unique(a normalizes-to_)
-- Confluence → (Walk(_⟶_) x y) → NormalForm(y) → (ReflexiveClosure(_⟶_) x y)
-- Confluence → (Walk(_⟶_) x y) → Unique(NormalForm)
-- Confluence → ∀{a} → Unique(a normalizes-to_)


{-# OPTIONS --without-K #-}
open import Type hiding (★)
open import Function
open import Relation.Binary.PropositionalEquality

open import Explore.Core
open import Explore.Properties

-- Explore ℓ is not an endo functor because of universe levels
module Explore.Monad {a} ℓ where

M = Explore {a} ℓ

module _ {A : ★ a} where
    return : A → M A
    return = point-explore

    mzero : M A
    mzero = empty-explore

    mplus : M A → M A → M A
    mplus = merge-explore

    module _ {p} where
        return-ind : ∀ x → ExploreInd p (return x)
        return-ind = point-explore-ind

        mzero-ind : ExploreInd p mzero
        mzero-ind = empty-explore-ind

        mplus-ind : ∀ {e₀ e₁ : M A}
                    → ExploreInd p e₀ → ExploreInd p e₁
                    → ExploreInd p (merge-explore e₀ e₁)
        mplus-ind Pe₀ Pe₁ P Pε _P∙_ Pf = (Pe₀ P Pε _P∙_ Pf) P∙ (Pe₁ P Pε _P∙_ Pf)

module _ {A B : ★ a} where

    infixl 1 _>>=_ _>>=-ind_
    _>>=_ : M A → (A → M B) → M B
    (expᴬ >>= expᴮ) ε _∙_ f = expᴬ ε _∙_ λ x → expᴮ x ε _∙_ f

    _>>=-ind_ : ∀ {p}
                  {expᴬ : M A} → ExploreInd p expᴬ →
                  {expᴮ : A → M B} → (∀ x → ExploreInd p (expᴮ x))
               → ExploreInd p (expᴬ >>= expᴮ)
    _>>=-ind_ {expᴬ} Pᴬ {expᴮ} Pᴮ P Pz _P∙_ Pf
      = Pᴬ (λ e → P (e >>= expᴮ)) Pz _P∙_ λ x → Pᴮ x P Pz _P∙_ Pf

    map : (A → B) → M A → M B
    map f e = e >>= return ∘ f

    map-ind : ∀ {p} (f : A → B) {expᴬ : M A} → ExploreInd p expᴬ → ExploreInd p (map f expᴬ)
    map-ind f Pᴬ = Pᴬ >>=-ind return-ind ∘ f

    private
        {- This law is for free: map f e = e >>= return ∘ f -}
        map' : (A → B) → M A → M B
        map' f exp ε _∙_ g = exp ε _∙_ (g ∘ f)

        map'≡map : map' ≡ map
        map'≡map = refl

-- universe issues...
-- join : M (M A) → M A

module _ {A B C : ★ a} (m : M A) (f : A → M B) (g : B → M C) where
    infix 0 _≡e_
    _≡e_ = λ {A} → _≡_ {A = M A}

    left-identity : f ≡ (λ x → return x >>= f)
    left-identity = refl

    right-identity : m ≡e m >>= return
    right-identity = refl

    associativity : m >>= (λ x → f x >>= g) ≡e (m >>= f) >>= g
    associativity = refl


open import Haskell.Prim
open import Agda.Builtin.Nat

data _≤_ : Nat → Nat → Set where
  instance
    zero-≤ : ∀ {n} → zero ≤ n
    suc-≤ : ∀ {m n} → @0 {{m ≤ n}} → suc m ≤ suc n

data Tree {l u : Nat} : Set where
  Leaf  : @0 {{l ≤ u}} → Tree {l} {u}
  Node  : (x : Nat) → Tree {l} {x} → Tree {x} {u} → Tree {l} {u}
{-# COMPILE AGDA2HS Tree #-}


open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Data.Product
open import Level

module IndexedMap
         {Index : Set} {Key : Index → Set} {_≈_ _<_ : Rel (∃ Key) zero}
         (isOrderedKeySet : IsStrictTotalOrder _≈_ _<_)
         -- Equal keys must have equal indices.
         (indicesEqual : _≈_ =[ proj₁ ]⇒ _≡_)
         (Value : Index → Set)
         where


{-# OPTIONS --safe #-}

module Cubical.Categories.Limits.Terminal where

open import Cubical.Foundations.Prelude
open import Cubical.Data.Sigma
open import Cubical.Foundations.HLevels
open import Cubical.Categories.Category
open import Cubical.Categories.Functor

private
  variable
    ℓ ℓ' : Level

module _ (C : Precategory ℓ ℓ') where
  open Precategory C

  isInitial : (x : ob) → Type (ℓ-max ℓ ℓ')
  isInitial x = ∀ (y : ob) → isContr (C [ x , y ])

  isFinal : (x : ob) → Type (ℓ-max ℓ ℓ')
  isFinal x = ∀ (y : ob) → isContr (C [ y , x ])

  hasInitialOb : Type (ℓ-max ℓ ℓ')
  hasInitialOb = Σ[ x ∈ ob ] isInitial x

  hasFinalOb : Type (ℓ-max ℓ ℓ')
  hasFinalOb = Σ[ x ∈ ob ] isFinal x

  -- Initiality of an object is a proposition.
  isPropIsInitial : (x : ob) → isProp (isInitial x)
  isPropIsInitial x = isPropΠ λ y → isPropIsContr

  -- Objects that are initial are isomorphic.
  isInitialToIso : {x y : ob} (hx : isInitial x) (hy : isInitial y) →
    CatIso {C = C} x y
  isInitialToIso {x = x} {y = y} hx hy =
    let x→y : C [ x , y ]
        x→y = fst (hx y) -- morphism forwards
        y→x : C [ y , x ]
        y→x = fst (hy x) -- morphism backwards
        x→y→x : x→y ⋆⟨ C ⟩ y→x ≡ id x
        x→y→x = isContr→isProp (hx x) _ _ -- compose to id by uniqueness
        y→x→y : y→x ⋆⟨ C ⟩ x→y ≡ id y
        y→x→y = isContr→isProp (hy y) _ _ -- similar.
    in catiso x→y y→x y→x→y x→y→x

  open isUnivalent

  -- The type of initial objects of a univalent precategory is a proposition,
  -- i.e. all initial objects are equal.
  isPropInitial : (hC : isUnivalent C) → isProp (hasInitialOb)
  isPropInitial hC x y =
    -- Being initial is a prop ∴ Suffices equal as objects in C.
    Σ≡Prop (isPropIsInitial)
    -- C is univalent ∴ Suffices isomorphic as objects in C.
    (CatIsoToPath hC (isInitialToIso (snd x) (snd y)))

  -- Now the dual argument for final objects.

  -- Finality of an object is a proposition.
  isPropIsFinal : (x : ob) → isProp (isFinal x)
  isPropIsFinal x = isPropΠ λ y → isPropIsContr

  -- Objects that are initial are isomorphic.
  isFinalToIso : {x y : ob} (hx : isFinal x) (hy : isFinal y) →
    CatIso {C = C} x y
  isFinalToIso {x = x} {y = y} hx hy =
    let x→y : C [ x , y ]
        x→y = fst (hy x) -- morphism forwards
        y→x : C [ y , x ]
        y→x = fst (hx y) -- morphism backwards
        x→y→x : x→y ⋆⟨ C ⟩ y→x ≡ id x
        x→y→x = isContr→isProp (hx x) _ _ -- compose to id by uniqueness
        y→x→y : y→x ⋆⟨ C ⟩ x→y ≡ id y
        y→x→y = isContr→isProp (hy y) _ _ -- similar.
    in catiso x→y y→x y→x→y x→y→x

  -- The type of final objects of a univalent precategory is a proposition,
  -- i.e. all final objects are equal.
  isPropFinal : (hC : isUnivalent C) → isProp (hasFinalOb)
  isPropFinal hC x y =
    -- Being final is a prop ∴ Suffices equal as objects in C.
    Σ≡Prop (isPropIsFinal)
    -- C is univalent ∴ Suffices isomorphic as objects in C.
    (CatIsoToPath hC (isFinalToIso (snd x) (snd y)))


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

open import Prelude

module _ {a} {A : Type a} (_∙_ : A → A → A) where
  Associative : Type a
  Associative = ∀ x y z → (x ∙ y) ∙ z ≡ x ∙ (y ∙ z)

  Commutative : Type _
  Commutative = ∀ x y → x ∙ y ≡ y ∙ x

  Idempotent : Type _
  Idempotent = ∀ x → x ∙ x ≡ x

module _ {a b} {A : Type a} {B : Type b} where
  Identityˡ : (A → B → B) → A → Type _
  Identityˡ _∙_ x = ∀ y → x ∙ y ≡ y

  Zeroˡ : (A → B → A) → A → Type _
  Zeroˡ _∙_ x = ∀ y → x ∙ y ≡ x

  Zeroʳ : (A → B → B) → B → Type _
  Zeroʳ _∙_ x = ∀ y → y ∙ x ≡ x

  Identityʳ : (A → B → A) → B → Type _
  Identityʳ _∙_ x = ∀ y → y ∙ x ≡ y

  _Distributesʳ_ : (A → B → B) → (B → B → B) → Type _
  _⊗_ Distributesʳ _⊕_ = ∀ x y z → x ⊗ (y ⊕ z) ≡ (x ⊗ y) ⊕ (x ⊗ z)

  _Distributesˡ_ : (B → A → B) → (B → B → B) → Type _
  _⊗_ Distributesˡ _⊕_ = ∀ x y z → (x ⊕ y) ⊗ z ≡ (x ⊗ z) ⊕ (y ⊗ z)

record  Semigroup ℓ : Type (ℓsuc ℓ) where
  infixl 6 _∙_
  field
    𝑆      : Type ℓ
    _∙_    : 𝑆 → 𝑆 → 𝑆
    assoc  : ∀ x y z → (x ∙ y) ∙ z ≡ x ∙ (y ∙ z)

record  Monoid ℓ : Type (ℓsuc ℓ) where
  infixl 6 _∙_
  field
    𝑆      : Type ℓ
    _∙_    : 𝑆 → 𝑆 → 𝑆
    ε      : 𝑆
    assoc  : ∀ x y z → (x ∙ y) ∙ z ≡ x ∙ (y ∙ z)
    ε∙     : ∀ x → ε ∙ x ≡ x
    ∙ε     : ∀ x → x ∙ ε ≡ x

  semigroup : Semigroup ℓ
  semigroup = record
    { 𝑆 = 𝑆; _∙_ = _∙_; assoc = assoc }

record MonoidHomomorphism_⟶_
         {ℓ₁ ℓ₂}
         (from : Monoid ℓ₁)
         (to : Monoid ℓ₂)
       : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  open Monoid from
  open Monoid to
    renaming ( 𝑆 to 𝑅
             ; _∙_ to _⊙_
             ; ε to ⓔ
             )
  field
    f : 𝑆 → 𝑅
    ∙-homo : ∀ x y → f (x ∙ y) ≡ f x ⊙ f y
    ε-homo : f ε ≡ ⓔ

record Group ℓ : Type (ℓsuc ℓ) where
  field
    monoid : Monoid ℓ
  open Monoid monoid public
  field
    inv : 𝑆 → 𝑆
    ∙⁻ : ∀ x → x ∙ inv x ≡ ε
    ⁻∙ : ∀ x → inv x ∙ x ≡ ε

record CommutativeMonoid ℓ : Type (ℓsuc ℓ) where
  field
    monoid : Monoid ℓ
  open Monoid monoid public
  field
    comm : Commutative _∙_

record Semilattice ℓ : Type (ℓsuc ℓ) where
  field
    commutativeMonoid : CommutativeMonoid ℓ
  open CommutativeMonoid commutativeMonoid public
  field
    idem : Idempotent _∙_

record NearSemiring ℓ : Type (ℓsuc ℓ) where
  infixl 6 _+_
  infixl 7 _*_
  field
    𝑅 : Type ℓ
    _+_ : 𝑅 → 𝑅 → 𝑅
    _*_ : 𝑅 → 𝑅 → 𝑅
    1# : 𝑅
    0# : 𝑅
    +-assoc : Associative _+_
    *-assoc : Associative _*_
    0+ : Identityˡ _+_ 0#
    +0 : Identityʳ _+_ 0#
    1* : Identityˡ _*_ 1#
    *1 : Identityʳ _*_ 1#
    0* : Zeroˡ _*_ 0#
    ⟨+⟩* : _*_ Distributesˡ _+_

record Semiring ℓ : Type (ℓsuc ℓ) where
  field
    nearSemiring : NearSemiring ℓ
  open NearSemiring nearSemiring public
  field
    +-comm : Commutative _+_
    *0 : Zeroʳ _*_ 0#
    *⟨+⟩ : _*_ Distributesʳ _+_

record IdempotentSemiring ℓ : Type (ℓsuc ℓ) where
  field
    semiring : Semiring ℓ
  open Semiring semiring public
  field
    +-idem : Idempotent _+_

record CommutativeSemiring ℓ : Type (ℓsuc ℓ) where
  field
    semiring : Semiring ℓ
  open Semiring semiring public
  field
    *-comm : Commutative _*_

record LeftSemimodule ℓ₁ ℓ₂ : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  field
    semiring : Semiring ℓ₁
  open Semiring semiring public
  field
    semimodule : CommutativeMonoid ℓ₂
  open CommutativeMonoid semimodule renaming (_∙_ to _∪_) public
    renaming (𝑆 to 𝑉
             ; assoc to ∪-assoc
             ; ε∙ to ∅∪
             ; ∙ε to ∪∅
             ; ε to ∅
             )
  infixr 7 _⋊_
  field
    _⋊_ : 𝑅 → 𝑉 → 𝑉
    ⟨*⟩⋊ : ∀ x y z → (x * y) ⋊ z ≡ x ⋊ (y ⋊ z)
    ⟨+⟩⋊ : ∀ x y z → (x + y) ⋊ z ≡ (x ⋊ z) ∪ (y ⋊ z)
    ⋊⟨∪⟩ : _⋊_ Distributesʳ _∪_
    1⋊ : Identityˡ _⋊_ 1#
    0⋊ : ∀ x → 0# ⋊ x ≡ ∅

record StarSemiring ℓ : Type (ℓsuc ℓ) where
  field
    semiring : Semiring ℓ
  open Semiring semiring public
  field
    _⋆ : 𝑅 → 𝑅
    star-iterʳ : ∀ x → x ⋆ ≡ 1# + x * x ⋆
    star-iterˡ : ∀ x → x ⋆ ≡ 1# + x ⋆ * x
  _⁺ : 𝑅 → 𝑅
  x ⁺ = x * x ⋆

record Functor ℓ₁ ℓ₂ : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  field
    𝐹   : Type ℓ₁ → Type ℓ₂
    map : (A → B) → 𝐹 A → 𝐹 B
    map-id : map (id {ℓ₁} {A}) ≡ id
    map-comp : (f : B → C) → (g : A → B) → map (f ∘ g) ≡ map f ∘ map g

record Applicative ℓ₁ ℓ₂ : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  field
    functor : Functor ℓ₁ ℓ₂
  open Functor functor public
  infixl 5 _<*>_
  field
    pure : A → 𝐹 A
    _<*>_ : 𝐹 (A → B) → 𝐹 A → 𝐹 B
    map-ap : (f : A → B) → map f ≡ pure f <*>_
    pure-homo : (f : A → B) → (x : A) → map f (pure x) ≡ pure (f x)
    <*>-interchange : (u : 𝐹 (A → B)) → (y : A) → u <*> pure y ≡ map (_$ y) u
    <*>-comp : (u : 𝐹 (B → C)) → (v : 𝐹 (A → B)) → (w : 𝐹 A) → pure _∘′_ <*> u <*> v <*> w ≡ u <*> (v <*> w)

record Monad ℓ₁ ℓ₂ : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  field
    applicative : Applicative ℓ₁ ℓ₂
  open Applicative applicative public
  infixl 1 _>>=_
  field
    _>>=_ : 𝐹 A → (A → 𝐹 B) → 𝐹 B
    >>=-idˡ : (f : A → 𝐹 B) → (x : A) → (pure x >>= f) ≡ f x
    >>=-idʳ : (x : 𝐹 A) → (x >>= pure) ≡ x
    >>=-assoc : (xs : 𝐹 A) (f : A → 𝐹 B) (g : B → 𝐹 C) → ((xs >>= f) >>= g) ≡ (xs >>= (λ x → f x >>= g))
  return : A → 𝐹 A
  return = pure

record Alternative ℓ₁ ℓ₂ : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  field
    applicative : Applicative ℓ₁ ℓ₂
  open Applicative applicative public
  field
    0# : 𝐹 A
    _<|>_ : 𝐹 A → 𝐹 A → 𝐹 A
    <|>-idˡ : (x : 𝐹 A) → 0# <|> x ≡ x
    <|>-idʳ : (x : 𝐹 A) → x <|> 0# ≡ x
    0-annˡ : (x : 𝐹 A) → 0# <*> x ≡ 0# {B}
    <|>-distrib : (x y : 𝐹 (A → B)) → (z : 𝐹 A) → (x <|> y) <*> z ≡ (x <*> z) <|> (y <*> z)

record MonadPlus ℓ₁ ℓ₂ : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  field
    monad : Monad ℓ₁ ℓ₂
  open Monad monad public
  field
    0# : 𝐹 A
    _<|>_ : 𝐹 A → 𝐹 A → 𝐹 A
    <|>-idˡ : (x : 𝐹 A) → 0# <|> x ≡ x
    <|>-idʳ : (x : 𝐹 A) → x <|> 0# ≡ x
    0-annˡ : (x : A → 𝐹 B) → (0# >>= x) ≡ 0#
    <|>-distrib : (x y : 𝐹 A) → (z : A → 𝐹 B) → ((x <|> y) >>= z) ≡ (x >>= z) <|> (y >>= z)

Endo : Type a → Type a
Endo A = A → A

endoMonoid : ∀ {a} → Type a → Monoid a
endoMonoid A .Monoid.𝑆 = Endo A
endoMonoid A .Monoid.ε x = x
endoMonoid A .Monoid._∙_ f g x = f (g x)
endoMonoid A .Monoid.assoc _ _ _ = refl
endoMonoid A .Monoid.ε∙ _ = refl
endoMonoid A .Monoid.∙ε _ = refl

record Foldable ℓ₁ ℓ₂ : Type (ℓsuc (ℓ₁ ℓ⊔ ℓ₂)) where
  field
    𝐹 : Type ℓ₁ → Type ℓ₂
  open Monoid ⦃ ... ⦄
  field
    foldMap : {A : Type ℓ₁} ⦃ _ : Monoid ℓ₁ ⦄ → (A → 𝑆) → 𝐹 A → 𝑆
  foldr : {A B : Type ℓ₁} → (A → B → B) → B → 𝐹 A → B
  foldr f b xs = foldMap ⦃ endoMonoid _ ⦄ f xs b


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

module AgdaIntroduction where

-- We add 3 to the fixities of the Agda standard library 0.8.1 (see
-- Data/Nat.agda).
infixl 10 _*_
infixl 9  _+_
infixr 5  _∷_ _++_
infix  4  _≡_

-- Dependent function types
id : (A : Set) → A → A
id A x = x

-- λ-notation
id₂ : (A : Set) → A → A
id₂ = λ A → λ x → x

id₃ : (A : Set) → A → A
id₃ = λ A x → x

-- Implicit arguments
id₄ : {A : Set} → A → A
id₄ x = x

id₅ : {A : Set} → A → A
id₅ = λ x → x

-- Inductively defined sets and families
data Bool : Set where
  false true : Bool

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

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

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

data Fin : ℕ → Set where
  fzero : {n : ℕ} → Fin (succ n)
  fsucc : {n : ℕ} → Fin n → Fin (succ n)

-- Structurally recursive functions and pattern matching
_+_ : ℕ → ℕ → ℕ
zero   + n = n
succ m + n = succ (m + n)

map : {A B : Set} → (A → B) → List A → List B
map f []       = []
map f (x ∷ xs) = f x ∷ map f xs

f : ℕ → ℕ
f zero = zero
{-# CATCHALL #-}
f _    = succ zero

-- The absurd pattern
magic : {A : Set} → Fin zero → A
magic ()

-- The with constructor

filter : {A : Set} → (A → Bool) → List A → List A
filter p [] = []
filter p (x ∷ xs) with p x
... | true  = x ∷ filter p xs
... | false = filter p xs

filter' : {A : Set} → (A → Bool) → List A → List A
filter' p [] = []
filter' p (x ∷ xs) with p x
filter' p (x ∷ xs) | true  = x ∷ filter' p xs
filter' p (x ∷ xs) | false = filter' p xs

-- Mutual definitions
even : ℕ → Bool
odd  : ℕ → Bool

even zero     = true
even (succ n) = odd n

odd zero   = false
odd (succ n) = even n

data EvenList : Set
data OddList  : Set

data EvenList where
  []  : EvenList
  _∷_ : ℕ → OddList → EvenList

data OddList where
  _∷_ : ℕ → EvenList → OddList

-- Normalisation

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

length : {A : Set} → List A → ℕ
length []       = zero
length (x ∷ xs) = succ zero + length xs

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

succCong : {m n : ℕ} → m ≡ n → succ m ≡ succ n
succCong refl = refl

length-++ : {A : Set}(xs ys : List A) →
            length (xs ++ ys) ≡ length xs + length ys
length-++ [] ys       = refl
length-++ (x ∷ xs) ys = succCong (length-++ xs ys)

-- Coverage and termination checkers
head : {A : Set} → List A → A
head []       = ?
head (x ∷ xs) = x

ack : ℕ → ℕ → ℕ
ack zero     n        = succ n
ack (succ m) zero     = ack m (succ zero)
ack (succ m) (succ n) = ack m (ack (succ m) n)

-- Combinators for equational reasoning

postulate
  sym   : {A : Set}{a b : A} → a ≡ b → b ≡ a
  trans : {A : Set}{a b c : A} → a ≡ b → b ≡ c → a ≡ c
  subst : {A : Set}(P : A → Set){a b : A} → a ≡ b → P a → P b

postulate
  _*_             : ℕ → ℕ → ℕ
  *-comm          : ∀ m n → m * n ≡ n * m
  *-rightIdentity : ∀ n → n * succ zero ≡ n

*-leftIdentity : ∀ n → succ zero * n ≡ n
*-leftIdentity n =
  trans {ℕ} {succ zero * n} {n * succ zero} {n} (*-comm (succ zero) n) (*-rightIdentity n)

module ER
  {A     : Set}
  (_∼_   : A → A → Set)
  (∼-refl  : ∀ {x} → x ∼ x)
  (∼-trans : ∀ {x y z} → x ∼ y → y ∼ z → x ∼ z)
  where

  infixr 5 _∼⟨_⟩_
  infix  6 _∎

  _∼⟨_⟩_ : ∀ x {y z} → x ∼ y → y ∼ z → x ∼ z
  _ ∼⟨ x∼y ⟩ y∼z = ∼-trans x∼y y∼z

  _∎ : ∀ x → x ∼ x
  _∎ _ = ∼-refl

open module ≡-Reasoning = ER _≡_ (refl {ℕ}) (trans {ℕ})
  renaming ( _∼⟨_⟩_ to _≡⟨_⟩_ )

*-leftIdentity' : ∀ n → succ zero * n ≡ n
*-leftIdentity' n =
  succ zero * n ≡⟨ *-comm (succ zero) n ⟩
  n * succ zero ≡⟨ *-rightIdentity n ⟩
  n             ∎


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

open import Sets.EquivalenceRelations
open import LogicalFormulae
open import Setoids.Setoids
open import Rings.Definition
open import Modules.Definition
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Lists.Lists
open import Vectors
open import Groups.Definition
open import Orders.Total.Definition
open import Groups.Homomorphisms.Definition
open import Groups.Homomorphisms.Lemmas
open import Rings.Homomorphisms.Definition

module Modules.PolynomialModule {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ _*_ : A → A → A} (R : Ring S _+_ _*_) where

open Ring R
open import Groups.Polynomials.Definition additiveGroup
open import Groups.Polynomials.Group additiveGroup
open import Rings.Polynomial.Multiplication R
open import Rings.Polynomial.Evaluation R
open import Rings.Polynomial.Ring R
open import Rings.Lemmas polyRing

polynomialRingModule : Module R abelianUnderlyingGroup (λ a b → _*P_ (polyInjection a) b)
Module.dotWellDefined (polynomialRingModule) r=s t=u = Ring.*WellDefined polyRing (r=s ,, record {}) t=u
Module.dotDistributesLeft (polynomialRingModule) {r} {s} {t} = Ring.*DistributesOver+ polyRing {polyInjection r} {s} {t}
Module.dotDistributesRight (polynomialRingModule) {r} {s} {t} = Ring.*DistributesOver+' polyRing {polyInjection r} {polyInjection s} {t}
Module.dotAssociative (polynomialRingModule) {r} {s} {t} = Equivalence.transitive (Setoid.eq naivePolySetoid) (Ring.*WellDefined polyRing m (Equivalence.reflexive (Setoid.eq naivePolySetoid) {t})) (Equivalence.symmetric (Setoid.eq naivePolySetoid) (Ring.*Associative polyRing {polyInjection r} {polyInjection s} {t}))
  where
    m : Setoid._∼_ naivePolySetoid ((r * s) :: []) ((r * s) :: (([] +P []) +P (0R :: [])))
    m = Equivalence.reflexive (Setoid.eq S) ,, (Equivalence.reflexive (Setoid.eq S) ,, record {})
Module.dotIdentity (polynomialRingModule) = Ring.identIsIdent polyRing

open import Modules.Span polynomialRingModule

polynomialBasis : ℕ → NaivePoly
polynomialBasis zero = polyInjection 1R
polynomialBasis (succ a) = 0R :: polynomialBasis a

count : (n : ℕ) → Vec ℕ n
count zero = []
count (succ n) = 0 ,- vecMap succ (count n)

lemma : {d : _} {D : Set d} → (f : D → List A) → {n : ℕ} → (m : Vec D n) (r : Vec A n)  → Setoid._∼_ naivePolySetoid (dot (vecMap (λ i → 0R :: f i) m) r) (0R :: dot (vecMap f m) r)
lemma f [] [] = reflexive ,, record {}
  where
    open Setoid S
    open Equivalence eq
lemma f (m ,- ms) (r ,- rs) rewrite refl {x = 0} = transitive (+WellDefined {(r * 0R) :: (((map (_*_ r) (f m)) +P []) +P (0R :: []))} {_} {(r * 0R) :: (((map (_*_ r) (f m)) +P []) +P (0R :: []))} (reflexive {(r * 0R) :: (((map (_*_ r) (f m)) +P []) +P (0R :: []))}) (lemma f ms rs)) (Equivalence.transitive (Setoid.eq S) (Group.identRight additiveGroup) (Ring.timesZero R) ,, +WellDefined {((map (_*_ r) (f m)) +P []) +P (0R :: [])} {dot (vecMap f ms) rs} {(r :: []) *P f m} {dot (vecMap f ms) rs} t (reflexive {dot (vecMap f ms) rs}))
  where
    open Setoid naivePolySetoid
    open Equivalence eq
    open Group polyGroup
    lemm : (v : List A) → polysEqual (map (_*_ r) v) ((r :: []) *P v)
    lemm [] = record {}
    lemm (x :: v) = Equivalence.reflexive (Setoid.eq S) ,, symmetric (transitive (+WellDefined {map (_*_ r) v +P []} {0R :: []} {_} {[]} reflexive (Equivalence.reflexive (Setoid.eq S) ,, record {})) (transitive (identRight {(map (_*_ r) v) +P []}) (identRight {map (_*_ r) v})))
    t : ((map (_*_ r) (f m) +P []) +P (0R :: [])) ∼ ((r :: []) *P f m)
    t = transitive (+WellDefined {map (_*_ r) (f m) +P []} {0R :: []} {_} {[]} reflexive (Equivalence.reflexive (Setoid.eq S) ,, record {})) (transitive (identRight {map (_*_ r) (f m) +P []}) (transitive (identRight {map (_*_ r) (f m)}) (lemm (f m))))

identityMap : (v : List A) → Setoid._∼_ naivePolySetoid (dot (vecMap polynomialBasis (count (length v))) (listToVec v)) v
identityMap [] = record {}
identityMap (x :: v) rewrite vecMapCompose succ polynomialBasis (count (length v)) = transitive (+WellDefined {(x * 1R) :: Group.0G additiveGroup :: []} {dot (vecMap (λ i → Group.0G additiveGroup :: polynomialBasis i) (count (length v))) (listToVec v)} {(x * 1R) :: 0R :: []} {0R :: dot (vecMap polynomialBasis (count (length v))) (listToVec v)} (reflexive {(x * 1R) :: 0R :: []}) (lemma polynomialBasis (count (length v)) (listToVec v))) (Equivalence.transitive (Setoid.eq S) (Group.identRight additiveGroup) (Equivalence.transitive (Setoid.eq S) *Commutative identIsIdent) ,, transitive (+WellDefined {0R :: []} {dot (vecMap polynomialBasis (count (length v))) (listToVec v)} {[]} (Equivalence.reflexive (Setoid.eq S) ,, record {}) reflexive) (transitive identLeft (identityMap v)))
  where
    open Group polyGroup
    open Setoid naivePolySetoid
    open Equivalence eq

polynomialBasisSpans : Spans polynomialBasis
polynomialBasisSpans m = length m , ((count (length m) ,, listToVec m) , identityMap m)

{-
private
  indepWithZero : {n : ℕ} (rs : Vec ℕ n) (indicesDistinct : {a b : ℕ} → (a<n : a <N succ n) (b<n : b <N succ n) → vecIndex (0 ,- rs) a a<n ≡ vecIndex (0 ,- rs) b b<n → a ≡ b) (b : A) (bs : Vec A n) (dotZero : Setoid._∼_ naivePolySetoid (((b * 1R) :: 0R :: []) +P (dot (vecMap polynomialBasis rs) bs)) []) → (nonzero : {a : ℕ} → (a<n : a <N n) → 0 <N vecIndex rs a a<n) → Setoid._∼_ S 0R b && _=V_ additiveGroup (vecPure 0R) bs
  indepWithZero rs indicesDistinct b bs dotZero indicesNonzero = symmetric b=0 ,, {!!}
    where
      open Setoid S
      open Equivalence eq
      open Group additiveGroup
      t : (inducedFunction (((b * 1R) :: 0R :: []) +P (dot (vecMap polynomialBasis rs) bs)) 0R) ∼ 0R
      t = inducedFunctionWellDefined dotZero 0R
      u : ((inducedFunction ((b * 1R) :: 0R :: []) 0R) + inducedFunction (dot (vecMap polynomialBasis rs) bs) 0R) ∼ 0R
      u = transitive (symmetric (GroupHom.groupHom (RingHom.groupHom (inducedFunctionIsHom 0R)) {((b * 1R) :: 0R :: [])} {dot (vecMap polynomialBasis rs) bs})) t
      b=0 : b ∼ 0R
      b=0 = transitive (symmetric (transitive (+WellDefined (transitive (transitive (transitive (+WellDefined reflexive (transitive *Commutative timesZero)) identRight) *Commutative) identIsIdent) {!imageOfIdentityIsIdentity (RingHom.groupHom (inducedFunctionIsHom 0R))!}) (identRight {b}))) u

polynomialBasisIndependent : Independent polynomialBasis
polynomialBasisIndependent [] indicesDistinct [] dotZero = record {}
polynomialBasisIndependent {succ n} (zero ,- rs) indicesDistinct (b ,- bs) dotZero = indepWithZero rs indicesDistinct b bs dotZero t
  where
    t : {a : ℕ} (a<n : a <N n) → 0 <N vecIndex rs a a<n
    t {a} a<n with TotalOrder.totality ℕTotalOrder 0 (vecIndex rs a a<n)
    t {a} a<n | inl (inl x) = x
    t {a} a<n | inr x with indicesDistinct {succ a} {0} (succPreservesInequality a<n) (succIsPositive n) (equalityCommutative x)
    ... | ()
polynomialBasisIndependent (succ r ,- rs) indicesDistinct (b ,- bs) dotZero = {!!}
  where
    rearr : {!!}
    rearr = {!!}

-}


{-# OPTIONS --verbose tc.constr.findInScope:15 #-}

module InstanceArguments.03-classes where

open import Algebra
open import Algebra.Structures
open import Algebra.FunctionProperties
open import Data.Nat.Properties as NatProps
open import Data.Nat
open import Data.Bool.Properties using (isCommutativeSemiring-∧-∨)
open import Data.Product using (proj₁)
open import Relation.Binary.PropositionalEquality
open import Relation.Binary

open import Level renaming (zero to lzero; suc to lsuc)

open CommutativeSemiring NatProps.commutativeSemiring using (semiring)
open IsCommutativeSemiring isCommutativeSemiring using (isSemiring)
open IsCommutativeSemiring isCommutativeSemiring-∧-∨ using () renaming (isSemiring to Bool-isSemiring)

record S (A : Set) : Set₁ where
  field
    z : A
    o : A
    _≈_ : Rel A lzero
    _⟨+⟩_ : Op₂ A
    _⟨*⟩_ : Op₂ A
    instance isSemiring' : IsSemiring _≈_ _⟨+⟩_ _⟨*⟩_ z o

instance
  ℕ-S : S ℕ
  ℕ-S = record { z = 0; o = 1;
                 _≈_ = _≡_; _⟨+⟩_ = _+_; _⟨*⟩_ = _*_;
                 isSemiring' = isSemiring }

zero' : {A : Set} → {{aRing : S A}} → A
zero' {{ARing}} = S.z ARing

zero-nat : ℕ
zero-nat = zero'

isZero : {A : Set} {{r : S A}} (let open S r) →
         Zero _≈_ z _⟨*⟩_
isZero {{r}} = IsSemiring.zero (S.isSemiring' r)

useIsZero : 0 * 5 ≡ 0
useIsZero = proj₁ isZero 5


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

open import Categories.Category

-- BinaryCoproducts -- a category with all binary coproducts
-- Cocartesian -- a category with all coproducts

-- since most of the work is dual to Categories.Category.Cartesian, so the idea
-- in this module is to make use of duality
module Categories.Category.Cocartesian {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level

private
  module 𝒞 = Category 𝒞
  open Category 𝒞
  open HomReasoning
  variable
    A B C D : Obj
    f g h i : A ⇒ B

open import Categories.Object.Initial 𝒞
open import Categories.Object.Coproduct 𝒞
open import Categories.Object.Duality 𝒞
open import Categories.Category.Monoidal
open import Categories.Category.Monoidal.Symmetric
open import Categories.Category.Cartesian 𝒞.op
open import Categories.Morphism 𝒞
open import Categories.Morphism.Properties 𝒞
open import Categories.Morphism.Duality 𝒞
open import Categories.Morphism.Reasoning 𝒞

open import Categories.Functor renaming (id to idF)
open import Categories.Functor.Properties
open import Categories.Functor.Bifunctor

record BinaryCoproducts : Set (levelOfTerm 𝒞) where

  infixr 6 _+_
  infixr 7 _+₁_

  field
    coproduct : ∀ {A B} → Coproduct A B

  module coproduct {A} {B} = Coproduct (coproduct {A} {B})

  _+_ : Obj → Obj → Obj
  A + B = coproduct.A+B {A} {B}

  open coproduct
    using (i₁; i₂; [_,_]; inject₁; inject₂; []-cong₂)
    renaming (unique to +-unique; η to +-η; g-η to +-g-η)
    public

  module Dual where
    op-binaryProducts : BinaryProducts
    op-binaryProducts = record { product = coproduct→product coproduct }

    module op-binaryProducts = BinaryProducts op-binaryProducts

  open Dual

  +-comm : A + B ≅ B + A
  +-comm = op-≅⇒≅ (op-binaryProducts.×-comm)

  +-assoc : A + B + C ≅ (A + B) + C
  +-assoc = op-≅⇒≅ (op-binaryProducts.×-assoc)

  _+₁_ : A ⇒ B → C ⇒ D → A + C ⇒ B + D
  _+₁_ = op-binaryProducts._⁂_

  open op-binaryProducts
    using ()
    renaming ( ⟨⟩-congʳ     to []-congʳ
             ; ⟨⟩-congˡ     to []-congˡ
             ; assocˡ       to +-assocʳ
             ; assocʳ       to +-assocˡ
             ; swap         to +-swap
             ; first        to +-first
             ; second       to +-second
             ; π₁∘⁂         to +₁∘i₁
             ; π₂∘⁂         to +₁∘i₂
             ; ⁂-cong₂      to +₁-cong₂
             ; ⁂∘⟨⟩         to []∘+₁
             ; ⁂∘⁂          to +₁∘+₁
             ; ⟨⟩∘          to ∘[]
             ; first↔second to +-second↔first
             ; swap∘⁂       to +₁∘+-swap
             ; swap∘swap    to +-swap∘swap
             )
    public

  -- since op-×- has type Bifunctor 𝒞.op 𝒞.op 𝒞.op,
  -- need to rewrap in order to type check
  -+- : Bifunctor 𝒞 𝒞 𝒞
  -+- = record
    { F₀           = op-×-.F₀
    ; F₁           = op-×-.F₁
    ; identity     = op-×-.identity
    ; homomorphism = op-×-.homomorphism
    ; F-resp-≈     = op-×-.F-resp-≈
    }
    where op-×- = op-binaryProducts.-×-
          module op-×- = Functor op-×-

  -+_ : Obj → Functor 𝒞 𝒞
  -+_ = appʳ -+-

  _+- : Obj → Functor 𝒞 𝒞
  _+- = appˡ -+-

record Cocartesian : Set (levelOfTerm 𝒞) where
  field
    initial    : Initial
    coproducts : BinaryCoproducts

  module initial    = Initial initial
  module coproducts = BinaryCoproducts coproducts

  open initial
    renaming (! to ¡; !-unique to ¡-unique; !-unique₂ to ¡-unique₂)
    public
  open coproducts hiding (module Dual) public

  module Dual where
    open coproducts.Dual public

    op-cartesian : Cartesian
    op-cartesian = record
      { terminal = ⊥⇒op⊤ initial
      ; products = op-binaryProducts
      }

    module op-cartesian = Cartesian op-cartesian

  open Dual

  ⊥+A≅A : ⊥ + A ≅ A
  ⊥+A≅A = op-≅⇒≅ (op-cartesian.⊤×A≅A)

  A+⊥≅A : A + ⊥ ≅ A
  A+⊥≅A = op-≅⇒≅ (op-cartesian.A×⊤≅A)

  open op-cartesian
    using ()
    -- both are natural isomorphism
    renaming (⊤×--id to ⊥+--id; -×⊤-id to -+⊥-id)
    public

  +-monoidal : Monoidal 𝒞
  +-monoidal = record
    { ⊗                    = -+-
    ; unit                 = unit
    ; unitorˡ              = ⊥+A≅A
    ; unitorʳ              = A+⊥≅A
    ; associator           = ≅.sym +-assoc
    ; unitorˡ-commute-from = ⟺ unitorˡ-commute-to
    ; unitorˡ-commute-to   = ⟺ unitorˡ-commute-from
    ; unitorʳ-commute-from = ⟺ unitorʳ-commute-to
    ; unitorʳ-commute-to   = ⟺ unitorʳ-commute-from
    ; assoc-commute-from   = ⟺ assoc-commute-to
    ; assoc-commute-to     = ⟺ assoc-commute-from
    -- the proof idea of triangle is that the opposite triangle is obtained for free,
    -- but notice that triangle and the opposite triangle form isomorphism.
    ; triangle             = λ {X Y} →
                               Iso-≈ triangle
                                     (Iso-∘ ([ X +- ]-resp-Iso (Iso-swap (iso ⊥+A≅A)))
                                            (iso +-assoc))
                                     ([ -+ Y ]-resp-Iso (Iso-swap (iso A+⊥≅A)))
    ; pentagon             = λ {X Y Z W} →
                               Iso-≈ pentagon
                                     (Iso-∘ ([ X +- ]-resp-Iso (iso +-assoc))
                                     (Iso-∘ (iso +-assoc)
                                            ([ -+ W ]-resp-Iso (iso +-assoc))))
                                     (Iso-∘ (iso +-assoc) (iso +-assoc))
    }
    where op-monoidal = op-cartesian.monoidal
          open Monoidal op-monoidal
          open _≅_

  module +-monoidal = Monoidal +-monoidal

  +-symmetric : Symmetric +-monoidal
  +-symmetric = record
    { braided     = record
      { braiding = record
        { F⇒G = record
          { η           = λ _ → +-swap
          ; commute     = λ _ → ⟺ +₁∘+-swap
          ; sym-commute = λ _ → +₁∘+-swap
          }
        ; F⇐G = record
          { η           = λ _ → +-swap
          ; commute     = λ _ → ⟺ +₁∘+-swap
          ; sym-commute = λ _ → +₁∘+-swap
          }
        ; iso = λ _ → iso +-comm
        }
      ; hexagon₁ = braided.hexagon₂
      ; hexagon₂ = braided.hexagon₁
      }
    ; commutative = commutative
    }
    where op-symmetric = op-cartesian.symmetric
          open Symmetric op-symmetric
          open _≅_

  -- we don't open this module publicly in order to prevent introducing conflicts
  -- with Cartesian category
  module +-symmetric = Symmetric +-symmetric


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

open import LogicalFormulae

open import Orders.Total.Definition

module Orders.Total.Lemmas {a b : _} {A : Set a} (order : TotalOrder A {b}) where

open TotalOrder order

equivMin : {x y : A} → (x < y) → min x y ≡ x
equivMin {x} {y} x<y with totality x y
equivMin {x} {y} x<y | inl (inl x₁) = refl
equivMin {x} {y} x<y | inl (inr y<x) = exFalso (irreflexive (<Transitive x<y y<x))
equivMin {x} {y} x<y | inr x=y rewrite x=y = refl

equivMin' : {x y : A} → (min x y ≡ x) → (x < y) || (x ≡ y)
equivMin' {x} {y} minEq with totality x y
equivMin' {x} {y} minEq | inl (inl x<y) = inl x<y
equivMin' {x} {y} minEq | inl (inr y<x) = exFalso (irreflexive (identityOfIndiscernablesLeft _<_ y<x minEq))
equivMin' {x} {y} minEq | inr x=y = inr x=y

minCommutes : (x y : A) → (min x y) ≡ (min y x)
minCommutes x y with totality x y
minCommutes x y | inl (inl x<y) with totality y x
minCommutes x y | inl (inl x<y) | inl (inl y<x) = exFalso (irreflexive (<Transitive y<x x<y))
minCommutes x y | inl (inl x<y) | inl (inr x<y') = refl
minCommutes x y | inl (inl x<y) | inr y=x = equalityCommutative y=x
minCommutes x y | inl (inr y<x) with totality y x
minCommutes x y | inl (inr y<x) | inl (inl y<x') = refl
minCommutes x y | inl (inr y<x) | inl (inr x<y) = exFalso (irreflexive (<Transitive y<x x<y))
minCommutes x y | inl (inr y<x) | inr y=x = refl
minCommutes x y | inr x=y with totality y x
minCommutes x y | inr x=y | inl (inl x₁) = x=y
minCommutes x y | inr x=y | inl (inr x₁) = refl
minCommutes x y | inr x=y | inr x₁ = x=y

minIdempotent : (x : A) → min x x ≡ x
minIdempotent x with totality x x
minIdempotent x | inl (inl x₁) = refl
minIdempotent x | inl (inr x₁) = refl
minIdempotent x | inr x₁ = refl

swapMin : {x y z : A} → (min x (min y z)) ≡ min y (min x z)
swapMin {x} {y} {z} with totality y z
swapMin {x} {y} {z} | inl (inl y<z) with totality x z
swapMin {x} {y} {z} | inl (inl y<z) | inl (inl x<z) = minCommutes x y
swapMin {x} {y} {z} | inl (inl y<z) | inl (inr z<x) with totality x y
swapMin {x} {y} {z} | inl (inl y<z) | inl (inr z<x) | inl (inl x<y) = exFalso (irreflexive (<Transitive y<z (<Transitive z<x x<y)))
swapMin {x} {y} {z} | inl (inl y<z) | inl (inr z<x) | inl (inr y<x) = equalityCommutative (equivMin y<z)
swapMin {x} {y} {z} | inl (inl y<z) | inl (inr z<x) | inr x=y rewrite x=y = equalityCommutative (equivMin y<z)
swapMin {x} {y} {z} | inl (inl y<z) | inr x=z = minCommutes x y
swapMin {x} {y} {z} | inl (inr z<y) with totality x z
swapMin {x} {y} {z} | inl (inr z<y) | inl (inl x<z) rewrite minCommutes y x = equalityCommutative (equivMin (<Transitive x<z z<y))
swapMin {x} {y} {z} | inl (inr z<y) | inl (inr z<x) with totality y z
swapMin {x} {y} {z} | inl (inr z<y) | inl (inr z<x) | inl (inl y<z) = exFalso (irreflexive (<Transitive z<y y<z))
swapMin {x} {y} {z} | inl (inr z<y) | inl (inr z<x) | inl (inr z<y') = refl
swapMin {x} {y} {z} | inl (inr z<y) | inl (inr z<x) | inr y=z = equalityCommutative y=z
swapMin {x} {y} {z} | inl (inr z<y) | inr x=z rewrite x=z | minCommutes y z = equalityCommutative (equivMin z<y)
swapMin {x} {y} {z} | inr y=z with totality x z
swapMin {x} {y} {z} | inr y=z | inl (inl x<z) = minCommutes x y
swapMin {x} {y} {z} | inr y=z | inl (inr z<x) rewrite y=z | minIdempotent z | minCommutes x z = equivMin z<x
swapMin {x} {y} {z} | inr y=z | inr x=z = minCommutes x y

minMin : {x y : A} → (min x (min x y)) ≡ min x y
minMin {x} {y} with totality x y
minMin {x} {y} | inl (inl x<y) = minIdempotent x
minMin {x} {y} | inl (inr y<x) with totality x y
minMin {x} {y} | inl (inr y<x) | inl (inl x<y) = exFalso (irreflexive (<Transitive y<x x<y))
minMin {x} {y} | inl (inr y<x) | inl (inr y<x') = refl
minMin {x} {y} | inl (inr y<x) | inr x=y = x=y
minMin {x} {y} | inr x=y = minIdempotent x

minFromBoth : {l x y : A} → (l < x) → (l < y) → (l < (min x y))
minFromBoth {a} {x = x} {y} prX prY with totality x y
minFromBoth {a} prX prY | inl (inl x<y) = prX
minFromBoth {a} prX prY | inl (inr y<x) = prY
minFromBoth {a} prX prY | inr x=y = prX


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

open import lib.Basics
open import lib.NConnected
open import lib.types.Bool
open import lib.types.Nat
open import lib.types.TLevel
open import lib.types.Suspension

module lib.types.IteratedSuspension where

⊙Susp^ : ∀ {i} (n : ℕ) → Ptd i → Ptd i
⊙Susp^ O X = X
⊙Susp^ (S n) X = ⊙Susp (⊙Susp^ n X)

abstract
  ⊙Susp^-conn : ∀ {i} (n : ℕ) {X : Ptd i} {m : ℕ₋₂}
    {{_ : is-connected m (de⊙ X)}} → is-connected (⟨ n ⟩₋₂ +2+ m) (de⊙ (⊙Susp^ n X))
  ⊙Susp^-conn O = ⟨⟩
  ⊙Susp^-conn (S n) = Susp-conn (⊙Susp^-conn n)

  ⊙Susp^-conn' : ∀ {i} (n : ℕ) {X : Ptd i}
    {{_ : is-connected 0 (de⊙ X)}} → is-connected ⟨ n ⟩ (de⊙ (⊙Susp^ n X))
  ⊙Susp^-conn' O = ⟨⟩
  ⊙Susp^-conn' (S n) = Susp-conn (⊙Susp^-conn' n)

⊙Susp^-+ : ∀ {i} (m n : ℕ) {X : Ptd i}
  → ⊙Susp^ m (⊙Susp^ n X) == ⊙Susp^ (m + n) X
⊙Susp^-+ O n = idp
⊙Susp^-+ (S m) n = ap ⊙Susp (⊙Susp^-+ m n)

⊙Susp^-fmap : ∀ {i j} (n : ℕ) {X : Ptd i} {Y : Ptd j}
  → X ⊙→ Y → ⊙Susp^ n X ⊙→ ⊙Susp^ n Y
⊙Susp^-fmap O f = f
⊙Susp^-fmap (S n) f = ⊙Susp-fmap (⊙Susp^-fmap n f)

⊙Susp^-fmap-idf : ∀ {i} (n : ℕ) (X : Ptd i)
  → ⊙Susp^-fmap n (⊙idf X) == ⊙idf (⊙Susp^ n X)
⊙Susp^-fmap-idf O X = idp
⊙Susp^-fmap-idf (S n) X =
  ap ⊙Susp-fmap (⊙Susp^-fmap-idf n X) ∙ ⊙Susp-fmap-idf (⊙Susp^ n X)

⊙Susp^-fmap-cst : ∀ {i j} (n : ℕ) {X : Ptd i} {Y : Ptd j}
  → ⊙Susp^-fmap n (⊙cst {X = X} {Y = Y}) == ⊙cst
⊙Susp^-fmap-cst O = idp
⊙Susp^-fmap-cst (S n) = ap ⊙Susp-fmap (⊙Susp^-fmap-cst n)
                           ∙ (⊙Susp-fmap-cst {X = ⊙Susp^ n _})

⊙Susp^-fmap-∘ : ∀ {i j k} (n : ℕ) {X : Ptd i} {Y : Ptd j} {Z : Ptd k}
  (g : Y ⊙→ Z) (f : X ⊙→ Y)
  → ⊙Susp^-fmap n (g ⊙∘ f) == ⊙Susp^-fmap n g ⊙∘ ⊙Susp^-fmap n f
⊙Susp^-fmap-∘ O g f = idp
⊙Susp^-fmap-∘ (S n) g f =
  ap ⊙Susp-fmap (⊙Susp^-fmap-∘ n g f)
  ∙ ⊙Susp-fmap-∘ (⊙Susp^-fmap n g) (⊙Susp^-fmap n f)

⊙Susp^-Susp-split-iso : ∀ {i} (n : ℕ) (X : Ptd i)
  → ⊙Susp^ (S n) X ⊙≃ ⊙Susp^ n (⊙Susp X)
⊙Susp^-Susp-split-iso O     X = ⊙ide _
⊙Susp^-Susp-split-iso (S n) X = ⊙Susp-emap (⊙Susp^-Susp-split-iso n X)

⊙Sphere : (n : ℕ) → Ptd₀
⊙Sphere n = ⊙Susp^ n ⊙Bool

Sphere : (n : ℕ) → Type₀
Sphere n = de⊙ (⊙Sphere n)

abstract
  instance
    Sphere-conn : ∀ (n : ℕ) → is-connected ⟨ n ⟩₋₁ (Sphere n)
    Sphere-conn 0 = inhab-conn true
    Sphere-conn (S n) = Susp-conn (Sphere-conn n)

-- favonia: [S¹] has its own elim rules in Circle.agda.
⊙S⁰ = ⊙Sphere 0
⊙S¹ = ⊙Sphere 1
⊙S² = ⊙Sphere 2
⊙S³ = ⊙Sphere 3
S⁰ = Sphere 0
S¹ = Sphere 1
S² = Sphere 2
S³ = Sphere 3


{-# OPTIONS --without-K --safe #-}
module Categories.Category.Dagger.Instance.Rels where

open import Data.Product
open import Function
open import Relation.Binary.PropositionalEquality
open import Level

open import Categories.Category.Dagger
open import Categories.Category.Instance.Rels

RelsHasDagger : ∀ {o ℓ} → HasDagger (Rels o ℓ)
RelsHasDagger = record
  { _† = flip
  ; †-identity = λ _ _ → (λ p → lift (sym (lower p))) , λ p → lift (sym (lower p))
  ; †-homomorphism = λ _ _ → map₂ swap , map₂ swap
  ; †-resp-≈ = flip
  ; †-involutive = λ _ _ _ → id , id
  }

RelsDagger : ∀ o ℓ → DaggerCategory (suc o) (suc (o ⊔ ℓ)) (o ⊔ ℓ)
RelsDagger o ℓ = record
  { C = Rels o ℓ
  ; hasDagger = RelsHasDagger
  }


module Avionics.Bool where

open import Data.Bool using (Bool; true; false; _∧_; T)
open import Data.Unit using (⊤; tt)
open import Data.Product using (_×_; _,_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; inspect; [_])

--open import Avionics.Product using (_×_; ⟨_,_⟩)

--TODO: Replace with T⇔≡ from standard library
≡→T : ∀ {b : Bool} → b ≡ true → T b
≡→T refl = tt

T→≡ : ∀ {b : Bool} → T b → b ≡ true
T→≡ {true} tt = refl

T∧→× : ∀ {x y} → T (x ∧ y) → (T x) × (T y)
T∧→× {true} {true} tt = tt , tt
--TODO: Find a way to extract the function below from `T-∧` (standard library)
--T∧→× {x} {y} = ? -- Equivalence.to (T-∧ {x} {y})

×→T∧ : ∀ {x y} → (T x) × (T y) → T (x ∧ y)
×→T∧ {true} {true} (tt , tt) = tt

lem∧ : {a b : Bool} → a ∧ b ≡ true → a ≡ true × b ≡ true
lem∧ {true} {true} refl = refl , refl

∧≡true→×≡ : ∀ {A B : Set} {f : A → Bool} {g : B → Bool}
            (n : A) (m : B)
          → f n ∧ g m ≡ true
          → f n ≡ true × g m ≡ true
∧≡true→×≡ {f = f} {g = g} n m fn∧gm≡true = lem∧ {f n} {g m} fn∧gm≡true


-- Some theorems about operations on non-deterministic values

module nondet-thms where

open import bool
open import bool-thms
open import nat
open import eq
open import nat-thms
open import functions
open import nondet

----------------------------------------------------------------------
-- Theorems about values contained in non-deterministic values:

-- A proof that x is value of the non-deterministic tree y:
-- either it is equal to a deterministic value (ndrefl)
-- or it is somewhere in the tree.
-- If it is in the tree then we need to construct both branches of the tree,
-- and a proof that x is in one of the branches
-- A consequence of this is that any proof that x ∈ y contains the path
-- to x in the tree.
--
-- Example:
-- hInCoin : H ∈ coin
-- hInCoin = left (Val H) (Val T) ndrefl
--
-- Since H is on the left side of coin, we use the left constructor
-- The branches of the tree are (Val H) and (Val T),
-- and since H is identically equal to H this completes the proof.
data _∈_ {A : Set} (x : A) : (y : ND A) → Set where
  ndrefl : x ∈ (Val x)
  left   : (l : ND A) → (r : ND A) → x ∈ l → x ∈ (l ?? r)
  right  : (l : ND A) → (r : ND A) → x ∈ r → x ∈ (l ?? r)

-- A basic inductive lemma that shows that ∈ is closed under function
-- application. That is, if x ∈ nx, then f x ∈ mapND f nx
--
-- Example:
-- ndCons : ... → xs ∈ nxs → (x :: xs) ∈ mapND (_::_ x) nxs
∈-apply : {A B : Set} → (f : A → B) → (x : A) → (nx : ND A)
        → x ∈ nx → (f x) ∈ (mapND f nx)
∈-apply f x (Val .x) ndrefl = ndrefl
∈-apply f x (l ?? r) (left  .l .r k) =
  left  (mapND f l) (mapND f r) (∈-apply f x l k)
∈-apply f x (l ?? r) (right .l .r k) =
  right (mapND f l) (mapND f r) (∈-apply f x r k)

----------------------------------------------------------------------
-- Theorems about 'mapND':

-- Combine two mapND applications into one:
mapND-mapND : ∀ {A B C : Set} → (f : B → C) (g : A → B) (xs : ND A)
            → mapND f (mapND g xs) ≡ mapND (f ∘ g) xs
mapND-mapND f g (Val x) = refl
mapND-mapND f g (t1 ?? t2)
  rewrite mapND-mapND f g t1 | mapND-mapND f g t2 = refl

----------------------------------------------------------------------
-- Theorems about 'always':

-- Extend validity of a function with a deterministic argument to validity of
-- the corresponding non-deterministic function:
always-mapND : ∀ {A : Set} → (p : A → 𝔹) (xs : ND A)
            → ((y : A) → p y ≡ tt)
            → always (mapND p xs) ≡ tt
always-mapND _ (Val y) prf = prf y
always-mapND p (t1 ?? t2) prf
  rewrite always-mapND p t1 prf
        | always-mapND p t2 prf = refl

-- Extend validity of a function with a deterministic argument to validity of
-- the corresponding non-deterministic function:
always-with-nd-arg : ∀ {A : Set} → (p : A → ND 𝔹) (xs : ND A)
               → ((y : A) → always (p y) ≡ tt)
               → always (with-nd-arg p xs) ≡ tt
always-with-nd-arg _ (Val y) prf = prf y
always-with-nd-arg p (t1 ?? t2) prf
  rewrite always-with-nd-arg p t1 prf
        | always-with-nd-arg p t2 prf = refl

-- Extend validity of a deterministic function to validity of
-- corresponding function with non-deterministic result:
always-toND : ∀ {A : Set} → (p : A → 𝔹) (x : A)
          → (p x) ≡ tt → always (toND p x) ≡ tt
always-toND _ _ p = p

-- Extend validity of a deterministic function to validity of
-- corresponding non-deterministic function:
always-det-to-nd : ∀ {A : Set} → (p : A → 𝔹)
          → ((y : A) → (p y) ≡ tt)
          → (xs : ND A) → always (det-to-nd p xs) ≡ tt
always-det-to-nd p u xs =
  always-with-nd-arg (toND p) xs (λ x → always-toND p x (u x))

----------------------------------------------------------------------
-- Theorems about 'satisfy':

-- A theorem like filter-map in functional programming:
satisfy-mapND : ∀ {A B : Set} → (f : A → B) (xs : ND A) (p : B → 𝔹)
             → (mapND f xs) satisfy p ≡ xs satisfy (p ∘ f)
satisfy-mapND _ (Val x) _ = refl
satisfy-mapND f (t1 ?? t2) p
 rewrite satisfy-mapND f t1 p
       | satisfy-mapND f t2 p = refl

-- Extend validity of function with deterministic argument to validity of
-- non-deterministic function:
satisfy-with-nd-arg : ∀ {A B : Set} → (p : B → 𝔹) (f : A → ND B) (xs : ND A)
               → ((y : A) → (f y) satisfy p ≡ tt)
               → (with-nd-arg f xs) satisfy p ≡ tt
satisfy-with-nd-arg _ _ (Val y) prf = prf y
satisfy-with-nd-arg p f (t1 ?? t2) prf
  rewrite satisfy-with-nd-arg p f t1 prf
        | satisfy-with-nd-arg p f t2 prf = refl

----------------------------------------------------------------------
-- Theorems about 'every':

mapNDval : ∀ (f : ℕ → ℕ) (v : ℕ) (x : ND ℕ) →
         every _=ℕ_ v x ≡ tt → every _=ℕ_ (f v) (mapND f x) ≡ tt
mapNDval f v (Val x) u rewrite =ℕ-to-≡ {v} {x} u | =ℕ-refl (f x) = refl
mapNDval f v (t1 ?? t2) u
  rewrite mapNDval f v t1 (&&-fst u)
        | mapNDval f v t2 (&&-snd {every _=ℕ_ v t1} {every _=ℕ_ v t2} u) = refl

----------------------------------------------------------------------
-- This theorms allows to weaken a predicate which is always satisfied:
weak-always-predicate : ∀ {A : Set} → (p p1 : A → 𝔹) (xs : ND A)
                → xs satisfy p ≡ tt
                → xs satisfy (λ x → p1 x || p x) ≡ tt
weak-always-predicate p p1 (Val x) u rewrite u | ||-tt (p1 x) = refl
weak-always-predicate p p1 (t1 ?? t2) u
  rewrite weak-always-predicate p p1 t1 (&&-fst u)
        | weak-always-predicate p p1 t2 (&&-snd {t1 satisfy p} {t2 satisfy p} u)
  = refl

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


{-# OPTIONS --cubical-compatible --rewriting --local-confluence-check #-}

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

infix 4 _≡_

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

{-# BUILTIN REWRITE _≡_ #-}

run : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → A → B
run refl x = x

ap : ∀ {a b} {A : Set a} {B : Set b} (f : A → B) {a₁ a₂} → a₁ ≡ a₂ → f a₁ ≡ f a₂
ap f refl = refl

transport1 : ∀ {a b} {A : Set a} (B : A → Set b) {x y : A} (p : x ≡ y) → B x → B y
transport1 B p = run (ap B p)

ap-const : ∀ {a b} {A : Set a} {B : Set b} (f : B) {a₁ a₂ : A} (p : a₁ ≡ a₂) → ap (\ _ → f) p ≡ refl
ap-const f refl = refl
{-# REWRITE ap-const #-}

ap2 : ∀ {a b rv} {A : Set a} {B : A → Set b} {RV : Set rv} (fn : ∀ a → B a → RV) {a₁ a₂} (pa : a₁ ≡ a₂) {b₁ b₂} (pb : transport1 B pa b₁ ≡ b₂) → fn a₁ b₁ ≡ fn a₂ b₂
ap2 fn refl refl = refl

transport2 : ∀ {a b rv} {A : Set a} {B : A → Set b} (RV : ∀ a → B a → Set rv) {a₁ a₂} (pa : a₁ ≡ a₂) {b₁ b₂} (pb : transport1 B pa b₁ ≡ b₂) → RV a₁ b₁  → RV a₂ b₂
transport2 RV pa pb = run (ap2 RV pa pb)

ap2-const : ∀ {a b rv} {A : Set a} {B : A → Set b} {RV : Set rv} (fn : RV) {a₁ a₂} (pa : a₁ ≡ a₂) {b₁ b₂} (pb : transport1 B pa b₁ ≡ b₂) → ap2 {a} {b} {rv} {A} {B} {RV} (λ _ _ → fn) pa pb ≡ refl
ap2-const fn refl refl = refl
{-# REWRITE ap2-const #-}

ap2-const' : ∀ {a b rv} {A : Set a} {B : A → Set b} {RV : Set rv} (fn : RV) {a₁ a₂} (pa : a₁ ≡ a₂) {b₁ b₂} (pb : transport1 B pa b₁ ≡ b₂) → ap2 {a} {b} {rv} {A} {B} {RV} (λ _ _ → fn) pa pb ≡ refl
ap2-const' {a} {b} {rv} {A} {B} {RV} fn pa pb = {!ap2 {a} {b} {_} {A} {_} {_} (λ _ _ → fn ≡ fn) pa _!}


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

module hott.truncation.const where

open import sum
open import equality
open import function.overloading
open import hott.truncation.core
open import hott.level

const-factorisation : ∀ {i j}{A : Set i}{B : Set j}
                    → h 2 B
                    → (f : A → B)
                    → ((x y : A) → f x ≡ f y)
                    → (Trunc 1 A → B)
const-factorisation {A = A}{B} hB f c = f'
  where
    E : Set _
    E = Σ B λ b → (a : A) → f a ≡ b

    p : E → B
    p (b , _) = b

    lem : (a₀ : A)(b : B)(u : (a : A) → f a ≡ b)
        → (_≡_ {A = E} (f a₀ , λ a → c a a₀) (b , u))
    lem a₀ b u = unapΣ (u a₀ , h1⇒prop (Π-level (λ a → hB (f a) b)) _ u)

    hE : A → contr E
    hE a₀ = (f a₀ , λ a → c a a₀) , λ { (b , u) → lem a₀ b u }

    u : Trunc 1 A → contr E
    u = Trunc-elim 1 _ _ (contr-h1 E) hE

    s : Trunc 1 A → E
    s a = proj₁ (u a)

    f' : Trunc 1 A → B
    f' a = p (s a)


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

syntax Sum | S

type
  _⊕_ : 2-ary | l30

term
  inl  : α  ->  α ⊕ β
  inr  : β  ->  α ⊕ β
  case : α ⊕ β  α.γ  β.γ  ->  γ

theory
  (lβ) a : α   f : α.γ  g : β.γ |> case (inl(a), x.f[x], y.g[y])      = f[a]
  (rβ) b : β   f : α.γ  g : β.γ |> case (inr(b), x.f[x], y.g[y])      = g[b]
  (cη) s : α ⊕ β  c : (α ⊕ β).γ |> case (s, x.c[inl(x)], y.c[inr(y)]) = c[s]
-}

module Sum.Signature where

open import SOAS.Context

-- Type declaration
data ST : Set where
  _⊕_ : ST → ST → ST
infixl 30 _⊕_

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

-- Operator symbols
data Sₒ : Set where
  inlₒ inrₒ : {α β : ST} → Sₒ
  caseₒ : {α β γ : ST} → Sₒ

-- Term signature
S:Sig : Signature Sₒ
S:Sig = sig λ
  { (inlₒ  {α}{β})    → (⊢₀ α) ⟼₁ α ⊕ β
  ; (inrₒ  {α}{β})    → (⊢₀ β) ⟼₁ α ⊕ β
  ; (caseₒ {α}{β}{γ}) → (⊢₀ α ⊕ β) , (α ⊢₁ γ) , (β ⊢₁ γ) ⟼₃ γ
  }

open Signature S:Sig public


{-# OPTIONS --without-K  #-}
module algebra.group.core where

open import level
open import algebra.monoid.core
open import equality.core
open import function.isomorphism
open import sum

record IsGroup {i} (G : Set i) : Set i where
  field instance mon : IsMonoid G
  open IsMonoid mon public

  field
    inv : G → G
    linv : (x : G) → inv x * x ≡ e
    rinv : (x : G) → x * inv x ≡ e

Group : ∀ i → Set (lsuc i)
Group i = Σ (Set i) IsGroup

module _ {i} {G : Set i} ⦃ grp : IsGroup G ⦄ where
  open IsGroup ⦃ ... ⦄

  left-translation-iso : (g : G) → G ≅ G
  left-translation-iso g = record
    { to = λ x → g * x
    ; from = λ x → inv g * x
    ; iso₁ = λ x → sym (assoc _ _ _)
           · ap (λ u → u * x) (linv g)
           · lunit x
    ; iso₂ = λ x → sym (assoc _ _ _)
           · ap (λ u → u * x) (rinv g)
           · lunit x }

  right-translation-iso : (g : G) → G ≅ G
  right-translation-iso g = record
    { to = λ x → x * g
    ; from = λ x → x * inv g
    ; iso₁ = λ x → assoc _ _ _
           · ap (λ u → x * u) (rinv g)
           · runit x
    ; iso₂ = λ x → assoc _ _ _
           · ap (λ u → x * u) (linv g)
           · runit x }


module Thesis.SIRelBigStep.DenSem where

open import Data.Nat
open import Data.Product
open import Thesis.SIRelBigStep.Syntax

open import Data.Nat

⟦_⟧Type : Type → Set
⟦ σ ⇒ τ ⟧Type = ⟦ σ ⟧Type → ⟦ τ ⟧Type
⟦ nat ⟧Type = ℕ
⟦ pair τ1 τ2 ⟧Type = ⟦ τ1 ⟧Type × ⟦ τ2 ⟧Type

import Base.Denotation.Environment
module Den = Base.Denotation.Environment Type ⟦_⟧Type
open import Base.Data.DependentList

⟦_⟧Const : ∀ {τ} → Const τ → ⟦ τ ⟧Type
⟦ lit n ⟧Const = n

⟦_⟧Primitive : ∀ {τ} → Primitive τ → ⟦ τ ⟧Type
⟦ succ ⟧Primitive = suc
⟦ add ⟧Primitive = λ { (n1 , n2) → n1 + n2}

⟦_⟧Term : ∀ {Γ τ} → Term Γ τ → Den.⟦ Γ ⟧Context → ⟦ τ ⟧Type
⟦_⟧SVal : ∀ {Γ τ} → SVal Γ τ → Den.⟦ Γ ⟧Context → ⟦ τ ⟧Type
⟦ var x ⟧SVal ρ = Den.⟦ x ⟧Var ρ
⟦ abs t ⟧SVal ρ = λ v → ⟦ t ⟧Term (v • ρ)
⟦ cons sv1 sv2 ⟧SVal ρ = ⟦ sv1 ⟧SVal ρ , ⟦ sv2 ⟧SVal ρ
⟦ const c ⟧SVal ρ = ⟦ c ⟧Const

⟦ val sv ⟧Term ρ = ⟦ sv ⟧SVal ρ
⟦ app s t ⟧Term ρ = ⟦ s ⟧SVal ρ (⟦ t ⟧SVal ρ)
⟦ lett s t ⟧Term ρ = ⟦ t ⟧Term ((⟦ s ⟧Term ρ) • ρ)
⟦ primapp vs vt ⟧Term ρ = ⟦ vs ⟧Primitive (⟦ vt ⟧SVal ρ)


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

module Fragment.Examples.CSemigroup.Arith.Reasoning where

open import Fragment.Examples.CSemigroup.Arith.Base

+-direct : ∀ {m n} → (m + 2) + (3 + n) ≡ m + (n + 5)
+-direct {m} {n} = begin
    (m + 2) + (3 + n)
  ≡⟨ fragment CSemigroupFrex +-csemigroup ⟩
    m + (n + 5)
  ∎

open import Data.Nat.Properties using (*-distribˡ-+)

+-inner : ∀ {m n k} → k * (m + 2) + k * (3 + n) ≡ (m + n + 5) * k
+-inner {m} {n} {k} = begin
    k * (m + 2) + k * (3 + n)
  ≡⟨ sym (*-distribˡ-+ k (m + 2) (3 + n)) ⟩
    k * ((m + 2) + (3 + n))
  ≡⟨ cong (k *_) (fragment CSemigroupFrex +-csemigroup) ⟩
    k * (m + n + 5)
  ≡⟨ fragment CSemigroupFrex *-csemigroup ⟩
    (m + n + 5) * k
  ∎


{-# OPTIONS --without-K #-}
module sets.list.properties where

open import level
open import equality.core
open import sets.list.core

module _ {i}{A : Set i} where
  data all {j}(P : A → Set j) : List A → Set (i ⊔ j) where
    mk-all : ∀ {x xs} → P x → all P xs → all P (x ∷ xs)

  data any {j}(P : A → Set j) : List A → Set (i ⊔ j) where
    hd-any : ∀ {x xs} → P x → any P (x ∷ xs)
    tl-any : ∀ {x xs} → any P xs → any P (x ∷ xs)

  elem : A → List A → Set i
  elem x = any (λ x' → x ≡ x')


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.Band.Properties where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Data.Nat
open import Cubical.Data.NatPlusOne

open import Cubical.Algebra
open import Cubical.Algebra.Properties
open import Cubical.Algebra.Semigroup.Properties using (isPropIsSemigroup)

open import Cubical.Relation.Binary.Reasoning.Equality

private
  variable
    ??? : Level

isPropIsBand : ??? {B : Type ???} {_???_} ??? isProp (IsBand B _???_)
isPropIsBand {_} {_} {_???_} (isband aSemigroup aIdem) (isband bSemigroup bIdem) =
  cong??? isband (isPropIsSemigroup aSemigroup bSemigroup) (isPropIdempotent (IsSemigroup.is-set aSemigroup) _???_ aIdem bIdem)

module BandLemmas (S : Band ???) where
  open Band S

  ^-id : ??? x n ??? x ^ n ??? x
  ^-id x one          = refl
  ^-id x (2+ zero)    = idem x
  ^-id x (2+ (suc n)) =
    x ??? (x ??? x ^ 1+ n) ???????? assoc x x (x ^ 1+ n) ???
    x ??? x ??? x ^ 1+ n   ?????? cong (_??? x ^ 1+ n) (idem x) ???
    x ??? x ^ 1+ n       ?????? ^-id x (2+ n) ???
    x                  ???

open BandLemmas public


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

module hott.functions where

open import hott.core.universe
open import hott.core.equality

-- Composition of functions.
_∘_ : ∀ {ℓ₀ ℓ₁ ℓ₂ : Level} → {A : Type ℓ₀} {B : Type ℓ₁} {C : Type ℓ₂}
    → (B → C) → (A → B) → A → C
f ∘ g = λ x → f (g x)

-- The identity function.
id : ∀{ℓ} {A : Type ℓ} → A → A
id x = x

-- Change the order of arguments in a bivariate function.
flip : {a b c : Level}{A : Type a}{B : Type b}{C : Type c}
     → (A → B → C) → (B → A → C)
flip f b a = f a b

-- We want compostion to have very high precedence.
infixr 100 _∘_

-- The constant function.
constant : ∀ {ℓ₀ ℓ₁}{A : Type ℓ₀}{B : Type ℓ₁} → A → B → A
constant a b = a

-- Alternate syntax for dependent function type.
Π : ∀{ℓ₀ ℓ₁}{A : Type ℓ₀}(B : A → Type ℓ₁) → Type (ℓ₀ ⊔ ℓ₁)
Π {_}{_}{A} B = (a : A) → B(a)

-- One should use f ~ g to mean that f and g are homotopic.
_~_   : ∀{ℓ₀ ℓ₁}{A : Type ℓ₀}{B : Type ℓ₁} (f g : A → B) → Type (ℓ₁ ⊔ ℓ₀)
f ~ g = Π  λ x → f x ≡ g x

infixr 1   _~_


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

open import Fragment.Algebra.Signature

module Fragment.Equational.Theory.Laws (Σ : Signature) where

open import Fragment.Equational.Theory.Base using (Eq)

open import Function using (_∘_)
open import Data.Empty using (⊥)
open import Data.Fin using (#_)
open import Data.Sum using (inj₁; inj₂)
open import Data.Product using (_,_)
import Relation.Binary.PropositionalEquality as PE

open import Fragment.Algebra.Free Σ
open import Fragment.Algebra.Free.Syntax Σ (PE.setoid ⊥)

module _ where

  private
    a = # 0

  dne : ops Σ 1 → Eq Σ 1
  dne ~ = ⟨ ~ ⟩₁ ⟨ ~ ⟩₁ ⟨ a ⟩ , ⟨ a ⟩

module _ (e : ops Σ 0) where

  private
    a = # 0

  idₗ : ops Σ 2 → Eq Σ 1
  idₗ • = ⟨ e ⟩₀ ⟨ • ⟩₂ ⟨ a ⟩ , ⟨ a ⟩

  idᵣ : ops Σ 2 → Eq Σ 1
  idᵣ • = ⟨ a ⟩ ⟨ • ⟩₂ ⟨ e ⟩₀ , ⟨ a ⟩

  anₗ : ops Σ 2 → Eq Σ 1
  anₗ • = ⟨ e ⟩₀ ⟨ • ⟩₂ ⟨ a ⟩ , ⟨ e ⟩₀

  anᵣ : ops Σ 2 → Eq Σ 1
  anᵣ • = ⟨ a ⟩ ⟨ • ⟩₂ ⟨ e ⟩₀ , ⟨ e ⟩₀

  invₗ : ops Σ 1 → ops Σ 2 → Eq Σ 1
  invₗ ~ • = (⟨ ~ ⟩₁ ⟨ a ⟩) ⟨ • ⟩₂ ⟨ a ⟩ , ⟨ e ⟩₀

  invᵣ : ops Σ 1 → ops Σ 2 → Eq Σ 1
  invᵣ ~ • = ⟨ a ⟩ ⟨ • ⟩₂ (⟨ ~ ⟩₁ ⟨ a ⟩) , ⟨ e ⟩₀

module _ where

  private

    a = # 0
    b = # 1
    c = # 2

  hom : ops Σ 1 → ∀ {n} → ops Σ n → Eq Σ n
  hom h {n} f =
      ⟨ h ⟩₁ term f (map ⟨_⟩ (allFin n))
    ,
      term f (map (⟨ h ⟩₁_ ∘ ⟨_⟩) (allFin n))
    where open import Data.Vec using (map; allFin)

  comm : ops Σ 2 → Eq Σ 2
  comm • = ⟨ a ⟩ ⟨ • ⟩₂ ⟨ b ⟩ , ⟨ b ⟩ ⟨ • ⟩₂ ⟨ a ⟩

  assoc : ops Σ 2 → Eq Σ 3
  assoc • =
      (⟨ a ⟩ ⟨ • ⟩₂ ⟨ b ⟩) ⟨ • ⟩₂ ⟨ c ⟩
    ,
      ⟨ a ⟩ ⟨ • ⟩₂ (⟨ b ⟩ ⟨ • ⟩₂ ⟨ c ⟩)


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

open import LogicalFormulae
open import Setoids.Setoids
open import Functions.Definition
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Sets.FinSet.Definition
open import Groups.Definition
open import Groups.SymmetricGroups.Definition
open import Decidable.Sets
open import Boolean.Definition

module Groups.FreeGroup.Definition where

data FreeCompletion {a : _} (A : Set a) : Set a where
  ofLetter : A → FreeCompletion A
  ofInv : A → FreeCompletion A

freeCompletionMap : {a b : _} {A : Set a} {B : Set b} (f : A → B) (w : FreeCompletion A) → FreeCompletion B
freeCompletionMap f (ofLetter x) = ofLetter (f x)
freeCompletionMap f (ofInv x) = ofInv (f x)

freeInverse : {a : _} {A : Set a} (l : FreeCompletion A) → FreeCompletion A
freeInverse (ofLetter x) = ofInv x
freeInverse (ofInv x) = ofLetter x

ofLetterInjective : {a : _} {A : Set a} {x y : A} → (ofLetter x ≡ ofLetter y) → x ≡ y
ofLetterInjective refl = refl

ofInvInjective : {a : _} {A : Set a} {x y : A} → (ofInv x ≡ ofInv y) → x ≡ y
ofInvInjective refl = refl

ofLetterOfInv : {a : _} {A : Set a} {x y : A} → ofLetter x ≡ ofInv y → False
ofLetterOfInv ()

decidableFreeCompletion : {a : _} {A : Set a} → DecidableSet A → DecidableSet (FreeCompletion A)
decidableFreeCompletion {A = A} dec = pr
  where
    pr : (a b : FreeCompletion A) → (a ≡ b) || (a ≡ b → False)
    pr (ofLetter x) (ofLetter y) with dec x y
    ... | inl refl = inl refl
    ... | inr x!=y = inr λ p → x!=y (ofLetterInjective p)
    pr (ofLetter x) (ofInv y) = inr λ ()
    pr (ofInv x) (ofLetter y) = inr λ ()
    pr (ofInv x) (ofInv y) with dec x y
    ... | inl refl = inl refl
    ... | inr x!=y = inr λ p → x!=y (ofInvInjective p)

freeCompletionEqual : {a : _} {A : Set a} (dec : DecidableSet A) (x y : FreeCompletion A) → Bool
freeCompletionEqual dec x y with decidableFreeCompletion dec x y
freeCompletionEqual dec x y | inl x₁ = BoolTrue
freeCompletionEqual dec x y | inr x₁ = BoolFalse

freeCompletionEqualFalse : {a : _} {A : Set a} (dec : DecidableSet A) {x y : FreeCompletion A} → ((x ≡ y) → False) → (freeCompletionEqual dec x y) ≡ BoolFalse
freeCompletionEqualFalse dec {x = x} {y} x!=y with decidableFreeCompletion dec x y
freeCompletionEqualFalse dec {x} {y} x!=y | inl x=y = exFalso (x!=y x=y)
freeCompletionEqualFalse dec {x} {y} x!=y | inr _ = refl

freeCompletionEqualFalse' : {a : _} {A : Set a} (dec : DecidableSet A) {x y : FreeCompletion A} → .((freeCompletionEqual dec x y) ≡ BoolFalse) → (x ≡ y) → False
freeCompletionEqualFalse' dec {x} {y} pr with decidableFreeCompletion dec x y
freeCompletionEqualFalse' dec {x} {y} () | inl x₁
freeCompletionEqualFalse' dec {x} {y} pr | inr ans = ans


import      Lvl
open import Type

module Type.Cardinality {ℓₗ : Lvl.Level} where

import Type.Functions
import Logic.Predicate

module _ {ℓₒ₁}{ℓₒ₂} (X : Type{ℓₒ₁}) (Y : Type{ℓₒ₂}) where
  open Type.Functions{ℓₗ}{ℓₒ₁}{ℓₒ₂}
  open Logic.Predicate{ℓₗ}

  _≍_ : Type{ℓₗ Lvl.⊔ ℓₒ₁ Lvl.⊔ ℓₒ₂}
  _≍_ = ∃(Bijective{X}{Y})

  _≼_ : Type{ℓₗ Lvl.⊔ ℓₒ₁ Lvl.⊔ ℓₒ₂}
  _≼_ = ∃(Injective{X}{Y})

  _≽_ : Type{ℓₗ Lvl.⊔ ℓₒ₁ Lvl.⊔ ℓₒ₂}
  _≽_ = ∃(Surjective{X}{Y})


{-# OPTIONS --type-in-type #-}
module Primitive where

infixr 2 _,_
record Σ (A : Set)(B : A → Set) : Set where
  constructor _,_
  field fst : A
        snd : B fst

open Σ

data ⊤ : Set where
  tt : ⊤

∃ : {A : Set}(B : A → Set) → Set
∃ B = Σ _ B

infix 10 _≡_

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

trans : ∀ {A B C}{a : A}{b : B}{c : C} → a ≡ b → b ≡ c → a ≡ c
trans refl p = p

sym : ∀ {A B}{a : A}{b : B} → a ≡ b → b ≡ a
sym refl = refl

resp : ∀ {A}{B : A → Set}{a a' : A} →
       (f : (a : A) → B a) → a ≡ a' → f a ≡ f a'
resp f refl = refl

Cat : Set
Cat =
  ∃ λ (Obj : Set) →
  ∃ λ (Hom : Obj → Obj → Set) →
  ∃ λ (id : ∀ X → Hom X X) →
  ∃ λ (_○_ : ∀ {X Y Z} → Hom Y Z → Hom X Y → Hom X Z) →
  ∃ λ (idl : ∀ {X Y}{f : Hom X Y} → id Y ○ f ≡ f) →
  ∃ λ (idr : ∀ {X Y}{f : Hom X Y} → f ○ id X ≡ f) →
  ∃ λ (assoc : ∀ {W X Y Z}{f : Hom W X}{g : Hom X Y}{h : Hom Y Z} →
                (h ○ g) ○ f ≡ h ○ (g ○ f)) →
  ⊤

Obj : (C : Cat) → Set
Obj C = fst C

Hom : (C : Cat) → Obj C → Obj C → Set
Hom C = fst (snd C)

id : (C : Cat) → ∀ X → Hom C X X
id C = fst (snd (snd C))

comp : (C : Cat) → ∀ {X Y Z} → Hom C Y Z → Hom C X Y → Hom C X Z
comp C = fst (snd (snd (snd C)))

idl : (C : Cat) → ∀ {X Y}{f : Hom C X Y} → comp C (id C Y) f ≡ f
idl C = fst (snd (snd (snd (snd C))))

idr : (C : Cat) → ∀ {X Y}{f : Hom C X Y} → comp C f (id C X) ≡ f
idr C = fst (snd (snd (snd (snd (snd C)))))

assoc : (C : Cat) → ∀ {W X Y Z}{f : Hom C W X}{g : Hom C X Y}{h : Hom C Y Z} →
        comp C (comp C h g) f ≡ comp C h (comp C g f)
assoc C = fst (snd (snd (snd (snd (snd (snd C))))))

{-
record Functor (C D : Cat) : Set where
  field Fun : Obj C → Obj D
        map : ∀ {X Y} → (Hom C X Y) → Hom D (Fun X) (Fun Y)
        mapid : ∀ {X} → map (id C X) ≡ id D (Fun X)
        map○ : ∀ {X Y Z}{f : Hom C X Y}{g : Hom C Y Z} →
               map (_○_ C g f) ≡ _○_ D (map g) (map f)

open Functor

idF : ∀ C → Functor C C
idF C = record {Fun = \x → x; map = \x → x; mapid = refl; map○ = refl}

_•_ : ∀ {C D E} → Functor D E → Functor C D → Functor C E
F • G = record {Fun = \X → Fun F (Fun G X);
                 map = \f → map F (map G f);
                 mapid = trans (resp (\x → map F x) (mapid G)) (mapid F);
                 map○ = trans (resp (\x → map F x) (map○ G)) (map○ F)}

record Nat {C D : Cat} (F G : Functor C D) : Set where
  field η : (X : Obj C) → Hom D (Fun F X) (Fun G X)
        law : {X Y : Obj C}{f : Hom C X Y} →
              _○_ D (η Y) (map F f) ≡ _○_ D (map G f) (η X)

open Nat

_▪_ : ∀ {C D : Cat}{F G H : Functor C D} → Nat G H → Nat F G → Nat F H
_▪_ {D = D} A B =
  record {
    η = \X → _○_ D (η A X) (η B X);
    law = \{X}{Y} →
      trans (assoc D)
            (trans (resp (\f → _○_ D (η A Y) f) (law B))
                   (trans (sym (assoc D))
                          (trans (resp (\g → _○_ D g (η B X)) (law A))
                                 (assoc D))))
  }

-}


------------------------------------------------------------------------
-- The "always true" predicate, □
------------------------------------------------------------------------

{-# OPTIONS --sized-types #-}

module Delay-monad.Sized.Always where

open import Prelude
open import Prelude.Size

open import Delay-monad.Sized
open import Delay-monad.Sized.Monad

-- The "always true" predicate, □.

mutual

  data □ {a p} {A : Size → Type a} (i : Size) (P : A ∞ → Type p) :
         Delay A ∞ → Type (a ⊔ p) where
    now   : ∀ {x} → P x → □ i P (now x)
    later : ∀ {x} → □′ i P (force x) → □ i P (later x)

  record □′ {a p} {A : Size → Type a} (i : Size) (P : A ∞ → Type p)
            (x : Delay A ∞) : Type (a ⊔ p) where
    coinductive
    field
      force : {j : Size< i} → □ j P x

open □′ public

-- □ is closed, in a certain sense, under bind.

□->>= :
  ∀ {i a b p q}
    {A : Size → Type a} {B : Size → Type b}
    {P : A ∞ → Type p} {Q : B ∞ → Type q}
    {x : Delay A ∞} {f : ∀ {i} → A i → Delay B i} →
  □ i P x → (∀ {x} → P x → □ i Q (f x)) → □ i Q (x >>= f)
□->>= (now P-x)   □-f = □-f P-x
□->>= (later □-x) □-f = later λ { .force → □->>= (force □-x) □-f }


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

module CombiningProofs.CommAddGlobalHints where

open import PA.Axiomatic.Standard.Base

+-leftIdentity : ∀ n → zero + n ≡ n
+-leftIdentity = PA₃

+-rightIdentity : ∀ n → n + zero ≡ n
+-rightIdentity = ℕ-ind A A0 is
  where
  A : ℕ → Set
  A i = i + zero ≡ i
  {-# ATP definition A #-}

  A0 : A zero
  A0 = +-leftIdentity zero

  postulate is : ∀ i → A i → A (succ i)
  {-# ATP prove is #-}

x+Sy≡S[x+y] : ∀ m n → m + succ n ≡ succ (m + n)
x+Sy≡S[x+y] m n = ℕ-ind A A0 is m
  where
  A : ℕ → Set
  A i = i + succ n ≡ succ (i + n)
  {-# ATP definition A #-}

  postulate A0 : A zero
  {-# ATP prove A0 #-}

  postulate is : ∀ i → A i → A (succ i)
  {-# ATP prove is #-}

-- Global hints
{-# ATP hints x+Sy≡S[x+y] +-rightIdentity #-}

+-comm : ∀ m n → m + n ≡ n + m
+-comm m n = ℕ-ind A A0 is m
  where
  A : ℕ → Set
  A i = i + n ≡ n + i
  {-# ATP definition A #-}

  postulate A0 : A zero
  {-# ATP prove A0 #-}

  postulate is : ∀ i → A i → A (succ i)
  {-# ATP prove is #-}


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

open import Functions.Definition
open import Functions.Lemmas
open import LogicalFormulae
open import Numbers.Naturals.Definition
open import Numbers.Naturals.Order
open import Sets.FinSet.Definition
open import Sets.FinSet.Lemmas
open import Sets.Cardinality.Infinite.Definition
open import Sets.Cardinality.Finite.Lemmas
open import Numbers.Reals.Definition
open import Numbers.Rationals.Definition
open import Numbers.Integers.Definition
open import Sets.Cardinality.Infinite.Lemmas
open import Setoids.Setoids

module Sets.Cardinality.Infinite.Examples where

ℕIsInfinite : InfiniteSet ℕ
ℕIsInfinite n f bij = pigeonhole (le 0 refl) badInj
  where
    inv : ℕ → FinSet n
    inv = Invertible.inverse (bijectionImpliesInvertible bij)
    invInj : Injection inv
    invInj = Bijection.inj (invertibleImpliesBijection (inverseIsInvertible (bijectionImpliesInvertible bij)))
    bumpUp : FinSet n → FinSet (succ n)
    bumpUp = intoSmaller (le 0 refl)
    bumpUpInj : Injection bumpUp
    bumpUpInj = intoSmallerInj (le 0 refl)
    nextInj : Injection (toNat {succ n})
    nextInj = finsetInjectIntoℕ {succ n}
    bad : FinSet (succ n) → FinSet n
    bad a = (inv (toNat a))
    badInj : Injection bad
    badInj = injComp nextInj invInj

ℝIsInfinite : DedekindInfiniteSet ℝ
DedekindInfiniteSet.inj ℝIsInfinite n = injectionR (injectionQ (nonneg n))
DedekindInfiniteSet.isInjection ℝIsInfinite {x} {y} pr = nonnegInjective (injectionQInjective (injectionRInjective pr))


module HT where

open import Prelude
open import T
open import SubstTheory
open import DynTheory

module HT where

  ---- Halting and Hereditary Termination
  -- An old comment about lhs-halt

  -- Mostly for fun, I didn't want to include "and it halts" as part
  -- of the definition of HT for arrows, and I didn't want to define
  -- it in terms of evaluating to a lambda and then substituting.
  -- This seems to require being able to generate an inhabitant of an
  -- arbitrary type as well as a proof that it is HT. The former is
  -- easy in T and we accomplish the latter by appealing to all-HT,
  -- although we could have also generated the proof along with the
  -- inhabitant.  This all seems to be handwaved away when doing it on
  -- paper. Things get more unclear when in a system where not all
  -- types are inhabited; if we know that either a type is inhabited or
  -- it is not, then we are fine. But since we are constructive, we would
  -- get tripped up by a language like System F in which type inhabitability
  -- is undecidable. (Of course, the proof is easy to repair in a number of
  -- ways by modifying the definition of HT.)
  --
  -- When I went to make the system deterministic, I found that I now depended
  -- on HT-halts in all-HT, which broke the previous proof technique.
  -- I decided that proving the inhabitant we construct is HT would be
  -- annoying, so I decided to not bother and went back to hanging onto the
  -- proof that arrows halt.

  -- Extract that the lhs must halt if its application to something halts.
  -- I think this isn't actually useful, though, since to use it we would
  -- need to be able to produce an argument to the function.
  {-
  lhs-halt : {A B : TTp} {e : TCExp (A ⇒ B)} {e' : TCExp A} →
              THalts (e $ e') → THalts e
  lhs-halt (halts eval-refl ())
  lhs-halt (halts (eval-cons (step-app-l S1) E) val) with lhs-halt (halts E val)
  ... | halts E' val' = halts (eval-cons S1 E') val'
  lhs-halt (halts (eval-cons step-beta E) val) = halts eval-refl val-lam
  -}

  -- I think the induction principle for this datatype is the definition of
  -- HTω from http://www.cs.cmu.edu/~rwh/courses/typesys/hw3/hw3-handout.pdf
  data HTω : TNat → Set where
    HT-z : {e : TNat} → (E : e ~>* zero) → HTω e
    HT-s : {e e' : TNat} → (E : e ~>* suc e') → (HT : HTω e') → HTω e

  -- definition of hereditary termination
  HT : (A : TTp) → TCExp A → Set
  HT nat e = THalts e
  -- It is kind of ugly to have to hang on to the halting proof.
  HT (A ⇒ B) e = THalts e × ((e' : TCExp A) → HT A e' → HT B (e $ e'))

  -- proof that hereditary termination implies termination
  HT-halts : ∀{A} → (e : TCExp A) → HT A e → THalts e
  HT-halts {nat} e h = h
  HT-halts {A ⇒ B} _ (h , _) = h

  -- extend HT to substitutions
  HTΓ : (Γ : Ctx) → TSubst Γ [] → Set
  HTΓ Γ γ = ∀{A} (x : A ∈ Γ) -> HT A (γ x)

  emptyHTΓ : ∀{γ : TSubst [] []} -> HTΓ [] γ
  emptyHTΓ ()

  extendHTΓ : ∀{Γ A} {e : TCExp A} {γ : TSubst Γ []} ->
              HTΓ Γ γ -> HT A e -> HTΓ (A :: Γ) (extendγ γ e)
  extendHTΓ η ht Z = ht
  extendHTΓ {_} {_} {e} {γ} η ht {B} (S n) =
             ID.coe1 (HT B) (extend-nofail-s γ e n) (η n)

  -- head expansion lemma
  head-expansion : ∀{A} {e e' : TCExp A} → (e ~>* e') → HT A e' → HT A e
  head-expansion {nat} eval (halts eval₁ val) = halts (eval-trans eval eval₁) val
  head-expansion {A ⇒ B} eval (halts eval' val , ht-logic) =
     halts (eval-trans eval eval') val ,
     (λ e' ht → head-expansion (eval-compat step-app-l eval) (ht-logic e' ht))

  -- the main theorem
  all-HT : ∀{Γ A} {γ : TSubst Γ []} → (e : TExp Γ A) → HTΓ Γ γ
            → HT A (ssubst γ e)
  all-HT (var x) η = η x
  all-HT (e₁ $ e₂) η with all-HT e₁ η
  ... | _ , HT₁ = HT₁ (ssubst _ e₂) (all-HT e₂ η)
  all-HT zero η = halts eval-refl val-zero
  all-HT (suc e) η with all-HT e η
  ... | halts eval val = halts (eval-compat step-suc eval) (val-suc val)

  all-HT {Γ} {A ⇒ B} {γ} (Λ e) η =
    (halts eval-refl val-lam) ,
     lam-case
    where lam-case : (e' : TCExp A) → HT A e' → HT B (Λ (ssubst (liftγ γ) e) $ e')
          lam-case e' ht' with all-HT {γ = extendγ γ e'} e (extendHTΓ η ht')
          ... | ht with eval-step (step-beta {e = (ssubst (liftγ γ) e)})
          ... | steps-full with combine-subst-noob γ e e'
          ... | eq = head-expansion steps-full (ID.coe1 (HT B) eq ht)

  all-HT {Γ} {A} {γ} (rec e e₀ es) η with all-HT e η
  ... | halts E val = head-expansion (eval-compat step-rec E) (inner val)
    where inner : {n : TNat} → TVal n → HT A (rec n (ssubst γ e₀) (ssubst (liftγ γ) es))
          inner val-zero = head-expansion (eval-step step-rec-z) (all-HT e₀ η)
          inner (val-suc v) with all-HT es (extendHTΓ η (inner v))
          ... | ht with eval-step (step-rec-s v)
          ... | steps with combine-subst-noob γ es _
          ... | eq = head-expansion steps (ID.coe1 (HT A) eq ht)

  -- Prove that all programs in Gödel's System T halt.
  all-halt : ∀{A} → (e : TCExp A) → THalts e
  all-halt {A} e = HT-halts e (ID.coe1 (HT A) (subid e) (all-HT e (emptyHTΓ {emptyγ})))

open HT public


module Data.List.Relation.Binary.Subset.Propositional.Instances where

open import Data.List using (List; _∷_; [])
open import Data.List.Relation.Unary.Any using (here; there)
open import Data.List.Membership.Propositional using (_∈_; _∉_)
open import Data.List.Membership.Setoid.Properties using (∈-resp-≈)
open import Data.List.Relation.Binary.Subset.Propositional using (_⊆_)

open import Relation.Nullary.Negation using (contradiction)

open import Relation.Binary.PropositionalEquality using (sym; setoid)

open import Level using (Level)

private
  variable
    a : Level
    A : Set a
    x y : A
    xs ys : List A

-- ----------------------------------------------------------------------
-- Wrapped subset. Could use Data.Wrap but required curried arguments
-- Easier to define specific data type.

infix 4 ⦅_⊆_⦆
data ⦅_⊆_⦆ {a} {A : Set a} : List A → List A → Set a where
  [_] : xs ⊆ ys → ⦅ xs ⊆ ys ⦆

proj : ⦅ xs ⊆ ys ⦆ → xs ⊆ ys
proj [ xs⊆ys ] = xs⊆ys

-- ----------------------------------------------------------------------
-- Lemmas used for instance searching

x∉[] : x ∉ []
x∉[] = λ ()

[]⊆xs : [] ⊆ xs
[]⊆xs = λ x∈[] → contradiction x∈[] x∉[]

xs⊆x∷xs : xs ⊆ x ∷ xs
xs⊆x∷xs = there

xs⊆ys⇒x∷xs⊆x∷ys : xs ⊆ ys → x ∷ xs ⊆ x ∷ ys
xs⊆ys⇒x∷xs⊆x∷ys xs⊆ys (here y≡x) = here y≡x
xs⊆ys⇒x∷xs⊆x∷ys xs⊆ys (there y∈x∷xs) = there (xs⊆ys y∈x∷xs)

x∈ys-xs⊆ys⇒x∷xs⊆ys : x ∈ ys → xs ⊆ ys → x ∷ xs ⊆ ys
x∈ys-xs⊆ys⇒x∷xs⊆ys x∈ys xs⊆ys (here y≡x) = ∈-resp-≈ (setoid _) (sym y≡x) x∈ys
x∈ys-xs⊆ys⇒x∷xs⊆ys x∈ys xs⊆ys (there y∈x∷xs) = xs⊆ys y∈x∷xs

-- ----------------------------------------------------------------------
-- Instances

instance
  ⦃[]⊆xs⦄ : ⦅ [] ⊆ xs ⦆
  ⦃[]⊆xs⦄ = [ []⊆xs ]

  -- Removed to improve instance search, syntax directed.

  -- ⦃xs⊆x∷xs⦄ : ⦅ xs ⊆ x ∷ xs ⦆
  -- ⦃xs⊆x∷xs⦄ = [ xs⊆x∷xs ]

  -- ⦃xs⊆ys⇒x∷xs⊆x∷ys⦄ : ⦃ ⦅ xs ⊆ ys ⦆ ⦄ → ⦅ x ∷ xs ⊆ x ∷ ys ⦆
  -- ⦃xs⊆ys⇒x∷xs⊆x∷ys⦄ ⦃ [ xs⊆ys ] ⦄ = [ xs⊆ys⇒x∷xs⊆x∷ys xs⊆ys ]

  ⦃x∈ys-xs⊆ys⇒x∷xs⊆ys⦄ : ⦃ x ∈ ys ⦄ → ⦃ ⦅ xs ⊆ ys ⦆ ⦄ → ⦅ x ∷ xs ⊆ ys ⦆
  ⦃x∈ys-xs⊆ys⇒x∷xs⊆ys⦄ ⦃ x∈ys ⦄ ⦃ [ xs⊆ys ] ⦄ = [ x∈ys-xs⊆ys⇒x∷xs⊆ys x∈ys xs⊆ys ]


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

open import lib.Basics
open import lib.types.Paths
open import lib.types.Pointed
open import lib.types.Pushout
open import lib.types.PushoutFmap
open import lib.types.Sigma
open import lib.types.Span

module lib.types.Join  where

module _ {i j} (A : Type i) (B : Type j) where

  *-span : Span
  *-span = span A B (A × B) fst snd

  infix 80 _*_

  _*_ : Type _
  _*_ = Pushout *-span

module _ {i j} {A : Type i} {B : Type j} where
  jleft : A → A * B
  jleft = left

  jright : B → A * B
  jright = right

  jglue : ∀ a b → jleft a == jright b
  jglue = curry glue

  module JoinElim {k} {P : A * B → Type k}
    (jleft* : (a : A) → P (jleft a)) (jright* : (b : B) → P (jright b))
    (jglue* : ∀ a b → jleft* a == jright* b [ P ↓ jglue a b ]) where

    private
      module M = PushoutElim {d = *-span A B} {P = P} jleft* jright* (uncurry jglue*)
    f = M.f
    glue-β = curry M.glue-β

  Join-elim = JoinElim.f

  module JoinRec {k} {C : Type k}
    (jleft* : (a : A) → C) (jright* : (b : B) → C)
    (jglue* : ∀ a b → jleft* a == jright* b) where

    private
      module M = PushoutRec jleft* jright* (uncurry jglue*)
    f = M.f
    glue-β = curry M.glue-β

  Join-rec = JoinRec.f

module _ {i j} (X : Ptd i) (Y : Ptd j) where

  ⊙*-span : ⊙Span
  ⊙*-span = ⊙span X Y (X ⊙× Y) ⊙fst ⊙snd

  infix 80 _⊙*_

  _⊙*_ : Ptd _
  _⊙*_ = ⊙Pushout ⊙*-span

module _ {i i' j j'} {A : Type i} {A' : Type i'} {B : Type j} {B' : Type j'}
  (eqA : A ≃ A') (eqB : B ≃ B') where

  *-span-emap : SpanEquiv (*-span A B) (*-span A' B')
  *-span-emap = ( span-map (fst eqA) (fst eqB) (×-fmap (fst eqA) (fst eqB)) (comm-sqr λ _ → idp) (comm-sqr λ _ → idp)
                , snd eqA , snd eqB , ×-isemap (snd eqA) (snd eqB))

  *-emap : A * B ≃ A' * B'
  *-emap = Pushout-emap *-span-emap

module _ {i i' j j'} {X : Ptd i} {X' : Ptd i'} {Y : Ptd j} {Y' : Ptd j'} where

  ⊙*-emap : X ⊙≃ X' → Y ⊙≃ Y' → X ⊙* Y ⊙≃ X' ⊙* Y'
  ⊙*-emap ⊙eqX ⊙eqY = ≃-to-⊙≃ (*-emap (⊙≃-to-≃ ⊙eqX) (⊙≃-to-≃ ⊙eqY)) (ap left (snd (⊙–> ⊙eqX)))


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

syntax Monoid | M

type
  * : 0-ary

term
  unit : * | ε
  add  : *  *  ->  * | _⊕_ l20

theory
  (εU⊕ᴸ) a |> add (unit, a) = a
  (εU⊕ᴿ) a |> add (a, unit) = a
  (⊕A) a b c |> add (add(a, b), c) = add (a, add(b, c))
-}

module Monoid.Equality where

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

open import Monoid.Signature
open import Monoid.Syntax

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

private
  variable
    α β γ τ : *T
    Γ Δ Π : Ctx

infix 1 _▹_⊢_≋ₐ_

-- Axioms of equality
data _▹_⊢_≋ₐ_ : ∀ 𝔐 Γ {α} → (𝔐 ▷ M) α Γ → (𝔐 ▷ M) α Γ → Set where
  εU⊕ᴸ : ⁅ * ⁆̣             ▹ ∅ ⊢       ε ⊕ 𝔞 ≋ₐ 𝔞
  εU⊕ᴿ : ⁅ * ⁆̣             ▹ ∅ ⊢       𝔞 ⊕ ε ≋ₐ 𝔞
  ⊕A   : ⁅ * ⁆ ⁅ * ⁆ ⁅ * ⁆̣ ▹ ∅ ⊢ (𝔞 ⊕ 𝔟) ⊕ 𝔠 ≋ₐ 𝔞 ⊕ (𝔟 ⊕ 𝔠)

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