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

open import LogicalFormulae
open import Setoids.Setoids
open import Rings.Definition
open import Sets.EquivalenceRelations
open import Rings.IntegralDomains.Definition

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

open import Rings.Divisible.Definition R
open import Rings.IntegralDomains.Lemmas intDom
open import Rings.Ideals.Definition R
open import Rings.Primes.Definition intDom
open import Rings.Ideals.Prime.Definition {R = R}
open import Rings.Irreducibles.Definition intDom
open Ring R
open Setoid S
open Equivalence eq

primeImpliesPrimeIdeal : {a : A} → Prime a → PrimeIdeal (generatedIdeal a)
primeImpliesPrimeIdeal {a} record { isPrime = isPrime ; nonzero = nonzero ; nonunit = nonunit } = record { isPrime = λ {r} {s} → isPrime r s ; notContained = 1R ; notContainedIsNotContained = bad }
  where
    bad : a ∣ 1R → False
    bad (c , ac=1) = nonunit (c , ac=1)

primeIdealImpliesPrime : {a : A} → ((a ∼ 0R) → False) → PrimeIdeal (generatedIdeal a) → Prime a
Prime.isPrime (primeIdealImpliesPrime {a} a!=0 record { isPrime = isPrime ; notContained = notContained ; notContainedIsNotContained = notContainedIsNotContained }) r s a|rs aNot|r = isPrime a|rs aNot|r
Prime.nonzero (primeIdealImpliesPrime {a} a!=0 record { isPrime = isPrime ; notContained = notContained ; notContainedIsNotContained = notContainedIsNotContained }) = a!=0
Prime.nonunit (primeIdealImpliesPrime {a} a!=0 record { isPrime = isPrime ; notContained = notContained ; notContainedIsNotContained = notContainedIsNotContained }) (c , ac=1) = notContainedIsNotContained ((c * notContained) , transitive *Associative (transitive (*WellDefined ac=1 reflexive) identIsIdent))

primeIsIrreducible : {a : A} → Prime a → Irreducible a
Irreducible.nonzero (primeIsIrreducible {a} prime) = Prime.nonzero prime
Irreducible.nonunit (primeIsIrreducible {a} prime) = Prime.nonunit prime
Irreducible.irreducible (primeIsIrreducible {a} prime) x y xy=a xNonunit = underlying pr , yUnit
  where
    a|xy : a ∣ (x * y)
    a|xy = 1R , transitive *Commutative (transitive identIsIdent (symmetric xy=a))
    a|yFalse : (a ∣ y) → False
    a|yFalse (c , ac=y) = xNonunit (c , transitive *Commutative t)
      where
        s : (a * (c * x)) ∼ a
        s = transitive *Associative (transitive (*WellDefined ac=y reflexive) (transitive *Commutative xy=a))
        t : (c * x) ∼ 1R
        t = cancelIntDom {a} {c * x} {1R} (transitive s (symmetric (transitive *Commutative identIsIdent))) (Prime.nonzero prime)
    pr : Sg A (λ c → (a * c) ∼ x)
    pr = Prime.isPrime prime y x (divisibleWellDefined reflexive *Commutative a|xy) a|yFalse
    yUnit : (y * underlying pr) ∼ 1R
    yUnit with pr
    ... | c , ac=x = transitive *Commutative (cancelIntDom {a} {c * y} {1R} (transitive *Associative (transitive (*WellDefined ac=x reflexive) (transitive xy=a (symmetric (transitive *Commutative identIsIdent))))) (Prime.nonzero prime))


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

open import LogicalFormulae
open import Setoids.Setoids
open import Groups.Definition

module Groups.DirectSum.Definition {m n o p : _} {A : Set m} {S : Setoid {m} {o} A} {_·A_ : A → A → A} {B : Set n} {T : Setoid {n} {p} B} {_·B_ : B → B → B} (G : Group S _·A_) (H : Group T _·B_) where

open import Setoids.Product S T

directSumGroup : Group productSetoid (λ x1 y1 → (((_&&_.fst x1) ·A (_&&_.fst y1)) ,, ((_&&_.snd x1) ·B (_&&_.snd y1))))
Group.+WellDefined directSumGroup (s ,, t) (u ,, v) = Group.+WellDefined G s u ,, Group.+WellDefined H t v
Group.0G directSumGroup = (Group.0G G ,, Group.0G H)
Group.inverse directSumGroup (g1 ,, H1) = (Group.inverse G g1) ,, (Group.inverse H H1)
Group.+Associative directSumGroup = Group.+Associative G ,, Group.+Associative H
Group.identRight directSumGroup = Group.identRight G ,, Group.identRight H
Group.identLeft directSumGroup = Group.identLeft G ,, Group.identLeft H
Group.invLeft directSumGroup = Group.invLeft G ,, Group.invLeft H
Group.invRight directSumGroup = Group.invRight G ,, Group.invRight H


module logic where

open import Level
open import Relation.Nullary
open import Relation.Binary hiding (_⇔_ )
open import Data.Empty

data Bool : Set where
    true : Bool
    false : Bool

record  _∧_  {n m : Level} (A  : Set n) ( B : Set m ) : Set (n ⊔ m) where
   constructor ⟪_,_⟫
   field
      proj1 : A
      proj2 : B

data  _∨_  {n m : Level} (A  : Set n) ( B : Set m ) : Set (n ⊔ m) where
   case1 : A → A ∨ B
   case2 : B → A ∨ B

_⇔_ : {n m : Level } → ( A : Set n ) ( B : Set m )  → Set (n ⊔ m)
_⇔_ A B =  ( A → B ) ∧ ( B → A )

contra-position : {n m : Level } {A : Set n} {B : Set m} → (A → B) → ¬ B → ¬ A
contra-position {n} {m} {A} {B}  f ¬b a = ¬b ( f a )

double-neg : {n  : Level } {A : Set n} → A → ¬ ¬ A
double-neg A notnot = notnot A

double-neg2 : {n  : Level } {A : Set n} → ¬ ¬ ¬ A → ¬ A
double-neg2 notnot A = notnot ( double-neg A )

de-morgan : {n  : Level } {A B : Set n} →  A ∧ B  → ¬ ( (¬ A ) ∨ (¬ B ) )
de-morgan {n} {A} {B} and (case1 ¬A) = ⊥-elim ( ¬A ( _∧_.proj1 and ))
de-morgan {n} {A} {B} and (case2 ¬B) = ⊥-elim ( ¬B ( _∧_.proj2 and ))

dont-or :　{n m : Level} {A  : Set n} { B : Set m } →  A ∨ B → ¬ A → B
dont-or {A} {B} (case1 a) ¬A = ⊥-elim ( ¬A a )
dont-or {A} {B} (case2 b) ¬A = b

dont-orb :　{n m : Level} {A  : Set n} { B : Set m } →  A ∨ B → ¬ B → A
dont-orb {A} {B} (case2 b) ¬B = ⊥-elim ( ¬B b )
dont-orb {A} {B} (case1 a) ¬B = a

infixr  130 _∧_
infixr  140 _∨_
infixr  150 _⇔_

_/\_ : Bool → Bool → Bool
true /\ true = true
_ /\ _ = false

_\/_ : Bool → Bool → Bool
false \/ false = false
_ \/ _ = true

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

_<=>_ : Bool → Bool → Bool
true <=> true = true
false <=> false = true
_ <=> _ = false

infixr  130 _\/_
infixr  140 _/\_

open import Relation.Binary.PropositionalEquality

≡-Bool-func : {A B : Bool } → ( A ≡ true → B ≡ true ) → ( B ≡ true → A ≡ true ) → A ≡ B
≡-Bool-func {true} {true} a→b b→a = refl
≡-Bool-func {false} {true} a→b b→a with b→a refl
... | ()
≡-Bool-func {true} {false} a→b b→a with a→b refl
... | ()
≡-Bool-func {false} {false} a→b b→a = refl

bool-≡-? : (a b : Bool) → Dec ( a ≡ b )
bool-≡-? true true = yes refl
bool-≡-? true false = no (λ ())
bool-≡-? false true = no (λ ())
bool-≡-? false false = yes refl

¬-bool-t : {a : Bool} →  ¬ ( a ≡ true ) → a ≡ false
¬-bool-t {true} ne = ⊥-elim ( ne refl )
¬-bool-t {false} ne = refl

¬-bool-f : {a : Bool} →  ¬ ( a ≡ false ) → a ≡ true
¬-bool-f {true} ne = refl
¬-bool-f {false} ne = ⊥-elim ( ne refl )

¬-bool : {a : Bool} →  a ≡ false  → a ≡ true → ⊥
¬-bool refl ()

lemma-∧-0 : {a b : Bool} → a /\ b ≡ true → a ≡ false → ⊥
lemma-∧-0 {true} {true} refl ()
lemma-∧-0 {true} {false} ()
lemma-∧-0 {false} {true} ()
lemma-∧-0 {false} {false} ()

lemma-∧-1 : {a b : Bool} → a /\ b ≡ true → b ≡ false → ⊥
lemma-∧-1 {true} {true} refl ()
lemma-∧-1 {true} {false} ()
lemma-∧-1 {false} {true} ()
lemma-∧-1 {false} {false} ()

bool-and-tt : {a b : Bool} → a ≡ true → b ≡ true → ( a /\ b ) ≡ true
bool-and-tt refl refl = refl

bool-∧→tt-0 : {a b : Bool} → ( a /\ b ) ≡ true → a ≡ true
bool-∧→tt-0 {true} {true} refl = refl
bool-∧→tt-0 {false} {_} ()

bool-∧→tt-1 : {a b : Bool} → ( a /\ b ) ≡ true → b ≡ true
bool-∧→tt-1 {true} {true} refl = refl
bool-∧→tt-1 {true} {false} ()
bool-∧→tt-1 {false} {false} ()

bool-or-1 : {a b : Bool} → a ≡ false → ( a \/ b ) ≡ b
bool-or-1 {false} {true} refl = refl
bool-or-1 {false} {false} refl = refl
bool-or-2 : {a b : Bool} → b ≡ false → (a \/ b ) ≡ a
bool-or-2 {true} {false} refl = refl
bool-or-2 {false} {false} refl = refl

bool-or-3 : {a : Bool} → ( a \/ true ) ≡ true
bool-or-3 {true} = refl
bool-or-3 {false} = refl

bool-or-31 : {a b : Bool} → b ≡ true  → ( a \/ b ) ≡ true
bool-or-31 {true} {true} refl = refl
bool-or-31 {false} {true} refl = refl

bool-or-4 : {a : Bool} → ( true \/ a ) ≡ true
bool-or-4 {true} = refl
bool-or-4 {false} = refl

bool-or-41 : {a b : Bool} → a ≡ true  → ( a \/ b ) ≡ true
bool-or-41 {true} {b} refl = refl

bool-and-1 : {a b : Bool} →  a ≡ false → (a /\ b ) ≡ false
bool-and-1 {false} {b} refl = refl
bool-and-2 : {a b : Bool} →  b ≡ false → (a /\ b ) ≡ false
bool-and-2 {true} {false} refl = refl
bool-and-2 {false} {false} refl = refl


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

-- Discrete Functor
--   from Setoids to Cats.

open import Categories.Category
open import Categories.Functor
open import Categories.Category.Instance.Setoids
open import Categories.Category.Instance.Cats
open import Categories.NaturalTransformation.NaturalIsomorphism
  hiding (refl)
import Categories.Category.SetoidDiscrete as D

open import Relation.Binary
open import Function renaming (id to idf; _∘_ to _●_)
open import Function.Equality renaming (id to id⟶)

Discrete : ∀ {o ℓ e} → Functor (Setoids o ℓ) (Cats o ℓ e)
Discrete {o} {ℓ} {e} = record
   { F₀ = D.Discrete
   ; F₁ = DiscreteFunctor
   ; identity = λ {A} → DiscreteId {A}
   ; homomorphism = λ {X} {Y} {Z} {g} {h} → PointwiseHom {X} {Y} {Z} {g} {h}
   ; F-resp-≈ = λ {A} {B} {f} {g} → ExtensionalityNI {A} {B} {f} {g}
   }
   where
     DiscreteFunctor : {A B : Setoid o ℓ} → (A ⟶ B) → Cats o ℓ e [ D.Discrete A , D.Discrete B ]
     DiscreteFunctor f = record
       { F₀ = f ⟨$⟩_
       ; F₁ = cong f
       ; identity = _
       ; homomorphism = _
       ; F-resp-≈ = _
       }
     DiscreteId : {A : Setoid o ℓ} → NaturalIsomorphism (DiscreteFunctor {A} id⟶) id
     DiscreteId {A} = record
       { F⇒G = record { η = λ _ → refl ; commute = _ }
       ; F⇐G = record { η = λ _ → refl ; commute = _ }
       } where open Setoid A
     PointwiseHom : {X Y Z : Setoid o ℓ} {g : X ⟶ Y} {h : Y ⟶ Z} →
       NaturalIsomorphism (DiscreteFunctor (h ∘ g)) (DiscreteFunctor h ∘F DiscreteFunctor g)
     PointwiseHom {_} {_} {Z} = record
       { F⇒G = record { η = λ _ → refl }
       ; F⇐G = record { η = λ _ → refl }
       }
       where open Setoid Z
     ExtensionalityNI : {A B : Setoid o ℓ} {f g : A ⟶ B} → let open Setoid A in
      ({x y : Carrier} → x ≈ y → Setoid._≈_ B (f ⟨$⟩ x) (g ⟨$⟩ y)) →
      NaturalIsomorphism (DiscreteFunctor f) (DiscreteFunctor g)
     ExtensionalityNI {A} {B} cong≈ = record
       { F⇒G = record { η = λ X → cong≈ A.refl }
       ; F⇐G = record { η = λ X → B.sym (cong≈ A.refl) }
       }
       where
       module A = Setoid A
       module B = Setoid B


module PLRTree.Complete.Correctness.Alternative {A : Set} where

open import BTree.Complete.Alternative {A}
open import BTree.Complete.Alternative.Properties {A}
open import BTree.Equality {A}
open import PLRTree {A}
open import PLRTree.Complete {A} renaming (Complete to Complete' ; _⋗_ to _⋗'_ ; _⋘_ to _⋘'_ ; _⋙_ to _⋙'_)
open import PLRTree.Equality.Correctness {A}

lemma-⋗'-⋗ : {l r : PLRTree} → l ⋗' r → forget l ⋗ forget r
lemma-⋗'-⋗ (⋗lf x) = ⋗lf x
lemma-⋗'-⋗ (⋗nd x x' l≃'r l'≃'r' l⋗'l') = ⋗nd x x'  (lemma-≃'-≃ l≃'r) (lemma-≃'-≃ l'≃'r') (lemma-⋗'-⋗ l⋗'l')

mutual
  lemma-⋘'-⋘ : {l r : PLRTree} → l ⋘' r → forget l ⋘ forget r
  lemma-⋘'-⋘ (x⋘ x y z) = lr⋘ x z (⋙lf y) ≃lf (⋗lf y)
  lemma-⋘'-⋘ (l⋘ x x' l'⋘'r' l'≃'r' r≃'l') = ll⋘ x x' (lemma-⋘'-⋘ l'⋘'r') (lemma-≃'-≃ l'≃'r') (lemma-≃'-≃ r≃'l')
  lemma-⋘'-⋘ (r⋘ x x' l'⋙'r' l'≃'r' l⋗'l') = lr⋘ x x' (lemma-⋙'-⋙ l'⋙'r') (lemma-≃'-≃ l'≃'r') (lemma-⋗'-⋗ l⋗'l')

  lemma-⋙'-⋙ : {l r : PLRTree} → l ⋙' r → forget l ⋙ forget r
  lemma-⋙'-⋙ (⋙p l⋗'r) = lemma-⋗-⋙ (lemma-⋗'-⋗ l⋗'r)
  lemma-⋙'-⋙ (⋙l x x' l≃'r l'⋘'r' l⋗'r') = ⋙rl x x' (lemma-≃'-≃ l≃'r) (lemma-⋘'-⋘ l'⋘'r') (lemma-⋗'-⋗ l⋗'r')
  lemma-⋙'-⋙ (⋙r x x' l≃'r l'⋙'r' l≃'l') = ⋙rr x x' (lemma-≃'-≃ l≃'r) (lemma-⋙'-⋙ l'⋙'r') (lemma-≃'-≃ l≃'l')

lemma-complete'-complete : {t : PLRTree} → Complete' t → Complete (forget t)
lemma-complete'-complete leaf = leaf
lemma-complete'-complete (perfect x c'l c'r l≃'r) =  left x cl cr l⋘r
                   where cl = lemma-complete'-complete c'l ;
                              cr = lemma-complete'-complete c'r ;
                              l⋘r = lemma-≃-⋘ (lemma-≃'-≃ l≃'r)
lemma-complete'-complete (left x c'l c'r l⋘'r) = left x cl cr l⋘r
                   where cl = lemma-complete'-complete c'l ;
                              cr = lemma-complete'-complete c'r ;
                              l⋘r = lemma-⋘'-⋘ l⋘'r
lemma-complete'-complete (right x c'l c'r l⋙'r) = right x cl cr l⋙r
                   where cl = lemma-complete'-complete c'l ;
                              cr = lemma-complete'-complete c'r ;
                              l⋙r = lemma-⋙'-⋙ l⋙'r


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

module HoTT.Ident where

data Id (X : Set) : X → X → Set  where
 refl : (x : X) → Id X x x

_≡_ : {X : Set} → X → X → Set
x ≡ y = Id _ x y

𝕁 : {X : Set}
  → (A : (x y : X) → x ≡ y → Set)
  → ((x : X) → A x x (refl x))
  → (x y : X) → (p : x ≡ y) → A x y p
𝕁 A f x x (refl x) = f x

ℍ : {X : Set}
  → (x : X)
  → (B : (y : X) → x ≡ y → Set)
  → B x (refl x)
  → (y : X) → (p : x ≡ y) → B y p
ℍ x B b x (refl x) = b

-- Defining `𝕁` in terms of `ℍ`.

𝕁' : {X : Set}
  → (A : (x y : X) → x ≡ y → Set)
  → ((x : X) → A x x (refl x))
  → (x y : X) → (p : x ≡ y) → A x y p
𝕁' A f x = ℍ x (A x) (f x)

-- Defining `ℍ` in terms of `𝕁`.

transport : {X : Set} → (f : X → Set) → (x y : X) → (x ≡ y) → f x → f y
transport f = 𝕁 (λ x y p → f x → f y) (λ x y → y)

data Σ (A : Set) (p : A → Set) : Set  where
  _,_ : (x : A) → p x → Σ A p

curry : {A : Set} {B : A → Set} → ((x : A) → B x → Set) → Σ A B → Set
curry f (x , y) = f x y

-- This is just for the "Note" below.
singl : (A : Set) → A → Set
singl A x = Σ A (λ y → x ≡ y)

-- Note: `≡` in the conclusion is WRT `Id (singl X x)`.
-- Source: http://www.cse.chalmers.se/~coquand/singl.pdf
lemma : {X : Set} → (x y : X) → (p : x ≡ y) → (x , refl x) ≡ (y , p)
lemma = 𝕁 (λ x y p → (x , refl x) ≡ (y , p)) (λ x → refl (x , refl x))

ℍ' : {X : Set}
  → (x : X)
  → (B : (y : X) → x ≡ y → Set)
  → B x (refl x)
  → (y : X) → (p : x ≡ y) → B y p
ℍ' x B b y p = transport (curry B) (x , refl x) (y , p) (lemma x y p) b


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

open import Bound.Total A

data LeB : Bound → Bound → Set where
  lebx : {b : Bound}
                   → LeB bot b
  lexy : {x y : A}
                   → x ≤ y
                   → LeB (val x) (val y)
  lext : {b : Bound}
                   → LeB b top


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.Monoid.Morphism where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Functions.Embedding

open import Cubical.Algebra
open import Cubical.Algebra.Semigroup.Morphism

private
  variable
    m n : Level

record IsMonoidHom (M : Monoid m) (N : Monoid n) (f : ⟨ M ⟩ → ⟨ N ⟩) : Type (ℓ-max m n) where
  constructor ismonoidhom
  field
    preservesOp : Homomorphic₂ f (Monoid._•_ M) (Monoid._•_ N)
    preservesId : Homomorphic₀ f (Monoid.ε M)   (Monoid.ε N)

record MonoidHom (M : Monoid m) (N : Monoid n) : Type (ℓ-max m n) where
  constructor monoidhom
  field
    fun : ⟨ M ⟩ → ⟨ N ⟩
    isHom : IsMonoidHom M N fun

  open IsMonoidHom isHom public

record MonoidEquiv (M : Monoid m) (N : Monoid n) : Type (ℓ-max m n) where
  constructor monoidequiv
  field
    eq : ⟨ M ⟩ ≃ ⟨ N ⟩
    isHom : IsMonoidHom M N (equivFun eq)

  open IsMonoidHom isHom public

  hom : MonoidHom M N
  hom = record { isHom = isHom }

instance
  MonoidHomOperators : HomOperators (Monoid m) (Monoid n) (ℓ-max m n)
  MonoidHomOperators = record { _⟶ᴴ_ = MonoidHom; _≃ᴴ_ = MonoidEquiv }

private
  variable
    M : Monoid m
    N : Monoid n

IsMonoidHom→IsSemigroupHom : {f : ⟨ M ⟩ → ⟨ N ⟩} → IsMonoidHom M N f → IsSemigroupHom (Monoid.semigroup M) (Monoid.semigroup N) f
IsMonoidHom→IsSemigroupHom = IsMonoidHom.preservesOp

MonoidHom→SemigroupHom : (M ⟶ᴴ N) → (Monoid.semigroup M ⟶ᴴ Monoid.semigroup N)
MonoidHom→SemigroupHom hom .SemigroupHom.fun = hom .MonoidHom.fun
MonoidHom→SemigroupHom hom .SemigroupHom.isHom = IsMonoidHom→IsSemigroupHom (hom .MonoidHom.isHom)

MonoidEquiv→SemigroupEquiv : M ≃ᴴ N → Monoid.semigroup M ≃ᴴ Monoid.semigroup N
MonoidEquiv→SemigroupEquiv eq .SemigroupEquiv.eq = eq .MonoidEquiv.eq
MonoidEquiv→SemigroupEquiv eq .SemigroupEquiv.isHom = IsMonoidHom→IsSemigroupHom (eq .MonoidEquiv.isHom)


-- Minimal implicational modal logic, vector-based de Bruijn approach, initial encoding

module Vi.BoxMp where

open import Lib using (Nat; suc; _+_; Fin; fin; Vec; []; _,_; proj; VMem; mem)

-- Types

infixr 0 _=>_
data Ty : Set where
  UNIT :             Ty
  _=>_ : Ty -> Ty -> Ty
  BOX  : Ty       -> Ty

-- Context and truth/validity judgements

Cx : Nat -> Set
Cx n = Vec Ty n

isTrue : forall {tn} -> Ty -> Fin tn -> Cx tn -> Set
isTrue a i tc = VMem a i tc

isValid : forall {vn} -> Ty -> Fin vn -> Cx vn -> Set
isValid a i vc = VMem a i vc

-- Terms

module BoxMp where
  infixl 1 _$_
  infixr 0 lam=>_
  data Tm {vn tn} (vc : Cx vn) (tc : Cx tn) : Ty -> Set where
    var     : forall {a i} -> isTrue a i tc                   -> Tm vc tc a
    lam=>_  : forall {a b} -> Tm vc (tc , a) b                -> Tm vc tc (a => b)
    _$_     : forall {a b} -> Tm vc tc (a => b) -> Tm vc tc a -> Tm vc tc b
    var#    : forall {a i} -> isValid a i vc                  -> Tm vc tc a
    box     : forall {a}   -> Tm vc [] a                      -> Tm vc tc (BOX a)
    unbox'' : forall {a b} -> Tm vc tc (BOX a)  -> Tm (vc , a) tc b -> Tm vc tc b

  syntax unbox'' x' x = unbox x' => x

  v : forall {vn tn} {vc : Cx vn} (k : Nat) {tc : Cx (suc (k + tn))} -> Tm vc tc (proj tc (fin k))
  v i = var (mem i)

  v# : forall {vn tn} (k : Nat) {vc : Cx (suc (k + vn))} {tc : Cx tn} -> Tm vc tc (proj vc (fin k))
  v# i = var# (mem i)

  Thm : Ty -> Set
  Thm a = forall {vn tn} {vc : Cx vn} {tc : Cx tn} -> Tm vc tc a
open BoxMp public

-- Example theorems

rNec : forall {a} -> Thm a -> Thm (BOX a)
rNec x =
  box x

aK : forall {a b} -> Thm (BOX (a => b) => BOX a => BOX b)
aK =
  lam=>
    lam=>
      (unbox v 1 =>
        unbox v 0 =>
          box (v# 1 $ v# 0))

aT : forall {a} -> Thm (BOX a => a)
aT =
  lam=>
    (unbox v 0 => v# 0)

a4 : forall {a} -> Thm (BOX a => BOX (BOX a))
a4 =
  lam=>
    (unbox v 0 => box (box (v# 0)))

t1 : forall {a} -> Thm (a => BOX (a => a))
t1 =
  lam=> box (lam=> (v 0))


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

module Agda.Builtin.Nat where

open import Agda.Builtin.Bool

data Nat : Set where
  zero : Nat
  suc  : (n : Nat) → Nat

{-# BUILTIN NATURAL Nat #-}

infix  4 _==_ _<_
infixl 6 _+_ _-_
infixl 7 _*_

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

{-# BUILTIN NATPLUS _+_ #-}

_-_ : Nat → Nat → Nat
n     - zero = n
zero  - suc m = zero
suc n - suc m = n - m

{-# BUILTIN NATMINUS _-_ #-}

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

{-# BUILTIN NATTIMES _*_ #-}

_==_ : Nat → Nat → Bool
zero  == zero  = true
suc n == suc m = n == m
_     == _     = false

{-# BUILTIN NATEQUALS _==_ #-}

_<_ : Nat → Nat → Bool
_     < zero  = false
zero  < suc _ = true
suc n < suc m = n < m

{-# BUILTIN NATLESS _<_ #-}

-- Helper function  div-helper  for Euclidean division.
---------------------------------------------------------------------------
--
-- div-helper computes n / 1+m via iteration on n.
--
--   n div (suc m) = div-helper 0 m n m
--
-- The state of the iterator has two accumulator variables:
--
--   k: The quotient, returned once n=0.  Initialized to 0.
--
--   j: A counter, initialized to the divisor m, decreased on each iteration step.
--      Once it reaches 0, the quotient k is increased and j reset to m,
--      starting the next countdown.
--
-- Under the precondition j ≤ m, the invariant is
--
--   div-helper k m n j = k + (n + m - j) div (1 + m)

div-helper : (k m n j : Nat) → Nat
div-helper k m  zero    j      = k
div-helper k m (suc n)  zero   = div-helper (suc k) m n m
div-helper k m (suc n) (suc j) = div-helper k       m n j

{-# BUILTIN NATDIVSUCAUX div-helper #-}

-- Proof of the invariant by induction on n.
--
--   clause 1: div-helper k m 0 j
--           = k                                        by definition
--           = k + (0 + m - j) div (1 + m)              since m - j < 1 + m
--
--   clause 2: div-helper k m (1 + n) 0
--           = div-helper (1 + k) m n m                 by definition
--           = 1 + k + (n + m - m) div (1 + m)          by induction hypothesis
--           = 1 + k +          n  div (1 + m)          by simplification
--           = k +   (n + (1 + m)) div (1 + m)          by expansion
--           = k + (1 + n + m - 0) div (1 + m)          by expansion
--
--   clause 3: div-helper k m (1 + n) (1 + j)
--           = div-helper k m n j                       by definition
--           = k + (n + m - j) div (1 + m)              by induction hypothesis
--           = k + ((1 + n) + m - (1 + j)) div (1 + m)  by expansion
--
-- Q.e.d.

-- Helper function  mod-helper  for the remainder computation.
---------------------------------------------------------------------------
--
-- (Analogous to div-helper.)
--
-- mod-helper computes n % 1+m via iteration on n.
--
--   n mod (suc m) = mod-helper 0 m n m
--
-- The invariant is:
--
--   m = k + j  ==>  mod-helper k m n j = (n + k) mod (1 + m).

mod-helper : (k m n j : Nat) → Nat
mod-helper k m  zero    j      = k
mod-helper k m (suc n)  zero   = mod-helper 0       m n m
mod-helper k m (suc n) (suc j) = mod-helper (suc k) m n j

{-# BUILTIN NATMODSUCAUX mod-helper #-}

-- Proof of the invariant by induction on n.
--
--   clause 1: mod-helper k m 0 j
--           = k                               by definition
--           = (0 + k) mod (1 + m)             since m = k + j, thus k < m
--
--   clause 2: mod-helper k m (1 + n) 0
--           = mod-helper 0 m n m              by definition
--           = (n + 0)       mod (1 + m)       by induction hypothesis
--           = (n + (1 + m)) mod (1 + m)       by expansion
--           = (1 + n) + k)  mod (1 + m)       since k = m (as l = 0)
--
--   clause 3: mod-helper k m (1 + n) (1 + j)
--           = mod-helper (1 + k) m n j        by definition
--           = (n + (1 + k)) mod (1 + m)       by induction hypothesis
--           = ((1 + n) + k) mod (1 + m)       by commutativity
--
-- Q.e.d.


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

open import LogicalFormulae
open import Setoids.Setoids
open import Groups.Definition
open import Sets.EquivalenceRelations

module Groups.Groups where

reflGroupWellDefined : {lvl : _} {A : Set lvl} {m n x y : A} {op : A → A → A} → m ≡ x → n ≡ y → (op m n) ≡ (op x y)
reflGroupWellDefined {lvl} {A} {m} {n} {.m} {.n} {op} refl refl = refl
fourWay+Associative : {a b : _} → {A : Set a} → {S : Setoid {a} {b} A} → {_·_ : A → A → A} → (G : Group S _·_) → {r s t u : A} → (Setoid._∼_ S) (r · ((s · t) · u)) ((r · s) · (t · u))
fourWay+Associative {S = S} {_·_} G {r} {s} {t} {u} = transitive p1 (transitive p2 p3)
  where
    open Group G renaming (inverse to _^-1)
    open Setoid S
    open Equivalence eq
    p1 : r · ((s · t) · u) ∼ (r · (s · t)) · u
    p2 : (r · (s · t)) · u ∼ ((r · s) · t) · u
    p3 : ((r · s) · t) · u ∼ (r · s) · (t · u)
    p1 = Group.+Associative G
    p2 = Group.+WellDefined G (Group.+Associative G) reflexive
    p3 = symmetric (Group.+Associative G)

fourWay+Associative' : {m n : _} {A : Set m} {S : Setoid {m} {n} A} {_·_ : A → A → A} (G : Group S _·_) {a b c d : A} → (Setoid._∼_ S (((a · b) · c) · d) (a · ((b · c) · d)))
fourWay+Associative' {S = S} G = transitive (symmetric +Associative) (symmetric (fourWay+Associative G))
  where
    open Group G
    open Setoid S
    open Equivalence eq

fourWay+Associative'' : {m n : _} {A : Set m} {S : Setoid {m} {n} A} {_·_ : A → A → A} (G : Group S _·_) {a b c d : A} → (Setoid._∼_ S (a · (b · (c · d))) (a · ((b · c) · d)))
fourWay+Associative'' {S = S} {_·_ = _·_} G = transitive +Associative (symmetric (fourWay+Associative G))
  where
    open Group G
    open Setoid S
    open Equivalence eq


module sv20.exam1 where

open import Data.Product using (∃-syntax) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function.Base using (_∘_)

record _⇔_ (A B : Set) : Set where
  field
    to   : A → B
    from : B → A

-- An idiom that makes things slightly more readable (sometimes)
case_of_ : ∀ {a b} {A : Set a} {B : Set b} → A → (A → B) → B
case x of f = f x

-- Exam starts from here:

-- 1.

first : ∀ {Object : Set} {P Q : Object → Set}
      → (∃[ x ] (P x ⊎ Q x)) ⇔ (∃[ x ] (P x) ⊎ ∃[ x ] (Q x))
-- We prove each side separately of the bijection separately. If we are able to
-- prove both ways, we will have proved the bijection
first =
    record { to = to ; from = from }
  where
  -- First, we prove that (∃[ x ] (P x ⊎ Q x)) → (∃[ x ] (P x) ⊎ ∃[ x ] (Q x))
  to : ∀ {Object : Set} {P Q : Object → Set}
     → (∃[ x ] (P x ⊎ Q x)) → (∃[ x ] (P x) ⊎ ∃[ x ] (Q x))
  -- Proof
  --to ⟨ x , inj₁ px ⟩ = inj₁ ⟨ x , px ⟩
  --to ⟨ x , inj₂ qx ⟩ = inj₂ ⟨ x , qx ⟩
  --
  -- Proof explained:
  to ∃x-px⊎qx =
    let
      ⟨ x , px⊎qx ⟩ = ∃x-px⊎qx  -- From ∃[ x ] (P x ⊎ Q x) we find an element x that fullfills (P x ⊎ Q x)
    in case px⊎qx of            -- P x ⊎ Q x  indicates two possible cases, either
      λ { (inj₁ px) → inj₁ ⟨ x , px ⟩  -- P x  is true, and so ∃[ x ] (P x)
        ; (inj₂ qx) → inj₂ ⟨ x , qx ⟩  -- or, Q x is true, and so ∃[ x ] (Q x)
      }

  -- Now, we prove the inverse (∃[ x ] (P x) ⊎ ∃[ x ] (Q x)) → (∃[ x ] (P x ⊎ Q x))
  from : ∀ {Object : Set} {P Q : Object → Set}
       → (∃[ x ] (P x) ⊎ ∃[ x ] (Q x)) → (∃[ x ] (P x ⊎ Q x))
  -- Proof
  --from (inj₁ ⟨ x , px ⟩) = ⟨ x , inj₁ px ⟩
  --from (inj₂ ⟨ x , qx ⟩) = ⟨ x , inj₂ qx ⟩
  --
  -- Proof explained:
  -- There are two possible properties that get fulfilled, either
  from (inj₁ ⟨ x , px ⟩) = ⟨ x , inj₁ px ⟩  -- ∃[ x ] (P x) gets fulfilled
  from (inj₂ ⟨ x , qx ⟩) = ⟨ x , inj₂ qx ⟩  -- or, ∃[ x ] (Q x) gets fulfilled

-- 2.

second : ∀ {Object : Set} {P Q : Object → Set} {_R_ : Object → Object → Set}
       → ∃[ x ] (P x)
       → ∃[ x ] (Q x)
       → (∀ x → P x → ∀ y → Q y → x R y)
       ---------------------------------
       → ∃[ x ] ∃[ y ] (x R y)
--Proof:
--second ⟨ x₁ , px₁ ⟩ ⟨ x₂ , qx₂ ⟩ ∀x→px→∀y→qy→xry = ⟨ x₁ , ⟨ x₂ , ∀x→px→∀y→qy→xry x₁ px₁ x₂ qx₂ ⟩ ⟩
--
--Proof explained:
second ∃x-px ∃x-qx ∀x→px→∀y→qy→xry =
  let
    ⟨ x₁ , px₁ ⟩ = ∃x-px  -- If we have a value from ∃[ x ] (P x), we can get an x₁ that fulfills P
    ⟨ x₂ , qx₂ ⟩ = ∃x-qx  -- and there is a value x₂ that fulfills Q
    px→∀y→qy→xry = ∀x→px→∀y→qy→xry x₁   -- For all x it is true that (P x → ∀ y → Q y → x R y), including x₁
    ∀y→qy→xry    = px→∀y→qy→xry px₁     -- P is fulfilled by x₁
    xry          = ∀y→qy→xry x₂ qx₂     -- In a similar way, x₂ is a value that fulfills Qy, so we can instanciate (∀ y → Q y → x₁ R y) into (x₁ R x₂)
  in ⟨ x₁ , ⟨ x₂ , xry ⟩ ⟩ -- So, we know there is an element x₁ and an element x₂ for which x₁ R x₂ is true


{-# OPTIONS --sized-types #-}
module SOList.Lower.Properties {A : Set}(_≤_ : A → A → Set)  where

open import Bound.Lower A
open import Bound.Lower.Order _≤_
open import Size
open import List.Sorted _≤_
open import SOList.Lower _≤_

lemma-solist-sorted : {ι : Size}{b : Bound} → (xs : SOList {ι} b) →  Sorted (forget xs)
lemma-solist-sorted onil = nils
lemma-solist-sorted (:< {x = x} _ onil) = singls x
lemma-solist-sorted (:< b≤x (:< (lexy x≤y) ys)) = conss x≤y  (lemma-solist-sorted (:< (lexy x≤y) ys))


{-# OPTIONS --enable-prop #-}

open import Agda.Builtin.Nat

-- You can define datatypes in Prop, even with multiple constructors.
-- However, all constructors are considered (definitionally) equal.
data TestProp : Prop where
  p₁ p₂ : TestProp

-- Pattern matching on a datatype in Prop is disallowed unless the
-- target type is a Prop:
test-case : {P : Prop} (x₁ x₂ : P) → TestProp → P
test-case x₁ x₂ p₁ = x₁
test-case x₁ x₂ p₂ = x₂

-- All elements of a Prop are definitionally equal:
data _≡Prop_ {A : Prop} (x : A) : A → Set where
  refl : x ≡Prop x

p₁≡p₂ : p₁ ≡Prop p₂
p₁≡p₂ = refl

-- A special case are empty types in Prop: these can be eliminated to
-- any other type.
data ⊥ : Prop where

absurd : {A : Set} → ⊥ → A
absurd ()

-- We can also define record types in Prop, such as the unit:
record ⊤ : Prop  where
  constructor tt

-- We have Prop : Set₀, so we can store predicates in a small datatype:
data NatProp : Set₁ where
  c : (Nat → Prop) → NatProp

-- To define more interesting predicates, we need to define them by pattern matching:
_≤_ : Nat → Nat → Prop
zero  ≤ y     = ⊤
suc x ≤ suc y = x ≤ y
_     ≤ _     = ⊥

-- We can also define the induction principle for predicates defined in this way,
-- using the fact that we can eliminate absurd propositions with a () pattern.
≤-ind : (P : (m n : Nat) → Set)
      → (pzy : (y : Nat) → P zero y)
      → (pss : (x y : Nat) → P x y → P (suc x) (suc y))
      → (m n : Nat) → m ≤ n → P m n
≤-ind P pzy pss zero y pf = pzy y
≤-ind P pzy pss (suc x) (suc y) pf = pss x y (≤-ind P pzy pss x y pf)
≤-ind P pzy pss (suc _) zero ()

-- We can define equality as a Prop, but (currently) we cannot define
-- the corresponding eliminator, so the equality is only useful for
-- refuting impossible equations.
data _≡P_ {A : Set} (x : A) : A → Prop where
  refl : x ≡P x

0≢1 : 0 ≡P 1 → ⊥
0≢1 ()


module Setoid where

open import Logic.Base

record Setoid : Set1 where
  field
    A     : Set
    _==_  : A -> A -> Prop
    refl  : {x : A} -> x == x
    sym   : {x y : A} -> x == y -> y == x
    trans : {x y z : A} -> x == y -> y == z -> x == z

module Set-Ar where

  !_! : (S : Setoid) -> Set
  ! S ! = Setoid.A S

  record SetoidArrow (S₁ S₂ : Setoid) : Set where
    field
      map  : ! S₁ ! -> ! S₂ !
      stab : {x y : Setoid.A S₁} -> Setoid._==_ S₁ x y -> Setoid._==_ S₂ (map x) (map y)

  _∘_ : {S₁ S₂ S₃ : Setoid} -> SetoidArrow S₂ S₃ -> SetoidArrow S₁ S₂ -> SetoidArrow S₁ S₃
  _∘_ {S₁} F₁ F₂ = record
    { map  = \x -> SetoidArrow.map F₁ (SetoidArrow.map F₂ x)
    ; stab = \{x y : ! S₁ !}(p : Setoid._==_ S₁ x y) -> SetoidArrow.stab F₁ (SetoidArrow.stab F₂ p)
    }

  id : {S : Setoid} -> SetoidArrow S S
  id = record
    { map  = \x -> x
    ; stab = \p -> p
    }

  _==→_ : {S₁ S₂ : Setoid} -> SetoidArrow S₁ S₂ -> SetoidArrow S₁ S₂ -> Set
  _==→_ {_} {S₂} F₁ F₂ = (forall x -> Setoid._==_ S₂ (SetoidArrow.map F₁ x) (SetoidArrow.map F₂ x)) -> True

module Set-Fam where

  open Set-Ar

  record SetoidFam (S : Setoid) : Set1 where
    field
      index     : ! S ! -> Setoid
      reindex   : {x x' : ! S !} -> Setoid._==_ S x x' -> SetoidArrow (index x) (index x')
      id-coh    : {x : ! S !} -> (reindex (Setoid.refl S)) ==→ id {index x}
      sym-coh-l : {x y : ! S !}(p : Setoid._==_ S x y) -> ((reindex (Setoid.sym S p)) ∘ (reindex p)) ==→ id
      sym-coh-r : {x y : ! S !}(p : Setoid._==_ S x y) -> ((reindex p) ∘ (reindex (Setoid.sym S p))) ==→ id
      trans-coh : {x y z : ! S !}(p : Setoid._==_ S x y)(p' : Setoid._==_ S y z) ->
                  (reindex (Setoid.trans S p p')) ==→ ((reindex p') ∘ (reindex p))

module Set-Fam-Ar where

  open Set-Ar
  open Set-Fam

  record SetoidFamArrow {S₁ S₂ : Setoid}(F₁ : SetoidFam S₁)(F₂ : SetoidFam S₂) : Set where
    field
      indexingmap : SetoidArrow S₁ S₂
      indexmap    : (x : ! S₁ !) -> SetoidArrow (SetoidFam.index F₁ x)
                    (SetoidFam.index F₂ (SetoidArrow.map indexingmap x))
      reindexmap  : (x x' : ! S₁ !)(p : Setoid._==_ S₁ x' x) ->
                    ((indexmap x) ∘ (SetoidFam.reindex F₁ p)) ==→
                    ((SetoidFam.reindex F₂ (SetoidArrow.stab indexingmap p)) ∘ (indexmap x'))


module Problem1 where

-- 1.1

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

-- 1.2

infixl 60 _+_

_+_ : Nat -> Nat -> Nat
zero  + m = m
suc n + m = suc (n + m)

-- 1.3

infixl 70 _*_

_*_ : Nat -> Nat -> Nat
zero  * m = zero
suc n * m = m + n * m

-- 1.4

infix 30 _==_

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

cong : {A B : Set}(f : A -> B){x y : A} -> x == y -> f x == f y
cong f refl = refl

assoc : (x y z : Nat) -> x + (y + z) == (x + y) + z
assoc zero    y z = refl
assoc (suc x) y z = cong suc (assoc x y z)

-- Alternative solution using 'with'. Note that in order
-- to be able to pattern match on the induction hypothesis
-- we have to abstract (using with) over the left hand side
-- of the equation.

assoc' : (x y z : Nat) -> x + (y + z) == (x + y) + z
assoc' zero    y z = refl
assoc' (suc x) y z with x + (y + z) | assoc x y z
...                | .((x + y) + z) | refl = refl


module Numeral.Natural.Prime where

import Lvl
open import Data.Boolean.Stmt
open import Logic
open import Logic.Propositional
open import Numeral.Natural
open import Numeral.Natural.Relation.Divisibility
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Comparisons
open import Relator.Equals

PrimeProof : {_ : ℕ} → Stmt{Lvl.𝟎}
PrimeProof{n} = (∀{x} → (𝐒(x) ∣ 𝐒(𝐒(n))) → ((x ≡ 𝟎) ∨ (x ≡ 𝐒(n))))

-- A prime number is a number `n` in which its only divisors are `{1,n}`.
data Prime : ℕ → Stmt{Lvl.𝟎} where
  intro : ∀{n} → PrimeProof{n} → Prime(𝐒(𝐒(n)))

-- A composite number is a number which are the product of two numbers greater than or equals 2.
data Composite : ℕ → Stmt{Lvl.𝟎} where
  intro : (a b : ℕ) → Composite(𝐒(𝐒(a)) ⋅ 𝐒(𝐒(b)))

Composite-intro : (a b : ℕ) → ⦃ _ : IsTrue(a ≥? 2) ⦄ ⦃ _ : IsTrue(b ≥? 2) ⦄ → Composite(a ⋅ b)
Composite-intro (𝐒(𝐒 a)) (𝐒(𝐒 b)) = intro a b

-- PrimeFactor(n)(p) means that `p` is a prime factor of `n`.
-- A prime factor `p` of `n` is a prime number that divides `n`.
record PrimeFactor(n : ℕ) (p : ℕ) : Stmt{Lvl.𝟎} where
  constructor intro
  field
    ⦃ prime ⦄  : Prime(p)
    ⦃ factor ⦄ : (p ∣ n)

-- greater-prime-existence : ∀{p} → Prime(p) → ∃(p₂ ↦ Prime(p₂) ∧ (p₂ > p))

-- TODO: https://math.stackexchange.com/questions/2786458/a-formal-statement-of-the-fundamental-theorem-of-arithmetic
-- TODO: Needs to be a finite multiset of primes.
-- PrimeMultiset = Type{Lvl.𝟎}
-- PrimeMultiSet = ((p : ℕ) → ⦃ _ : Prime(p) ⦄ → ℕ)


import Relation.Binary.EqReasoning as EqReasoning
open import SemiNearRingRecords
module OrderLemmas (snro : SemiNearRing) where

open SemiNearRing snro -- public
open import CommAssocLemmas s _≃s_ _+s_ zers isCommMon
     using (assoc; comm)
     renaming (SA to Ss)

open EqReasoning Ss

monoPlusLeft : ∀ {a} {b} {c} →  a ≤s b  →
                        (a +s c)  ≤s  (b +s c)
monoPlusLeft {a} {b} {c} a≤b =
  begin
    (a +s c)  +s  (b +s c)
  ≈⟨ assoc _ _ _ ⟩
    a +s (c  +s  (b +s c))
  ≈⟨ refls <+> comm _ _ ⟩
    a +s ((b +s c) +s c)
  ≈⟨ refls <+> assoc _ _ _ ⟩
    a +s (b +s (c +s c))
  ≈⟨ sym (assoc _ _ _) ⟩
    (a +s b) +s (c +s c)
  ≈⟨ a≤b <+> idem _ ⟩
    b +s c
  ∎

monoTimesLeft : ∀ {a} {b} {c} →  a ≤s b →
                         (a *s c)  ≤s  (b *s c)
monoTimesLeft {a} {b} {c} a≤b =
  begin
    (a *s c) +s (b *s c)
  ≈⟨ sym (distr _ _ _) ⟩
    (a +s b) *s c
  ≈⟨  a≤b    <*> refls  ⟩ -- a≤=b means a+b==b
          b  *s c
  ∎
infixl 6 _[+]_
infixl 7 _[*]_

_[+]_ : ∀ {a} {a'} {b} {b'} ->  a ≤s a' -> b ≤s b' ->
                                (a +s b) ≤s (a' +s b')
_[+]_ {a} {a'} {b} {b'} pa pb =
  begin
    (a +s b) +s (a' +s b')
  ≈⟨ assoc _ _ _ ⟩
    a +s (b +s (a' +s b'))
  ≈⟨  refls <+> comm _ _  ⟩
    a +s ((a' +s b') +s b)
  ≈⟨  refls <+> assoc _ _ _  ⟩
    a +s (a' +s (b' +s b))
  ≈⟨  sym (assoc _ _ _)  ⟩
    (a +s a') +s (b' +s b)
  ≈⟨  pa <+> comm _ _  ⟩
    a' +s (b +s b')
  ≈⟨  refls <+> pb  ⟩
    a' +s b'
  ∎

_[*]_ : ∀ {a} {a'} {b} {b'} ->  a ≤s a' -> b ≤s b' ->
                                (a *s b) ≤s (a' *s b')
_[*]_ {a} {a'} {b} {b'} pa pb =
  begin
    (a *s b) +s (a' *s b')
  ≈⟨  refls <+> (sym pa <*> refls)  ⟩
    a *s b +s (a +s a') *s b'
  ≈⟨  refls <+> distr _ _ _  ⟩
    a *s b +s (a *s b' +s a' *s b')
  ≈⟨  sym (assoc _ _ _)  ⟩
    (a *s b +s a *s b') +s a' *s b'
  ≈⟨  sym (distl _ _ _) <+> (refls <*> sym pb)  ⟩
    a *s (b +s b') +s a' *s (b +s b')
  ≈⟨  sym (distr _ _ _)  ⟩
    (a +s a') *s (b +s b')
  ≈⟨  pa <*> pb  ⟩
    a' *s b'
  ∎

≤s-trans : ∀ {a b c} →  a ≤s b  →  b ≤s c  →  a ≤s c
≤s-trans {a} {b} {c} p q =
  begin
    a +s c
  ≈⟨  refls <+> sym q ⟩
    a +s (b +s c)
  ≈⟨  sym (assoc _ _ _) ⟩
    (a +s b) +s c
  ≈⟨  p <+> refls ⟩
    b +s c
  ≈⟨ q ⟩
    c
  ∎

≃sTo≤s : ∀ {a b} →  a ≃s b  →  a ≤s b
≃sTo≤s {a} {b} a=b =
  begin
    a +s b
  ≈⟨ a=b <+> refls ⟩
    b +s b
  ≈⟨ idem _ ⟩
    b
  ∎


-- Andreas, 2015-05-02 Integrate copatterns with with.

{-# OPTIONS --copatterns #-}

open import Common.Prelude hiding (map)
open import Common.Product
open import Common.Equality

dup : {A : Set} → A → A × A
proj₁ (dup a) = a
proj₂ (dup a) with a
proj₂ (dup a) | x = x

record Stream (A : Set) : Set where
  coinductive
  constructor delay
  field
    force : A × Stream A
open Stream

map : ∀{A B} → (A → B) → Stream A → Stream B
force (map f s) with force s
... | a , as = f a , map f as

zipWith : ∀{A B C} → (A → B → C) → Stream A → Stream B → Stream C
force (zipWith f s t) with force s | force t
... | a , as | b , bs = f a b , zipWith f as bs

interleave : ∀{A} (s t : Stream A) → Stream A
force (interleave s t) with force s
... | a , as = a , interleave t as

mutual
  evens : ∀{A} (s : Stream A) → Stream A
  force (evens s) with force s
  ... | a , as = a , odds as

  odds : ∀{A} (s : Stream A) → Stream A
  odds s with force s
  ... | a , as = evens as

take : ∀{A} (n : Nat) (s : Stream A) → List A
take 0       s = []
take (suc n) s with force s
... | a , as = a ∷ take n as

record Bisim {A B} (R : A → B → Set) (s : Stream A) (t : Stream B) : Set where
  coinductive
  constructor ~delay
  field
    ~force : let a , as = force s
                 b , bs = force t
             in  R a b × Bisim R as bs
open Bisim

SEq : ∀{A} (s t : Stream A) → Set
SEq = Bisim (_≡_)

~refl : ∀{A} (s : Stream A) → SEq s s
~force (~refl s) with force s
... | a , as = refl , ~refl as

~sym : ∀{A}{s t : Stream A} → SEq s t → SEq t s
~force (~sym p) with ~force p
... | q , r = sym q , ~sym r

~sym' : ∀{A} {s t : Stream A} → SEq s t → SEq t s
~force (~sym' {s = s} {t} p) with force s | force t | ~force p
... | a , as | b , bs | r , q rewrite r = refl , ~sym' q

-- ~sym' : ∀{A} {s t : Stream A} → SEq s t → SEq t s
-- ~force (~sym' {s = s} {t} p) with force s | force t | ~force p
-- ... | x | y | q , r = {!x!} -- C-c C-c prints internal with-name

~trans : ∀{A}{r s t : Stream A} → SEq r s → SEq s t → SEq r t
~force (~trans p q) with ~force p | ~force q
... | ph , pt | qh , qt = trans ph qh , ~trans pt qt

~take : ∀{A} (s t : Stream A) (p : SEq s t) (n : Nat) → take n s ≡ take n t
~take s t p zero = refl
~take s t p (suc n) with force s | force t | ~force p
~take s t p (suc n) | a , as | .a , bs | refl , q rewrite ~take as bs q n = refl


module Lib.Vec where

open import Common.Nat
open import Lib.Fin
open import Common.Unit
import Common.List as List; open List using (List ; [] ; _∷_)

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

infixr 30 _++_

_++_ : {A : Set}{m n : Nat} → Vec A m → Vec A n → Vec A (m + n)
[]       ++ ys = ys
(x ∷ xs) ++ ys = x ∷ (xs ++ ys)

snoc : {A : Set}{n : Nat} → Vec A n → A → Vec A (suc n)
snoc []       e = e ∷ []
snoc (x ∷ xs) e = x ∷ snoc xs e

-- Recursive length.

length : {A : Set}{n : Nat} → Vec A n → Nat
length [] = zero
length (x ∷ xs) = 1 + length xs

length' : {A : Set}{n : Nat} → Vec A n → Nat
length' {n = n} _ = n

zipWith3 : ∀ {A B C D n} → (A → B → C → D) → Vec A n → Vec B n → Vec C n → Vec D n
zipWith3 f []       []       []       = []
zipWith3 f (x ∷ xs) (y ∷ ys) (z ∷ zs) = f x y z ∷ zipWith3 f xs ys zs

zipWith : ∀ {A B C n} → (A → B → C) → Vec A n → Vec B n → {u : Unit} → Vec C n
zipWith _ [] [] = []
zipWith f (x ∷ xs) (y ∷ ys) = f x y ∷ zipWith f xs ys {u = unit}

_!_ : ∀ {A n} → Vec A n → Fin n → A
(x ∷ xs) ! fz   = x
(_ ∷ xs) ! fs n = xs ! n
[] ! ()

-- Update vector at index

_[_]=_ : {A : Set}{n : Nat} → Vec A n → Fin n → A → Vec A n
(a ∷ as) [ fz   ]= e = e ∷ as
(a ∷ as) [ fs n ]= e = a ∷ (as [ n ]= e)
[] [ () ]= e

map : ∀ {A B n}(f : A → B)(xs : Vec A n) → Vec B n
map f []        = []
map f (x ∷ xs) = f x ∷ map f xs

-- Vector to List, forget the length.

forgetL : {A : Set}{n : Nat} → Vec A n → List A
forgetL []       = []
forgetL (x ∷ xs) = x ∷ forgetL xs

-- List to Vector, "rem"member the length.

rem : {A : Set}(xs : List A) → Vec A (List.length xs)
rem [] = []
rem (x ∷ xs) = x ∷ rem xs


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

module FiniteFunctions where

open import Data.Vec using (tabulate; _∷_)
open import Data.Fin using (Fin; zero; suc)
open import Data.Nat using (ℕ; suc)
open import Relation.Binary.PropositionalEquality
  using (_≡_; refl; cong; module ≡-Reasoning)
open import Function using (_∘_)

------------------------------------------------------------------------------
-- Important: Extensionality for finite functions

finext : {n : ℕ} {A : Set} → {f g : Fin n → A} → ((i : Fin n) → f i ≡ g i) →
         (tabulate f ≡ tabulate g)
finext {0} _ = refl
finext {suc n} {_} {f} {g} fi≡gi =
  begin (tabulate {suc n} f
           ≡⟨ refl ⟩
         f zero ∷ tabulate {n} (f ∘ suc)
           ≡⟨ cong (λ x → x ∷ tabulate {n} (f ∘ suc)) (fi≡gi zero) ⟩
         g zero ∷ tabulate {n} (f ∘ suc)
           ≡⟨ cong (_∷_ (g zero))
                (finext {f = f ∘ suc} {g ∘ suc} (fi≡gi ∘ suc)) ⟩
         g zero ∷ tabulate {n} (g ∘ suc)
           ≡⟨ refl ⟩
         tabulate g ∎)
  where open ≡-Reasoning

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


module nat where

open import Data.Nat renaming ( zero to Zero ; suc to Suc ;  ℕ to Nat ; _⊔_ to _n⊔_ )
open import Data.Empty
open import Relation.Nullary
open import  Relation.Binary.PropositionalEquality
open import  logic

nat-<> : { x y : Nat } → x < y → y < x → ⊥
nat-<>  (s≤s x<y) (s≤s y<x) = nat-<> x<y y<x

nat-<≡ : { x : Nat } → x < x → ⊥
nat-<≡  (s≤s lt) = nat-<≡ lt

nat-≡< : { x y : Nat } → x ≡ y → x < y → ⊥
nat-≡< refl lt = nat-<≡ lt

¬a≤a : {la : Nat} → Suc la ≤ la → ⊥
¬a≤a  (s≤s lt) = ¬a≤a  lt

a<sa : {la : Nat} → la < Suc la
a<sa {Zero} = s≤s z≤n
a<sa {Suc la} = s≤s a<sa

=→¬< : {x : Nat  } → ¬ ( x < x )
=→¬< {Zero} ()
=→¬< {Suc x} (s≤s lt) = =→¬< lt

>→¬< : {x y : Nat  } → (x < y ) → ¬ ( y < x )
>→¬< (s≤s x<y) (s≤s y<x) = >→¬< x<y y<x

<-∨ : { x y : Nat } → x < Suc y → ( (x ≡ y ) ∨ (x < y) )
<-∨ {Zero} {Zero} (s≤s z≤n) = case1 refl
<-∨ {Zero} {Suc y} (s≤s lt) = case2 (s≤s z≤n)
<-∨ {Suc x} {Zero} (s≤s ())
<-∨ {Suc x} {Suc y} (s≤s lt) with <-∨ {x} {y} lt
<-∨ {Suc x} {Suc y} (s≤s lt) | case1 eq = case1 (cong (λ k → Suc k ) eq)
<-∨ {Suc x} {Suc y} (s≤s lt) | case2 lt1 = case2 (s≤s lt1)

max : (x y : Nat) → Nat
max Zero Zero = Zero
max Zero (Suc x) = (Suc x)
max (Suc x) Zero = (Suc x)
max (Suc x) (Suc y) = Suc ( max x y )


{-# OPTIONS --without-K --safe #-}
open import Categories.Category.Groupoid

module Categories.Category.Groupoid.Properties {o ℓ e} (G : Groupoid o ℓ e) where

import Categories.Morphism as Morphism
import Categories.Morphism.Properties as MorphismProps
import Categories.Morphism.Reasoning as MR

open Groupoid G
open Morphism category
open MorphismProps category
open HomReasoning
open MR category

private
  variable
    A B C : Obj

mono : {f : A ⇒ B} → Mono f
mono = Iso⇒Mono iso

epi : {f : A ⇒ B} → Epi f
epi = Iso⇒Epi iso

id-inverse : id {A = A} ⁻¹ ≈ id
id-inverse = ⟺ identityˡ ○ iso.isoʳ

⁻¹-involutive : {f : A ⇒ B} → f ⁻¹ ⁻¹ ≈ f
⁻¹-involutive {f = f} = begin
  f ⁻¹ ⁻¹            ≈⟨ introʳ iso.isoˡ ⟩
  f ⁻¹ ⁻¹ ∘ f ⁻¹ ∘ f ≈⟨ sym-assoc ○ elimˡ iso.isoˡ ⟩
                   f ∎

⁻¹-commute : {f : A ⇒ B} {g : C ⇒ A} → (f ∘ g) ⁻¹ ≈ g ⁻¹ ∘ f ⁻¹
⁻¹-commute {f = f} {g} = epi _ _ ( begin
  (f ∘ g) ⁻¹ ∘ f ∘ g    ≈⟨ iso.isoˡ ⟩
  id                    ≈˘⟨ iso.isoˡ ⟩
  g ⁻¹ ∘ g              ≈˘⟨ cancelInner iso.isoˡ ⟩
  (g ⁻¹ ∘ f ⁻¹) ∘ f ∘ g ∎ )


module integer7 where

import Relation.Binary.PropositionalEquality as PropEq
open PropEq using (_≡_; refl; cong; sym)
open import Data.Nat

-- Int
data Int : Set where
  O : Int
  I : ℕ → ℕ → Int
postulate
  zeroZ : (x : ℕ) → I x x ≡ O
-- plusInt
_++_ : Int → Int → Int
O ++ O = O
O ++ X = X
X ++ O = X
I x y ++ I z w = I (x + z) (y + w)
postulate
  ++Assoc : (X Y Z : Int) → (X ++ Y) ++ Z ≡ X ++ (Y ++ Z)
  ++Comm : (X Y : Int) → X ++ Y ≡ Y ++ X
-- productInt
_**_ : Int → Int → Int
O ** O = O
O ** _ = O
_ ** O = O
I x y ** I z w = I (x * z + y * w) (x * w + y * z)
postulate
  **Assoc : (X Y Z : Int) → (X ** Y) ** Z ≡ X ** (Y ** Z)
  **Dist : (X Y Z : Int) → X ** (Y ++ Z) ≡ (X ** Y) ++ (X ** Z)

-- (-1) ** (-1) = 1
minus1 : I 0 1 ** I 0 1 ≡ I 1 0
minus1 = refl
-1+1 : I 0 1 ++ I 1 0 ≡ I 1 1
-1+1 = refl
-1*1 : I 0 1 ** I 1 0 ≡ I 0 1
-1*1 = refl
minus2 : I 0 1 ** I 0 1 ≡ I 1 0
minus2 = begin
    I 0 1 ** I 0 1
  ≡⟨ refl ⟩
    (I 0 1 ** I 0 1) ++ O
  ≡⟨ sym (cong (\ x → (I 0 1 ** I 0 1) ++ x) (zeroZ 1)) ⟩
    (I 0 1 ** I 0 1) ++ (I 1 1)
  ≡⟨ sym (cong (\ x → (I 0 1 ** I 0 1) ++ x) -1+1) ⟩
    (I 0 1 ** I 0 1) ++ (I 0 1 ++ I 1 0)
  ≡⟨ sym (++Assoc O O (I (suc (suc zero)) (suc zero))) ⟩
    ((I 0 1 ** I 0 1) ++ I 0 1) ++ I 1 0
  ≡⟨ sym (cong (\ x → ((I 0 1 ** I 0 1) ++ x) ++ I 1 0) -1*1) ⟩
    ((I 0 1 ** I 0 1) ++ (I 0 1 ** I 1 0)) ++ I 1 0
  ≡⟨ sym (cong (\ x → x ++ I 1 0) (**Dist (I 0 1) (I 0 1) (I 1 0))) ⟩
    (I 0 1 ** (I 0 1 ++ I 1 0)) ++ I 1 0
  ≡⟨ refl ⟩
    (I 0 1 ** I 1 1) ++ I 1 0
  ≡⟨ cong (\ x → ((I 0 1 ** x) ++ I 1 0)) (zeroZ 1) ⟩
    (I 0 1 ** O) ++ I 1 0
  ≡⟨ refl ⟩
    O ++ I 1 0
  ≡⟨ refl ⟩
    I 1 0
  ∎
  where open PropEq.≡-Reasoning


module List.Permutation.Alternative (A : Set) where

open import Data.List

data _∼_ : List A → List A → Set where
  ∼refl : {xs : List A}
                   → xs ∼ xs
  ∼trans : {xs ys zs : List A}
                   → xs ∼ ys
                   → ys ∼ zs
                   → xs ∼ zs
  ∼head : {xs ys : List A}(x : A)
                   → xs ∼ ys
                   → (x ∷ xs) ∼ (x ∷ ys)
  ∼swap : {xs ys : List A}{x y : A}
                   → (x ∷ y ∷ xs) ∼ ys
                   → (y ∷ x ∷ xs) ∼ ys


module Category where

open import Agda.Primitive

open import Equality
open import Finite

record Category ℓ : Set (lsuc ℓ) where
  field
    obj : Set ℓ
    hom : obj → obj → Set ℓ
    id-hom : ∀ {x} → hom x x
    compose : ∀ {x y z} → hom y z → hom x y → hom x z
    compose-id-left : ∀ {x y} {f : hom x y} → compose id-hom f ≡ f
    compose-id-right : ∀ {x y} {f : hom x y} → compose f id-hom ≡ f
    compose-assoc : ∀ {x y z w} {f : hom x y} {g : hom y z} {h : hom z w} → compose (compose h g) f ≡ compose h (compose g f)

record FPCategory ℓ : Set (lsuc ℓ) where
  open Category

  field
    {{category}} : Category ℓ
    product : ∀ n (xs : Fin n → obj category) → obj category
    project : ∀ n {xs : Fin n → obj category} → ∀ (i : Fin n) → hom category (product n xs) (xs i)
    tuple : ∀ n {xs : Fin n → obj category} {y} → ∀ (f : ∀ i → hom category y (xs i)) → hom category y (product n xs)
    project-tuple : ∀ {n} {xs : Fin n → obj category} {y} {f : ∀ i → hom category y (xs i)} {j} →
                   compose category (project n j) (tuple n f) ≡ f j
    tuple-project : ∀ {n} {xs : Fin n → obj category} {y} {u v : hom category y (product n xs)} →
                   (∀ i → compose category (project n i) u ≡ compose category (project n i) v) → u ≡ v

  tuple-hom : ∀ n {xs ys : Fin n → obj category} (f : ∀ i → hom category (xs i) (ys i)) →
              hom category (product n xs) (product n ys)
  tuple-hom n f = tuple n (λ i → compose category (f i) (project n i))

  power : ℕ → obj category → obj category
  power n x = product n (λ _  → x)

  power-hom : ∀ n {x y : obj category} → hom category x y → hom category (power n x) (power n y)
  power-hom n f = tuple-hom n (λ i → f)

  terminal-obj : obj category
  terminal-obj = product Z (λ ())

  terminal-hom : ∀ {x : obj category} → hom category x terminal-obj
  terminal-hom = tuple Z (λ ())

  terminal-eq : ∀ {x : obj category} {f g : hom category x terminal-obj} → f ≡ g
  terminal-eq {x} {f} {g} = tuple-project λ ()


{-# OPTIONS --without-K #-}
module PathStructure.Product {a b} {A : Set a} {B : Set b} where

open import Equivalence
open import PathOperations
open import Types

split-path : {x y : A × B} → x ≡ y → (π₁ x ≡ π₁ y) × (π₂ x ≡ π₂ y)
split-path p = ap π₁ p , ap π₂ p

merge-path : {x₁ x₂ : A} {y₁ y₂ : B} →
  (x₁ ≡ x₂) × (y₁ ≡ y₂) → Id (A × B) (x₁ , y₁) (x₂ , y₂)
merge-path (p , q) = ap₂ _,_ p q

split-merge-eq : {x y : A × B} →
  (x ≡ y) ≃ (π₁ x ≡ π₁ y) × (π₂ x ≡ π₂ y)
split-merge-eq
  = split-path
  , (merge-path , λ pq → J
      (λ _ _ p → ∀ {b₁ b₂} (q : b₁ ≡ b₂) →
        split-path (merge-path (p , q)) ≡ p , q)
      (λ _ q → J
        (λ _ _ q →
          split-path (merge-path (refl , q)) ≡ refl , q)
        (λ _ → refl) _ _ q)
      _ _ (π₁ pq) (π₂ pq))
  , (merge-path , J (λ _ _ p → merge-path (split-path p) ≡ p)
      (λ _ → refl) _ _)


module Example where

loop : Set
loop = loop

_∞_ : Set -> Set -> Set
x ∞ y = x ∞ y

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

id : Nat -> Nat
id zero = zero
id (succ n) = succ (id n)

bad : Nat -> Nat
bad n = bad n

_+_ : Nat -> Nat -> Nat
zero     + n = n
(succ m) + n = succ (m + n)

bad2 : Nat -> Nat
bad2 (succ x) = bad2 x + bad2 (succ x)
bad2 x        = bad2 x

data Bool : Set where
    true : Bool
    false : Bool

_&&_ : Bool -> Bool -> Bool
true && a = a
false && a = false

mutual

  even : Nat -> Bool
  even zero = true
  even (succ n) = odd n

  odd  : Nat -> Bool
  odd zero = false
  odd (succ n) = even n

data Ty : {_ : Nat} -> Set where
    Base : forall {n} -> Ty {succ n}
    Arr  : forall {n} -> Ty {n} -> Ty {n} -> Ty {succ n}

eqty : forall {n} -> Ty {n} -> Ty {n} -> Bool
eqty Base Base = true
eqty (Arr a b) (Arr a' b') = (eqty a a') && (eqty b b')
eqty _ _ = false

subty : forall {n} -> Ty {n} -> Ty {n} -> Bool
subty Base Base = true
subty (Arr a b) (Arr a' b') = (subty a' a) && (subty b b')
subty _ _ = false

-- the following is enough for making it termination check
subty' : forall {n} -> Ty {n} -> Ty {n} -> Bool
subty' Base Base = true
subty' {succ n} (Arr a b) (Arr a' b')
     = (subty' a' a) && (subty' b b')
subty' _ _ = false

subty'' : forall {n} -> Ty {n} -> Ty {n} -> Bool
subty'' Base Base = true
subty'' {succ n} (Arr {.n} a b) (Arr .{n} a'' b'')
     = (subty'' {n} a'' a) && (subty'' {n} b b'')
subty'' _ _ = false

data _×_ (A B : Set) : Set where
    _,_ : A -> B -> A × B

add : Nat × Nat -> Nat
add (zero   , m) = m
add (succ n , m) = succ (add (n , m))

eq : Nat × Nat -> Bool
eq (zero   , zero  ) = true
eq (succ n , succ m) = eq (n , m)
eq _ = false

-- the following should not termination check

mutual

  f : Nat -> Nat -> Nat
  f zero y = zero
  f (succ x) zero = zero
  f (succ x) (succ y) = (g x (succ y)) + (f  (succ (succ x)) y)

  g : Nat -> Nat -> Nat
  g zero y = zero
  g (succ x) zero = zero
  g (succ x) (succ y) = (f (succ x) (succ y)) + (g x (succ (succ y)))

mutual

  badf : Nat ×  Nat -> Nat
  badf (zero , y) = zero
  badf (succ x , zero) = zero
  badf (succ x , succ y) = badg (x , succ y) + badf  (succ (succ x) , y)

  badg : Nat × Nat -> Nat
  badg (zero , y) = zero
  badg (succ x , zero) = zero
  badg (succ x , succ y) = badf (succ x , succ y) +  badg (x , succ (succ y))

-- these are ok, however

mutual

  f' : Nat -> Nat -> Nat
  f' zero y = zero
  f' (succ x) zero = zero
  f' (succ x) (succ y) = (g' x (succ y)) + (f'  (succ (succ x)) y)

  g' : Nat -> Nat -> Nat
  g' zero y = zero
  g' (succ x) zero = zero
  g' (succ x) (succ y) = (f' (succ x) (succ y)) + (g' x (succ y))

-- these are ok, however

bla : Nat
bla = succ (succ zero)

mutual

  f'' : Nat -> Nat -> Nat
  f'' zero y = zero
  f'' (succ x) zero = zero
  f'' (succ x) (succ y) = (g'' x (succ y)) + (f'' bla y)

  g'' : Nat -> Nat -> Nat
  g'' zero y = zero
  g'' (succ x) zero = zero
  g'' (succ x) (succ y) = (f'' (succ x) (succ y)) + (g'' x (succ y))

-- Ackermann

ack : Nat -> Nat -> Nat
ack zero y = succ y
ack (succ x) zero = ack x (succ zero)
ack (succ x) (succ y) = ack x (ack (succ x) y)

ack' : Nat × Nat -> Nat
ack' (zero , y) = succ y
ack' (succ x , zero) = ack' (x , succ zero)
ack' (succ x , succ y) = ack' (x , ack' (succ x , y))

-- Maximum of 3 numbers

max3 : Nat -> Nat -> Nat -> Nat
max3 zero zero z = z
max3 zero y zero = y
max3 x zero zero = x
max3 (succ x) (succ y) zero = succ (max3 x y zero)
max3 (succ x) zero (succ z) = succ (max3 x zero z)
max3 zero (succ y) (succ z) = succ (max3 zero y z)
max3 (succ x) (succ y) (succ z) = succ (max3 x y z)

-- addition of Ordinals

data Ord : Set where
   ozero : Ord
   olim  : (Nat -> Ord) -> Ord

addord : Ord -> Ord -> Ord
addord x ozero = x
addord x (olim f) = olim (\ n -> addord x (f n))

-- Higher-order example which should not pass the termination checker.
-- (Not the current one, anyway.)

foo : Ord -> (Nat -> Ord) -> Ord
foo ozero    g = ozero
foo (olim f) g = olim (\n -> foo (g n) f)

-- Examples checking that a function can be used with several
-- different numbers of arguments on the right-hand side.

const : {a b : Set1} -> a -> b -> a
const x _ = x

ok : Nat -> Nat -> Set
ok zero     y = Nat
ok (succ x) y = const Nat (const (ok x y) (ok x))

notOK : Set -> Set
notOK x = const (notOK Ord) notOK

-- An example which should fail (37 is an arbitrary number):

data ⊤ : Set where
  tt : ⊤

mutual

  foo37 : ⊤ -> ⊤
  foo37 x = bar37 x

  bar37 : ⊤ -> ⊤
  bar37 tt = foo37 tt

-- Some examples involving with.

-- Not OK:

withNo : Nat -> Nat
withNo n with n
withNo n | m = withNo m

-- OK:

withYes : Nat -> Nat
withYes n with n
withYes n | zero   = zero
withYes n | succ m = withYes m

-- Some rather convoluted examples.

-- OK:

number : Nat
number = zero
  where
  data Foo12 : Nat -> Set where
    foo12 : Foo12 number

-- Should the occurrence of number' in the type signature of foo12
-- really be highlighted here?

number' : Nat
number' with zero
number' | x = g12 foo12
  where
  data Foo12 : Nat -> Set where
    foo12 : Foo12 number'
  abstract
    g12 : {i : Nat} -> Foo12 i -> Nat
    g12 foo12 = zero

-- Tests highlighting (but does not type check yet):

-- number'' : Nat
-- number'' with zero
-- number'' | x = g12 (foo12 x)
--   where
--   data Foo12 : Nat -> Set where
--     foo12 : (n : Nat) -> Foo12 (number'' | n)
--   abstract
--     g12 : {i : Nat} -> Foo12 i -> Nat
--     g12 (foo12 n) = n

data List (A : Set) : Set where
  [] : List A
  _::_ : A -> List A -> List A

infixr 50 _::_

-- butlast function
good1 : {A : Set} -> List A -> A
good1 (a :: []) = a
good1 (a :: b :: bs) = good1 (b :: bs)

infixl 10 _⊕_
postulate
  _⊕_ : {A : Set} -> A -> A -> A  -- non-deterministic choice

-- a funny formulation of insert
-- insert (a :: l)  inserts a into l
insert : {A : Set} -> List A -> List A
insert [] = []
insert (a :: []) = a :: []
insert (a :: b :: bs) = a :: b :: bs ⊕        -- case a <= b
                        b :: insert (a :: bs) -- case a > b

-- list flattening
flat : {A : Set} -> List (List A) -> List A
flat [] = []
flat ([] :: ll) = flat ll
flat ((x :: l) :: ll) = x :: flat (l :: ll)

-- leaf-labelled trees

data Tree (A : Set) : Set where
  leaf : A -> Tree A
  node : Tree A -> Tree A -> Tree A

-- flattening (does not termination check)

tflat : {A : Set} -> Tree A -> List A
tflat (leaf a) = a :: []
tflat (node (leaf a) r) = a :: tflat r
tflat (node (node l1 l2) r) = tflat (node l1 (node l2 r))

-- Maximum of 3 numbers
-- mixing tupling and swapping: does not work with structured orders

max3' : Nat × Nat -> Nat -> Nat
max3' (zero , zero) z = z
max3' (zero , y) zero = y
max3' (x , zero) zero = x
max3' (succ x , succ y) zero   = succ (max3' (x , y) zero)
max3' (succ x , zero) (succ z) = succ (max3' (x , z) zero)
max3' (zero , succ y) (succ z) = succ (max3' (y , z) zero)
max3' (succ x , succ y) (succ z) = succ (max3' (z , x) y)


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

module Cubical.HITs.Modulo.FinEquiv where

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

open import Cubical.Data.Fin
open import Cubical.Data.Nat
open import Cubical.Data.Nat.Order

open import Cubical.HITs.Modulo.Base

-- For positive `k`, every `Modulo k` can be reduced to its
-- residue modulo `k`, given by a value of type `Fin k`. This
-- forms an equivalence between `Fin k` and `Modulo k`.
module Reduction {k₀ : ℕ} where
  private
    k = suc k₀

  fembed : Fin k → Modulo k
  fembed = embed ∘ toℕ

  ResiduePath : ℕ → Type₀
  ResiduePath n =  Σ[ f ∈ Fin k ] fembed f ≡ embed n

  rbase : ∀ n (n<k : n < k) → ResiduePath n
  rbase n n<k = (n , n<k) , refl

  rstep : ∀ n → ResiduePath n → ResiduePath (k + n)
  rstep n (f , p) = f , p ∙ step n

  rstep≡
    : ∀ n (R : ResiduePath n)
    → PathP (λ i → fembed (fst R) ≡ step n i) (snd R) (snd (rstep n R))
  rstep≡ n (f , p) = λ i j → compPath-filler p (step n) i j

  residuePath : ∀ n → ResiduePath n
  residuePath = +induction k₀ ResiduePath rbase rstep

  lemma₁ : ∀ n → rstep n (residuePath n) ≡ residuePath (k + n)
  lemma₁ = sym ∘ +inductionStep k₀ ResiduePath rbase rstep

  residueStep₁
    : ∀ n →  fst (residuePath n) ≡ fst (residuePath (k + n))
  residueStep₁ = cong fst ∘ lemma₁

  residueStep₂
    : ∀ n → PathP (λ i → fembed (residueStep₁ n i) ≡ step n i)
              ((snd ∘ residuePath) n)
              ((snd ∘ residuePath) (k + n))
  residueStep₂ n i j
    = hfill (λ ii → λ
            { (i = i0) → snd (residuePath n) j
            ; (j = i0) → fembed (residueStep₁ n (i ∧ ii))
            ; (i = i1) → snd (lemma₁ n ii) j
            ; (j = i1) → step n i
            })
        (inS (rstep≡ n (residuePath n) i j))
        i1

  residue : Modulo k → Fin k
  residue (embed n) = fst (residuePath n)
  residue (step n i) = residueStep₁ n i

  sect : section residue fembed
  sect (r , r<k) = cong fst (+inductionBase k₀ ResiduePath rbase rstep r r<k)

  retr : retract residue fembed
  retr (embed n) = snd (residuePath n)
  retr (step n i) = residueStep₂ n i

  Modulo≡Fin : Modulo k ≡ Fin k
  Modulo≡Fin = isoToPath (iso residue fembed sect retr)

open Reduction using (fembed; residue; Modulo≡Fin) public


module Five where

open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

import Data.Nat as ℕ
import Data.Nat.Properties as ℕₚ
import Data.List as List
import Data.List.Properties as Listₚ
import Data.Product as Product

open List using (List; []; _∷_; _++_)
open ℕ using (ℕ; zero; suc; _+_)
open Product using (Σ; _,_)

-- Our language consists of constants and addition
data Expr : Set where
  const : ℕ → Expr
  plus : Expr → Expr → Expr

-- Straightforward semantics
eval-expr : Expr → ℕ
eval-expr (const n) = n
eval-expr (plus e1 e2) = eval-expr e1 + eval-expr e2

data Instr : Set where
  push : ℕ → Instr
  add : Instr

Prog = List Instr

Stack = List ℕ

run : Prog → Stack → Stack
run [] s = s
run (push n ∷ p) s = run p (n ∷ s)
run (add ∷ p) (a1 ∷ a2 ∷ s) = run p (a1 + a2 ∷ s)
run (add ∷ p) s = run p s

compile : Expr → Prog
compile (const n) = push n ∷ []
compile (plus e1 e2) = compile e1 ++ compile e2 ++ add ∷ []

-- Task 2. Prove that you get the expected result when you compile and run the program.
compile-correct-split : ∀ p q s → run (p ++ q) s ≡ run q (run p s)
compile-correct-split = {!!}

compile-correct-exist : ∀ e s → Σ ℕ (λ m → run (compile e) s ≡ m ∷ s)
compile-correct-exist = {!!}

compile-correct-gen : ∀ e s → run (compile e) s ≡ run (compile e) [] ++ s
compile-correct-gen = {!!}

compile-correct : ∀ e → run (compile e) [] ≡ eval-expr e ∷ []
compile-correct = {!!}


module Structure.Operator.IntegralDomain where

open import Functional
import      Lvl
open import Logic
open import Logic.Propositional
open import Logic.Predicate
open import Structure.Setoid
open import Structure.Operator.Properties
open import Structure.Operator.Ring
open import Type

-- Rng with no non-zero zero divisors.
record Domain {ℓ ℓₑ} {T : Type{ℓ}} ⦃ _ : Equiv{ℓₑ}(T) ⦄ (_+_  : T → T → T) (_⋅_  : T → T → T) ⦃ rng : Rng(_+_)(_⋅_) ⦄ : Stmt{ℓ Lvl.⊔ ℓₑ} where
  constructor intro
  open Rng(rng)
  field
    no-zero-divisors  : ∀{x y} → (x ⋅ y ≡ 𝟎) → ((x ≡ 𝟎) ∨ (y ≡ 𝟎))

  zero-zero-divisorₗ : ∀{x} → ZeroDivisorₗ(x) → (x ≡ 𝟎)
  zero-zero-divisorₗ {x} ([∃]-intro y ⦃ [∧]-intro y𝟎 xy𝟎 ⦄) = [∨]-elim id ([⊥]-elim ∘ y𝟎) (no-zero-divisors xy𝟎)

  zero-zero-divisorᵣ : ∀{x} → ZeroDivisorᵣ(x) → (x ≡ 𝟎)
  zero-zero-divisorᵣ {x} ([∃]-intro y ⦃ [∧]-intro y𝟎 xy𝟎 ⦄) = [∨]-elim ([⊥]-elim ∘ y𝟎) id (no-zero-divisors xy𝟎)

  zero-zero-divisor : ∀{x} → ZeroDivisor(x) → (x ≡ 𝟎)
  zero-zero-divisor {x} ([∃]-intro y ⦃ [∧]-intro y𝟎 ([∧]-intro xy𝟎 yx𝟎) ⦄) = [∨]-elim id ([⊥]-elim ∘ y𝟎) (no-zero-divisors xy𝟎)

-- Non-trivial commutative ring and domain.
record IntegralDomain {ℓ ℓₑ} {T : Type{ℓ}} ⦃ _ : Equiv{ℓₑ}(T) ⦄ (_+_  : T → T → T) (_⋅_  : T → T → T) : Stmt{ℓ Lvl.⊔ ℓₑ} where
  constructor intro
  field
    ⦃ ring ⦄              : Ring(_+_)(_⋅_)
    ⦃ domain ⦄            : Domain(_+_)(_⋅_)
    ⦃ [⋅]-commutativity ⦄ : Commutativity(_⋅_)
  open Ring  (ring)   public
  open Domain(domain) public

  field
    ⦃ distinct-identities ⦄ : DistinctIdentities

record IntegralDomainObject {ℓ ℓₑ} : Stmt{Lvl.𝐒(ℓ Lvl.⊔ ℓₑ)} where
  constructor intro
  field
    {T} : Type{ℓ}
    ⦃ equiv ⦄ : Equiv{ℓₑ}(T)
    _+_ : T → T → T
    _⋅_ : T → T → T
    ⦃ integralDomain ⦄ : IntegralDomain(_+_)(_⋅_)
  open IntegralDomain(integralDomain) public


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

open import Relation.Binary.Core

module Magma.Definitions
  {a ℓ} {A : Set a}   -- The underlying set
  (_≈_ : Rel A ℓ)     -- The underlying equality
  where

open import Algebra.Core
open import Data.Product

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

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

Alternative : Op₂ A → Set _
Alternative _∙_ = (Alternativeˡ _∙_ ) × ( Alternativeʳ _∙_)

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

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

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

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

Semimedial : Op₂ A → Set _
Semimedial _∙_ = (LeftSemimedial _∙_) × (RightSemimedial _∙_)


module #5 where

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

ind₌ : ∀{a b}{A : Set a} → (C : (x y : A) → (x ≡ y) → Set b) → ((x : A) → C x x refl) → {x y : A} → (p : x ≡ y) → C x y p
ind₌ C c {x}{y} p rewrite p = c y

transport : ∀ {i} {A : Set i}{P : A → Set i}{x y : A} → (p : x ≡ y) → (P x → P y)
transport {i} {A}{P} {x}{y} p = ind₌ D d p where
    D : (x y : A) → (p : x ≡ y) → Set i
    D x y p = P x → P y

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

record IsEquiv {i j}{A : Set i}{B : Set j}(to : A → B) : Set (i ⊔ j) where
  field
    from : B → A
    iso₁ : (x : A) → from (to x) ≡ x
    iso₂ : (y : B) → to (from y) ≡ y

{-
  Exercise 2.5. Prove that the functions (2.3.6) and (2.3.7) are inverse equivalences.
-}

lem2-3-6 : ∀ {i} {A B : Set i}{x y : A} → (p : x ≡ y) → (f : A → B) → (f x ≡ f y) → (transport p (f x) ≡ f y)
lem2-3-6 p f q rewrite p = refl

lem2-3-7 : ∀ {i} {A B : Set i}{x y : A} → (p : x ≡ y) → (f : A → B) → (transport p (f x) ≡ f y) → (f x ≡ f y)
lem2-3-7 p f q rewrite p = refl

lems-is-equiv : ∀ {i} {A B : Set i}{x y : A} → (p : x ≡ y) → (f : A → B) → IsEquiv (lem2-3-6 p f)
lems-is-equiv p f = record
  { from = lem2-3-7 p f
  ; iso₁ = λ x → {!!}
  ; iso₂ = λ y → {!!}
  }


module 4-the-natural-numbers where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; sym)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; step-≡; _∎)
open import Data.Nat using (ℕ; zero; suc; _+_; _*_; ⌊_/2⌋)

-- 4)
--sum-to-n : ℕ → ℕ
--sum-to-n n = sum (upTo (suc n))
open import Data.Nat.Properties using (*-comm; *-distribʳ-+; +-suc; +-comm; *-distribˡ-+)

1+⋯+n : ℕ → ℕ
1+⋯+n zero = zero
1+⋯+n (suc n) = suc n + 1+⋯+n n

n≡[n*2]/2 : ∀ (n : ℕ) → n ≡ ⌊ n * 2 /2⌋
n≡[n*2]/2 zero = refl
n≡[n*2]/2 (suc n) =
  begin
    suc n
  ≡⟨ cong suc (n≡[n*2]/2 n) ⟩
    suc ⌊  n * 2 /2⌋
  ≡⟨⟩
    1 + ⌊  n * 2 /2⌋
  ≡⟨⟩
    ⌊ 2 + n * 2 /2⌋
  ≡⟨⟩
    ⌊ suc n * 2 /2⌋
  ∎

data IsEven : ℕ → Set where
  even : (k : ℕ) → IsEven (k * 2)

rearrange-lemma : ∀ n → suc (suc n) * suc n ≡ suc n * 2 + suc n * n
rearrange-lemma n =
  begin
    suc (suc n) * suc n
  ≡⟨⟩
    suc (1 + n) * (1 + n)
  ≡⟨⟩
    (2 + n) * (1 + n)
  ≡⟨ *-distribʳ-+ (1 + n) 2 n ⟩
    2 * (1 + n) + n * (1 + n)
  ≡⟨ cong (2 * (1 + n) +_) (*-comm n (1 + n)) ⟩
    2 * (1 + n) + (1 + n) * n
  ≡⟨⟩
    2 * suc n + suc n * n
  ≡⟨ cong (_+ suc n * n) (*-comm 2 (suc n)) ⟩
    suc n * 2 + suc n * n
  ∎

even+even≡even : ∀ {m n : ℕ} → IsEven m → IsEven n → IsEven (m + n)
even+even≡even (even k) (even i) rewrite (sym (*-distribʳ-+ 2 k i)) = even (k + i)

[1+n]*n≡even : ∀ (n : ℕ) → IsEven (suc n * n)
[1+n]*n≡even zero = even 0
[1+n]*n≡even (suc n) rewrite rearrange-lemma n = even+even≡even (even (suc n)) ([1+n]*n≡even n)

even/2+even/2≡[even+even]/2 : ∀ {m n : ℕ} → IsEven m → IsEven n → ⌊ m /2⌋ + ⌊ n /2⌋ ≡ ⌊ m + n /2⌋
even/2+even/2≡[even+even]/2 (even k) (even i) =
  begin
    ⌊ k * 2 /2⌋ + ⌊ i * 2 /2⌋
  ≡⟨ cong (_+ ⌊ i * 2 /2⌋) (sym (n≡[n*2]/2 k)) ⟩
    k + ⌊ i * 2 /2⌋
  ≡⟨ cong (k +_) (sym (n≡[n*2]/2 i)) ⟩
    k + i
  ≡⟨ n≡[n*2]/2 (k + i) ⟩
    ⌊ (k + i) * 2 /2⌋
  ≡⟨ cong ⌊_/2⌋ (*-distribʳ-+ 2 k i) ⟩
    ⌊ k * 2 + i * 2 /2⌋
  ∎

gaussian-sum : ∀ (n : ℕ) → 1+⋯+n n ≡ ⌊ n * (n + 1) /2⌋
gaussian-sum zero = refl
gaussian-sum (suc n) =
  begin
    1+⋯+n (suc n)
  ≡⟨⟩
    suc n + 1+⋯+n n
  ≡⟨ cong (suc n +_) (gaussian-sum n)⟩
    suc n + ⌊ n * (n + 1) /2⌋
  ≡⟨ cong (_+ ⌊ n * (n + 1) /2⌋) (n≡[n*2]/2 (suc n)) ⟩
    ⌊ suc n * 2 /2⌋ + ⌊ n * (n + 1) /2⌋
  ≡⟨ cong (λ {term → ⌊ suc n * 2 /2⌋ + ⌊ n * term /2⌋}) (+-comm n 1) ⟩
    ⌊ suc n * 2 /2⌋ + ⌊ n * (1 + n) /2⌋
  ≡⟨⟩
    ⌊ suc n * 2 /2⌋ + ⌊ n * suc n /2⌋
  ≡⟨ cong (λ {term → ⌊ suc n * 2 /2⌋ + ⌊ term /2⌋}) (*-comm n (suc n)) ⟩
    ⌊ suc n * 2 /2⌋ + ⌊ suc n * n /2⌋
  ≡⟨ even/2+even/2≡[even+even]/2 (even (suc n)) ([1+n]*n≡even n) ⟩
    ⌊ suc n * 2 + suc n * n /2⌋
  ≡⟨ cong (⌊_/2⌋) (sym (*-distribˡ-+ (1 + n) 2 n)) ⟩
    ⌊ suc n * (2 + n) /2⌋
  ≡⟨ cong (λ {term → ⌊ suc n * term /2⌋}) (+-comm 2 n) ⟩
    ⌊ suc n * (n + 2) /2⌋
  ≡⟨ cong (λ {term → ⌊ suc n * term /2⌋}) (+-suc n 1) ⟩
    ⌊ suc n * (suc n + 1) /2⌋
  ∎


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

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

open import Bound.Total A
open import Bound.Total.Order _≤_
open import Data.List
open import Data.Product
open import Data.Sum
open import SBList _≤_
open import Size
open import SOList.Total _≤_

deal : {ι : Size}{b t : Bound}{x : A} → LeB b (val x) → LeB (val x) t → SBList {ι} b t → SBList {ι} b (val x) × SBList {ι} (val x) t
deal b≤x x≤t (nil b≤t) = (nil b≤x , nil x≤t)
deal {x = x} b≤x x≤t (cons y b≤y y≤t ys)
    with tot≤ x y | deal b≤x x≤t ys
... | inj₁ x≤y | (us , vs) = (us , cons y (lexy x≤y) y≤t vs)
... | inj₂ y≤x | (us , vs) = (cons y b≤y (lexy y≤x) us , vs)

quickSort : {ι : Size}{b t : Bound} → SBList {ι} b t → SOList b t
quickSort (nil b≤t) = onil b≤t
quickSort (cons x b≤x x≤t xs)
    with deal b≤x x≤t xs
... | (ys , zs) = ocons x (quickSort ys) (quickSort zs)