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

open import Categories.Category

module Categories.Category.Duality {o ℓ e} (C : Category o ℓ e) where

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

open import Categories.Category.Cartesian
open import Categories.Category.Cocartesian
open import Categories.Category.Complete
open import Categories.Category.Complete.Finitely
open import Categories.Category.Cocomplete
open import Categories.Category.Cocomplete.Finitely

open import Categories.Object.Duality
open import Categories.Diagram.Duality
open import Categories.Functor

private
  module C = Category C
  open C

coCartesian⇒Cocartesian : Cartesian C.op → Cocartesian C
coCartesian⇒Cocartesian Car = record
  { initial     = op⊤⇒⊥ C terminal
  ; coproducts  = record
    { coproduct = coProduct⇒Coproduct C product
    }
  }
  where open Cartesian Car

Cocartesian⇒coCartesian : Cocartesian C → Cartesian C.op
Cocartesian⇒coCartesian Co = record
  { terminal  = ⊥⇒op⊤ C initial
  ; products  = record
    { product = Coproduct⇒coProduct C coproduct
    }
  }
  where open Cocartesian Co

coComplete⇒Cocomplete : ∀ {o′ ℓ′ e′} → Complete o′ ℓ′ e′ C.op → Cocomplete o′ ℓ′ e′ C
coComplete⇒Cocomplete Com F = coLimit⇒Colimit C (Com F.op)
  where module F = Functor F

Cocomplete⇒coComplete : ∀ {o′ ℓ′ e′} → Cocomplete o′ ℓ′ e′ C → Complete o′ ℓ′ e′ C.op
Cocomplete⇒coComplete Coc F = Colimit⇒coLimit C (Coc F.op)
  where module F = Functor F

coFinitelyComplete⇒FinitelyCocomplete : FinitelyComplete C.op → FinitelyCocomplete C
coFinitelyComplete⇒FinitelyCocomplete FC = record
  { cocartesian = coCartesian⇒Cocartesian cartesian
  ; coequalizer = λ f g → coEqualizer⇒Coequalizer C (equalizer f g)
  }
  where open FinitelyComplete FC

FinitelyCocomplete⇒coFinitelyComplete : FinitelyCocomplete C → FinitelyComplete C.op
FinitelyCocomplete⇒coFinitelyComplete FC = record
  { cartesian = Cocartesian⇒coCartesian cocartesian
  ; equalizer = λ f g → Coequalizer⇒coEqualizer C (coequalizer f g)
  }
  where open FinitelyCocomplete FC

module DualityConversionProperties where

  private
    op-involutive : Category.op C.op ≡ C
    op-involutive = refl

    coCartesian⇔Cocartesian : ∀(coCartesian : Cartesian C.op)
                            → Cocartesian⇒coCartesian (coCartesian⇒Cocartesian coCartesian)
                              ≡ coCartesian
    coCartesian⇔Cocartesian _ = refl

    coFinitelyComplete⇔FinitelyCocomplete : ∀(coFinComplete : FinitelyComplete C.op) →
      FinitelyCocomplete⇒coFinitelyComplete
        (coFinitelyComplete⇒FinitelyCocomplete coFinComplete) ≡ coFinComplete
    coFinitelyComplete⇔FinitelyCocomplete _ = refl


module monad where

open import eq

record Monad (M : Set → Set) : Set₁ where
  field
    return : ∀{A : Set} → A → M A
    bind : ∀{A B : Set} → M A → (A → M B) → M B

    monad-left-id : ∀{A B : Set}{a : A}{f : A → M B}
      → bind (return a) f ≡ f a

    monad-right-id : ∀{A : Set}{c : M A}
      → bind c return ≡ c

    monad-assoc : ∀{A B C : Set}{c : M A}{f : A → M B}{g : B → M C}
      → bind (bind c f) g ≡ bind c (λ a → bind (f a) g)


------------------------------------------------------------------------
-- Some Vec-related properties
------------------------------------------------------------------------

module Data.Vec.Properties where

open import Algebra
open import Data.Vec
open import Data.Nat
import Data.Nat.Properties as Nat
open import Data.Fin using (Fin; zero; suc)
open import Data.Function
open import Relation.Binary

module UsingVectorEquality (S : Setoid) where

  private module SS = Setoid S
  open SS using () renaming (carrier to A)
  import Data.Vec.Equality as VecEq
  open VecEq.Equality S

  replicate-lemma : ∀ {m} n x (xs : Vec A m) →
                    replicate {n = n}     x ++ (x ∷ xs) ≈
                    replicate {n = 1 + n} x ++      xs
  replicate-lemma zero    x xs = refl (x ∷ xs)
  replicate-lemma (suc n) x xs = SS.refl ∷-cong replicate-lemma n x xs

  xs++[]=xs : ∀ {n} (xs : Vec A n) → xs ++ [] ≈ xs
  xs++[]=xs []       = []-cong
  xs++[]=xs (x ∷ xs) = SS.refl ∷-cong xs++[]=xs xs

  map-++-commute : ∀ {B m n} (f : B → A) (xs : Vec B m) {ys : Vec B n} →
                   map f (xs ++ ys) ≈ map f xs ++ map f ys
  map-++-commute f []       = refl _
  map-++-commute f (x ∷ xs) = SS.refl ∷-cong map-++-commute f xs

open import Relation.Binary.PropositionalEquality as PropEq
open import Relation.Binary.HeterogeneousEquality as HetEq

-- lookup is natural.

lookup-natural : ∀ {A B n} (f : A → B) (i : Fin n) →
                 lookup i ∘ map f ≗ f ∘ lookup i
lookup-natural f zero    (x ∷ xs) = refl
lookup-natural f (suc i) (x ∷ xs) = lookup-natural f i xs

-- map is a congruence.

map-cong : ∀ {A B n} {f g : A → B} →
           f ≗ g → _≗_ {Vec A n} (map f) (map g)
map-cong f≗g []       = refl
map-cong f≗g (x ∷ xs) = PropEq.cong₂ _∷_ (f≗g x) (map-cong f≗g xs)

-- map is functorial.

map-id : ∀ {A n} → _≗_ {Vec A n} (map id) id
map-id []       = refl
map-id (x ∷ xs) = PropEq.cong (_∷_ x) (map-id xs)

map-∘ : ∀ {A B C n} (f : B → C) (g : A → B) →
        _≗_ {Vec A n} (map (f ∘ g)) (map f ∘ map g)
map-∘ f g []       = refl
map-∘ f g (x ∷ xs) = PropEq.cong (_∷_ (f (g x))) (map-∘ f g xs)

-- sum commutes with _++_.

sum-++-commute : ∀ {m n} (xs : Vec ℕ m) {ys : Vec ℕ n} →
                 sum (xs ++ ys) ≡ sum xs + sum ys
sum-++-commute []            = refl
sum-++-commute (x ∷ xs) {ys} = begin
  x + sum (xs ++ ys)
    ≡⟨ PropEq.cong (λ p → x + p) (sum-++-commute xs) ⟩
  x + (sum xs + sum ys)
    ≡⟨ PropEq.sym (+-assoc x (sum xs) (sum ys)) ⟩
  sum (x ∷ xs) + sum ys
    ∎
  where
  open ≡-Reasoning
  open CommutativeSemiring Nat.commutativeSemiring hiding (_+_; sym)

-- foldr is a congruence.

foldr-cong : ∀ {A} {B₁} {f₁ : ∀ {n} → A → B₁ n → B₁ (suc n)} {e₁}
                   {B₂} {f₂ : ∀ {n} → A → B₂ n → B₂ (suc n)} {e₂} →
             (∀ {n x} {y₁ : B₁ n} {y₂ : B₂ n} →
                y₁ ≅ y₂ → f₁ x y₁ ≅ f₂ x y₂) →
             e₁ ≅ e₂ →
             ∀ {n} (xs : Vec A n) →
             foldr B₁ f₁ e₁ xs ≅ foldr B₂ f₂ e₂ xs
foldr-cong           _     e₁=e₂ []       = e₁=e₂
foldr-cong {B₁ = B₁} f₁=f₂ e₁=e₂ (x ∷ xs) =
  f₁=f₂ (foldr-cong {B₁ = B₁} f₁=f₂ e₁=e₂ xs)

-- foldl is a congruence.

foldl-cong : ∀ {A} {B₁} {f₁ : ∀ {n} → B₁ n → A → B₁ (suc n)} {e₁}
                   {B₂} {f₂ : ∀ {n} → B₂ n → A → B₂ (suc n)} {e₂} →
             (∀ {n x} {y₁ : B₁ n} {y₂ : B₂ n} →
                y₁ ≅ y₂ → f₁ y₁ x ≅ f₂ y₂ x) →
             e₁ ≅ e₂ →
             ∀ {n} (xs : Vec A n) →
             foldl B₁ f₁ e₁ xs ≅ foldl B₂ f₂ e₂ xs
foldl-cong           _     e₁=e₂ []       = e₁=e₂
foldl-cong {B₁ = B₁} f₁=f₂ e₁=e₂ (x ∷ xs) =
  foldl-cong {B₁ = B₁ ∘₀ suc} f₁=f₂ (f₁=f₂ e₁=e₂) xs

-- The (uniqueness part of the) universality property for foldr.

foldr-universal : ∀ {A} (B : ℕ → Set)
                  (f : ∀ {n} → A → B n → B (suc n)) {e}
                  (h : ∀ {n} → Vec A n → B n) →
                  h [] ≡ e →
                  (∀ {n} x → h ∘ _∷_ x ≗ f {n} x ∘ h) →
                  ∀ {n} → h ≗ foldr B {n} f e
foldr-universal B f     h base step []       = base
foldr-universal B f {e} h base step (x ∷ xs) = begin
  h (x ∷ xs)
    ≡⟨ step x xs ⟩
  f x (h xs)
    ≡⟨ PropEq.cong (f x) (foldr-universal B f h base step xs) ⟩
  f x (foldr B f e xs)
    ∎
  where open ≡-Reasoning

-- A fusion law for foldr.

foldr-fusion : ∀ {A} {B : ℕ → Set} {f : ∀ {n} → A → B n → B (suc n)} e
                     {C : ℕ → Set} {g : ∀ {n} → A → C n → C (suc n)}
               (h : ∀ {n} → B n → C n) →
               (∀ {n} x → h ∘ f {n} x ≗ g x ∘ h) →
               ∀ {n} → h ∘ foldr B {n} f e ≗ foldr C g (h e)
foldr-fusion {B = B} {f} e {C} h fuse =
  foldr-universal C _ _ refl (λ x xs → fuse x (foldr B f e xs))

-- The identity function is a fold.

idIsFold : ∀ {A n} → id ≗ foldr (Vec A) {n} _∷_ []
idIsFold = foldr-universal _ _ id refl (λ _ _ → refl)


{-# OPTIONS --sized-types #-}
module SNat.Properties where

open import Size
open import SNat
open import SNat.Order
open import SNat.Order.Properties
open import SNat.Sum

lemma-≅subtyping : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≅ n → m ≅ subtyping n
lemma-≅subtyping z≅z = z≅z
lemma-≅subtyping (s≅s m≅n) = s≅s (lemma-≅subtyping m≅n)

lemma-subtyping≅ : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≅ n → subtyping m ≅ n
lemma-subtyping≅ z≅z = z≅z
lemma-subtyping≅ (s≅s m≅n) = s≅s (lemma-subtyping≅ m≅n)

lemma-subtyping≅subtyping : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≅ n → subtyping m ≅ subtyping n
lemma-subtyping≅subtyping z≅z = z≅z
lemma-subtyping≅subtyping (s≅s m≅n) = s≅s (lemma-subtyping≅subtyping m≅n)

lemma-≤′subtyping : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≤′ n → m ≤′ subtyping n
lemma-≤′subtyping (≤′-eq m≅n) = ≤′-eq (lemma-≅subtyping m≅n)
lemma-≤′subtyping (≤′-step m≤′n) = ≤′-step (lemma-≤′subtyping m≤′n)

lemma-subtyping≤′ : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≤′ n → subtyping m ≤′ n
lemma-subtyping≤′ (≤′-eq m≅n) = ≤′-eq (lemma-subtyping≅ m≅n)
lemma-subtyping≤′ (≤′-step m≤′n) = ≤′-step (lemma-subtyping≤′ m≤′n)

lemma-subtyping≤subtyping : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≤ n → subtyping m ≤ subtyping n
lemma-subtyping≤subtyping (z≤n n) = z≤n (subtyping n)
lemma-subtyping≤subtyping (s≤s m≤n) = s≤s (lemma-subtyping≤subtyping m≤n)

lemma-subtyping≤′subtyping : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≤′ n → subtyping m ≤′ subtyping n
lemma-subtyping≤′subtyping m≤′n = lemma-≤-≤′ (lemma-subtyping≤subtyping (lemma-≤′-≤ m≤′n))

--

lemma-≅-/2 : {ι ι' : Size}{m : SNat {ι}}{n : SNat {ι'}} → m ≅ n → m /2 ≅ n /2
lemma-≅-/2 z≅z = z≅z
lemma-≅-/2 (s≅s z≅z) = z≅z
lemma-≅-/2 (s≅s (s≅s m≅n)) = s≅s (lemma-subtyping≅subtyping  (lemma-≅-/2 m≅n))

lemma-n/2≤′sn/2 : {ι : Size}(n : SNat {ι}) → n /2 ≤′ (succ n) /2
lemma-n/2≤′sn/2 zero = lemma-z≤′n zero
lemma-n/2≤′sn/2 (succ zero) = lemma-z≤′n (succ zero)
lemma-n/2≤′sn/2 (succ (succ n)) = lemma-s≤′s (lemma-subtyping≤′subtyping (lemma-n/2≤′sn/2 n))

--

lemma-m≤′m+n : (m n : SNat) → m ≤′ (m + n)
lemma-m≤′m+n zero n = lemma-z≤′n n
lemma-m≤′m+n (succ m) n = lemma-s≤′s (lemma-m≤′m+n m n)

lemma-2m≤′m+n+m+n : (m n : SNat) → (m + m) ≤′ ((m + n) + (m + n))
lemma-2m≤′m+n+m+n m n rewrite +-assoc-left (m + n) m n | +-comm (m + n) m | +-assoc-left m m n | +-assoc-right (m + m) n n = lemma-m≤′m+n (m + m) (n + n)

lemma-2m≅2n : {m n : SNat} → m ≅ n →  (m + m) ≅ (n + n)
lemma-2m≅2n z≅z = z≅z
lemma-2m≅2n (s≅s {m = m} {n = n} m≅n) rewrite +-assoc-succ m m | +-assoc-succ n n = s≅s (s≅s (lemma-2m≅2n m≅n))

lemma-2m≤′2n : {m n : SNat} → m ≤′ n →  (m + m) ≤′ (n + n)
lemma-2m≤′2n (≤′-eq m≅n) = ≤′-eq (lemma-2m≅2n m≅n)
lemma-2m≤′2n (≤′-step {n = n} m≤′n) rewrite +-assoc-succ n n = ≤′-step (≤′-step (lemma-2m≤′2n m≤′n))

lemma-n≤′2n : (n : SNat) → n ≤′ (n + n)
lemma-n≤′2n n = lemma-m≤′m+n n n

+-right-monotony-≅ : {m n : SNat}(k : SNat) → m ≅ n → (m + k) ≅ (n + k)
+-right-monotony-≅ k z≅z = refl≅
+-right-monotony-≅ k (s≅s m≅n) = s≅s (+-right-monotony-≅ k m≅n)

+-right-monotony-≤′ : {m n : SNat}(k : SNat) → m ≤′ n → (m + k) ≤′ (n + k)
+-right-monotony-≤′ k (≤′-eq m≅n) = ≤′-eq (+-right-monotony-≅ k m≅n)
+-right-monotony-≤′ k (≤′-step m≤′n) = ≤′-step (+-right-monotony-≤′ k m≤′n)

+-left-monotony-≤′ : {m n : SNat}(k : SNat) → m ≤′ n → (k + m) ≤′ (k + n)
+-left-monotony-≤′ {m} {n} k m≤′n rewrite +-comm k m | +-comm k n = +-right-monotony-≤′ k m≤′n

lemma-4m≤′n+m+n+m : {m n : SNat} → m ≤′ n → ((m + m) + (m + m)) ≤′ ((n + m) + (n + m))
lemma-4m≤′n+m+n+m {m} {n} m≤′n rewrite +-comm n m = lemma-2m≤′2n (+-left-monotony-≤′ m m≤′n)

lemma-n≤′2n/2 : (n : SNat) → n ≤′ (n + n) /2
lemma-n≤′2n/2 zero = ≤′-eq z≅z
lemma-n≤′2n/2 (succ n) rewrite +-assoc-succ (succ n) n = lemma-s≤′s (lemma-≤′subtyping (lemma-n≤′2n/2 n))

lemma-2n/2≤′n : (n : SNat) → (n + n) /2 ≤′ n
lemma-2n/2≤′n zero = refl≤′
lemma-2n/2≤′n (succ n) rewrite +-assoc-succ (succ n) n = lemma-s≤′s (lemma-subtyping≤′ (lemma-2n/2≤′n n))

lemma-n+1≤′2n+2/2 : (n : SNat) → succ n ≤′ (succ (succ (n + n))) /2
lemma-n+1≤′2n+2/2 zero = refl≤′
lemma-n+1≤′2n+2/2 (succ n) rewrite +-assoc-succ (succ n) n = lemma-s≤′s (lemma-≤′subtyping (lemma-s≤′s (lemma-≤′subtyping (lemma-n≤′2n/2 n))))


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

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

module Cubical.Algebra.Semigroup.Construct.Right {ℓ} (Aˢ : hSet ℓ) where

open import Cubical.Foundations.Prelude
open import Cubical.Algebra.Semigroup

import Cubical.Algebra.Magma.Construct.Right Aˢ as RMagma
open RMagma public hiding (Right-isMagma; RightMagma)

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

▸-assoc : Associative _▸_
▸-assoc _ _ _ = refl

Right-isSemigroup : IsSemigroup A _▸_
Right-isSemigroup = record
  { isMagma = RMagma.Right-isMagma
  ; assoc   = ▸-assoc
  }

RightSemigroup : Semigroup ℓ
RightSemigroup = record { isSemigroup = Right-isSemigroup }


module Formalization.LambdaCalculus.Terms.Combinators where

import      Lvl
open import Data
open import Formalization.LambdaCalculus
open import Numeral.Natural
open import Numeral.Finite
open import Syntax.Number
open import Type

module _ where
  open ExplicitLambdaSyntax

  I = 𝜆 0 0                               -- Identity
  K = 𝜆 0 (𝜆 1 0)                         -- Constant / Left of pair
  𝈲 = 𝜆 0 (𝜆 1 1)                         -- Right of pair
  S = 𝜆 0 (𝜆 1 (𝜆 2 ((0 ← 2) ← (1 ← 2)))) -- General composition
  B = 𝜆 0 (𝜆 1 (𝜆 2 (0 ← (1 ← 2))))       -- Composition
  C = 𝜆 0 (𝜆 1 (𝜆 2 ((0 ← 2) ← 1)))
  W = 𝜆 0 (𝜆 1 ((0 ← 1) ← 1))
  U = 𝜆 0 (0 ← 0)                         -- Self application
  ω = U
  Ω = ω ← ω
  Y = 𝜆 0 ((𝜆 1 (0 ← (1 ← 1))) ← (𝜆 1 (0 ← (1 ← 1))))

-- TODO: Move everything below

open import Formalization.LambdaCalculus.SyntaxTransformation

module Boolean where
  open ExplicitLambdaSyntax

  𝑇 = K
  𝐹 = 𝈲
  If = 𝜆 0 (𝜆 1 (𝜆 2 (0 ← 1 ← 2)))

module Tuple where
  open Boolean
  open ExplicitLambdaSyntax

  Pair = 𝜆 0 (𝜆 1 (𝜆 2 (2 ← 0 ← 1)))
  Projₗ = 𝜆 0 (0 ← var-𝐒 K)
  Projᵣ = 𝜆 0 (0 ← var-𝐒 𝈲)

-- Natural numbers (Church numerals).
module Natural where
  open ExplicitLambdaSyntax

  λ𝟎 = 𝈲
  λ𝐒 = 𝜆 0 (𝜆 1 (𝜆 2 (1 ← (0 ← 1 ← 2))))

  ℕrepr₂ : ℕ → Term(2)
  ℕrepr₂ 𝟎      = 1
  ℕrepr₂ (𝐒(n)) = 0 ← ℕrepr₂ n

  ℕrepr = \n → 𝜆 0 (𝜆 1 (ℕrepr₂ n))

  -- TODO: Prove (λ𝐒 ←ⁿ λ𝟎) β-reduces to (ℕrepr n)

module β-proofs where
  open import Formalization.LambdaCalculus.Semantics.Reduction
  open import Logic.Propositional hiding (_←_)
  open import Logic.Predicate
  open import ReductionSystem
  open import Relator.ReflexiveTransitiveClosure renaming (trans to _🝖_)
  open import Structure.Relator
  open import Structure.Relator.Properties
  open import Type.Dependent

  open ExplicitLambdaSyntax

  private variable n : ℕ
  private variable f g h x y z : Term(n)

  Ω-self-reduces : Ω β⇴ Ω
  Ω-self-reduces = β

  Ω-no-normal-form : ¬ NormalForm(_β⇴_)(Ω)
  Ω-no-normal-form (intro p) = p(Ω-self-reduces)

  -- Also called: Church-Rosser's theorem.
  -- TODO: Seems like the proof can be a bit complicated?
  postulate β-star-confluence : ∀{d} → Confluence(_β⇴*_ {d})

  I-reduction : ((I ← x) β⇴ x)
  I-reduction = β

  K-reduction : ((K ← x ← y) β⇴* x)
  K-reduction {x}{y} = super(cong-applyₗ β) 🝖 super β -- 🝖 substitute₂ₗ(_β⇴*_) (symmetry(_≡_) (substitute-var-𝐒 {0}{x}{y})) refl

  𝈲-reduction : ((𝈲 ← x ← y) β⇴* y)
  𝈲-reduction {x}{y} = super(cong-applyₗ β) 🝖 super β

  B-reduction : ((B ← f ← g ← x) β⇴* (f ← (g ← x)))
  B-reduction = super(cong-applyₗ(cong-applyₗ β)) 🝖 super(cong-applyₗ β) 🝖 super β

  C-reduction : ((C ← f ← g ← x) β⇴* ((f ← x) ← g))
  C-reduction = super(cong-applyₗ(cong-applyₗ β)) 🝖 super(cong-applyₗ β) 🝖 super β

  S-reduction : ((S ← f ← g ← x) β⇴* ((f ← x) ← (g ← x)))
  S-reduction = super(cong-applyₗ(cong-applyₗ β)) 🝖 super(cong-applyₗ β) 🝖 super β

  Y-reduction : ∀{f} → ((Y ← f) β⥈* (f ← (Y ← f)))
  Y-reduction = super([∨]-introᵣ β) 🝖 super([∨]-introᵣ β) 🝖 super([∨]-introₗ(cong-applyᵣ β))

  module _ where
    open Boolean

    If-𝑇-reduction : ((If ← 𝑇 ← x ← y) β⇴* x)
    If-𝑇-reduction = super(cong-applyₗ(cong-applyₗ β)) 🝖 super(cong-applyₗ β) 🝖 super β 🝖 K-reduction

    If-𝐹-reduction : ((If ← 𝐹 ← x ← y) β⇴* y)
    If-𝐹-reduction = super(cong-applyₗ(cong-applyₗ β)) 🝖 super(cong-applyₗ β) 🝖 super β 🝖 𝈲-reduction

  module _ where
    open Tuple

    Pair-projₗ-reduction : (Projₗ ← (Pair ← x ← y)) β⇴* x
    Pair-projₗ-reduction = super β 🝖 super(cong-applyₗ(cong-applyₗ β)) 🝖 super(cong-applyₗ β) 🝖 super β 🝖 super(cong-applyₗ β) 🝖 super β

    Pair-projᵣ-reduction : (Projᵣ ← (Pair ← x ← y)) β⇴* y
    Pair-projᵣ-reduction = super β 🝖 super(cong-applyₗ(cong-applyₗ β)) 🝖 super(cong-applyₗ β) 🝖 super β 🝖 super(cong-applyₗ β) 🝖 super β

  module _ where
    open import Function.Iteration

    open Natural

    {-
    -- λ𝟎 β⇴* ℕrepr 𝟎
    λ𝐒-of-ℕrepr : (λ𝐒 ← ℕrepr(n)) β⇴* ℕrepr(𝐒(n))
    λ𝐒-of-ℕrepr = super {!cong-applyₗ ?!}

    ℕrepr-correctness : (((λ𝐒 ←_) ^ n) λ𝟎) β⇴* (ℕrepr n)
    ℕrepr-correctness {𝟎} = refl
    ℕrepr-correctness {𝐒 n} = super {!!} 🝖 super {!ℕrepr-correctness {n}!}
    -}


module Numeral.Sign where

import      Lvl
open import Type

-- The set of plus or minus sign
data +|− : Type{Lvl.𝟎} where
  ➕ : (+|−)
  ➖ : (+|−)

−|+ = +|−

elim₂ : ∀{ℓ}{P : (+|−) → Type{ℓ}} → P(➖) → P(➕) → ((s : (+|−)) → P(s))
elim₂ neg pos ➖ = neg
elim₂ neg pos ➕ = pos

-- The set of signs: plus, minus and neutral
data +|0|− : Type{Lvl.𝟎} where
  ➕ : (+|0|−)
  𝟎 : (+|0|−)
  ➖ : (+|0|−)

−|0|+ = +|0|−

elim₃ : ∀{ℓ}{P : (+|0|−) → Type{ℓ}} → P(➖) → P(𝟎) → P(➕) → ((s : (+|0|−)) → P(s))
elim₃ neg zero pos ➖ = neg
elim₃ neg zero pos 𝟎 = zero
elim₃ neg zero pos ➕ = pos

zeroable : (+|−) → (+|0|−)
zeroable (➕) = (➕)
zeroable (➖) = (➖)


{-# OPTIONS --cubical-compatible #-}

open import Agda.Builtin.Nat
open import Agda.Builtin.Equality

data Fin : Nat → Set where
  zero : {n : Nat} → Fin (suc n)
  suc  : {n : Nat} (i : Fin n) → Fin (suc n)

-- From Data.Fin.Properties in the standard library (2016-12-30).
suc-injective : ∀ {o} {m n : Fin o} → Fin.suc m ≡ suc n → m ≡ n
suc-injective refl = refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Induction over _<_ for ℕᵇ.
------------------------------------------------------------------------

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

module Data.Nat.Binary.Induction where

open import Data.Nat.Binary.Base
open import Data.Nat.Binary.Properties
open import Data.Nat.Base as ℕ using (ℕ)
import Data.Nat.Induction as ℕ
open import Induction.WellFounded

------------------------------------------------------------------------
-- _<_ is wellFounded

<-wellFounded : WellFounded _<_
<-wellFounded x = Subrelation.accessible <⇒<ℕ toℕ[x]-acc
  where
  toℕ[x]-acc = InverseImage.accessible toℕ (ℕ.<-wellFounded (toℕ x))


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

record Σ (A : Set) (B : A → Set) : Set where
  constructor _,_
  field
    proj₁ : A
    proj₂ : B proj₁

open Σ

postulate
  I  : Set
  U  : I → Set
  El : ∀ {i} → U i → Set
  Ctxt : Set
  Env  : Ctxt → Set

Type : Ctxt → Set
Type Γ = Σ I λ i → Env Γ → U i

Value : (Γ : Ctxt) → Type Γ → Set
Value Γ σ = (γ : Env Γ) → El (proj₂ σ γ)

_/id : ∀ {Γ} → Type Γ → Type Γ
(i , σ) /id = i , σ

data [Type] : Set where
  [_] : ∀ {Γ} → Type Γ → [Type]

_≅-Type_ : ∀ {Γ} (σ₁ σ₂ : Type Γ) → Set
σ₁ ≅-Type σ₂ = [ σ₁ ] ≡ [ σ₂ ]

data [Value] : Set where
  [_] : ∀ {Γ σ} → Value Γ σ → [Value]

_≅-Value_ : ∀ {Γ σ} (v₁ v₂ : Value Γ σ) → Set
v₁ ≅-Value v₂ = [Value].[ v₁ ] ≡ [ v₂ ]

Foo : ∀ {Γ} {σ₁ σ₂ : Type Γ} {v : Value Γ (σ₁ /id)} →
      σ₁ ≅-Type σ₂ → v ≅-Value v → Set₁
Foo refl refl = Set


module Type.Dependent where

import      Lvl
open import Type

private
  module Module where
    -- Dependent product type (pi-type).
    -- Also called: Dependent function type.
    -- The right-hand side's type is a function type that uses the left-hand side's type as its "domain".
    -- And then the type of the resulting function of the two types depends on the argument.
    record Π {ℓ₁ ℓ₂} (A : Type{ℓ₁}) (B : A → Type{ℓ₂}) : Type{ℓ₁ Lvl.⊔ ℓ₂} where
      constructor intro
      field
        apply : (a : A) → B(a)

    -- Dependent sum type (sigma-type).
    -- Also called: Dependent pair type.
    -- The right-hand side's type is a function type that uses the left-hand side's type as its "domain".
    -- And then the type of the resulting pair depends on the left-hand side.
    record Σ {ℓ₁ ℓ₂} (A : Type{ℓ₁}) (B : A → Type{ℓ₂}) : Type{ℓ₁ Lvl.⊔ ℓ₂} where
      constructor intro
      field
        left  : A
        right : B(left)

ℰ : ∀{ℓ₁ ℓ₂}{A : Type{ℓ₁}} → (A → Type{ℓ₂}) → Type{ℓ₁ Lvl.⊔ ℓ₂}
ℰ {A = A} B = Module.Σ A B
module ℰ where
  pattern intro {left} right = Module.intro left right

open Module public
{-# BUILTIN SIGMA Σ #-}


-- Andreas, 2016-12-15, issue #2341
-- `with` needs to abstract also in sort of target type.

-- {-# OPTIONS -v tc.with:100 #-}

open import Agda.Primitive

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

{-# BUILTIN EQUALITY _≡_ #-}

postulate
  equalLevel : (x y : Level) → x ≡ y

id : ∀ {a} {A : Set a} → A → A
id x = x

Works : ∀ β α → Set α → Set β
Works β α with equalLevel α β
Works β .β | refl = id

Coerce : ∀ β α → Set α → Set β
Coerce β α rewrite equalLevel α β = id

-- Should succeed

{-
Set α →{1+β⊔α} Set β
added with function .Issue2341.rewrite-42 of type
  (β α w : Level) → w ≡ β → Set w → Set β

  (β α : Level) → (w : Level) →{1+β⊔α} w ≡ β →{1+β⊔α} Set w →{1+β⊔α} Set β

  raw with func. type = El {_getSort = Inf, unEl =
Pi ru(El {_getSort = Type (Max []), unEl = Def Agda.Primitive.Level []}) (Abs "\946" El {_getSort = Inf, unEl =
Pi ru(El {_getSort = Type (Max []), unEl = Def Agda.Primitive.Level []}) (Abs "\945"
  El {_getSort = Type (Max [Plus 1 (UnreducedLevel (Var 0 [])),Plus 1 (UnreducedLevel (Var 1 []))]), unEl =
Pi ru(El {_getSort = Type (Max []), unEl = Def Agda.Primitive.Level []}) (Abs "w"
  El {_getSort = Type (Max [Plus 1 (UnreducedLevel (Var 1 [])),Plus 1 (UnreducedLevel (Var 2 []))]), unEl =
Pi ru(El {_getSort = Type (Max []), unEl = Def Issue2341._≡_ [Apply ru{Level (Max [])},Apply ru{Def Agda.Primitive.Level []},Apply ru(Var 0 []),Apply ru(Var 2 [])]}) (NoAbs "w"
  El {_getSort = Type (Max [Plus 1 (UnreducedLevel (Var 1 [])),Plus 1 (UnreducedLevel (Var 2 []))]), unEl =
Pi ru(El {_getSort = Type (Max [Plus 1 (UnreducedLevel (Var 0 []))]), unEl = Sort (Type (Max [Plus 0 (UnreducedLevel (Var 0 []))]))}) (NoAbs "_"
  El {_getSort = Type (Max [Plus 1 (UnreducedLevel (Var 2 []))]), unEl =
Sort (Type (Max [Plus 0 (UnreducedLevel (Var 2 []))]))})})})})})}
-}


open import Type

module Relator.ReflexiveTransitiveClosure {ℓ₁ ℓ₂} {T : Type{ℓ₁}} (_▫_ : T → T → Type{ℓ₂}) where

open import Graph.Walk
open import Graph.Walk.Proofs
import      Lvl
open import Logic
open import Logic.Propositional
import      Structure.Relator.Names as Names
open import Structure.Relator.Properties
open import Syntax.Function

-- Reflexive closure of a relation.
-- Constructs a reflexive relation from an existing relation.
-- Sometimes also notated ((_▫_) ∪ (_▫⁰_)) for a relation (_▫_).
data ReflexiveClosure : T → T → Type{ℓ₁ Lvl.⊔ ℓ₂} where
  super : Names.Subrelation(_▫_)(ReflexiveClosure)
  refl  : Names.Reflexivity(ReflexiveClosure)

-- Symmetric closure of a relation.
-- Constructs a symmetric relation from an existing relation.
-- Sometimes also notated (_▫⁻¹_) or (Converse(_▫_) ∪ (_▫_)) for a relation (_▫_).
SymmetricClosure : T → T → Type{ℓ₂}
SymmetricClosure a b = (b ▫ a) ∨ (a ▫ b)

-- Reflexive-transitive closure of a relation.
-- Constructs a reflexive and transitive relation from an existing relation.
-- Sometimes also notated (_▫*_) for a relation (_▫_).
data ReflexiveTransitiveClosure : T → T → Type{ℓ₁ Lvl.⊔ ℓ₂} where
  super : Names.Subrelation(_▫_)(ReflexiveTransitiveClosure)
  refl  : Names.Reflexivity(ReflexiveTransitiveClosure)
  trans : Names.Transitivity(ReflexiveTransitiveClosure)
infixl 1000 trans

-- Transitive closure of a relation.
-- Constructs a transitive relation from an existing relation.
-- Sometimes also notated (_▫⁺_) for a relation (_▫_).
data TransitiveClosure : T → T → Type{ℓ₁ Lvl.⊔ ℓ₂} where
  super : Names.Subrelation(_▫_)(TransitiveClosure)
  trans : Names.Transitivity(TransitiveClosure)

module _ where
  open import Numeral.Natural

  -- Sometimes also notated (_▫ⁿ_) for a relation (_▫_).
  data FiniteTransitiveClosure : ℕ → T → T → Type{ℓ₁ Lvl.⊔ ℓ₂} where
    base : ∀{a} → (a ▫ a) → (FiniteTransitiveClosure 𝟎 a a)
    step : ∀{a b c} → (a ▫ b) → ∀{n} → (FiniteTransitiveClosure n b c) → (FiniteTransitiveClosure (𝐒(n)) a c)

instance
  ReflexiveTransitiveClosure-reflexivity : Reflexivity(ReflexiveTransitiveClosure)
  ReflexiveTransitiveClosure-reflexivity = intro refl

instance
  ReflexiveTransitiveClosure-transitivity : Transitivity(ReflexiveTransitiveClosure)
  ReflexiveTransitiveClosure-transitivity = intro trans

-- The "prepend"-property of reflexive-transitive closure
ReflexiveTransitiveClosure-prepend : ∀{a b c} → (a ▫ b) → ReflexiveTransitiveClosure b c → ReflexiveTransitiveClosure a c
ReflexiveTransitiveClosure-prepend ab bc = trans (super ab) bc

-- A reflexive-transitive closure is the same as a path.
ReflexiveTransitiveClosure-Path-equivalence : ∀{a b} → (ReflexiveTransitiveClosure a b) ↔ (Walk(_▫_) a b)
ReflexiveTransitiveClosure-Path-equivalence = [↔]-intro l r where
  r : ∀{a b} → ReflexiveTransitiveClosure a b → Walk(_▫_) a b
  r ReflexiveTransitiveClosure.refl              = reflexivity(Walk(_▫_))
  r (ReflexiveTransitiveClosure.super ab)        = sub₂(_▫_)(Walk(_▫_)) ab
  r (ReflexiveTransitiveClosure.trans rab1 rb1b) = transitivity(Walk(_▫_)) (r rab1) (r rb1b)

  l : ∀{a b} → Walk(_▫_) a b → ReflexiveTransitiveClosure a b
  l Walk.at        = ReflexiveTransitiveClosure.refl
  l (Walk.prepend ab1 sb1b) = ReflexiveTransitiveClosure-prepend ab1 (l sb1b)


{-# OPTIONS --cubical #-}

module Type.Cubical.Path.Category{ℓ} where

open import Data.Tuple as Tuple using (_,_)
open import Data
open import Functional
open import Function.Axioms
open import Logic.Propositional
open import Structure.Category
open import Structure.Categorical.Properties
open import Structure.Operator
open import Structure.Relator.Properties
open import Type
open import Type.Cubical.Path
open import Type.Cubical.Path.Equality
open import Type.Properties.Singleton

-- The type category is a category containing all types of a single universe level in the language.
-- The objects are all sets/types.
-- The morphisms are all functions where the domain/codomain-pair are from these objects.
typeFunctionPathCategory : Category{Obj = Type{ℓ}}(_→ᶠ_)
Category._∘_ typeFunctionPathCategory = _∘_
Category.id  typeFunctionPathCategory = id
Morphism.Associativity.proof (Category.associativity typeFunctionPathCategory)      = reflexivity(Path)
Morphism.Identityₗ.proof (Tuple.left (Category.identity typeFunctionPathCategory))  = reflexivity(Path)
Morphism.Identityᵣ.proof (Tuple.right (Category.identity typeFunctionPathCategory)) = reflexivity(Path)

typeFunctionPathCategoryObject : CategoryObject
typeFunctionPathCategoryObject = intro typeFunctionPathCategory

Empty-initialObject : Object.Initial{Obj = Type{ℓ}}(_→ᶠ_) (Empty)
IsUnit.unit       Empty-initialObject       = empty
IsUnit.uniqueness (Empty-initialObject {T}) = functionExtensionality(Empty)(T) \{}

Unit-terminalObject : Object.Terminal{Obj = Type{ℓ}}(_→ᶠ_) (Unit)
IsUnit.unit       Unit-terminalObject = const <>
IsUnit.uniqueness Unit-terminalObject = reflexivity(Path)


module Cats.Category.Setoids where

open import Cats.Util.SetoidMorphism public using
  (_⇒_ ; _≈_ ; ≈-intro ; ≈-elim ; ≈-elim′ ; equiv ; _∘_ ; id ; ∘-resp ; assoc ; id-l
  ; id-r)

open import Level using (_⊔_ ; suc)
open import Relation.Binary using (Setoid)

open import Cats.Category.Base
open import Cats.Category.Sets using (Sets)
open import Cats.Util.Conv

instance
  HasArrow-⇒ : ∀ {l l≈} {A B : Setoid l l≈}
    → HasArrow (A ⇒ B) (suc l) l l
  HasArrow-⇒ {l} = record { Cat = Sets l ; _⃗ = _⇒_.arr }

Setoids : ∀ l l≈ → Category (suc (l ⊔ l≈)) (l ⊔ l≈) (l ⊔ l≈)
Setoids l l≈ = record
    { Obj = Setoid l l≈
    ; _⇒_ = λ A B → A ⇒ B
    ; _≈_ = _≈_
    ; id = id
    ; _∘_ = _∘_
    ; equiv = equiv
    ; ∘-resp = λ {A} {B} {C} {f} {g} {h} {i} → ∘-resp {f = f} {g} {h} {i}
    ; id-r = λ {A} {B} {f} → id-r {f = f}
    ; id-l = λ {A} {B} {f} → id-l {f = f}
    ; assoc = λ {A} {B} {C} {D} {f} {g} {h} → assoc {f = f} {g} {h}
    }


module Human.List where

open import Human.Nat

infixr 5 _,_
data List {a} (A : Set a) : Set a where
  end : List A
  _,_ : (x : A) (xs : List A) → List A

{-# BUILTIN LIST List #-}

{-# COMPILE JS  List = function(x,v) { if (x.length < 1) { return v["[]"](); } else { return v["_∷_"](x[0], x.slice(1)); } } #-}
{-# COMPILE JS end = Array() #-}
{-# COMPILE JS _,_ = function (x) { return function(y) { return Array(x).concat(y); }; } #-}

foldr : ∀ {A : Set} {B : Set} → (A → B → B) → B → List A → B
foldr c n end       = n
foldr c n (x , xs) = c x (foldr c n xs)

length : ∀ {A : Set} → List A → Nat
length = foldr (λ a n → suc n) zero


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

open import LogicalFormulae
open import Setoids.Setoids
open import Rings.Definition
open import Rings.IntegralDomains.Definition
open import Vectors
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Numbers.Naturals.Definition

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

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

open import Rings.Units.Definition R
open import Rings.Irreducibles.Definition intDom
open import Rings.Associates.Definition intDom
open import Rings.Primes.Definition intDom
open Ring R
open Setoid S

private
  power : A → ℕ → A
  power x zero = 1R
  power x (succ n) = x * power x n

  allDistinct : {n : ℕ} → Vec A n → Set (a ⊔ b)
  allDistinct [] = True'
  allDistinct (x ,- xs) = (allDistinct xs) && vecAllTrue (λ n → (n ∼ x) → False) xs

record Factorisation {r : A} .(nonzero : (r ∼ 0R) → False) .(nonunit : (Unit r) → False) : Set (a ⊔ b) where
  field
    len : ℕ
    factorise : Vec (A && ℕ) len
    factoriseIsFactorisation : vecFold (λ x y → y * power (_&&_.fst x) (succ (_&&_.snd x))) 1R factorise ∼ r
    factoriseIsIrreducibles : vecAllTrue Irreducible (vecMap _&&_.fst factorise)
    distinct : allDistinct (vecMap _&&_.fst factorise)

private
  equality : {n : ℕ} (v1 v2 : Vec (A && ℕ) n) → Set (a ⊔ b)
  equality [] [] = True'
  equality {succ n} ((a ,, an) ,- v1) v2 = Sg ℕ (λ index → Sg (index <N succ n) (λ i<n → (Associates (_&&_.fst (vecIndex v2 index i<n)) a) && ((_&&_.snd (vecIndex v2 index i<n) ≡ an) && equality v1 (vecDelete index i<n v2))))

factorisationEquality : {r : A} → .{nonzero : (r ∼ 0R) → False} → .{nonunit : (Unit r) → False} → Factorisation nonzero nonunit → Factorisation nonzero nonunit → Set (a ⊔ b)
factorisationEquality record { len = lenA ; factorise = factoriseA ; factoriseIsFactorisation = factoriseIsFactorisationA ; factoriseIsIrreducibles = factoriseIsIrreduciblesA ; distinct = distinctA } record { len = lenB ; factorise = factoriseB ; factoriseIsFactorisation = factoriseIsFactorisationB ; factoriseIsIrreducibles = factoriseIsIrreduciblesB ; distinct = distinctB } with ℕDecideEquality lenA lenB
factorisationEquality record { len = a ; factorise = factoriseA } record { len = .a ; factorise = factoriseB } | inl refl = equality factoriseA factoriseB
factorisationEquality record { len = a ; factorise = factoriseA } record { len = b ; factorise = factoriseB } | inr _ = False'

record UFD : Set (a ⊔ b) where
  field
    factorisation : {r : A} → (nonzero : (r ∼ 0R) → False) → (nonunit : (Unit r) → False) → Factorisation nonzero nonunit
    uniqueFactorisation : {r : A} → (nonzero : (r ∼ 0R) → False) → (nonunit : (Unit r) → False) → (f1 f2 : Factorisation nonzero nonunit) → factorisationEquality f1 f2

record UFD' : Set (a ⊔ b) where
  field
    factorisation : {r : A} → (nonzero : (r ∼ 0R) → False) → (nonunit : (Unit r) → False) → Factorisation nonzero nonunit
    irreduciblesArePrime : {r : A} → Irreducible r → Prime r


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

open import Cubical.Foundations.Prelude

open import Cubical.Data.Empty as ⊥
open import Cubical.Data.Nat hiding (_·_) renaming (_+_ to _+n_)
open import Cubical.Data.Nat.Order
open import Cubical.Data.Sigma

open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Ring
open import Cubical.Algebra.CommRing
open import Cubical.Algebra.GradedRing.DirectSumFun

private variable
  ℓ : Level

module _
  (ACommRing@(A , Astr) : CommRing ℓ)
  where

  open CommRingStr Astr
  open RingTheory (CommRing→Ring ACommRing)

  UnivariatePolyFun-CommRing : CommRing ℓ
  UnivariatePolyFun-CommRing = ⊕FunGradedRing-CommRing
                   _+n_ (makeIsMonoid isSetℕ +-assoc +-zero λ _ → refl) (λ _ _ → refl)
                   (λ _ → A)
                   (λ _ → snd (Ring→AbGroup (CommRing→Ring ACommRing)))
                   1r _·_ 0LeftAnnihilates 0RightAnnihilates
                   (λ a b c → ΣPathP ((+-assoc _ _ _) , (·Assoc _ _ _)))
                   (λ a → ΣPathP ((+-zero _) , (·IdR _)))
                   (λ a → ΣPathP (refl , (·IdL _)))
                   ·DistR+
                   ·DistL+
                   λ x y → ΣPathP ((+-comm _ _) , (·Comm _ _))

nUnivariatePolyFun : (A' : CommRing ℓ) → (n : ℕ) → CommRing ℓ
nUnivariatePolyFun A' zero = A'
nUnivariatePolyFun A' (suc n) = UnivariatePolyFun-CommRing (nUnivariatePolyFun A' n)


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

module Categories.Category.Concrete where

open import Level

open import Categories.Category.Core using (Category)
open import Categories.Category.Instance.Setoids using (Setoids)
open import Categories.Functor.Core using (Functor)
open import Categories.Functor.Representable using (Representable)
open import Categories.Functor.Properties using (Faithful)

-- A Concrete Category is a category along with a faithful
-- functor to Setoid.
-- [Normally Set, but that doesn't work so well here]

private
  variable
    o ℓ e : Level

record Concrete (C : Category o ℓ e) (ℓ′ e′ : Level) : Set (o ⊔ ℓ ⊔ e ⊔ suc (ℓ′ ⊔ e′)) where
  field
    concretize : Functor C (Setoids ℓ′ e′)
    conc-faithful : Faithful concretize

-- Because of the use of the Hom functor, some levels collapse
record RepresentablyConcrete (C : Category o ℓ e) : Set (o ⊔ suc (e ⊔ ℓ)) where
  open Concrete
  field
    conc : Concrete C ℓ e
    representable : Representable (concretize conc)


module seven where

open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Naturals using (ℕ; zero; suc)

seven : ℕ
seven = suc (suc (suc (suc (suc (suc (suc zero))))))

_ : seven ≡ 7
_ = refl


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

open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import LogicalFormulae
open import Numbers.Integers.Integers
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Subtraction
open import Numbers.Naturals.Naturals
open import Numbers.Naturals.Order
open import Numbers.Naturals.Exponentiation
open import Numbers.Primes.PrimeNumbers
open import Maybe
open import Semirings.Definition
open import Numbers.Naturals.EuclideanAlgorithm
open import Sequences
open import Vectors

module LectureNotes.NumbersAndSets.Examples1 where

open Semiring ℕSemiring
open import Semirings.Solver ℕSemiring multiplicationNIsCommutative

private
  abstract
    q1Lemma1 : {q r : ℕ} → 3 *N succ q +N r ≡ succ (succ (succ (3 *N q +N r)))
    q1Lemma1 {q} {r} rewrite sumZeroRight q | commutative q (succ q) | commutative q (succ (succ (q +N q))) | +Associative q q q = refl

    q1Lemma : {n : ℕ} → (2 <N n) → ((3 ∣ n) || (3 ∣ (n +N 2))) || (3 ∣ (n +N 4))
    q1Lemma {zero} ()
    q1Lemma {succ zero} (le zero ())
    q1Lemma {succ zero} (le (succ x) ())
    q1Lemma {succ (succ zero)} (le (succ x) proof) rewrite Semiring.commutative ℕSemiring x 2 = exFalso (naughtE (equalityCommutative (succInjective (succInjective proof))))
    q1Lemma {succ (succ (succ zero))} 2<n = inl (inl (aDivA 3))
    q1Lemma {succ (succ (succ (succ zero)))} 2<n = inl (inr (divides (record { quot = 2 ; rem = zero ; pr = refl ; remIsSmall = inl (le 2 refl) ; quotSmall = inl (le 2 refl)}) refl))
    q1Lemma {succ (succ (succ (succ (succ zero))))} 2<n = inr (divides (record { quot = 3 ; rem = zero ; pr = refl ; remIsSmall = inl (le 2 refl) ; quotSmall = inl (le 2 refl)}) refl)
    q1Lemma {succ (succ (succ (succ (succ (succ n)))))} 2<n with q1Lemma {succ (succ (succ n))} (le n (applyEquality succ (Semiring.commutative ℕSemiring n 2)))
    q1Lemma {succ (succ (succ (succ (succ (succ n)))))} 2<n | inl (inl (divides record { quot = quot ; rem = rem ; pr = pr ; remIsSmall = remIsSmall ; quotSmall = quotSmall } x)) = inl (inl (divides (record { quot = succ quot ; rem = rem ; pr = transitivity (q1Lemma1 {quot} {rem}) (applyEquality (λ x → succ (succ (succ x))) pr) ; remIsSmall = remIsSmall ; quotSmall = inl (le 2 refl) }) x))
    q1Lemma {succ (succ (succ (succ (succ (succ n)))))} 2<n | inl (inr (divides record { quot = quot ; rem = rem ; pr = pr ; remIsSmall = remIsSmall ; quotSmall = quotSmall } x)) = inl (inr (divides record { quot = succ quot ; rem = rem ; pr = transitivity (q1Lemma1 {quot} {rem}) (applyEquality (λ x → succ (succ (succ x))) pr) ; remIsSmall = remIsSmall ; quotSmall = inl (le 2 refl) } x))
    q1Lemma {succ (succ (succ (succ (succ (succ n)))))} 2<n | inr (divides record { quot = quot ; rem = rem ; pr = pr ; remIsSmall = remIsSmall ; quotSmall = quotSmall } x) = inr (divides record { quot = succ quot ; rem = rem ; pr = transitivity (q1Lemma1 {quot} {rem}) (applyEquality (λ x → succ (succ (succ x))) pr) ; remIsSmall = remIsSmall ; quotSmall = inl (le 2 refl) } x)

q1 : {n : ℕ} → Prime n → Prime (n +N 2) → Prime (n +N 4) → n ≡ 3
q1 {succ zero} record { p>1 = (le zero ()) ; pr = pr } pN+2 pN+4
q1 {succ zero} record { p>1 = (le (succ x) ()) ; pr = pr } pN+2 pN+4
q1 {succ (succ zero)} pN record { p>1 = p>1 ; pr = pr } pN+4 with pr {2} (divides (record { quot = 2 ; rem = zero ; pr = refl ; remIsSmall = inl (le 1 refl) ; quotSmall = inl (le 1 refl)}) refl) (le 1 refl) (le 1 refl)
q1 {succ (succ zero)} pN record { p>1 = p>1 ; pr = pr } pN+4 | ()
q1 {succ (succ (succ n))} pN pN+2 pN+4 with q1Lemma {succ (succ (succ n))} (le n (applyEquality succ (commutative n 2)))
q1 {succ (succ (succ n))} pN pN+2 pN+4 | inl (inl 3|n) = equalityCommutative (primeDivPrimeImpliesEqual threeIsPrime pN 3|n)
q1 {succ (succ (succ n))} pN pN+2 pN+4 | inl (inr 3|n+2) with primeDivPrimeImpliesEqual threeIsPrime pN+2 3|n+2
... | bl rewrite commutative n 2 = exFalso (naughtE (succInjective (succInjective (succInjective bl))))
q1 {succ (succ (succ n))} pN pN+2 pN+4 | inr 3|n+4 with primeDivPrimeImpliesEqual threeIsPrime pN+4 3|n+4
... | bl rewrite commutative n 4 = exFalso (naughtE (succInjective (succInjective (succInjective bl))))

q3Differences : ℕ → ℕ
q3Differences a = 2 *N a
q3Seq : (start : ℕ) → ℕ → ℕ
q3Seq start zero = start
q3Seq start (succ n) = q3Differences (succ n) +N q3Seq start n
q3SeqFirst : take 5 (funcToSequence (q3Seq 41)) ≡ 41 ,- 43 ,- 47 ,- 53 ,- 61 ,- []
q3SeqFirst = refl
q3N : (start : ℕ) (a : ℕ) → q3Seq start a ≡ start +N (a +N (a *N a))
q3N start zero = equalityCommutative (sumZeroRight start)
q3N start (succ a) rewrite q3N start a | sumZeroRight a =
  from (succ (plus (plus (const a) (succ (const a))) (plus (const start) (plus (const a) (times (const a) (const a))))))
  to (plus (const start) (succ (plus (const a) (succ (plus (const a) (times (const a) (succ (const a))))))))
  by applyEquality (λ i → succ (succ i)) (transitivity (+Associative (a +N a) start _) (transitivity (transitivity (applyEquality (_+N (a +N a *N a)) (commutative (a +N a) start)) (equalityCommutative (+Associative start _ _))) (applyEquality (start +N_) (equalityCommutative (+Associative a a (a +N a *N a))))))
q3NDivision : (start : ℕ) → start ∣ (q3Seq start start)
q3NDivision 0 = aDivA 0
q3NDivision (succ start) rewrite q3N (succ start) (succ start) = dividesBothImpliesDividesSum {succ start} {succ start} (aDivA (succ start)) (dividesBothImpliesDividesSum {succ start} {succ start} (aDivA (succ start)) (divides (record { quot = succ start ; rem = 0 ; pr = sumZeroRight _ ; remIsSmall = inl (succIsPositive start) ; quotSmall = inl (succIsPositive start) }) refl))

q3 : (start : ℕ) → ((n : ℕ) → Prime (q3Seq start n)) → False
q3 zero a with a 2
... | record { p>1 = p>1 ; pr = pr } with pr {2} (divides (record { quot = 3 ; rem = 0 ; pr = refl ; remIsSmall = inl (le 1 refl) ; quotSmall = inl (le 1 refl) }) refl) (le 3 refl) (succIsPositive 1)
... | ()
q3 (succ zero) a with a 0
... | record { p>1 = le zero () ; pr = pr }
... | record { p>1 = le (succ x) () ; pr = pr }
q3 (succ (succ start)) a with q3NDivision (succ (succ start))
... | r with a (succ (succ start))
... | s = compositeImpliesNotPrime (succ (succ start)) _ (succPreservesInequality (succIsPositive start)) (le (succ (succ start) +N ((start +N succ start) +N q3Seq (succ (succ start)) start)) (applyEquality (λ i → succ (succ i)) (from (succ (plus (plus (const start) (plus (plus (const start) (succ (const start))) (const (q3Seq (succ (succ start)) start)))) (succ (succ (const start))))) to plus (plus (const start) (succ (succ (plus (const start) zero)))) (succ (plus (plus (const start) (succ (plus (const start) zero))) (const (q3Seq (succ (succ start)) start)))) by applyEquality (λ i → succ (succ (succ (succ i)))) (transitivity (commutative _ start) (+Associative start start _))))) r s

q3' : ((n : ℕ) → Prime (q3Seq 41 n)) → False
q3' = q3 41

q6 : {n : ℕ} → 3 ∣ (n *N n) → 3 ∣ n
q6 {n} 3|n^2 with primesArePrime {3} {n} {n} threeIsPrime 3|n^2
q6 {n} 3|n^2 | inl x = x
q6 {n} 3|n^2 | inr x = x

_*q10_ : {a : ℕ} → {b : ℕ} → (0 <N a) → (0 <N b) → ℕ
*q10Pos : {a : ℕ} → {b : ℕ} → (0<a : 0 <N a) → (0<b : 0 <N b) → 0 <N (_*q10_ 0<a 0<b)

_*q10_ {succ zero} {succ b} 0<a 0<b = succ (succ b)
_*q10_ {succ (succ a)} {succ zero} 0<a 0<b = _*q10_ {succ a} {2} (le a (applyEquality succ (sumZeroRight a))) (le 1 refl)
_*q10_ {succ (succ a)} {succ (succ b)} 0<a 0<b = _*q10_ {succ a} {_*q10_ {succ (succ a)} {succ b} 0<a (le b (applyEquality succ (sumZeroRight b)))} (le a (applyEquality succ (sumZeroRight a))) (*q10Pos 0<a (le b (applyEquality succ (sumZeroRight b))))
*q10Pos {succ zero} {succ b} 0<a 0<b = le (succ b) (applyEquality (λ i → succ (succ i)) (sumZeroRight b))
*q10Pos {succ (succ a)} {succ zero} 0<a 0<b = *q10Pos (le a (applyEquality succ (sumZeroRight a))) (le 1 refl)
*q10Pos {succ (succ a)} {succ (succ b)} 0<a 0<b = *q10Pos (le a (applyEquality succ (sumZeroRight a))) (*q10Pos 0<a (le b (applyEquality succ (sumZeroRight b))))


-- 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 ∈ f $* nx
--
-- Example:
-- ndCons : ... → xs ∈ nxs → (x :: xs) ∈ (_::_ x) $* nxs
∈-$* : {A B : Set} → (f : A → B) → (x : A) → (nx : ND A)
        → x ∈ nx → (f x) ∈ (f $* nx)
∈-$* f x (Val .x) ndrefl = ndrefl
∈-$* f x (l ?? r) (left  .l .r k) =
  left  (f $* l) (f $* r) (∈-$* f x l k)
∈-$* f x (l ?? r) (right .l .r k) =
  right (f $* l) (f $* r) (∈-$* f x r k)

-- This is a similar result as ∈-$* but for non-deterministic application:
∈-*$* : {A B : Set} → (x : A) → (nx : ND A) → (f : A → B)
        → (nf : A → ND B) → x ∈ nx → f x ∈ nf x → f x ∈ (nf *$* nx)
∈-*$* x (Val .x) f nf ndrefl pf = pf
∈-*$* x (l ?? r) f nf (left  .l .r p) pf =
  left (nf *$* l) (nf *$* r) (∈-*$* x l f nf p pf)
∈-*$* x (l ?? r) f nf (right .l .r p) pf =
  right (nf *$* l) (nf *$* r) (∈-*$* x r f nf p pf)

----------------------------------------------------------------------
-- Theorems about '$*':

-- Combine two $* applications into one:
$*-$* : ∀ {A B C : Set} → (f : B → C) (g : A → B) (xs : ND A)
            → f $* (g $* xs) ≡ (f ∘ g) $* xs
$*-$* f g (Val x) = refl
$*-$* f g (t1 ?? t2) rewrite $*-$* f g t1 | $*-$* 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-$* : ∀ {A : Set} → (p : A → 𝔹) (xs : ND A)
          → ((y : A) → p y ≡ tt)
          → always (p $* xs) ≡ tt
always-$* _ (Val y) prf = prf y
always-$* p (t1 ?? t2) prf
  rewrite always-$* p t1 prf
        | always-$* p t2 prf = refl

-- Extend validity of a function with a deterministic argument to validity of
-- the corresponding non-deterministic function:
always-*$* : ∀ {A : Set} → (p : A → ND 𝔹) (xs : ND A)
               → ((y : A) → always (p y) ≡ tt)
               → always (p *$* xs) ≡ tt
always-*$* _ (Val y) prf = prf y
always-*$* p (t1 ?? t2) prf
  rewrite always-*$* p t1 prf
        | always-*$* 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

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

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

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

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

every-$* : ∀ (f : ℕ → ℕ) (v : ℕ) (x : ND ℕ) →
         every _=ℕ_ v x ≡ tt → every _=ℕ_ (f v) (f $* x) ≡ tt
every-$* f v (Val x) u rewrite =ℕ-to-≡ {v} {x} u | =ℕ-refl (f x) = refl
every-$* f v (t1 ?? t2) u
  rewrite every-$* f v t1 (&&-fst u)
        | every-$* 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 --safe #-}
module Cubical.Algebra.CommMonoid.Properties where

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

open import Cubical.Data.Sigma

open import Cubical.Algebra.Monoid
open import Cubical.Algebra.CommMonoid.Base

private
  variable
    ℓ ℓ' : Level

module _
    (M : CommMonoid ℓ)
    (P : ⟨ M ⟩ → hProp ℓ')
    where
  open CommMonoidStr (snd M)
  module _
    (·Closed : (x y : ⟨ M ⟩) → ⟨ P x ⟩ → ⟨ P y ⟩ → ⟨ P (x · y) ⟩)
    (εContained : ⟨ P ε ⟩)
    where
    private
      subtype = Σ[ x ∈ ⟨ M ⟩ ] ⟨ P x ⟩

    makeSubCommMonoid : CommMonoid _
    fst makeSubCommMonoid = subtype
    CommMonoidStr.ε (snd makeSubCommMonoid) = ε , εContained
    CommMonoidStr._·_ (snd makeSubCommMonoid) (x , xContained) (y , yContained) =
      (x · y) , ·Closed x y xContained yContained
    IsCommMonoid.isMonoid (CommMonoidStr.isCommMonoid (snd makeSubCommMonoid)) =
      makeIsMonoid
        (isOfHLevelΣ 2 (isSetFromIsCommMonoid isCommMonoid) λ _ → isProp→isSet (snd (P _)))
        (λ x y z → Σ≡Prop (λ _ → snd (P _)) (·Assoc (fst x) (fst y) (fst z)))
        (λ x → Σ≡Prop (λ _ → snd (P _)) (·IdR (fst x)))
        λ x → Σ≡Prop (λ _ → snd (P _)) (·IdL (fst x))
    IsCommMonoid.·Comm (CommMonoidStr.isCommMonoid (snd makeSubCommMonoid)) =
      λ x y → Σ≡Prop (λ _ → snd (P _)) (·Comm (fst x) (fst y))

module CommMonoidTheory (M' : CommMonoid ℓ) where
 open CommMonoidStr (snd M')
 private M = ⟨ M' ⟩

 commAssocl : (x y z : M) → x · (y · z) ≡ y · (x · z)
 commAssocl x y z = ·Assoc x y z ∙∙ cong (_· z) (·Comm x y) ∙∙ sym (·Assoc y x z)

 commAssocr : (x y z : M) → x · y · z ≡ x · z · y
 commAssocr x y z = sym (·Assoc x y z) ∙∙ cong (x ·_) (·Comm y z) ∙∙ ·Assoc x z y

 commAssocr2 : (x y z : M) → x · y · z ≡ z · y · x
 commAssocr2 x y z = commAssocr _ _ _ ∙∙ cong (_· y) (·Comm _ _) ∙∙ commAssocr _ _ _

 commAssocSwap : (x y z w : M) → (x · y) · (z · w) ≡ (x · z) · (y · w)
 commAssocSwap x y z w = ·Assoc (x · y) z w ∙∙ cong (_· w) (commAssocr x y z)
                                               ∙∙ sym (·Assoc (x · z) y w)


module Equality where

open import Function using (_∘_)
open import Relation.Binary.PropositionalEquality using (_≡_)
open import Data.Product using (_×_; _,_; ∃-syntax; proj₁; proj₂)
open import Data.Bool using (Bool; true; false)
open import Data.Nat using (ℕ)

--
-- Relation
--

record Relation (R : Set → Set) (A : Set) : Set where
  field
    relate : A × A → Bool
    to-witness : ∀ x → relate x ≡ true → R A
    from-witness : R A → ∃[ x ] (relate x ≡ true)
    to-from-witness : ∀ x d → x ≡ (proj₁ ∘ from-witness) (to-witness x d)

  Related : A × A → Set
  Related (x , y) = R A × relate (x , y) ≡ true

-- Properties

IsReflexive : ∀ R A (rel : Relation R A) → Set
IsReflexive R A rel = ∀ x → Related (x , x)
  where open Relation rel

IsSymmetric : ∀ R A (rel : Relation R A) → Set
IsSymmetric R A rel = ∀ x y → Related (x , y) → Related (y , x)
  where open Relation rel

IsTransitive : ∀ R A (rel : Relation R A) → Set
IsTransitive R A rel = ∀ x y z → Related (x , y) → Related (y , z) → Related (x , z)
  where open Relation rel

--
-- Equality
--

record Equality (E : Set → Set) (A : Set) : Set where
  field
    rel : Relation E A
    isReflexive  : IsReflexive  E A rel
    isSymmetric  : IsSymmetric  E A rel
    isTransitive : IsTransitive E A rel

--
-- SMT Equality
--

postulate
  -- datatype
  EqualitySMT : ∀ A → A → A → Set

  -- instances
  equalitySMT-Bool : Equality EqualitySMT Bool
  equalitySMT-ℕ    : Equality EqualitySMT ℕ

  -- eq-smt : (A : Set) (x y : A) → Bool

--
-- Propositional Equality
--

postulate
  eq-prop : ∀ (A : Set) (x y : A) → Bool

data EqualityProp : ∀ A → A → A → Set where
  injection-SMT :
    ∀ (A : Set) (equ : Equality EqualitySMT A) x y →
      Relation.Related EqualitySMT (x , y) →
      Relation.Related EqualityProp (x , y)
  -- extensional :
  --   ∀ (A B : Set) f g →
  --     (∀ x → EqualityProp


------------------------------------------------------------------------
-- The Agda standard library
--
-- Automatic solvers for equations over integers
------------------------------------------------------------------------

-- See README.Integer for examples of how to use this solver

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

module Data.Integer.Tactic.RingSolver where

open import Agda.Builtin.Reflection

open import Data.Maybe.Base using (just; nothing)
open import Data.Integer.Base
open import Data.Integer.Properties
open import Level using (0ℓ)
open import Data.Unit using (⊤)
open import Relation.Binary.PropositionalEquality
import Tactic.RingSolver as Solver
import Tactic.RingSolver.Core.AlmostCommutativeRing as ACR

------------------------------------------------------------------------
-- A module for automatically solving propositional equivalences
-- containing _+_ and _*_

ring : ACR.AlmostCommutativeRing 0ℓ 0ℓ
ring = ACR.fromCommutativeRing +-*-commutativeRing
  λ { +0 → just refl; _ → nothing }

macro
  solve-∀ : Term → TC ⊤
  solve-∀ = Solver.solve-∀-macro (quote ring)

macro
  solve : Term → Term → TC ⊤
  solve n = Solver.solve-macro n (quote ring)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Membership for containers
------------------------------------------------------------------------

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

module Data.Container.Membership where

open import Level using (_⊔_)
open import Relation.Unary using (Pred)
open import Relation.Binary.PropositionalEquality

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

module _ {s p} {C : Container s p} {x} {X : Set x} where

  infix 4 _∈_
  _∈_ : X → Pred (⟦ C ⟧ X) (p ⊔ x)
  x ∈ xs = ◇ C (_≡_ x) xs


module Data.Tuple.Equivalence where

import      Lvl
open import Data using (Unit ; <>)
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Logic.Propositional
open import Structure.Setoid
open import Structure.Function
open import Structure.Operator
open import Structure.Relator.Equivalence
open import Structure.Relator.Properties
open import Type

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

module _ {A : Type{ℓₒ₁}} ⦃ _ : Equiv{ℓₑ₁}(A) ⦄ {B : Type{ℓₒ₂}} ⦃ _ : Equiv{ℓₑ₂}(B) ⦄ where
  instance
    Tuple-equiv : Equiv(A ⨯ B)
    _≡_ ⦃ Tuple-equiv ⦄ (x₁ , y₁) (x₂ , y₂) = (x₁ ≡ x₂) ∧ (y₁ ≡ y₂)
    Equiv-equivalence ⦃ Tuple-equiv ⦄ = intro where
      instance
        [≡]-reflexivity : Reflexivity(_≡_ ⦃ Tuple-equiv ⦄)
        Reflexivity.proof([≡]-reflexivity) = [∧]-intro (reflexivity(_≡_)) (reflexivity(_≡_))

      instance
        [≡]-symmetry : Symmetry(_≡_ ⦃ Tuple-equiv ⦄)
        Symmetry.proof([≡]-symmetry) ([∧]-intro l r) = [∧]-intro (symmetry(_≡_) l) (symmetry(_≡_) r)

      instance
        [≡]-transitivity : Transitivity(_≡_ ⦃ Tuple-equiv ⦄)
        Transitivity.proof([≡]-transitivity) ([∧]-intro l1 r1) ([∧]-intro l2 r2) = [∧]-intro (transitivity(_≡_) l1 l2) (transitivity(_≡_) r1 r2)

  instance
    left-function : Function(Tuple.left)
    Function.congruence left-function = Tuple.left

  instance
    right-function : Function(Tuple.right)
    Function.congruence right-function = Tuple.right

  instance
    [,]-function : BinaryOperator(_,_)
    BinaryOperator.congruence [,]-function a b = (a , b)

module _ {A : Type{ℓₒ₁}} ⦃ equiv-A : Equiv{ℓₑ₁}(A) ⦄ {B : Type{ℓₒ₂}} ⦃ equiv-B : Equiv{ℓₑ₂}(B) ⦄ where
  instance
    swap-function : Function ⦃ Tuple-equiv ⦃ equiv-A ⦄ ⦃ equiv-B ⦄ ⦄ ⦃ Tuple-equiv ⦄ (Tuple.swap)
    Function.congruence swap-function = Tuple.swap

module _ {A : Type{ℓₒ}} ⦃ equiv : Equiv{ℓₑ}(A) ⦄ where
  instance
    repeat-function : Function(Tuple.repeat{A = A})
    Function.congruence repeat-function = Tuple.repeat

module _
  {A₁ : Type{ℓₒ₁}} ⦃ equiv-A₁ : Equiv{ℓₑ₁}(A₁) ⦄
  {A₂ : Type{ℓₒ₂}} ⦃ equiv-A₂ : Equiv{ℓₑ₂}(A₂) ⦄
  {B₁ : Type{ℓₒ₃}} ⦃ equiv-B₁ : Equiv{ℓₑ₃}(B₁) ⦄
  {B₂ : Type{ℓₒ₄}} ⦃ equiv-B₂ : Equiv{ℓₑ₄}(B₂) ⦄
  {f : A₁ → A₂} ⦃ func-f : Function(f) ⦄
  {g : B₁ → B₂} ⦃ func-g : Function(g) ⦄
  where

  instance
    map-function : Function(Tuple.map f g)
    Function.congruence map-function = Tuple.map (congruence₁(f)) (congruence₁(g))

module _
  {A : Type{ℓₒ₁}} ⦃ equiv-A : Equiv{ℓₑ₁}(A) ⦄
  {B : Type{ℓₒ₂}} ⦃ equiv-B : Equiv{ℓₑ₂}(B) ⦄
  {C : Type{ℓₒ₃}} ⦃ equiv-C : Equiv{ℓₑ₃}(C) ⦄
  where

  instance
    associateLeft-function : Function(Tuple.associateLeft {A = A}{B = B}{C = C})
    Function.congruence associateLeft-function = Tuple.associateLeft

  instance
    associateRight-function : Function(Tuple.associateRight {A = A}{B = B}{C = C})
    Function.congruence associateRight-function = Tuple.associateRight


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

open import Relation.Binary.PropositionalEquality as P

data Phantom {i} {A : Set i} (a : A) : Set where
  phantom : Phantom a

module _ where
  private
    data #Σ-aux (A : Set) (B : A → Set) : Set where
      #pair : (x : A) → B x → #Σ-aux A B

  Σ : (A : Set) → (A → Set) → Set
  Σ A B = #Σ-aux A B

  pair : ∀ {A : Set} {B : A → Set} (x : A) → B x → Σ A B
  pair = #pair

  module ΣElim {A} {B} {S : Σ A B → Set}
    (pair* : ∀(a : A) (b : B a) → S (pair a b))
    where
      f-aux : Phantom pair* → (x : Σ A B) → S x
      f-aux x (#pair a b) = pair* a b

      f : (x : Σ A B) → S x
      f = f-aux phantom

open ΣElim public renaming (f to Σ-elim)

Σ-rec : ∀ {A} {B} {S : Set} → ((x : A) → B x → S) → Σ A B → S
Σ-rec f = Σ-elim f

isΣ-hom : ∀ {A B} {S : Set} (α : (a : A) → B a → S) →
          (Σ A B → S) → Set
isΣ-hom α f = ∀ a b → f (pair a b) ≡ α a b

Σ-rec-unique : ∀ {A B S} {α : (a : A) → B a → S} {f : Σ A B → S} → isΣ-hom α f →
               ∀ x → f x ≡ Σ-rec α x
Σ-rec-unique f-hom = Σ-elim f-hom

π₁ : ∀ {A B} → Σ A B → A
π₁ = Σ-rec (λ a _ → a)

π₂ : ∀ {A B} → (x : Σ A B) → B (π₁ x)
π₂ = Σ-elim (λ a b → b)

record ΣRecStruct (A : Set) (B : A → Set) : Set₁ where
  field
    Carrier : Set
    inj : (a : A) → B a → Carrier
    rec : ∀{S : Set} → ((a : A) → B a → S) → Carrier → S
    rec-hom : ∀ {S : Set} (α : (a : A) → B a → S) →
                 (∀ a b → rec α (inj a b) ≡ α a b)
    rec-unique : ∀ {S : Set} {α : (a : A) → B a → S} {f : Carrier → S} →
                 (∀ a b → f (inj a b) ≡ α a b) →
                 ∀ x → f x ≡ rec α x
-- open ΣRecStruct public

Σ-ΣRecStruct : ∀ A B → ΣRecStruct A B
Σ-ΣRecStruct A B = record
  { Carrier = Σ A B
  ; inj = pair
  ; rec = Σ-rec
  ; rec-hom = λ α a b → refl
  ; rec-unique = Σ-rec-unique
  }

ΣRecStruct-HasInduction : ∀{A B} → ΣRecStruct A B → Set₁
ΣRecStruct-HasInduction {A} {B} R =
  ∀ {S : Carrier → Set} (inj* : ∀(a : A) (b : B a) → S (inj a b)) →
  (x : Carrier) → S x
  where open ΣRecStruct R

-- I don't think that this is provable without resorting to π₂.
-- But I also conjecture that internally the negation is neither
-- provable.
∀ΣRecStruct-haveInduction : ∀{A B} (R : ΣRecStruct A B) →
                            ΣRecStruct-HasInduction R
∀ΣRecStruct-haveInduction R {S} inj* x = {!!}
  where
    open ΣRecStruct R

    S-aux : Set
    S-aux = Σ Carrier S

    f : Carrier → S-aux
    f = rec (λ a b → pair (inj a b) (inj* a b))


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

module Categories.Category.Monoidal.Construction.Minus2 where

-- Any -2-Category is Monoidal.  Of course, One is Monoidal, but
-- we don't need to shrink to do this, it can be done directly.
-- The assumptions in the construction of a -2-Category are all
-- needed to make things work properly.

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

open import Categories.Minus2-Category
open import Categories.Category.Monoidal
import Categories.Morphism as M

-- Doing it manually is just as easy as going through Cartesian here
-2-Monoidal : ∀ {o ℓ e} → (C : -2-Category {o} {ℓ} {e}) → Monoidal (-2-Category.cat C)
-2-Monoidal C = record
  { ⊗ = record
    { F₀ = proj₁
    ; F₁ = proj₁
    ; identity = Hom-Conn
    ; homomorphism = Hom-Conn
    ; F-resp-≈ = λ _ → Hom-Conn
    }
  ; unit = proj₁ Obj-Contr
  ; unitorˡ = λ {X} → proj₂ Obj-Contr X
  ; unitorʳ = M.≅.refl cat
  ; associator = M.≅.refl cat
  ; unitorˡ-commute-from = Hom-Conn
  ; unitorˡ-commute-to = Hom-Conn
  ; unitorʳ-commute-from = Hom-Conn
  ; unitorʳ-commute-to = Hom-Conn
  ; assoc-commute-from = Hom-Conn
  ; assoc-commute-to = Hom-Conn
  ; triangle = Hom-Conn
  ; pentagon = Hom-Conn
  }
  where
    open -2-Category C


open import Algebra using (CommutativeMonoid)
open import Relation.Binary.Structures using (IsEquivalence)
open import Relation.Binary.PropositionalEquality using () renaming (cong to ≡-cong)

module AKS.Exponentiation {c ℓ} (M : CommutativeMonoid c ℓ) where

open import AKS.Nat using (ℕ; _+_; _<_)
open ℕ
open import AKS.Nat using (ℕ⁺; ℕ+; ⟅_⇓⟆)
open import AKS.Nat using (Acc; acc; <-well-founded)
open import AKS.Binary using (2*; 𝔹; 𝔹⁺; ⟦_⇑⟧; ⟦_⇓⟧; ⟦_⇑⟧⁺; ⟦_⇓⟧⁺; ℕ→𝔹→ℕ; ⌈log₂_⌉)
open 𝔹
open 𝔹⁺
open CommutativeMonoid M
  using (_≈_; isEquivalence; setoid; ε; _∙_; ∙-cong; ∙-congˡ; identityˡ; identityʳ; assoc; comm)
  renaming (Carrier to C)
open IsEquivalence isEquivalence using (refl; sym)
open import Relation.Binary.Reasoning.Setoid setoid

_^ⁱ_ : C → ℕ → C
x ^ⁱ zero = ε
x ^ⁱ suc n = x ∙ x ^ⁱ n

^ⁱ-homo : ∀ x n m → x ^ⁱ (n + m) ≈ x ^ⁱ n ∙ x ^ⁱ m
^ⁱ-homo x zero m = sym (identityˡ (x ^ⁱ m))
^ⁱ-homo x (suc n) m = begin
  x ∙ x ^ⁱ (n + m) ≈⟨ ∙-congˡ (^ⁱ-homo x n m) ⟩
  x ∙ (x ^ⁱ n ∙ x ^ⁱ m) ≈⟨ sym (assoc _ _ _) ⟩
  x ∙ x ^ⁱ n ∙ x ^ⁱ m ∎

∙-^ⁱ-dist : ∀ x y n → (x ∙ y) ^ⁱ n ≈ x ^ⁱ n ∙ y ^ⁱ n
∙-^ⁱ-dist x y zero = sym (identityˡ ε)
∙-^ⁱ-dist x y (suc n) = begin
  x ∙ y ∙ ((x ∙ y) ^ⁱ n) ≈⟨ ∙-congˡ (∙-^ⁱ-dist x y n) ⟩
  x ∙ y ∙ (x ^ⁱ n ∙ y ^ⁱ n) ≈⟨ assoc _ _ _ ⟩
  x ∙ (y ∙ (x ^ⁱ n ∙ y ^ⁱ n)) ≈⟨ ∙-congˡ (comm _ _) ⟩
  x ∙ (x ^ⁱ n ∙ y ^ⁱ n ∙ y) ≈⟨ ∙-congˡ (assoc _ _ _) ⟩
  x ∙ (x ^ⁱ n ∙ (y ^ⁱ n ∙ y)) ≈⟨ ∙-congˡ (∙-congˡ (comm _ _)) ⟩
  x ∙ (x ^ⁱ n ∙ (y ∙ y ^ⁱ n)) ≈⟨ sym (assoc _ _ _) ⟩
  x ∙ (x ^ⁱ n) ∙ (y ∙ (y ^ⁱ n)) ∎

_^ᵇ⁺_ : C → 𝔹⁺ → C
x ^ᵇ⁺ 𝕓1ᵇ = x
x ^ᵇ⁺ (b 0ᵇ) = (x ∙ x) ^ᵇ⁺ b
x ^ᵇ⁺ (b 1ᵇ) = x ∙ (x ∙ x) ^ᵇ⁺ b

_^ᵇ_ : C → 𝔹 → C
x ^ᵇ 𝕓0ᵇ = ε
x ^ᵇ (+ b) = x ^ᵇ⁺ b

_^⁺_ : C → ℕ⁺ → C
x ^⁺ n = x ^ᵇ⁺ ⟦ n ⇑⟧⁺

_^_ : C → ℕ → C
x ^ n = x ^ᵇ ⟦ n ⇑⟧

x^n≈x^ⁱn : ∀ x n → x ^ n ≈ x ^ⁱ n
x^n≈x^ⁱn x n = begin
  x ^ n ≈⟨ loop x ⟦ n ⇑⟧ ⟩
  x ^ⁱ ⟦ ⟦ n ⇑⟧ ⇓⟧ ≡⟨ ≡-cong (λ t → x ^ⁱ t) (ℕ→𝔹→ℕ n) ⟩
  x ^ⁱ n ∎
  where
  even : ∀ x b → (x ∙ x) ^ᵇ⁺ b ≈ x ^ⁱ 2* ⟦ b ⇓⟧⁺
  loop⁺ : ∀ x b → x ^ᵇ⁺ b ≈ x ^ⁱ ⟦ b ⇓⟧⁺

  even x b = begin
    (x ∙ x) ^ᵇ⁺ b ≈⟨ loop⁺ (x ∙ x) b ⟩
    (x ∙ x) ^ⁱ ⟦ b ⇓⟧⁺ ≈⟨ ∙-^ⁱ-dist x x ⟦ b ⇓⟧⁺ ⟩
    x ^ⁱ ⟦ b ⇓⟧⁺ ∙ x ^ⁱ ⟦ b ⇓⟧⁺ ≈⟨ sym (^ⁱ-homo x ⟦ b ⇓⟧⁺ ⟦ b ⇓⟧⁺) ⟩
    x ^ⁱ 2* ⟦ b ⇓⟧⁺ ∎

  loop⁺ x 𝕓1ᵇ = sym (identityʳ x)
  loop⁺ x (b 0ᵇ) = even x b
  loop⁺ x (b 1ᵇ) = ∙-congˡ (even x b)

  loop : ∀ x b → x ^ᵇ b ≈ x ^ⁱ ⟦ b ⇓⟧
  loop x 𝕓0ᵇ = refl
  loop x (+ b) = loop⁺ x b

^-homo : ∀ x n m → x ^ (n + m) ≈ x ^ n ∙ x ^ m
^-homo x n m = begin
  x ^ (n + m)     ≈⟨ x^n≈x^ⁱn x (n + m) ⟩
  x ^ⁱ (n + m)    ≈⟨ ^ⁱ-homo x n m ⟩
  x ^ⁱ n ∙ x ^ⁱ m ≈⟨ ∙-cong (sym (x^n≈x^ⁱn x n)) (sym (x^n≈x^ⁱn x m)) ⟩
  x ^ n ∙ x ^ m   ∎

x^n≈x^⁺n : ∀ x n → x ^ ⟅ n ⇓⟆ ≈ x ^⁺ n
x^n≈x^⁺n x (ℕ+ n) = refl

^-^⁺-homo : ∀ x n m → x ^ (n + ⟅ m ⇓⟆) ≈ x ^ n ∙ x ^⁺ m
^-^⁺-homo x n (ℕ+ m) = ^-homo x n (suc m)


-- Andreas, 2019-07-15, issue #3901, requested by msuperdock
--
-- Allow function spaces  {A} → B  and  {{A}} → B.

postulate
  A B : Set
  foo : {{A}} → B
  bar : {A} → B

-- Original feature request:

open import Agda.Builtin.Unit using (⊤; tt)

data ⊥ : Set where

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

_≤_ : Nat → Nat → Set
zero ≤ _      = ⊤
suc m ≤ zero  = ⊥
suc m ≤ suc n = m ≤ n

data SList (bound : Nat) : Set where
  []    : SList bound
  scons : (head : Nat)
        → {head ≤ bound}       -- here: anonymous binding
        → (tail : SList head)
        → SList bound

xs : SList zero
xs = scons zero []


------------------------------------------------------------------------
-- The Agda standard library
--
-- Lists defined in terms of the reflexive-transitive closure, Star
------------------------------------------------------------------------

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

module Data.Star.List where

open import Data.Star.Nat
open import Data.Unit
open import Relation.Binary.Construct.Always using (Always)
open import Relation.Binary.Construct.Constant using (Const)
open import Relation.Binary.Construct.Closure.ReflexiveTransitive

-- Lists.

List : ∀ {a} → Set a → Set a
List A = Star (Const A) tt tt

-- Nil and cons.

[] : ∀ {a} {A : Set a} → List A
[] = ε

infixr 5 _∷_

_∷_ : ∀ {a} {A : Set a} → A → List A → List A
_∷_ = _◅_

-- The sum of the elements in a list containing natural numbers.

sum : List ℕ → ℕ
sum = fold (Star Always) _+_ zero


-- 2018-01-05, Jesper: having a `rewrite` after a `with` caused problems
-- because the patterns stripped by with-desugaring were not propagated
-- to the generated rewrite-clause. This should now be fixed.

open import Agda.Builtin.Equality

postulate
  lem : Set ≡ Set

simple-test : {A : Set₁} → A ≡ Set → Set₁
simple-test {A = A} refl with Set
simple-test {A = A} refl | _ rewrite lem = A

record ⊤ : Set where constructor tt

data G : Set → Set₁ where
  d : (A : Set) → G A → G A

postulate
  exists : (A : Set) → G A
  unique : (A : Set) (x : G A) → exists A ≡ x

test : (A : Set) → G A → ⊤
test _ (d A x) with unique A x
test _ (d A _) | refl rewrite refl {x = tt} = tt


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

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

import Cubical.Data.Empty as ⊥
open import Cubical.Data.Nat using (ℕ; zero; suc)
open import Cubical.Data.Bool.Base
open import Cubical.Relation.Nullary

private
  variable
    ℓ : Level
    A B : Type ℓ

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

toℕ : ∀ {n} → Fin n → ℕ
toℕ zero    = 0
toℕ (suc i) = suc (toℕ i)

fromℕ : (n : ℕ) → Fin (suc n)
fromℕ zero    = zero
fromℕ (suc n) = suc (fromℕ n)

¬Fin0 : ¬ Fin 0
¬Fin0 ()

_==_ : ∀ {n} → Fin n → Fin n → Bool
zero == zero   = true
zero == suc _  = false
suc _ == zero  = false
suc m == suc n = m == n

predFin : {n : ℕ} → Fin (suc (suc n)) → Fin (suc n)
predFin zero = zero
predFin (suc x) = x

foldrFin : ∀ {n} → (A → B → B) → B → (Fin n → A) → B
foldrFin {n = zero}  _ b _ = b
foldrFin {n = suc n} f b l = f (l zero) (foldrFin f b (l ∘ suc))

elim
  : ∀(P : ∀{k} → Fin k → Type ℓ)
  → (∀{k} → P {suc k} zero)
  → (∀{k} → {fn : Fin k} → P fn → P (suc fn))
  → {k : ℕ} → (fn : Fin k) → P fn

elim P fz fs {zero} = ⊥.rec ∘ ¬Fin0
elim P fz fs {suc k} zero = fz
elim P fz fs {suc k} (suc fj) = fs (elim P fz fs fj)

rec : ∀{k} → (a0 aS : A) → Fin k → A
rec a0 aS zero = a0
rec a0 aS (suc x) = aS


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

pattern plus-two n = suc (suc n)

f : Nat → Nat
f (plus-two n) = f n
f (suc zero) = plus-two zero
f zero = zero


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

open import HoTT
open import cohomology.Exactness
open import cohomology.Theory

module cohomology.Sn {i} (OT : OrdinaryTheory i) where

open OrdinaryTheory OT

C-Sphere-≠ : (n : ℤ) (m : ℕ) → (n ≠ ℕ-to-ℤ m)
  → C n (⊙Lift (⊙Sphere m)) == Lift-Unit-group
C-Sphere-≠ n O neq = C-dimension n neq
C-Sphere-≠ n (S m) neq =
  C n (⊙Lift (⊙Sphere (S m)))
    =⟨ ! $ ⊙Susp-⊙Lift (⊙Sphere m) |in-ctx C n ⟩
  C n (⊙Susp (⊙Lift (⊙Sphere m)))
    =⟨ ! (succ-pred n) |in-ctx (λ k → C k (⊙Susp (⊙Lift (⊙Sphere m)))) ⟩
  C (succ (pred n)) (⊙Susp (⊙Lift (⊙Sphere m)))
    =⟨ group-ua (C-Susp (pred n) (⊙Lift (⊙Sphere m))) ⟩
  C (pred n) (⊙Lift (⊙Sphere m))
    =⟨ C-Sphere-≠ (pred n) m (λ p → neq (pred-injective n (ℕ-to-ℤ (S m)) p)) ⟩
  Lift-Unit-group
    ∎

C-Sphere-diag : (m : ℕ) → C (ℕ-to-ℤ m) (⊙Lift (⊙Sphere m)) == C 0 (⊙Lift ⊙S⁰)
C-Sphere-diag O = idp
C-Sphere-diag (S m) =
  C (ℕ-to-ℤ (S m)) (⊙Lift (⊙Sphere (S m)))
    =⟨ ! $ ⊙Susp-⊙Lift (⊙Sphere m) |in-ctx C (ℕ-to-ℤ (S m)) ⟩
  C (ℕ-to-ℤ (S m)) (⊙Susp (⊙Lift (⊙Sphere m)))
    =⟨ group-ua (C-Susp (ℕ-to-ℤ m) (⊙Lift (⊙Sphere m))) ⟩
  C (ℕ-to-ℤ m) (⊙Lift (⊙Sphere m))
    =⟨ C-Sphere-diag m ⟩
  C 0 (⊙Lift ⊙S⁰)
    ∎


module Foundation.Semigroup where

open import Foundation.Primitive
open import Foundation.Equivalence
open import Agda.Primitive

record IsAssociative {a} {A : Set a} {ℓ} ⦃ _ : Equivalence A ℓ ⦄ (_∙_ : A → A → A) : ℞ a ⊔ ℓ where
  field
    associativity : ∀ x y z → ((x ∙ y) ∙ z) ≈ (x ∙ (y ∙ z))

open IsAssociative ⦃ … ⦄

record Semigroup {c} (A : Set c) ℓ : Set (c ⊔ ⟰ ℓ) where
  field
    ⦃ equivalence ⦄ : Equivalence A ℓ
    _∙_ : A → A → A
    isAssociative : IsAssociative _∙_

open Semigroup ⦃ … ⦄

record Monoid {a} (A : Set a) ℓ : Set (a ⊔ ⟰ ℓ) where
  field
    ⦃ semigroup ⦄ : Semigroup A ℓ
    ε : A
    left-identity : ∀ x → ε ∙ x ≈ x
    right-identity : ∀ x → x ∙ ε ≈ x

open Monoid ⦃ … ⦄

open import Relation.Binary.Core
open import Algebra.FunctionProperties.Core

PowerRightIdentity : ∀ {a ℓ} {A : Set a} → Rel A ℓ → ∀ {b} {B : Set b} → B → (B → A → A) → Set _
PowerRightIdentity _≈_ e _◃_ = ∀ x → (e ◃ x) ≈ x

PowerAssociative : ∀ {a b ℓ} {A : Set a} {B : Set b} → (A → A → Set ℓ) → (B → A → A) → (B → B → B) → Set _
PowerAssociative _≈_ _◃_ _∙_ = ∀ x a b → ((b ∙ a) ◃ x) ≈ (b ◃ (a ◃ x))

_over_ : ∀ {f} {F : Set f} {g} → (F → F → Set g) → ∀ {i} {I : Set i} {a} {A : Set a} → (A → I → F) → A → A → Set (i ⊔ g)
_*_ over f = λ x y → ∀ i → f x i * f y i

record IsMonoidTransformer {s ℓˢ} {S : Set s} (≈ˢ : Rel S ℓˢ) {m ℓᵐ} {M : Set m} (≈ᵐ : Rel M ℓᵐ) (∙ : Op₂ M) (ε : M) (◃ : M → S → S) : Set (s ⊔ ℓˢ ⊔ m ⊔ ℓᵐ) where
  field
    ◃-identity : PowerRightIdentity ≈ˢ ε ◃
    ≈ˢ-over-◃-⟶-≈ᵐ : ≈ˢ over ◃ ⇒ ≈ᵐ
    ≈ᵐ-to-≈ˢ-over-◃ : ≈ᵐ ⇒ ≈ˢ over ◃
    ◃-extracts-∙ : PowerAssociative ≈ˢ ◃ ∙

open IsMonoidTransformer ⦃ … ⦄

record MonoidTransformer {s} (S : Set s) ℓˢ {m} (M : Set m) ℓᵐ : Set (s ⊔ m ⊔ lsuc (ℓˢ ⊔ ℓᵐ)) where
  field
    ⦃ base ⦄ : Equivalence S ℓˢ
    ⦃ exponent ⦄ : Monoid M ℓᵐ

  infixl 6 _◃_
  field
    _◃_ : M → S → S
    instance isMonoidTransformer : IsMonoidTransformer _≈_ _≈_ _∙_ ε _◃_


module Structure.Groupoid.Functor where

open import Functional using (_on₂_)
open import Lang.Instance
import      Lvl
open import Logic.Predicate
open import Structure.Category
import      Structure.Category.Functor as Category
open import Structure.Function
open import Structure.Groupoid
import      Structure.Relator.Names as Names
open import Structure.Setoid
open import Syntax.Function
open import Type

private variable ℓ ℓₒ ℓₘ ℓₗₒ ℓₗₘ ℓᵣₒ ℓᵣₘ ℓₑ ℓₗₑ ℓᵣₑ : Lvl.Level
private variable Obj Objₗ Objᵣ : Type{ℓ}
private variable _⟶_ _⟶ₗ_ _⟶ᵣ_ : Objₗ → Objᵣ → Type{ℓ}

module _
  ⦃ morphism-equivₗ : ∀{x y : Objₗ} → Equiv{ℓₗₑ}(x ⟶ₗ y) ⦄
  ⦃ morphism-equivᵣ : ∀{x y : Objᵣ} → Equiv{ℓᵣₑ}(x ⟶ᵣ y) ⦄
  (Groupoidₗ : Groupoid(_⟶ₗ_))
  (Groupoidᵣ : Groupoid(_⟶ᵣ_))
  where

  -- A covariant functor.
  -- A mapping which transforms objects and morphisms from one category to another while "preserving" the groupoid structure.
  -- A homomorphism between groupoids.
  record Functor (F : Objₗ → Objᵣ) : Type{Lvl.of(Type.of(Groupoidₗ)) Lvl.⊔ Lvl.of(Type.of(Groupoidᵣ))} where
    constructor intro
    open Groupoid ⦃ … ⦄

    private instance _ = Groupoidₗ
    private instance _ = Groupoidᵣ

    field
      map : Names.Subrelation(_⟶ₗ_) ((_⟶ᵣ_) on₂ F)

    field
      ⦃ map-function ⦄     : ∀{x y} → Function(map{x}{y})
      ⦃ op-preserving ⦄    : ∀{x y z : Objₗ}{f : y ⟶ₗ z}{g : x ⟶ₗ y} → (map(f ∘ g) ≡ map(f) ∘ map(g))
      ⦃ inv-preserving ⦄   : ∀{x y : Objₗ}{f : x ⟶ₗ y} → (map(inv f) ≡ inv(map f))
      ⦃ id-preserving ⦄    : ∀{x : Objₗ} → (map(id {x = x}) ≡ id)

    categoryFunctor : Category.Functor(category ⦃ r = Groupoidₗ ⦄)(category ⦃ r = Groupoidᵣ ⦄) (F)
    Category.Functor.map           categoryFunctor = map
    Category.Functor.map-function  categoryFunctor = map-function
    Category.Functor.op-preserving categoryFunctor = op-preserving
    Category.Functor.id-preserving categoryFunctor = id-preserving
    open Category.Functor(categoryFunctor) public hiding (map ; map-function ; op-preserving ; id-preserving)

module _
  ⦃ morphism-equiv : ∀{x y : Obj} → Equiv{ℓₑ}(x ⟶ y) ⦄
  (Groupoid : Groupoid(_⟶_))
  where

  Endofunctor = Functor(Groupoid)(Groupoid)
  module Endofunctor = Functor{Groupoidₗ = Groupoid}{Groupoidᵣ = Groupoid}

_→ᶠᵘⁿᶜᵗᵒʳ_ : GroupoidObject{ℓₗₒ}{ℓₗₘ}{ℓₗₑ} → GroupoidObject{ℓᵣₒ}{ℓᵣₘ}{ℓᵣₑ} → Type
grpₗ →ᶠᵘⁿᶜᵗᵒʳ grpᵣ = ∃(Functor (GroupoidObject.groupoid(grpₗ)) ((GroupoidObject.groupoid(grpᵣ))))

⟲ᶠᵘⁿᶜᵗᵒʳ_ : GroupoidObject{ℓₒ}{ℓₘ}{ℓₑ} → Type
⟲ᶠᵘⁿᶜᵗᵒʳ grp = grp →ᶠᵘⁿᶜᵗᵒʳ grp


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

module FinEquivTypeEquiv where

-- The goal is to establish that finite sets and equivalences form a
-- commutative semiring.

import Level using (zero)

open import Data.Nat using (ℕ; _+_; _*_)
open import Data.Fin using (Fin)

open import Relation.Binary using (IsEquivalence)
open import Algebra using (CommutativeSemiring)
open import Algebra.Structures
  using (IsSemigroup; IsCommutativeMonoid; IsCommutativeSemiring)

open import Equiv using (_≃_; id≃; sym≃; trans≃; _●_; _⊎≃_; _×≃_)
open import TypeEquiv
  using (assocl₊equiv; unite₊equiv; unite₊′equiv; swap₊equiv;
         unite⋆equiv; unite⋆′equiv; swap⋆equiv; assocl⋆equiv;
         distzequiv; distzrequiv; distequiv; distlequiv)

open import FinEquivPlusTimes using (F0≃⊥; module Plus; Fin1≃⊤; module Times)
open Plus using (+≃⊎; ⊎≃+)
open Times using (*≃×; ×≃*)

------------------------------------------------------------------------------
-- This is the relation we are interested in showing is a commutative
-- semiring.

_fin≃_ : (m n : ℕ) → Set
m fin≃ n = Fin m ≃ Fin n

------------------------------------------------------------------------------
-- Additive monoid

module PlusE where

  infix 9 _+F_

  -- additive monoid equivalences

  -- unite+

  unite+ : {m : ℕ} → Fin (0 + m) ≃ Fin m
  unite+ = unite₊equiv ● F0≃⊥ ⊎≃ id≃ ● +≃⊎

  -- and on the other side as well

  unite+r : {m : ℕ} → Fin (m + 0) ≃ Fin m
  unite+r = unite₊′equiv ● id≃ ⊎≃ F0≃⊥ ● +≃⊎

  -- swap₊

  swap+ : {m n : ℕ} → Fin (m + n) ≃ Fin (n + m)
  swap+ {m} = ⊎≃+ ● swap₊equiv ● +≃⊎ {m}

  -- associativity

  assocl+ : {m n o : ℕ} → Fin (m + (n + o)) ≃ Fin ((m + n) + o)
  assocl+ {m} = ⊎≃+ ● ⊎≃+ ⊎≃ id≃ ● assocl₊equiv ● id≃ ⊎≃ +≃⊎ ● +≃⊎ {m}

  -- congruence

  _+F_ : {m n o p : ℕ} → (Fin m ≃ Fin n) → (Fin o ≃ Fin p) →
              Fin (m + o) ≃ Fin (n + p)
  Fm≃Fn +F Fo≃Fp = ⊎≃+ ● Fm≃Fn ⊎≃ Fo≃Fp ● +≃⊎

  uniti+ : {m : ℕ} → Fin m ≃ Fin (0 + m)
  uniti+ = sym≃ unite+

  uniti+r : {m : ℕ} → Fin m ≃ Fin (m + 0)
  uniti+r = sym≃ unite+r

  assocr+ : {m n o : ℕ} → Fin ((m + n) + o) ≃ Fin (m + (n + o))
  assocr+ {m} = sym≃ (assocl+ {m})

  sswap+ : {m n : ℕ} → Fin (n + m) ≃ Fin (m + n)
  sswap+ {m} {n} = sym≃ (swap+ {m} {n})

-----------------------------------------------------------------------------
-- Multiplicative monoid

module TimesE where

  infixl 7 _*F_

  -- multiplicative monoid equivalences

  -- unite*

  unite* : {m : ℕ} → Fin (1 * m) ≃ Fin m
  unite* {m} = unite⋆equiv ● Fin1≃⊤ ×≃ id≃ ● *≃×

  -- unite*r

  unite*r : {m : ℕ} → Fin (m * 1) ≃ Fin m
  unite*r {m} = unite⋆′equiv ● id≃ ×≃ Fin1≃⊤ ● *≃×

  -- swap*

  swap* : {m n : ℕ} → Fin (m * n) ≃ Fin (n * m)
  swap* {m} {n} = ×≃* ● swap⋆equiv ● *≃× {m}

  -- associativity

  assocl* : {m n o : ℕ} → Fin (m * (n * o)) ≃ Fin ((m * n) * o)
  assocl* {m} {n} {o} = ×≃* ● ×≃* ×≃ id≃ ● assocl⋆equiv ● id≃ ×≃ *≃× ● *≃× {m}

  -- congruence

  _*F_ : {m n o p : ℕ} → Fin m ≃ Fin n → Fin o ≃ Fin p →
              Fin (m * o) ≃ Fin (n * p)
  Fm≃Fn *F Fo≃Fp = ×≃* ● Fm≃Fn ×≃ Fo≃Fp ● *≃×

  uniti* : {m : ℕ} → Fin m ≃ Fin (1 * m)
  uniti* = sym≃ unite*

  uniti*r : {m : ℕ} → Fin m ≃ Fin (m * 1)
  uniti*r = sym≃ unite*r

  assocr* : {m n o : ℕ} → Fin ((m * n) * o) ≃ Fin (m * (n * o))
  assocr* {m} {n} {o} = sym≃ (assocl* {m})

  sswap* : {m n : ℕ} → Fin (n * m) ≃ Fin (m * n)
  sswap* {m} {n} = sym≃ (swap* {m} {n})

------------------------------------------------------------------------------
-- Distributivity of multiplication over addition

module PlusTimesE where

  -- now that we have two monoids, we need to check distributivity

  -- note that the sequence below is "logically right", *but* could be
  -- replaced by id≃ !
  distz : {m : ℕ} → Fin (0 * m) ≃ Fin 0
  distz {m} = sym≃ F0≃⊥ ● distzequiv ● F0≃⊥ ×≃ id≃ ● *≃× {0} {m}
    where open Times

  distzr : {m : ℕ} → Fin (m * 0) ≃ Fin 0
  distzr {m} = sym≃ F0≃⊥ ● distzrequiv ● id≃ ×≃ F0≃⊥ ● *≃× {m} {0}
    where open Times

  dist : {m n o : ℕ} → Fin ((m + n) * o) ≃ Fin ((m * o) + (n * o))
  dist {m} {n} {o} = ⊎≃+ {m * o} {n * o} ● ×≃* {m} ⊎≃ ×≃* ● distequiv ● +≃⊎ ×≃ id≃ ● *≃×
    where open Times
          open Plus

  distl : {m n o : ℕ} → Fin (m * (n + o)) ≃ Fin ((m * n) + (m * o))
  distl {m} {n} {o} = ⊎≃+ {m * n} {m * o} ● ×≃* {m} ⊎≃ ×≃* ● distlequiv ● id≃ ×≃ +≃⊎ ● *≃×
    where open Plus
          open Times

  factorzr : {n : ℕ} → Fin 0 ≃ Fin (n * 0)
  factorzr {n} = sym≃ (distzr {n})

  factorz : {m : ℕ} → Fin 0 ≃ Fin (0 * m)
  factorz {m} = sym≃ (distz {m})

  factor : {m n o : ℕ} → Fin ((m * o) + (n * o)) ≃ Fin ((m + n) * o)
  factor {m} = sym≃ (dist {m})

  factorl : {m n o : ℕ} → Fin ((m * n) + (m * o)) ≃ Fin (m * (n + o))
  factorl {m} = sym≃ (distl {m})

------------------------------------------------------------------------------
-- Summarizing... we have a commutative semiring structure

fin≃IsEquiv : IsEquivalence _fin≃_
fin≃IsEquiv = record {
  refl = id≃ ;
  sym = sym≃ ;
  trans = trans≃
  }

finPlusIsSG : IsSemigroup _fin≃_ _+_
finPlusIsSG = record {
  isEquivalence = fin≃IsEquiv ;
  assoc = λ m n o → PlusE.assocr+ {m} {n} {o} ;
  ∙-cong = PlusE._+F_
  }

finTimesIsSG : IsSemigroup _fin≃_ _*_
finTimesIsSG = record {
  isEquivalence = fin≃IsEquiv ;
  assoc = λ m n o → TimesE.assocr* {m} {n} {o} ;
  ∙-cong = TimesE._*F_
  }

finPlusIsCM : IsCommutativeMonoid _fin≃_ _+_ 0
finPlusIsCM = record {
  isSemigroup = finPlusIsSG ;
  identityˡ = λ m → id≃ ;
  comm = λ m n → PlusE.swap+ {m} {n}
  }

finTimesIsCM : IsCommutativeMonoid _fin≃_ _*_ 1
finTimesIsCM = record {
  isSemigroup = finTimesIsSG ;
  identityˡ = λ m → TimesE.unite* {m} ;
  comm = λ m n → TimesE.swap* {m} {n}
  }

finIsCSR : IsCommutativeSemiring _fin≃_ _+_ _*_ 0 1
finIsCSR = record {
  +-isCommutativeMonoid = finPlusIsCM ;
  *-isCommutativeMonoid = finTimesIsCM ;
  distribʳ = λ o m n → PlusTimesE.dist {m} {n} {o} ;
  zeroˡ = λ m → PlusTimesE.distz {m}
  }

finCSR : CommutativeSemiring Level.zero Level.zero
finCSR = record {
  Carrier = ℕ ;
  _≈_ = _fin≃_ ;
  _+_ = _+_ ;
  _*_ = _*_ ;
  0# = 0 ;
  1# = 1 ;
  isCommutativeSemiring = finIsCSR
  }

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


open import Data.Product using ( ∃ ; _×_ ; _,_ )
open import Relation.Binary.PropositionalEquality using
  ( _≡_ ; refl ; trans ; cong₂ )
open import Relation.Unary using ( ∅ ; _∪_ )
open import Web.Semantic.DL.Signature using ( Signature ; CN ; RN )
open import Web.Semantic.Util using ( id ; _∘_ ; Subset ; ⁅_⁆ )

module Web.Semantic.DL.ABox where

infixr 5 _∼_ _∈₁_ _∈₂_
infixr 4 _,_

data ABox (Σ : Signature) (X : Set) : Set where
  ε : ABox Σ X
  _,_ : (A B : ABox Σ X) → ABox Σ X
  _∼_ : (x y : X) → ABox Σ X
  _∈₁_ : (x : X) → (c : CN Σ) → ABox Σ X
  _∈₂_ : (xy : X × X) → (r : RN Σ) → ABox Σ X

⟨ABox⟩ : ∀ {Σ X Y} → (X → Y) → ABox Σ X → ABox Σ Y
⟨ABox⟩ f ε              = ε
⟨ABox⟩ f (A , B)        = (⟨ABox⟩ f A , ⟨ABox⟩ f B)
⟨ABox⟩ f (x ∼ y)        = (f x ∼ f y)
⟨ABox⟩ f (x ∈₁ C)       = (f x ∈₁ C)
⟨ABox⟩ f ((x , y) ∈₂ R) = ((f x , f y) ∈₂ R)

⟨ABox⟩-resp-id : ∀ {Σ X} (A : ABox Σ X) → (⟨ABox⟩ id A ≡ A)
⟨ABox⟩-resp-id ε = refl
⟨ABox⟩-resp-id (A , B) = cong₂ _,_ (⟨ABox⟩-resp-id A) (⟨ABox⟩-resp-id B)
⟨ABox⟩-resp-id (x ∼ y) = refl
⟨ABox⟩-resp-id (x ∈₁ c) = refl
⟨ABox⟩-resp-id ((x , y) ∈₂ r) = refl

⟨ABox⟩-resp-∘ : ∀ {Σ X Y Z} (f : Y → Z) (g : X → Y) (A : ABox Σ X) → (⟨ABox⟩ f (⟨ABox⟩ g A) ≡ ⟨ABox⟩ (f ∘ g) A)
⟨ABox⟩-resp-∘ f g ε = refl
⟨ABox⟩-resp-∘ f g (A , B) = cong₂ _,_ (⟨ABox⟩-resp-∘ f g A) (⟨ABox⟩-resp-∘ f g B)
⟨ABox⟩-resp-∘ f g (x ∼ y) = refl
⟨ABox⟩-resp-∘ f g (x ∈₁ c) = refl
⟨ABox⟩-resp-∘ f g ((x , y) ∈₂ r) = refl

⟨ABox⟩-resp-∘² : ∀ {Σ W X Y Z} (f : Y → Z) (g : X → Y) (h : W → X) →
  ∀ (A : ABox Σ W) → (⟨ABox⟩ f (⟨ABox⟩ g (⟨ABox⟩ h A)) ≡ ⟨ABox⟩ (f ∘ g ∘ h) A)
⟨ABox⟩-resp-∘² f g h A =
  trans (⟨ABox⟩-resp-∘ f g (⟨ABox⟩ h A)) (⟨ABox⟩-resp-∘ (f ∘ g) h A)

Assertions : ∀ {Σ X} → ABox Σ X → Subset (ABox Σ X)
Assertions ε         = ∅
Assertions (A , B)   = (Assertions A) ∪ (Assertions B)
Assertions (x ∼ y)   = ⁅ x ∼ y ⁆
Assertions (x ∈₁ c)  = ⁅ x ∈₁ c ⁆
Assertions (xy ∈₂ r) = ⁅ xy ∈₂ r ⁆


open import Common.Reflect
open import Common.Prelude
open import Common.Equality

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

_<$>_ : ∀ {A B} → (A → B) → Maybe A → Maybe B
f <$> just x  = just (f x)
f <$> nothing = nothing

_==_ = primQNameEquality

-- This is awkward!
awkwardUnquoteNat : Term → Maybe Nat
awkwardUnquoteNat (con z []) =
  if z == quote Nat.zero
  then just 0
  else nothing
awkwardUnquoteNat (con s (arg _ n ∷ [])) =
  if s == quote Nat.suc
  then suc <$> awkwardUnquoteNat n
  else nothing
awkwardUnquoteNat v = nothing

testAwkward : just 10 ≡ awkwardUnquoteNat (quoteTerm 10)
testAwkward = refl

-- This is nicer!
pattern `zero  = con (quote Nat.zero) []
pattern `suc n = con (quote Nat.suc) (arg _ n ∷ [])

unquoteNat : Term → Maybe Nat
unquoteNat `zero    = just zero
unquoteNat (`suc n) = suc <$> unquoteNat n
unquoteNat _        = nothing

test : just 10 ≡ unquoteNat (quoteTerm 10)
test = refl


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

open import Cubical.Foundations.Prelude

open import Cubical.Algebra.CommRing.Base
open import Cubical.Algebra.CommRing.Ideal using (IdealsIn; Ideal→CommIdeal)
open import Cubical.Algebra.Ring.Kernel using () renaming (kernelIdeal to ringKernelIdeal)

private
  variable
    ℓ : Level

-- If R and S were implicit, their ·Comm component could (almost?) never be inferred.
kernelIdeal : (R S : CommRing ℓ) (f : CommRingHom R S) → IdealsIn R
kernelIdeal _ _ f = Ideal→CommIdeal (ringKernelIdeal f)


module Prelude.Product where

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

open _×_ public


module Categories.2-Category.Categories where

open import Level
open import Data.Product

open import Categories.Category
open import Categories.2-Category
open import Categories.Functor using (module Functor) renaming (id to idF; _∘_ to _∘F_)
open import Categories.Functor.Constant
open import Categories.FunctorCategory
open import Categories.Bifunctor using (Bifunctor)
open import Categories.NaturalTransformation
open import Categories.Product using (Product)

Categories : ∀ o ℓ e → 2-Category (suc (o ⊔ ℓ ⊔ e)) (o ⊔ ℓ ⊔ e) (o ⊔ ℓ ⊔ e) (o ⊔ e)
Categories o ℓ e = record
  { Obj = Category o ℓ e
  ; _⇒_ = Functors
  ; id = λ {A} → Constant {D = Functors A A} idF
  ; —∘— = my-∘
  ; assoc = {!!}
  ; identityˡ = λ {A B} η → Heterogeneous.≡⇒∼ {C = Functors A B} {f = proj₂ η ∘₁ id} {proj₂ η} (Category.identityʳ B)
  ; identityʳ = λ {A B f g} η → Heterogeneous.≡⇒∼ {_} {_} {_} {C = Functors A B} {proj₁ f} {proj₁ g} {f = record {
                                                                                η =
                                                                                λ X →
                                                                                Category._∘_ B (Functor.F₁ (proj₁ g) (Category.id A))
                                                                                (NaturalTransformation.η (proj₁ η) X);
                                                                                commute = λ {a} {b} h → let open Category.HomReasoning B in begin
                    B [ B [ Functor.F₁ (proj₁ g) (Category.id A) ∘ NaturalTransformation.η (proj₁ η) b ] ∘ {!.Categories.NaturalTransformation.Core.F.F₁ (proj₁ f) (proj₁ g) h!} ]
                  ↓⟨ {!!} ⟩
                    B [ Functor.F₁ {!!} {!!} ∘ B [ Functor.F₁ (proj₁ g) (Category.id A) ∘ NaturalTransformation.η (proj₁ η) a ] ]
                  ∎ }
         } {proj₁ {_} {_} {_} {_} η} (Category.Equiv.trans B (Category.∘-resp-≡ˡ B (Functor.identity (proj₁ g))) (Category.identityˡ B))
  }
  where
  my-∘ : {A B C : Category o ℓ e} → Bifunctor (Functors B C) (Functors A B) (Functors A C)
  my-∘ {A} {B} {C} = record
    { F₀ = uncurry′ _∘F_
    ; F₁ = uncurry′ _∘₀_
    ; identity = λ {Fs} → Category.Equiv.trans C (Category.identityʳ C) (Functor.identity (proj₁ Fs))
    ; homomorphism = λ {_ _ _ f g} → Category.Equiv.sym C (interchange {α = proj₁ g} {proj₂ g} {proj₁ f} {proj₂ f})
    ; F-resp-≡ = λ {_ _ f g} → my-resp {f = f} {g}
    }
    where
    PF = Product (Functors B C) (Functors A B)

    .my-resp : ∀ {F G} {f g : PF [ F , G ]} → PF [ f ≡ g ] → Functors A C [ uncurry′ _∘₀_ f ≡ uncurry _∘₀_ g ]
    my-resp {f = f₁ , f₂} {g₁ , g₂} (f₁≡g₁ , f₂≡g₂) = ∘₀-resp-≡ {f = f₁} {g₁} {f₂} {g₂} f₁≡g₁ f₂≡g₂


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

test₁ : (n : Nat) → Nat
test₁ n with zero
... | x = {!x!}

data Tree : Set where
  leaf : Tree
  node : Tree → Tree → Tree

test₂ : (n : Tree) → Tree
test₂ n₁ with leaf
... | n = {!n!}


{-# OPTIONS --without-K #-}
module Computability.Function where

open import Computability.Prelude
import Function

variable
  l₀ l₁ : Level

Injective : {A : Set l₀}{B : Set l₁} → (A → B) → Set _
Injective = Function.Injective _≡_ _≡_

Surjective : {A : Set l₀}{B : Set l₁} → (A → B) → Set _
Surjective {A = A} {B = B} = Function.Surjective {A = A} {B = B} _≡_ _≡_

Bijective : {A : Set l₀}{B : Set l₁} → (A → B) → Set _
Bijective = Function.Bijective _≡_ _≡_


module Nats.Multiply.Distrib where

open import Nats
open import Equality
open import Function

open import Nats.Multiply.Comm
open import Nats.Add.Assoc
open import Nats.Add.Comm

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

private

  a*1+b=a+a*b : ∀ a b → a * suc b ≡ a + a * b
  a*1+b=a+a*b a b
    rewrite nat-multiply-comm a $ suc b
          | nat-multiply-comm a b
            = refl

  a*c+b*c=/a+b/*c : ∀ a b c → a * c + b * c ≡ (a + b) * c
  a*c+b*c=/a+b/*c a b    zero
    rewrite nat-multiply-comm a 0
          | nat-multiply-comm b 0
          | nat-multiply-comm (a + b) 0
            = refl
  a*c+b*c=/a+b/*c a b sc@(suc c)
    rewrite nat-add-comm a b
          | a*1+b=a+a*b a c
          | nat-add-assoc a (a * c) (b * sc)
          | nat-add-comm a $ a * c + b * sc
          | a*1+b=a+a*b b c
          | nat-multiply-comm (b + a) sc
          | nat-add-assoc b a $ c * (b + a)
          | nat-add-comm a $ c * (b + a)
          | sym $ nat-add-assoc b (c * (b + a)) a
          | nat-multiply-comm c $ b + a
          | sym $ a*c+b*c=/a+b/*c b a c
          | sym $ nat-add-assoc (a * c) b (b * c)
          | nat-add-comm (b * c) (a * c)
          | sym $ nat-add-assoc b (b * c) (a * c)
          | sym $ nat-add-assoc b (a * c) (b * c)
          | nat-add-comm b $ a * c
            = refl

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

nat-multiply-distrib : ∀ a b c → a * c + b * c ≡ (a + b) * c
nat-multiply-distrib = a*c+b*c=/a+b/*c


module Numeral.Natural.Function.GreatestCommonDivisor.Extended where

import Lvl
open import Data
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Logic.Propositional
open import Numeral.Integer as ℤ
open import Numeral.Integer.Oper
open import Numeral.Integer.Proofs hiding (_≤_)
open import Numeral.Natural as ℕ
open import Numeral.Natural.Function.GreatestCommonDivisor
import      Numeral.Natural.Oper as ℕ
open import Numeral.Natural.Oper.FlooredDivision
open import Numeral.Natural.Oper.Modulo
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Classical
open import Syntax.Number
open import Type

-- TODO: Does the same algorithm work in the naturals? https://math.stackexchange.com/questions/237372/finding-positive-b%C3%A9zout-coefficients https://math.stackexchange.com/questions/1230224/positive-solutions-of-893x-2432y-19?rq=1
gcdExt : ℕ → ℕ → (ℕ ⨯ ℤ ⨯ ℤ)
gcdExt a b = gcdFold(\{a (𝐒 b) _ (succ min) _ (x , y) → (y , (x − ((+ₙ(a ⌊/⌋ ℕ.𝐒(b))) ⋅ y)))}) (\_ _ _ _ _ → Tuple.swap) (1 , 0) a b

open import Logic.IntroInstances
open import Logic.Predicate
open import Numeral.Natural.Inductions
open import Numeral.Natural.Oper.Proofs
open import Numeral.Natural.Oper.DivMod.Proofs
open import Numeral.Natural.Oper.Modulo.Proofs
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals
open import Relator.Equals.Proofs.Equiv
open import Structure.Function
open import Structure.Function.Domain
open import Structure.Function.Multi
open import Structure.Operator
open import Structure.Operator.Proofs.Util
open import Structure.Operator.Properties
open import Syntax.Function
open import Syntax.Transitivity

private variable a b d : ℕ

gcd-gcdExt-equal : (gcd a b ≡ Tuple.left(gcdExt a b))
gcd-gcdExt-equal {a}{b} = Gcd-unique {a}{b} Gcd-gcd Gcd-gcdFold

-- Also called: Bézout's identity, extended Euclid's algorithm.
gcd-linearCombination-existence : ∃{Obj = ℤ ⨯ ℤ}(\{(x , y) → (((+ₙ a) ⋅ x) + ((+ₙ b) ⋅ y) ≡ +ₙ(gcd a b))})
gcd-linearCombination-existence {a}{b} = [ℕ]-strong-induction {φ = b ↦ ∀{a} → ∃{Obj = ℤ ⨯ ℤ}(\{(x , y) → (((+ₙ a) ⋅ x) + ((+ₙ b) ⋅ y) ≡ +ₙ(gcd a b))})} base step {b}{a} where
  base : ∀{a} → ∃{Obj = ℤ ⨯ ℤ}(\{(x , y) → (((+ₙ a) ⋅ x) + (0 ⋅ y) ≡ +ₙ(gcd a 0))})
  ∃.witness (base {a})     = (1 , 0)
  ∃.proof   (base {ℕ.𝟎})   = [≡]-intro
  ∃.proof   (base {ℕ.𝐒 a}) = [≡]-intro

  step : ∀{i} → (∀{j} → (j ≤ i) → ∀{a} → ∃{Obj = ℤ ⨯ ℤ}(\{(x , y) → (((+ₙ a) ⋅ x) + ((+ₙ j) ⋅ y) ≡ +ₙ(gcd a j))})) → ∀{a} → ∃{Obj = ℤ ⨯ ℤ}(\{(x , y) → (((+ₙ a) ⋅ x) + ((+𝐒ₙ i) ⋅ y) ≡ +ₙ(gcd a (ℕ.𝐒(i))))})
  ∃.witness (step {i} prev {a}) with [≥]-or-[<] {a}{ℕ.𝐒(i)}
  ... | [∨]-introₗ ia with [∃]-intro (x , y) ← prev{a mod ℕ.𝐒(i)} ([≤]-without-[𝐒] (mod-maxᵣ {a = a})) {ℕ.𝐒(i)} = (y , ((x − ((+ₙ(a ⌊/⌋ ℕ.𝐒(i))) ⋅ y))))
  ... | [∨]-introᵣ (succ ai) with [∃]-intro (x , y) ← prev{a} ai {ℕ.𝐒(i)} = (y , x)
  ∃.proof (step {i} prev {a}) with [≥]-or-[<] {a}{ℕ.𝐒(i)}
  ... | [∨]-introₗ ia with [∃]-intro (x , y) ⦃ p ⦄ ← prev{a mod ℕ.𝐒(i)} ([≤]-without-[𝐒] (mod-maxᵣ {a = a})) {ℕ.𝐒(i)} =
    ((+ₙ a) ⋅ y) + ((+𝐒ₙ i) ⋅ (x − ((+ₙ(a ⌊/⌋ ℕ.𝐒(i))) ⋅ y)))             🝖[ _≡_ ]-[ congruence₂ᵣ(_+_)((+ₙ a) ⋅ y) (distributivityₗ(_⋅_)(_−_) {+𝐒ₙ i}{x}{(+ₙ(a ⌊/⌋ ℕ.𝐒(i))) ⋅ y}) ]
    ((+ₙ a) ⋅ y) + (((+𝐒ₙ i) ⋅ x) − ((+𝐒ₙ i) ⋅ ((+ₙ(a ⌊/⌋ ℕ.𝐒(i))) ⋅ y))) 🝖[ _≡_ ]-[ congruence₂ᵣ(_+_)((+ₙ a) ⋅ y) (congruence₂ᵣ(_−_)((+𝐒ₙ i) ⋅ x) p1) ]
    ((+ₙ a) ⋅ y) + (((+𝐒ₙ i) ⋅ x) − ((+ₙ(a ℕ.−₀ (a mod ℕ.𝐒(i)))) ⋅ y))    🝖[ _≡_ ]-[ One.commuteₗ-assocᵣ{a = (+ₙ a) ⋅ y}{b = (+𝐒ₙ i) ⋅ x} ]
    ((+𝐒ₙ i) ⋅ x) + (((+ₙ a) ⋅ y) − ((+ₙ(a ℕ.−₀ (a mod ℕ.𝐒(i)))) ⋅ y))    🝖[ _≡_ ]-[ congruence₂ᵣ(_+_)((+𝐒ₙ i) ⋅ x) (distributivityᵣ(_⋅_)(_−_) {+ₙ a}{_}{y}) ]-sym
    ((+𝐒ₙ i) ⋅ x) + (((+ₙ a) − (+ₙ(a ℕ.−₀ (a mod ℕ.𝐒(i))))) ⋅ y)          🝖[ _≡_ ]-[ congruence₂ᵣ(_+_)((+𝐒ₙ i) ⋅ x) (congruence₂ₗ(_⋅_)(y) p2) ]
    ((+𝐒ₙ i) ⋅ x) + ((+ₙ(a mod ℕ.𝐒(i))) ⋅ y)                              🝖[ _≡_ ]-[ p ]
    +ₙ(gcd (ℕ.𝐒(i)) (a mod ℕ.𝐒(i)))                                       🝖-end
    where
      p0 =
        (ℕ.𝐒 i) ℕ.⋅ (a ⌊/⌋ ℕ.𝐒(i)) 🝖[ _≡_ ]-[ commutativity(ℕ._⋅_) {ℕ.𝐒 i}{a ⌊/⌋ ℕ.𝐒(i)} ]
        (a ⌊/⌋ ℕ.𝐒(i)) ℕ.⋅ (ℕ.𝐒 i) 🝖[ _≡_ ]-[ OneTypeTwoOp.moveᵣ-to-invOp {b = a mod ℕ.𝐒(i)}{c = a} (([⌊/⌋][mod]-is-division-with-remainder {y = i})) ]
        a ℕ.−₀ (a mod ℕ.𝐒(i))      🝖-end

      p1 =
        (+𝐒ₙ i) ⋅ ((+ₙ(a ⌊/⌋ ℕ.𝐒(i))) ⋅ y)     🝖[ _≡_ ]-[ associativity(_⋅_) {+𝐒ₙ i} ]-sym
        ((+𝐒ₙ i) ⋅ (+ₙ(a ⌊/⌋ ℕ.𝐒(i)))) ⋅ y     🝖[ _≡_ ]-[]
        ((+ₙ(ℕ.𝐒 i)) ⋅ (+ₙ(a ⌊/⌋ ℕ.𝐒(i)))) ⋅ y 🝖[ _≡_ ]-[ congruence₂ₗ(_⋅_)(y) (preserving₂(+ₙ_)(ℕ._⋅_)(_⋅_) {ℕ.𝐒 i}) ]-sym
        (+ₙ((ℕ.𝐒 i) ℕ.⋅ (a ⌊/⌋ ℕ.𝐒(i)))) ⋅ y   🝖[ _≡_ ]-[ congruence₂ₗ(_⋅_)(y) (congruence₁(+ₙ_) p0) ]
        (+ₙ(a ℕ.−₀ (a mod ℕ.𝐒(i)))) ⋅ y        🝖-end

      p2 =
        (+ₙ a) − (+ₙ(a ℕ.−₀ (a mod ℕ.𝐒(i))))          🝖[ _≡_ ]-[ congruence₂ᵣ(_−_)(+ₙ a) ([+ₙ][−₀][−]-preserving (mod-maxₗ {a}{ℕ.𝐒(i)})) ]
        (+ₙ a) − ((+ₙ a) − (+ₙ(a mod ℕ.𝐒(i))))        🝖[ _≡_ ]-[ congruence₂ᵣ(_+_)(+ₙ a) (preserving₂(−_)(_+_)(_+_) {+ₙ a}{−(+ₙ(a mod ℕ.𝐒(i)))}) ]
        (+ₙ a) + ((−(+ₙ a)) − (−(+ₙ(a mod ℕ.𝐒(i)))))  🝖[ _≡_ ]-[ associativity(_+_) {+ₙ a}{−(+ₙ a)} ]-sym
        ((+ₙ a) − (+ₙ a)) − (−(+ₙ(a mod ℕ.𝐒(i))))     🝖[ _≡_ ]-[ congruence₂(_+_) (inverseFunctionᵣ(_+_)(−_) {+ₙ a}) (involution(−_)) ]
        0 + (+ₙ(a mod ℕ.𝐒(i)))                        🝖[ _≡_ ]-[ identityₗ(_+_)(0) ]
        +ₙ(a mod ℕ.𝐒(i))                              🝖[ _≡_ ]-end
  ... | [∨]-introᵣ (succ ai) with [∃]-intro (x , y) ⦃ p ⦄ ← prev{a} ai {ℕ.𝐒(i)} = commutativity(_+_) {(+ₙ a) ⋅ y}{(+ₙ ℕ.𝐒(i)) ⋅ x} 🝖 p


-- Andreas, 2017-06-20, issue #2613, reported by Jonathan Prieto.
-- Regression introduced by fix of #2458 (which is obsolete since #2403)

module _ where

open import Agda.Builtin.Nat

module Prop' (n : Nat) where

  data Prop' : Set where
    _∧_ _∨_ : Prop' → Prop' → Prop'

open Prop' zero

data DView : Prop' → Set where
  case₁ : (a b c : Prop') → DView ((a ∨ b) ∧ c)
  case₂ : (a : Prop')     → DView a

dView : (p : Prop') → DView p
dView ((a ∨ b) ∧ c) = case₁  _ _ _
dView a             = case₂ _

dist-∧ : Prop' → Prop'
dist-∧ p with dView p
dist-∧ .((a ∨ b) ∧ c) | case₁ a b c = dist-∧ (a ∧ c)
dist-∧ a              | case₂ .a = a

-- WAS:
-- Termination checking failed for the following functions:
--   dist-∧
-- Problematic calls:
--   dist-∧ (a ∧ c)

-- Should succeed.


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

module Categories.Diagram.End.Properties where

open import Level
open import Data.Product using (Σ; _,_)
open import Function using (_$_)

open import Categories.Category
open import Categories.Category.Product
open import Categories.Category.Construction.Functors
open import Categories.Functor
open import Categories.Functor.Bifunctor
open import Categories.NaturalTransformation
open import Categories.NaturalTransformation.Dinatural
open import Categories.Diagram.End as ∫

import Categories.Morphism.Reasoning as MR

private
  variable
    o ℓ e : Level
    C D E : Category o ℓ e

module _ {C : Category o ℓ e}
         (F : Functor E (Functors (Product (Category.op C) C) D)) where
  private
    module C = Category C
    module D = Category D
    module E = Category E
    module NT = NaturalTransformation
  open D
  open HomReasoning

  open MR D
  open Functor F
  open End hiding (E)
  open NT using (η)

  EndF : (∀ X → End (F₀ X)) → Functor E D
  EndF end = record
    { F₀           = λ X → End.E (end X)
    ; F₁           = F₁′
    ; identity     = λ {A} → unique (end A) (id-comm ○ ∘-resp-≈ˡ (⟺ identity))
    ; homomorphism = λ {A B C} {f g} → unique (end C) $ λ {Z} → begin
      dinatural.α (end C) Z ∘ F₁′ g ∘ F₁′ f                       ≈⟨ pullˡ (universal (end C)) ⟩
      (η (F₁ g) (Z , Z) ∘ dinatural.α (end B) Z) ∘ F₁′ f          ≈⟨ pullʳ (universal (end B)) ⟩
      η (F₁ g) (Z , Z) ∘ η (F₁ f) (Z , Z) ∘ dinatural.α (end A) Z ≈˘⟨ pushˡ homomorphism ⟩
      η (F₁ (g E.∘ f)) (Z , Z) ∘ dinatural.α (end A) Z            ∎
    ; F-resp-≈     = λ {A B f g} eq → unique (end B) $ λ {Z} → begin
      dinatural.α (end B) Z ∘ F₁′ g                               ≈⟨ universal (end B) ⟩
      η (F₁ g) (Z , Z) ∘ dinatural.α (end A) Z                    ≈˘⟨ F-resp-≈ eq ⟩∘⟨refl ⟩
      η (F₁ f) (Z , Z) ∘ dinatural.α (end A) Z                    ∎
    }
    where F₁′ : ∀ {X Y} → X E.⇒ Y → End.E (end X) ⇒ End.E (end Y)
          F₁′ {X} {Y} f = factor (end Y) $ record
            { E         = End.E (end X)
            ; dinatural = F₁ f <∘ dinatural (end X)
            }