------------------------------------------------------------------------
-- Heterogeneous equality
------------------------------------------------------------------------

module Relation.Binary.HeterogeneousEquality where

open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.Consequences
open import Relation.Binary.PropositionalEquality as PropEq
  using (_≡_; refl)
open import Data.Function
open import Data.Product

------------------------------------------------------------------------
-- Heterogeneous equality

infix 4 _≅_ _≇_ _≅₁_ _≇₁_

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

data _≅₁_ {a : Set₁} (x : a) : {b : Set₁} → b → Set where
  refl : x ≅₁ x

-- Nonequality.

_≇_ : {a : Set} → a → {b : Set} → b → Set
x ≇ y = ¬ x ≅ y

_≇₁_ : {a : Set₁} → a → {b : Set₁} → b → Set
x ≇₁ y = ¬ x ≅₁ y

------------------------------------------------------------------------
-- Conversion

≡-to-≅ : ∀ {a} {x y : a} → x ≡ y → x ≅ y
≡-to-≅ refl = refl

≅-to-≡ : ∀ {a} {x y : a} → x ≅ y → x ≡ y
≅-to-≡ refl = refl

------------------------------------------------------------------------
-- Some properties

reflexive : ∀ {a} → _⇒_ {a} _≡_ (λ x y → x ≅ y)
reflexive refl = refl

sym : ∀ {a b} {x : a} {y : b} → x ≅ y → y ≅ x
sym refl = refl

trans : ∀ {a b c} {x : a} {y : b} {z : c} → x ≅ y → y ≅ z → x ≅ z
trans refl refl = refl

subst : ∀ {a} → Substitutive {a} (λ x y → x ≅ y)
subst P refl p = p

subst₂ : ∀ {A B} (P : A → B → Set) →
         ∀ {x₁ x₂ y₁ y₂} → x₁ ≅ x₂ → y₁ ≅ y₂ → P x₁ y₁ → P x₂ y₂
subst₂ P refl refl p = p

subst₁ : ∀ {a} (P : a → Set₁) → ∀ {x y} → x ≅ y → P x → P y
subst₁ P refl p = p

subst-removable : ∀ {a} (P : a → Set) {x y} (eq : x ≅ y) z →
                  subst P eq z ≅ z
subst-removable P refl z = refl

≡-subst-removable : ∀ {a} (P : a → Set) {x y} (eq : x ≡ y) z →
                    PropEq.subst P eq z ≅ z
≡-subst-removable P refl z = refl

cong : ∀ {A : Set} {B : A → Set} {x y}
       (f : (x : A) → B x) → x ≅ y → f x ≅ f y
cong f refl = refl

cong₂ : ∀ {A : Set} {B : A → Set} {C : ∀ x → B x → Set} {x y u v}
        (f : (x : A) (y : B x) → C x y) → x ≅ y → u ≅ v → f x u ≅ f y v
cong₂ f refl refl = refl

resp₂ : ∀ {a} (∼ : Rel a) → ∼ Respects₂ (λ x y → x ≅ y)
resp₂ _∼_ = subst⟶resp₂ _∼_ subst

isEquivalence : ∀ {a} → IsEquivalence {a} (λ x y → x ≅ y)
isEquivalence = record
  { refl  = refl
  ; sym   = sym
  ; trans = trans
  }

setoid : Set → Setoid
setoid a = record
  { carrier       = a
  ; _≈_           = λ x y → x ≅ y
  ; isEquivalence = isEquivalence
  }

decSetoid : ∀ {a} → Decidable (λ x y → _≅_ {a} x y) → DecSetoid
decSetoid dec = record
  { _≈_              = λ x y → x ≅ y
  ; isDecEquivalence = record
      { isEquivalence = isEquivalence
      ; _≟_           = dec
      }
  }

isPreorder : ∀ {a} → IsPreorder {a} (λ x y → x ≅ y) (λ x y → x ≅ y)
isPreorder = record
  { isEquivalence = isEquivalence
  ; reflexive     = id
  ; trans         = trans
  ; ∼-resp-≈      = resp₂ (λ x y → x ≅ y)
  }

isPreorder-≡ : ∀ {a} → IsPreorder {a} _≡_ (λ x y → x ≅ y)
isPreorder-≡ = record
  { isEquivalence = PropEq.isEquivalence
  ; reflexive     = reflexive
  ; trans         = trans
  ; ∼-resp-≈      = PropEq.resp₂ (λ x y → x ≅ y)
  }

preorder : Set → Preorder
preorder a = record
  { carrier    = a
  ; _≈_        = _≡_
  ; _∼_        = λ x y → x ≅ y
  ; isPreorder = isPreorder-≡
  }

------------------------------------------------------------------------
-- The inspect idiom

-- See Relation.Binary.PropositionalEquality.Inspect.

data Inspect {a : Set} (x : a) : Set where
  _with-≅_ : (y : a) (eq : y ≅ x) → Inspect x

inspect : ∀ {a} (x : a) → Inspect x
inspect x = x with-≅ refl

------------------------------------------------------------------------
-- Convenient syntax for equational reasoning

module ≅-Reasoning where

  -- The code in Relation.Binary.EqReasoning cannot handle
  -- heterogeneous equalities, hence the code duplication here.

  infix  4 _IsRelatedTo_
  infix  2 _∎
  infixr 2 _≅⟨_⟩_ _≡⟨_⟩_
  infix  1 begin_

  data _IsRelatedTo_ {A} (x : A) {B} (y : B) : Set where
    relTo : (x≅y : x ≅ y) → x IsRelatedTo y

  begin_ : ∀ {A} {x : A} {B} {y : B} → x IsRelatedTo y → x ≅ y
  begin relTo x≅y = x≅y

  _≅⟨_⟩_ : ∀ {A} (x : A) {B} {y : B} {C} {z : C} →
           x ≅ y → y IsRelatedTo z → x IsRelatedTo z
  _ ≅⟨ x≅y ⟩ relTo y≅z = relTo (trans x≅y y≅z)

  _≡⟨_⟩_ : ∀ {A} (x : A) {y} {C} {z : C} →
           x ≡ y → y IsRelatedTo z → x IsRelatedTo z
  _ ≡⟨ x≡y ⟩ relTo y≅z = relTo (trans (reflexive x≡y) y≅z)

  _∎ : ∀ {A} (x : A) → x IsRelatedTo x
  _∎ _ = relTo refl


{-

This file proves a variety of basic results about paths:

- refl, sym, cong and composition of paths. This is used to set up
  equational reasoning.

- Transport, subst and functional extensionality

- J and its computation rule (up to a path)

- Σ-types and contractibility of singletons

- Converting PathP to and from a homogeneous path with transp

- Direct definitions of lower h-levels

- Export natural numbers

- Export universe lifting

-}
{-# OPTIONS --cubical --safe #-}
module Cubical.Foundations.Prelude where

open import Cubical.Core.Primitives public

infixr 30 _∙_
infix  3 _∎
infixr 2 _≡⟨_⟩_

-- Basic theory about paths. These proofs should typically be
-- inlined. This module also makes equational reasoning work with
-- (non-dependent) paths.

private
  variable
    ℓ ℓ' : Level
    A : Type ℓ
    B : A → Type ℓ
    x y z : A

refl : x ≡ x
refl {x = x} = λ _ → x

sym : x ≡ y → y ≡ x
sym p i = p (~ i)

symP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} →
       (p : PathP A x y) → PathP (λ i → A (~ i)) y x
symP p j = p (~ j)

cong : ∀ (f : (a : A) → B a) (p : x ≡ y) →
       PathP (λ i → B (p i)) (f x) (f y)
cong f p i = f (p i)

cong₂ : ∀ {C : (a : A) → (b : B a) → Type ℓ} →
        (f : (a : A) → (b : B a) → C a b) →
        (p : x ≡ y) →
        {u : B x} {v : B y} (q : PathP (λ i → B (p i)) u v) →
        PathP (λ i → C (p i) (q i)) (f x u) (f y v)
cong₂ f p q i = f (p i) (q i)

-- The filler of homogeneous path composition:
-- compPath-filler p q = PathP (λ i → x ≡ q i) p (p ∙ q)

compPath-filler : ∀ {x y z : A} → x ≡ y → y ≡ z → I → I → A
compPath-filler {x = x} p q j i =
  hfill (λ j → λ { (i = i0) → x
                  ; (i = i1) → q j }) (inS (p i)) j

_∙_ : x ≡ y → y ≡ z → x ≡ z
(p ∙ q) j = compPath-filler p q i1 j

-- The filler of heterogeneous path composition:
-- compPathP-filler p q = PathP (λ i → PathP (λ j → (compPath-filler (λ i → A i) B i j)) x (q i)) p (compPathP p q)

compPathP-filler : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → {B_i1 : Type ℓ} {B : A i1 ≡ B_i1} → {z : B i1} →
  (p : PathP A x y) → (q : PathP (λ i → B i) y z) → ∀ (i j : I) → compPath-filler (λ i → A i) B j i
compPathP-filler {A = A} {x = x} {B = B} p q i =
  fill (λ j → compPath-filler (λ i → A i) B j i)
       (λ j → λ { (i = i0) → x ;
                   (i = i1) → q j }) (inS (p i))

compPathP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → {B_i1 : Type ℓ} {B : (A i1) ≡ B_i1} → {z : B i1} →
  (p : PathP A x y) → (q : PathP (λ i → B i) y z) → PathP (λ j → ((λ i → A i) ∙ B) j) x z
compPathP p q j = compPathP-filler p q j i1

_≡⟨_⟩_ : (x : A) → x ≡ y → y ≡ z → x ≡ z
_ ≡⟨ x≡y ⟩ y≡z = x≡y ∙ y≡z

≡⟨⟩-syntax : (x : A) → x ≡ y → y ≡ z → x ≡ z
≡⟨⟩-syntax = _≡⟨_⟩_
infixr 2 ≡⟨⟩-syntax
syntax ≡⟨⟩-syntax x (λ i → B) y = x ≡[ i ]⟨ B ⟩ y

_∎ : (x : A) → x ≡ x
_ ∎ = refl

-- another definition of composition, useful for some proofs
compPath'-filler : ∀ {x y z : A} → x ≡ y → y ≡ z → I → I → A
compPath'-filler {z = z} p q j i =
  hfill (λ j → λ { (i = i0) → p (~ j)
                 ; (i = i1) → z }) (inS (q i)) j

_□_ : x ≡ y → y ≡ z → x ≡ z
(p □ q) j = compPath'-filler p q i1 j

□≡∙ : (p : x ≡ y) (q : y ≡ z) → p □ q ≡ p ∙ q
□≡∙ {x = x} {y = y} {z = z} p q i j = hcomp (λ k → \ { (i = i0) → compPath'-filler p q k j
                                             ; (i = i1) → compPath-filler p q k j
                                             ; (j = i0) → p ( ~ i ∧ ~ k)
                                             ; (j = i1) → q (k ∨ ~ i) }) (helper i j)
  where
    helper : PathP (λ i → p (~ i) ≡ q (~ i)) q p
    helper i j = hcomp (λ k → \ { (i = i0) → q (k ∧ j)
                                ; (i = i1) → p (~ k ∨ j)
                                ; (j = i0) → p (~ i ∨ ~ k)
                                ; (j = i1) → q (~ i ∧ k) })
                       y

-- Transport, subst and functional extensionality

-- transport is a special case of transp
transport : {A B : Type ℓ} → A ≡ B → A → B
transport p a = transp (λ i → p i) i0 a

-- Transporting in a constant family is the identity function (up to a
-- path). If we would have regularity this would be definitional.
transportRefl : (x : A) → transport refl x ≡ x
transportRefl {A = A} x i = transp (λ _ → A) i x

-- We want B to be explicit in subst
subst : (B : A → Type ℓ') (p : x ≡ y) → B x → B y
subst B p pa = transport (λ i → B (p i)) pa

substRefl : (px : B x) → subst B refl px ≡ px
substRefl px = transportRefl px

funExt : {f g : (x : A) → B x} → ((x : A) → f x ≡ g x) → f ≡ g
funExt p i x = p x i

-- J for paths and its computation rule

module _ (P : ∀ y → x ≡ y → Type ℓ') (d : P x refl) where
  J : (p : x ≡ y) → P y p
  J p = transport (λ i → P (p i) (λ j → p (i ∧ j))) d

  JRefl : J refl ≡ d
  JRefl = transportRefl d

-- Contractibility of singletons

singl : (a : A) → Type _
singl {A = A} a = Σ[ x ∈ A ] (a ≡ x)

contrSingl : (p : x ≡ y) → Path (singl x) (x , refl) (y , p)
contrSingl p i = (p i , λ j → p (i ∧ j))

-- Converting to and from a PathP

module _ {A : I → Type ℓ} {x : A i0} {y : A i1} where
  toPathP : transp A i0 x ≡ y → PathP A x y
  toPathP p i = hcomp (λ j → λ { (i = i0) → x
                               ; (i = i1) → p j })
                      (transp (λ j → A (i ∧ j)) (~ i) x)

  fromPathP : PathP A x y → transp A i0 x ≡ y
  fromPathP p i = transp (λ j → A (i ∨ j)) i (p i)

-- Direct definitions of lower h-levels

isContr : Type ℓ → Type ℓ
isContr A = Σ[ x ∈ A ] (∀ y → x ≡ y)

isProp : Type ℓ → Type ℓ
isProp A = (x y : A) → x ≡ y

isSet : Type ℓ → Type ℓ
isSet A = (x y : A) → isProp (x ≡ y)

Square
  : ∀{w x y z : A}
  → (p : w ≡ y) (q : w ≡ x) (r : y ≡ z) (s : x ≡ z)
  → Set _
Square p q r s = PathP (λ i → p i ≡ s i) q r

isSet' : Type ℓ → Type ℓ
isSet' A
  = {x y z w : A}
  → (p : x ≡ y) (q : z ≡ w) (r : x ≡ z) (s : y ≡ w)
  → Square r p q s

isGroupoid : Type ℓ → Type ℓ
isGroupoid A = ∀ a b → isSet (Path A a b)

Cube
  : ∀{w x y z w' x' y' z' : A}
  → {p : w ≡ y} {q : w ≡ x} {r : y ≡ z} {s : x ≡ z}
  → {p' : w' ≡ y'} {q' : w' ≡ x'} {r' : y' ≡ z'} {s' : x' ≡ z'}
  → {a : w ≡ w'} {b : x ≡ x'} {c : y ≡ y'} {d : z ≡ z'}
  → (ps : Square a p p' c) (qs : Square a q q' b)
  → (rs : Square c r r' d) (ss : Square b s s' d)
  → (f0 : Square p q r s) (f1 : Square p' q' r' s')
  → Set _
Cube ps qs rs ss f0 f1
  = PathP (λ k → Square (ps k) (qs k) (rs k) (ss k)) f0 f1

isGroupoid' : Set ℓ → Set ℓ
isGroupoid' A
  = ∀{w x y z w' x' y' z' : A}
  → {p : w ≡ y} {q : w ≡ x} {r : y ≡ z} {s : x ≡ z}
  → {p' : w' ≡ y'} {q' : w' ≡ x'} {r' : y' ≡ z'} {s' : x' ≡ z'}
  → {a : w ≡ w'} {b : x ≡ x'} {c : y ≡ y'} {d : z ≡ z'}
  → (fp : Square a p p' c) → (fq : Square a q q' b)
  → (fr : Square c r r' d) → (fs : Square b s s' d)
  → (f0 : Square p q r s) → (f1 : Square p' q' r' s')
  → Cube fp fq fr fs f0 f1

is2Groupoid : Type ℓ → Type ℓ
is2Groupoid A = ∀ a b → isGroupoid (Path A a b)

-- Essential consequences of isProp and isContr
isProp→PathP
  : ((x : A) → isProp (B x)) → {a0 a1 : A}
  → (p : a0 ≡ a1) (b0 : B a0) (b1 : B a1)
  → PathP (λ i → B (p i)) b0 b1
isProp→PathP {B = B} P p b0 b1 = toPathP {A = λ i → B (p i)} {b0} {b1} (P _ _ _)

isPropIsContr : isProp (isContr A)
isPropIsContr z0 z1 j =
  ( z0 .snd (z1 .fst) j
  , λ x i → hcomp (λ k → λ { (i = i0) → z0 .snd (z1 .fst) j
                           ; (i = i1) → z0 .snd x (j ∨ k)
                           ; (j = i0) → z0 .snd x (i ∧ k)
                           ; (j = i1) → z1 .snd x i })
                  (z0 .snd (z1 .snd x i) j))

isContr→isProp : isContr A → isProp A
isContr→isProp (x , p) a b i =
  hcomp (λ j → λ { (i = i0) → p a j
                 ; (i = i1) → p b j }) x

isProp→isSet : isProp A → isSet A
isProp→isSet h a b p q j i =
  hcomp (λ k → λ { (i = i0) → h a a k
                 ; (i = i1) → h a b k
                 ; (j = i0) → h a (p i) k
                 ; (j = i1) → h a (q i) k }) a

-- Universe lifting

record Lift {i j} (A : Type i) : Type (ℓ-max i j) where
  instance constructor lift
  field
    lower : A

open Lift public


module Naturals where

open import Library
open import Categories
open import Functors

open Fun

record NatT {a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}(F G : Fun C D) :
  Set (a ⊔ b ⊔ c ⊔ d) where
  constructor natural
  open Cat
  field cmp : ∀ {X} → Hom D (OMap F X) (OMap G X)
        nat : ∀{X Y}{f : Hom C X Y} →
              comp D (HMap G f) cmp ≅ comp D cmp (HMap F f)

NatTEq : ∀{a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}{F G : Fun C D}
         {α β : NatT F G} →
         (λ {X} → NatT.cmp α {X}) ≅ (λ {X} → NatT.cmp β {X}) →
         α ≅ β
NatTEq {α = natural cmp _} {natural .cmp _} refl =
  cong (natural cmp) (iext λ _ → iext λ _ → iext λ _ → ir _ _)

idNat : ∀{a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}{F : Fun C D} → NatT F F
idNat {D = D}{F} = let open Cat D in record {
  cmp = iden;
  nat = λ{X}{Y}{f} →
    proof
    comp (HMap F f) iden
    ≅⟨ idr ⟩
    HMap F f
    ≅⟨ sym idl ⟩
    comp iden (HMap F f) ∎}

compNat : ∀{a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}{F G H : Fun C D} →
          NatT G H → NatT F G → NatT F H
compNat {D = D}{F}{G}{H} α β = let open Cat D; open NatT in record {
  cmp = comp (cmp α) (cmp β);
  nat = λ{X}{Y}{f} →
    proof
    comp (HMap H f) (comp (cmp α) (cmp β))
    ≅⟨ sym ass ⟩
    comp (comp (HMap H f) (cmp α)) (cmp β)
    ≅⟨ cong (λ f₁ → comp f₁ (cmp β)) (nat α) ⟩
    comp (comp (cmp α) (HMap G f)) (cmp β)
    ≅⟨ ass ⟩
    comp (cmp α) (comp (HMap G f) (cmp β))
    ≅⟨ cong (comp (cmp α)) (nat β) ⟩
    comp (cmp α) (comp (cmp β) (HMap F f))
    ≅⟨ sym ass ⟩
    comp (comp (cmp α) (cmp β)) (HMap F f)
    ∎}

idlNat : ∀{a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}{F G : Fun C D}
         {α : NatT F G} → compNat idNat α ≅ α
idlNat {D = D} = NatTEq (iext λ _ → Cat.idl D)

idrNat : ∀{a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}{F G : Fun C D}
         {α : NatT F G} → compNat α idNat ≅ α
idrNat {D = D} = NatTEq (iext λ _ → Cat.idr D)

assNat : ∀{a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}{E F G H : Fun C D}
         {α : NatT G H}{β : NatT F G}{η : NatT E F} →
         compNat (compNat α β) η ≅ compNat α (compNat β η)
assNat {D = D} = NatTEq (iext λ _ → Cat.ass D)

-- Natural isomorphism

record Iso {l m}(C : Cat {l}{m}){A B}(f : Cat.Hom C A B) : Set (l ⊔ m)
  where
  constructor iso
  open Cat C
  field inv  : Hom B A
        rinv : comp f inv ≅ iden {B}
        linv : comp inv f ≅ iden {A}

record NatI {a b c d}{C : Cat {a}{b}}{D : Cat {c}{d}}(F G : Fun C D) :
  Set (a ⊔ b ⊔ c ⊔ d) where
  constructor natural
  open Cat
  field cmp : ∀ {X} → Hom D (OMap F X) (OMap G X)
        cmpI : ∀{X} -> Iso D (cmp {X})
        nat : ∀{X Y}{f : Hom C X Y} →
              comp D (HMap G f) cmp ≅ comp D cmp (HMap F f)


-- Andreas, 2013-03-15
-- Paolo Capriotti's formalization of Russell's paradox
{-# OPTIONS --cubical-compatible --type-in-type #-}
module Russell where

open import Common.Product
open import Common.Equality

data ⊥ : Set where

¬ : Set → Set
¬ A = A → ⊥

-- a model of set theory, uses Set : Set
data U : Set where
  set : (I : Set) → (I → U) → U

-- a set is regular if it doesn't contain itself
regular : U → Set
regular (set I f) = (i : I) → ¬ (f i ≡ set I f)

-- Russell's set: the set of all regular sets
R : U
R = set (Σ U regular) proj₁

-- R is not regular
R-nonreg : ¬ (regular R)
R-nonreg reg = reg (R , reg) refl

-- R is regular
R-reg : regular R
R-reg (x , reg) p = subst regular p reg (x , reg) p

-- contradiction

absurd : ⊥
absurd = R-nonreg R-reg


module unit where

open import level
open import eq

data ⊤ {ℓ : Level} : Set ℓ where
  triv : ⊤

{-# COMPILE GHC ⊤ = data () (()) #-}

single-range : ∀{ℓ}{U : Set ℓ}{g : U → ⊤ {ℓ}} → ∀{u : U} → g u ≡ triv
single-range {_}{U}{g}{u} with g u
... | triv = refl


{-# OPTIONS --no-termination-check #-}

module Lambda where

module Prelude where

  data Bool : Set where
    true  : Bool
    false : Bool

  if_then_else_ : {A : Set} -> Bool -> A -> A -> A
  if true  then x else y = x
  if false then x else y = y

  _∧_ : Bool -> Bool -> Bool
  true  ∧ y = y
  false ∧ y = false

  _∨_ : Bool -> Bool -> Bool
  true  ∨ y = true
  false ∨ y = y

  ¬_ : Bool -> Bool
  ¬ true  = false
  ¬ false = true

  data List (A : Set) : Set where
    nil    : List A
    _::_ : A -> List A -> List A

  _++_ : {A : Set} -> List A -> List A -> List A
  nil      ++ ys = ys
  (x :: xs) ++ ys = x :: xs ++ ys

  filter : {A : Set} -> (A -> Bool) -> List A -> List A
  filter p  nil      = nil
  filter p (x :: xs) = if p x then x :: filter p xs else filter p xs

  postulate
    String : Set
    Char   : Set

  {-# BUILTIN BOOL    Bool   #-}
  {-# BUILTIN FALSE   false  #-}
  {-# BUILTIN TRUE    true   #-}
  {-# BUILTIN STRING  String #-}
  {-# BUILTIN CHAR    Char   #-}
  {-# BUILTIN LIST    List   #-}
  {-# BUILTIN NIL     nil    #-}
  {-# BUILTIN CONS    _::_    #-}

  primitive
    primStringEquality : String -> String -> Bool

  _==_ = primStringEquality

  infix 10 if_then_else_
  infixr 50 _::_ _++_
  infixl 5 _∨_
  infixl 7 _∧_
  infix 50 ¬_
  infix 15 _==_

open Prelude

Name : Set
Name = String

data Exp : Set where
  var  : Name -> Exp
  ƛ_⟶_ : Name -> Exp -> Exp
  _$_  : Exp -> Exp -> Exp

infixl 50 _$_
infix  20 ƛ_⟶_

infix 80 _[_/_]
infix 15 _∈_

_∈_ : Name -> List Name -> Bool
x ∈ y :: ys = x == y ∨ x ∈ ys
x ∈ nil    = false

-- Free variables
FV : Exp -> List Name
FV (var x)   = x :: nil
FV (s $ t)   = FV s ++ FV t
FV (ƛ x ⟶ t) = filter (\y -> ¬ (x == y)) (FV t)

-- Fresh names
fresh : Name -> Exp -> Name
fresh x e = fresh' (FV e)
  where
    fresh' : List Name -> Name
    fresh' xs = "z" -- TODO

-- Substitution
_[_/_] : Exp -> Exp -> Name -> Exp
var x     [ r / z ] = if x == z then r else var x
(s $ t)   [ r / z ] = s [ r / z ] $ t [ r / z ]
(ƛ x ⟶ t) [ r / z ] =
       if x == z   then ƛ x ⟶ t
  else if x ∈ FV r then ( let y : Name
                              y = fresh x r
                          in  ƛ y ⟶ t [ var y / x ] [ r / z ]
                        )
  else                  ƛ x ⟶ t [ r / z ]


------------------------------------------------------------------------
-- The Agda standard library
--
-- Example of a Quotient: ℤ as (ℕ × ℕ / ∼)
------------------------------------------------------------------------

{-# OPTIONS --with-K --safe #-}

module Relation.Binary.HeterogeneousEquality.Quotients.Examples where

open import Relation.Binary.HeterogeneousEquality.Quotients
open import Level using (0ℓ)
open import Relation.Binary
open import Relation.Binary.HeterogeneousEquality hiding (isEquivalence)
import Relation.Binary.PropositionalEquality as ≡
open import Data.Nat
open import Data.Nat.Properties
open import Data.Product
open import Function
open ≅-Reasoning

ℕ² = ℕ × ℕ

_∼_ : ℕ² → ℕ² → Set
(x , y) ∼ (x' , y') = x + y' ≅ x' + y

infix 10 _∼_

∼-trans : ∀ {i j k} → i ∼ j → j ∼ k → i ∼ k
∼-trans {x₁ , y₁} {x₂ , y₂} {x₃ , y₃} p q =
  ≡-to-≅ $ +-cancelˡ-≡ y₂ $ ≅-to-≡ $ begin
  y₂ + (x₁ + y₃) ≡⟨ ≡.sym (+-assoc y₂ x₁ y₃) ⟩
  y₂ + x₁ + y₃   ≡⟨ ≡.cong (_+ y₃) (+-comm y₂ x₁) ⟩
  x₁ + y₂ + y₃   ≅⟨ cong (_+ y₃) p ⟩
  x₂ + y₁ + y₃   ≡⟨ ≡.cong (_+ y₃) (+-comm x₂ y₁) ⟩
  y₁ + x₂ + y₃   ≡⟨ +-assoc y₁ x₂ y₃ ⟩
  y₁ + (x₂ + y₃) ≅⟨ cong (y₁ +_) q ⟩
  y₁ + (x₃ + y₂) ≡⟨ +-comm y₁ (x₃ + y₂) ⟩
  x₃ + y₂ + y₁   ≡⟨ ≡.cong (_+ y₁) (+-comm x₃ y₂) ⟩
  y₂ + x₃ + y₁   ≡⟨ +-assoc y₂ x₃ y₁ ⟩
  y₂ + (x₃ + y₁) ∎

∼-isEquivalence : IsEquivalence _∼_
∼-isEquivalence = record
  { refl  = refl
  ; sym   = sym
  ; trans = λ {i} {j} {k} → ∼-trans {i} {j} {k}
  }

ℕ²-∼-setoid : Setoid 0ℓ 0ℓ
ℕ²-∼-setoid = record { isEquivalence = ∼-isEquivalence }

module Integers (quot : Quotients 0ℓ 0ℓ) where

  Int : Quotient ℕ²-∼-setoid
  Int = quot _

  open Quotient Int renaming (Q to ℤ)

  _+²_ : ℕ² → ℕ² → ℕ²
  (x₁ , y₁) +² (x₂ , y₂) = x₁ + x₂ , y₁ + y₂

  +²-cong : ∀{a b a' b'} → a ∼ a' → b ∼ b' → a +² b ∼ a' +² b'
  +²-cong {a₁ , b₁} {c₁ , d₁} {a₂ , b₂} {c₂ , d₂} ab∼cd₁ ab∼cd₂ = begin
    (a₁ + c₁) + (b₂ + d₂) ≡⟨ ≡.cong (_+ (b₂ + d₂)) (+-comm a₁ c₁) ⟩
    (c₁ + a₁) + (b₂ + d₂) ≡⟨ +-assoc c₁ a₁ (b₂ + d₂) ⟩
    c₁ + (a₁ + (b₂ + d₂)) ≡⟨ ≡.cong (c₁ +_) (≡.sym (+-assoc a₁ b₂ d₂)) ⟩
    c₁ + (a₁ + b₂ + d₂)   ≅⟨ cong (λ n → c₁ + (n + d₂)) ab∼cd₁ ⟩
    c₁ + (a₂ + b₁ + d₂)   ≡⟨ ≡.cong (c₁ +_) (+-assoc a₂ b₁ d₂) ⟩
    c₁ + (a₂ + (b₁ + d₂)) ≡⟨ ≡.cong (λ n → c₁ + (a₂ + n)) (+-comm b₁ d₂) ⟩
    c₁ + (a₂ + (d₂ + b₁)) ≡⟨ ≡.sym (+-assoc c₁ a₂ (d₂ + b₁)) ⟩
    (c₁ + a₂) + (d₂ + b₁) ≡⟨ ≡.cong (_+ (d₂ + b₁)) (+-comm c₁ a₂) ⟩
    (a₂ + c₁) + (d₂ + b₁) ≡⟨ +-assoc a₂ c₁ (d₂ + b₁) ⟩
    a₂ + (c₁ + (d₂ + b₁)) ≡⟨ ≡.cong (a₂ +_) (≡.sym (+-assoc c₁ d₂ b₁)) ⟩
    a₂ + (c₁ + d₂ + b₁)   ≅⟨ cong (λ n → a₂ + (n + b₁)) ab∼cd₂ ⟩
    a₂ + (c₂ + d₁ + b₁)   ≡⟨ ≡.cong (a₂ +_) (+-assoc c₂ d₁ b₁) ⟩
    a₂ + (c₂ + (d₁ + b₁)) ≡⟨ ≡.cong (λ n → a₂ + (c₂ + n)) (+-comm d₁ b₁) ⟩
    a₂ + (c₂ + (b₁ + d₁)) ≡⟨ ≡.sym (+-assoc a₂ c₂ (b₁ + d₁)) ⟩
    (a₂ + c₂) + (b₁ + d₁) ∎

  module _ (ext : ∀ {a b} {A : Set a} {B₁ B₂ : A → Set b} {f₁ : ∀ a → B₁ a}
                  {f₂ : ∀ a → B₂ a} → (∀ a → f₁ a ≅ f₂ a) → f₁ ≅ f₂) where

    _+ℤ_ : ℤ → ℤ → ℤ
    _+ℤ_ = Properties₂.lift₂ ext Int Int (λ i j → abs (i +² j))
         $ λ {a} {b} {c} p p' → compat-abs (+²-cong {a} {b} {c} p p')

    zero² : ℕ²
    zero² = 0 , 0

    zeroℤ : ℤ
    zeroℤ = abs zero²

    +²-identityʳ : (i : ℕ²) → (i +² zero²) ∼ i
    +²-identityʳ (x , y) = begin
      (x + 0) + y ≡⟨ ≡.cong (_+ y) (+-identityʳ x) ⟩
      x + y       ≡⟨ ≡.cong (x +_) (≡.sym (+-identityʳ y)) ⟩
      x + (y + 0) ∎

    +ℤ-on-abs≅abs-+₂ : ∀ a b → abs a +ℤ abs b ≅ abs (a +² b)
    +ℤ-on-abs≅abs-+₂ = Properties₂.lift₂-conv ext Int Int _
                     $ λ {a} {b} {c} p p′ → compat-abs (+²-cong {a} {b} {c} p p′)

    +ℤ-identityʳ : ∀ i → i +ℤ zeroℤ ≅ i
    +ℤ-identityʳ = lift _ eq (≅-heterogeneous-irrelevantʳ _ _ ∘ compat-abs) where

      eq : ∀ a → abs a +ℤ zeroℤ ≅ abs a
      eq a = begin
        abs a +ℤ zeroℤ      ≡⟨⟩
        abs a +ℤ abs zero²  ≅⟨ +ℤ-on-abs≅abs-+₂ a zero² ⟩
        abs (a +² zero²)    ≅⟨ compat-abs (+²-identityʳ a) ⟩
        abs a               ∎

    +²-identityˡ : (i : ℕ²) → (zero² +² i) ∼ i
    +²-identityˡ i = refl

    +ℤ-identityˡ : (i : ℤ)  → zeroℤ +ℤ i ≅ i
    +ℤ-identityˡ = lift _ eq (≅-heterogeneous-irrelevantʳ _ _ ∘ compat-abs) where

      eq : ∀ a → zeroℤ +ℤ abs a ≅ abs a
      eq a = begin
        zeroℤ +ℤ abs a     ≡⟨⟩
        abs zero² +ℤ abs a ≅⟨ +ℤ-on-abs≅abs-+₂ zero² a ⟩
        abs (zero² +² a)   ≅⟨ compat-abs (+²-identityˡ a) ⟩
        abs a              ∎

    +²-assoc : (i j k : ℕ²) → (i +² j) +² k ∼ i +² (j +² k)
    +²-assoc (a , b) (c , d) (e , f) = begin
      ((a + c) + e) + (b + (d + f)) ≡⟨ ≡.cong (_+ (b + (d + f))) (+-assoc a c e) ⟩
      (a + (c + e)) + (b + (d + f)) ≡⟨ ≡.cong ((a + (c + e)) +_) (≡.sym (+-assoc b d f)) ⟩
      (a + (c + e)) + ((b + d) + f) ∎

    +ℤ-assoc : ∀ i j k → (i +ℤ j) +ℤ k ≅ i +ℤ (j +ℤ k)
    +ℤ-assoc = Properties₃.lift₃ ext Int Int Int eq compat₃ where

      eq : ∀ i j k → (abs i +ℤ abs j) +ℤ abs k ≅ abs i +ℤ (abs j +ℤ abs k)
      eq i j k = begin
        (abs i +ℤ abs j) +ℤ abs k ≅⟨ cong (_+ℤ abs k) (+ℤ-on-abs≅abs-+₂ i j) ⟩
        (abs (i +² j) +ℤ abs k)   ≅⟨ +ℤ-on-abs≅abs-+₂ (i +² j) k ⟩
        abs ((i +² j) +² k)       ≅⟨ compat-abs (+²-assoc i j k) ⟩
        abs (i +² (j +² k))       ≅⟨ sym (+ℤ-on-abs≅abs-+₂ i (j +² k)) ⟩
        (abs i +ℤ abs (j +² k))   ≅⟨ cong (abs i +ℤ_) (sym (+ℤ-on-abs≅abs-+₂ j k)) ⟩
        abs i +ℤ (abs j +ℤ abs k) ∎

      compat₃ : ∀ {a a′ b b′ c c′} → a ∼ a′ → b ∼ b′ → c ∼ c′ → eq a b c ≅ eq a′ b′ c′
      compat₃ p q r = ≅-heterogeneous-irrelevantˡ _ _
                    $ cong₂ _+ℤ_ (cong₂ _+ℤ_ (compat-abs p) (compat-abs q))
                    $ compat-abs r


module Categories.Fam where

open import Level
open import Relation.Binary using (Rel)
import Relation.Binary.HeterogeneousEquality as Het
open Het using (_≅_) renaming (refl to ≣-refl)

open import Categories.Support.PropositionalEquality

open import Categories.Category

module Fam {a b : Level} where
  record Fam : Set (suc a ⊔ suc b) where
      constructor _,_
      field
        U : Set a
        T : U → Set b
  open Fam public

  record Hom (A B : Fam) : Set (a ⊔ b) where
    constructor _,_
    field
      f : U A → U B
      φ : (x : U A) → T A x → T B (f x)

  record _≡Fam_ {X Y} (f g : (Hom X Y)) : Set (a ⊔ b) where
      constructor _,_
      field
        f≡g : {x : _} → Hom.f f x ≣ Hom.f g x
        φ≡γ : {x : _} {bx : _} → Hom.φ f x bx ≅ Hom.φ g x bx

  module Eq = _≡Fam_

  Cat : Category (suc a ⊔ suc b) (a ⊔ b) (a ⊔ b)
  Cat = record {
                Obj = Fam;
                _⇒_ = Hom;
                _≡_ = _≡Fam_;
                id = id′;
                _∘_ = _∘′_;
                assoc = ≣-refl , ≣-refl;
                identityˡ = ≣-refl , ≣-refl;
                identityʳ = ≣-refl , ≣-refl;
                equiv = record {
                  refl  = ≣-refl , ≣-refl;
                  sym   = \ { (f≡g , φ≡γ) → ≣-sym f≡g , Het.sym φ≡γ };
                  trans = λ {(f≡g , φ≡γ) (g≡h , γ≡η) → ≣-trans f≡g g≡h , Het.trans φ≡γ γ≡η} };
                ∘-resp-≡ = ∘-resp-≡′ }
   where
     id′ : {A : Fam} → Hom A A
     id′ = (\ x → x) , (\ x bx → bx)

     _∘′_ : {A B C : Fam} → Hom B C → Hom A B → Hom A C
     _∘′_ (f , φ) (g , γ) = (λ x → f (g x)) , (λ x bx → φ (g x) (γ x bx))

     sym′ : ∀ {X Y} → Relation.Binary.Symmetric (_≡Fam_ {X} {Y})
     sym′ {Ax , Bx} {Ay , By} {f , φ} {g , γ} (f≡g , φ≡γ) = ≣-sym f≡g , Het.sym φ≡γ

     ∘-resp-≡′ : {A B C : Fam} {f h : Hom B C} {g i : Hom A B} → f ≡Fam h → g ≡Fam i → (f ∘′ g) ≡Fam (h ∘′ i)
     ∘-resp-≡′ {f = (f , φ)} {g , γ} {h , η} {i , ι} (f≡g , φ≡γ) (h≡i , η≡ι) =
       ≣-trans f≡g (≣-cong g h≡i) , Het.trans φ≡γ (Het.cong₂ γ (Het.≡-to-≅ h≡i) η≡ι)

  open Category Cat public

Fam : ∀ a b → Category (suc a ⊔ suc b) (a ⊔ b) (a ⊔ b)
Fam a b = Fam.Cat {a} {b}


-- Agda is an /interactive/ language;
-- that's very important difference (compared to language-pts)
module J where

open import Level
open import Data.Bool using (Bool; true; false)

data ⊤ : Set where
  I : ⊤

data ⊥ : Set where

data Eq {ℓ : Level} (A : Set ℓ) : A → A → Set ℓ where
  refl : {x : A} → Eq A x x

J : ∀ {ℓ ℓ′} (A : Set ℓ)
  → (C : (x : A) → (y : A) → (p : Eq A x y) → Set ℓ′)
  → (r : (x : A) → C x x refl)
  → (u : A)
  → (v : A)
  → (p : Eq A u v)
  → C u v p
J A C r u .u refl = r u

Eq-sym : ∀ {ℓ} (A : Set ℓ) (x y : A) → Eq A x y → Eq A y x
Eq-sym A x .x refl = refl

Eq-sym-with-J : ∀ {ℓ} (A : Set ℓ) (x y : A) → Eq A x y → Eq A y x
Eq-sym-with-J A = J A (λ x y _ → Eq A y x) (λ x → refl)

Eq-trans-with-J : ∀ {ℓ} (A : Set ℓ) (x y z : A) → Eq A x y → Eq A y z → Eq A x z
Eq-trans-with-J A x y z p = J A (λ u v _ → Eq A v z → Eq A u z) (λ _ r → r) x y p

Bool-elim : ∀ {ℓ} (P : Bool → Set ℓ) → P true → P false  → (b : Bool) → P b
Bool-elim P t f false = f
Bool-elim P t f true  = t

if1 : (r : Set1) → Bool → r → r → r
if1 r b t f = Bool-elim (λ _ → r) t f b

lemma-motive : Bool → Bool → Set
lemma-motive u v = if1 Set u (if1 Set v ⊤ ⊥) ⊤

lemma : Eq Bool true false → ⊥
lemma p = J Bool
  (λ u v _ → lemma-motive u v)
  (λ b → Bool-elim (λ c → lemma-motive c c) I I b )
  true false p


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

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure

open import Cubical.Data.Unit
open import Cubical.Data.Sigma

open import Cubical.Algebra.Ring
open import Cubical.Algebra.CommRing
open import Cubical.Algebra.CommRing.FiberedProduct
open import Cubical.Algebra.CommRing.Instances.Unit

open import Cubical.Categories.Category
open import Cubical.Categories.Limits.Terminal
open import Cubical.Categories.Limits.Pullback

open Category hiding (_∘_)
open CommRingHoms

private
  variable
    ℓ : Level

CommRingsCategory : Category (ℓ-suc ℓ) ℓ
ob CommRingsCategory                     = CommRing _
Hom[_,_] CommRingsCategory               = CommRingHom
id CommRingsCategory {R}                 = idCommRingHom R
_⋆_ CommRingsCategory {R} {S} {T}        = compCommRingHom R S T
⋆IdL CommRingsCategory {R} {S}           = compIdCommRingHom {R = R} {S}
⋆IdR CommRingsCategory {R} {S}           = idCompCommRingHom {R = R} {S}
⋆Assoc CommRingsCategory {R} {S} {T} {U} = compAssocCommRingHom {R = R} {S} {T} {U}
isSetHom CommRingsCategory               = isSetRingHom _ _

TerminalCommRing : Terminal {ℓ-suc ℓ-zero} CommRingsCategory
fst TerminalCommRing = UnitCommRing
fst (fst (snd TerminalCommRing y)) _ = tt
snd (fst (snd TerminalCommRing y)) = makeIsRingHom refl (λ _ _ → refl) (λ _ _ → refl)
snd (snd TerminalCommRing y) f = RingHom≡ (funExt (λ _ → refl))

open Pullback

{-
   A x_C B -----> A
      |           |
      |           | α
      |           |
      V           V
      B --------> C
            β
-}
PullbackCommRing : Pullbacks {ℓ-suc ℓ} CommRingsCategory
pbOb (PullbackCommRing (cospan A C B α β)) = fiberedProduct A B C α β
pbPr₁ (PullbackCommRing (cospan A C B α β)) = fiberedProductPr₁ A B C α β
pbPr₂ (PullbackCommRing (cospan A C B α β)) = fiberedProductPr₂ A B C α β
pbCommutes (PullbackCommRing (cospan A C B α β)) = fiberedProductPr₁₂Commutes A B C α β
univProp (PullbackCommRing (cospan A C B α β)) {d = D} = fiberedProductUnivProp A B C α β D


{-# OPTIONS --type-in-type #-}
open import Data.Empty
open import Data.Unit
open import Data.Bool
open import Data.Product hiding ( curry ; uncurry )
open import Data.Nat
open import Data.String
open import Relation.Binary.PropositionalEquality using ( refl ; _≢_ ; _≡_ )
open import Function
module ClosedTheory where

noteq = _≢_

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

data Desc (I : Set) : Set₁ where
  End : (i : I) → Desc I
  Rec : (i : I) (D : Desc I) → Desc I
  Arg : (A : Set) (B : A → Desc I) → Desc I

ISet : Set → Set₁
ISet I = I → Set

El : {I : Set} (D : Desc I) → ISet I → ISet I
El (End j) X i = j ≡ i
El (Rec j D) X i = X j × El D X i
El (Arg A B) X i = Σ A (λ a → El (B a) X i)

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

UncurriedEl : {I : Set} (D : Desc I) (X : ISet I) → Set
UncurriedEl D X = ∀{i} → El D X i → X i

CurriedEl : {I : Set} (D : Desc I) (X : ISet I) → Set
CurriedEl (End i) X = X i
CurriedEl (Rec i D) X = (x : X i) → CurriedEl D X
CurriedEl (Arg A B) X = (a : A) → CurriedEl (B a) X

CurriedEl' : {I : Set} (D : Desc I) (X : ISet I) (i : I) → Set
CurriedEl' (End j) X i = j ≡ i → X i
CurriedEl' (Rec j D) X i = (x : X j) → CurriedEl' D X i
CurriedEl' (Arg A B) X i = (a : A) → CurriedEl' (B a) X i

curryEl : {I : Set} (D : Desc I) (X : ISet I)
  → UncurriedEl D X → CurriedEl D X
curryEl (End i) X cn = cn refl
curryEl (Rec i D) X cn = λ x → curryEl D X (λ xs → cn (x , xs))
curryEl (Arg A B) X cn = λ a → curryEl (B a) X (λ xs → cn (a , xs))

uncurryEl : {I : Set} (D : Desc I) (X : ISet I)
  → CurriedEl D X → UncurriedEl D X
uncurryEl (End i) X cn refl = cn
uncurryEl (Rec i D) X cn (x , xs) = uncurryEl D X (cn x) xs
uncurryEl (Arg A B) X cn (a , xs) = uncurryEl (B a) X (cn a) xs

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

data μ {I : Set} (D : Desc I) (i : I) : Set where
  init : El D (μ D) i → μ D i

Inj : {I : Set} (D : Desc I) → Set
Inj D = CurriedEl D (μ D)

inj : {I : Set} (D : Desc I) → Inj D
inj D = curryEl D (μ D) init

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

data VecT : Set where
  nilT consT : VecT

VecC : (A : Set) → VecT → Desc ℕ
VecC A nilT = End zero
VecC A consT = Arg ℕ (λ n → Arg A λ _ → Rec n (End (suc n)))

VecD : (A : Set) → Desc ℕ
VecD A = Arg VecT (VecC A)

Vec : (A : Set) → ℕ → Set
Vec A = μ (VecD A)

InjConsT : Set → ℕ → Set
InjConsT A m = El (VecC A consT) (Vec A) m → Vec A m

InjConsT' : Set → ℕ → Set
InjConsT' A m = Σ ℕ (λ n → A × Vec A n × suc n ≡ m) → Vec A m

test-InjConsT : (A : Set) (n : ℕ) → InjConsT A n ≡ InjConsT' A n
test-InjConsT A n = refl

nil : (A : Set) → Vec A zero
nil A = init (nilT , refl)

cons : (A : Set) (n : ℕ) (x : A) (xs : Vec A n) → Vec A (suc n)
cons A n x xs = init (consT , n , x , xs , refl)

nil2 : (A : Set) → Vec A zero
nil2 A = inj (VecD A) nilT

cons2 : (A : Set) (n : ℕ) (x : A) (xs : Vec A n) → Vec A (suc n)
cons2 A = inj (VecD A) consT

bit : Vec Bool (suc zero)
bit = cons Bool zero true (nil Bool)

bit2 : Vec Bool (suc zero)
bit2 = init (consT , zero , true , init (nilT , refl) , refl)

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

data TreeT : Set where
  leaf₁T leaf₂T branchT : TreeT

TreeC : (A B : Set) → TreeT → Desc (ℕ × ℕ)
TreeC A B leaf₁T = Arg A λ _ → End (suc zero , zero)
TreeC A B leaf₂T = Arg B λ _ → End (zero , suc zero)
TreeC A B branchT = Arg ℕ λ m → Arg ℕ λ n
                  → Arg ℕ λ x → Arg ℕ λ y
                  → Rec (m , n) $ Rec (x , y)
                  $ End (m + x , n + y)

TreeD : (A B : Set) → Desc (ℕ × ℕ)
TreeD A B = Arg TreeT (TreeC A B)

Tree : (A B : Set) (m n : ℕ) → Set
Tree A B m n = μ (TreeD A B) (m , n)

leaf₁ : (A B : Set) → A → Tree A B (suc zero) zero
leaf₁ A B a = init (leaf₁T , a , refl)

leaf₁2 : (A B : Set) → A → Tree A B (suc zero) zero
leaf₁2 A B = inj (TreeD A B) leaf₁T

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


module prelude.Stream where
open import prelude
open import Data.List as L using (List)

record Stream (a : Set) : Set where
    constructor _∷_
    coinductive
    field
        hd : a
        tl : Stream a
open Stream

take : ∀ {a} → ℕ → Stream a → List a
take ℕz xs = L.[]
take (ℕs n) xs = hd xs L.∷ take n (tl xs)


-- Andreas, 2022-06-14, issue #4725 reported by nad

-- The termination checker needs to recognize
-- dotted variable and record patterns as patterns
-- for this example to pass.
-- These should be harmless even with --cubical
-- (dotted constructor patterns are not, see #4606).
-- Keep fingers crossed.

{-# OPTIONS --cubical #-}

open import Agda.Builtin.Sigma

mutual

  data D : Set where
    d : S → D

  S : Set
  S = Σ D λ x → R x

  fst′ : S → D
  fst′ s = fst s

  data R : D → Set where
    r : ∀ x → R (fst′ x) → R (d x)

module _
  (P : D → Set)
  (Q : ∀ x → P x → R x → Set)
  (p : ∀ s (p : P (fst s)) → Q (fst s) p (snd s) → P (d s))
  (q : ∀ s rs (ps : P (fst s)) (qs : Q (fst s) ps (snd s)) →
       Q (fst s) ps rs → Q (d s) (p s ps qs) (r s rs))
  where

  mutual

    f : (x : D) → P x
    f (d (x , r₁)) = p (x , r₁) (f x) (g x r₁)

    g : (x : D) (x⊑y : R x) → Q x (f x) x⊑y
    g (d (x , r₁)) (r .(x , r₁) r₂) =
      q (x , r₁) r₂ (f x) (g x r₁) (g (fst′ (x , r₁)) r₂)

-- Should termination check.


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

module Categories.NaturalTransformation.Properties where

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

open import Categories.Category
open import Categories.Category.Product
open import Categories.Category.Instance.Setoids
open import Categories.Functor
open import Categories.Functor.Construction.Constant
open import Categories.Functor.Construction.LiftSetoids
open import Categories.Functor.Bifunctor
open import Categories.NaturalTransformation renaming (id to idN)
open import Categories.NaturalTransformation.NaturalIsomorphism
open import Categories.NaturalTransformation.Dinatural hiding (_≃_)

import Categories.Morphism.Reasoning as MR

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

module _ {F G : Functor C D} where
  private
    module C = Category C
    module D = Category D
    open D
    open MR D
    open HomReasoning
    open Functor

    F′ : Bifunctor C.op C D
    F′ = F ∘F πʳ

    G′ : Bifunctor C.op C D
    G′ = G ∘F πʳ

  NT⇒Dinatural : NaturalTransformation F G → DinaturalTransformation F′ G′
  NT⇒Dinatural β = dtHelper record
    { α       = η
    ; commute = λ f → ∘-resp-≈ʳ (elimʳ (identity F)) ○ ⟺ (commute f) ○ introˡ (identity G)
    }
    where open NaturalTransformation β

  Dinatural⇒NT : DinaturalTransformation F′ G′ → NaturalTransformation F G
  Dinatural⇒NT θ = ntHelper record
    { η       = α
    ; commute = λ f → introˡ (identity G) ○ ⟺ (commute f) ○ ∘-resp-≈ʳ (elimʳ (identity F))
    }
    where open DinaturalTransformation θ

  replaceˡ : ∀ {F′} → NaturalTransformation F G → F ≃ F′ → NaturalTransformation F′ G
  replaceˡ {F′} α F≃F′ = ntHelper record
    { η       = λ X → η X ∘ ⇐.η X
    ; commute = λ {X Y} f → begin
      (η Y ∘ ⇐.η Y) ∘ F₁ F′ f ≈⟨ pullʳ (⇐.commute f) ⟩
      η Y ∘ F₁ F f ∘ ⇐.η X    ≈⟨ pullˡ (commute f) ○ assoc ⟩
      F₁ G f ∘ η X ∘ ⇐.η X    ∎
    }
    where open NaturalIsomorphism F≃F′
          open NaturalTransformation α

  replaceʳ : ∀ {G′} → NaturalTransformation F G → G ≃ G′ → NaturalTransformation F G′
  replaceʳ {G′} α G≃G′ = ntHelper record
    { η       = λ X → ⇒.η X ∘ η X
    ; commute = λ {X Y} f → begin
      (⇒.η Y ∘ η Y) ∘ F₁ F f ≈⟨ pullʳ (commute f) ⟩
      ⇒.η Y ∘ F₁ G f ∘ η X   ≈⟨ pullˡ (⇒.commute f) ○ assoc ⟩
      F₁ G′ f ∘ ⇒.η X ∘ η X  ∎
    }
    where open NaturalIsomorphism G≃G′
          open NaturalTransformation α

module _ (F : Bifunctor C D E) where

  -- there is natural transformation between two partially applied bifunctors.

  appˡ-nat : ∀ {X Y} → (f : Category._⇒_ C X Y) → NaturalTransformation (appˡ F X) (appˡ F Y)
  appˡ-nat f = F ∘ˡ (constNat f ※ⁿ idN)

  appʳ-nat : ∀ {X Y} → (f : Category._⇒_ D X Y) → NaturalTransformation (appʳ F X) (appʳ F Y)
  appʳ-nat f = F ∘ˡ (idN ※ⁿ constNat f)

module _ {F G : Bifunctor C D E} (α : NaturalTransformation F G) where
  private
    module C = Category C
    module D = Category D
    module E = Category E

  appˡ′ : ∀ X → NaturalTransformation (appˡ F X) (appˡ G X)
  appˡ′ X = α ∘ₕ idN

  appʳ′ : ∀ X → NaturalTransformation (appʳ F X) (appʳ G X)
  appʳ′ X = α ∘ₕ idN

-- unlift universe level
module _ {c ℓ ℓ′ e} {F G : Functor C (Setoids c ℓ)} (α : NaturalTransformation (LiftSetoids ℓ′ e ∘F F) (LiftSetoids ℓ′ e ∘F G)) where
  open NaturalTransformation α
  open Π

  unlift-nat : NaturalTransformation F G
  unlift-nat = ntHelper record
    { η       = λ X → record
      { _⟨$⟩_ = λ x → lower (η X ⟨$⟩ lift x)
      ; cong = λ eq → lower (cong (η X) (lift eq))
      }
    ; commute = λ f eq → lower (commute f (lift eq))
    }


module Data.Num.Redundant where

--  Base: 2
--  Digit: { 0, 1, 2 }
--
--  Numeral System which maxports efficient addition, substraction
--  and arithmetic shift.

open import Data.List using (List ; []; _∷_) public
open import Data.Nat renaming (_+_ to _+ℕ_; _<_ to _<ℕ_)
open import Data.Num.Bij

open import Data.Empty
open import Relation.Nullary
open import Relation.Nullary.Negation using (contradiction; contraposition)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as PropEq
    using (_≡_; _≢_)
import Level
open PropEq.≡-Reasoning

--------------------------------------------------------------------------------
--  Digits
--------------------------------------------------------------------------------

data Digit : Set where
    zero : Digit
    one : Digit
    two : Digit

-- plus
_⊕_ : Digit → Digit → Digit
zero ⊕ y    = y
x    ⊕ zero = x
one  ⊕ one  = two
one  ⊕ two  = one
two  ⊕ one  = one
two  ⊕ two  = two

-- minus
_⊝_ : Digit → Digit → Digit
zero ⊝ y    = zero
x    ⊝ zero = x
one  ⊝ one  = zero
one  ⊝ two  = one
two  ⊝ one  = one
two  ⊝ two  = zero

-- carry
_⊙_ : Digit → Digit → Digit
one ⊙ two = one
two ⊙ one = one
two ⊙ two = one
_   ⊙ _   = zero

-- borrow
_⊘_ : Digit → Digit → Digit
zero ⊘ one = one
zero ⊘ two = one
one  ⊘ two = one
_    ⊘ _   = zero

--------------------------------------------------------------------------------
--  Sequence of Digits
--------------------------------------------------------------------------------

Redundant : Set
Redundant = List Digit

-- "one-sided"
incr : Digit → Redundant → Redundant
incr x [] = x ∷ []
incr x (y ∷ ys) = x ⊕ y ∷ incr (x ⊙ y) ys

decr : Digit → Redundant → Redundant
decr x [] = []
decr x (y ∷ ys) = x ⊝ y ∷ decr (x ⊘ y) ys

-- "two-sided"
_+_ : Redundant → Redundant → Redundant
[] + ys = ys
xs + [] = xs
(x ∷ xs) + (y ∷ ys) = x ⊕ y ∷ incr (x ⊙ y) (xs + ys)

_─_ : Redundant → Redundant → Redundant
[] ─ ys = []
xs ─ [] = xs
(x ∷ xs) ─ (y ∷ ys) = x ⊝ y ∷ decr (x ⊘ y) (xs ─ ys)

-- arithmetic shift
>> : Redundant → Redundant
>> xs = zero ∷ xs

<< : Redundant → Redundant
<< [] = []
<< (x ∷ xs) = xs

_>>>_ : ℕ → Redundant → Redundant
zero >>> xs = xs
suc n >>> xs = n >>> (>> xs)

_<<<_ : ℕ → Redundant → Redundant
zero  <<< xs = xs
suc n <<< [] = []
suc n <<< (x ∷ xs) = n <<< xs

--------------------------------------------------------------------------------
-- instances of Conversion, so that we can convert Redundant to B
--------------------------------------------------------------------------------

instance convRedundant : Conversion Redundant
convRedundant = conversion [_]' !_!' [!!]-id'
    where   [_]' : Redundant → Bij
            [     [] ]' = []
            [ zero ∷ xs ]' =    *2 [ xs ]'
            [ one  ∷ xs ]' = one ∷ [ xs ]'
            [ two  ∷ xs ]' = two ∷ [ xs ]'

            !_!' : Bij → Redundant
            ! []     !' = []
            ! one ∷ xs !' = one ∷ ! xs !'
            ! two ∷ xs !' = two ∷ ! xs !'

            [!!]-id' : ∀ xs → [ ! xs !' ]' ≡ xs
            [!!]-id' [] = PropEq.refl
            [!!]-id' (one ∷ xs) = PropEq.cong (λ x → one ∷ x) ([!!]-id' xs)
            [!!]-id' (two ∷ xs) = PropEq.cong (λ x → two ∷ x) ([!!]-id' xs)

--------------------------------------------------------------------------------
--  Equivalence relation
--------------------------------------------------------------------------------

infix 4 _≈_ _≉_

data _≈_ (a b : Redundant) : Set where
    eq : ([a]≡[b] : [ a ] ≡ [ b ]) → a ≈ b

-- the inverse of `eq`
to≡ : ∀ {a b} → a ≈ b → [ a ] ≡ [ b ]
to≡ (eq x) = x

_≉_ : (a b : Redundant) → Set
a ≉ b = a ≈ b → ⊥

-- decidable
{-
_≈?_ : Decidable {A = Redundant} _≈_
a ≈? b with [ a ] ≟ [ b ]
a ≈? b | yes p = yes (eq p)
a ≈? b | no ¬p = no (contraposition to≡ ¬p)
-}

--------------------------------------------------------------------------------
--  Ordering
--------------------------------------------------------------------------------

infix 4 _≲_ _<_
data _≲_ : Rel Redundant Level.zero where
    le : ∀ {a b} ([a]≤[b] : [ a ] ≤B [ b ]) → a ≲ b

-- the inverse of `le`
to≤ : ∀ {a b} → a ≲ b → [ a ] ≤B [ b ]
to≤ (le [a]≤B[b]) = [a]≤B[b]

_<_ : Rel Redundant Level.zero
a < b = incr one a ≲ b

{-
-- decidable
_≲?_ : Decidable _≲_
a ≲? b with [ a ] ≤? [ b ]
a ≲? b | yes p = yes (le p)
a ≲? b | no ¬p = no (contraposition to≤ ¬p)
-}


module Issue462 where

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

postulate A : Set

record R (_≈_ _∼_ : A → A → Set) : Set where
  field
    ≈-refl      : (x : A) → x ≈ x
    ∼-reflexive : (x y : A) → x ≈ y → x ∼ y

  ∼-refl : (x : A) → x ∼ x
  ∼-refl x = ∼-reflexive x x (≈-refl x)

postulate
  _≈_    : A → A → Set
  ≈-refl : ((x : A) → x ≡ x) → (x : A) → x ≈ x
  ≈-irr  : (x : A) (p : x ≈ x) → p ≡ p

≡-r : R _≡_ _≡_
≡-r = record
  { ≈-refl      = ≡-refl
  ; ∼-reflexive = λ _ _ p → p
  }

≈-reflexive : (x y : A) → x ≡ y → x ≈ y
≈-reflexive .x .x (≡-refl x) = ≈-refl (R.∼-refl ≡-r) x

≈-r : R _≡_ _≈_
≈-r = record
  { ≈-refl      = ≡-refl
  ; ∼-reflexive = ≈-reflexive
  }

foo : A → Set₁
foo x with ≈-irr x (R.∼-refl ≈-r x)
foo x | _ = Set

-- The generated with function should not contain unsolved
-- meta-variables.


module Mockingbird.Forest.Base where

open import Algebra using (Op₂; Congruent₂; LeftCongruent; RightCongruent)
open import Level using (_⊔_) renaming (suc to lsuc)
open import Relation.Binary using (Rel; IsEquivalence; Setoid)
open import Relation.Nullary using (¬_)

record IsForest {b ℓ} (Bird : Set b) (_≈_ : Rel Bird ℓ) (_∙_ : Op₂ Bird) : Set (b ⊔ ℓ) where
  field
    isEquivalence : IsEquivalence _≈_
    cong : Congruent₂ _≈_ _∙_

  open IsEquivalence isEquivalence public

  setoid : Setoid b ℓ
  setoid = record { isEquivalence = isEquivalence }

  congˡ : LeftCongruent _≈_ _∙_
  congˡ A≈B = cong refl A≈B

  congʳ : RightCongruent _≈_ _∙_
  congʳ A≈B = cong A≈B refl

record Forest {b ℓ} : Set (lsuc (b ⊔ ℓ)) where
  infix  4 _≈_
  infixl 6 _∙_

  field
    Bird : Set b
    _≈_ : Rel Bird ℓ
    _∙_ : Op₂ Bird
    isForest : IsForest Bird _≈_ _∙_

  _≉_ : Rel Bird ℓ
  x ≉ y = ¬ (x ≈ y)

  open IsForest isForest public

  import Relation.Binary.Reasoning.Base.Single _≈_ refl trans as Base
  open Base using (begin_; _∎) public

  infixr 2 _≈⟨⟩_ step-≈ step-≈˘

  _≈⟨⟩_ : ∀ x {y} → x Base.IsRelatedTo y → x Base.IsRelatedTo y
  _ ≈⟨⟩ x≈y = x≈y

  step-≈ = Base.step-∼
  syntax step-≈ x y≈z x≈y = x ≈⟨ x≈y ⟩ y≈z

  step-≈˘ : ∀ x {y z} → y Base.IsRelatedTo z → y ≈ x → x Base.IsRelatedTo z
  step-≈˘ x y∼z y≈x = x ≈⟨ sym y≈x ⟩ y∼z
  syntax step-≈˘ x y≈z y≈x = x ≈˘⟨ y≈x ⟩ y≈z


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Relation.Nullary.Decidable where

open import Cubical.Core.Everything
open import Cubical.Data.Empty using (⊥)

private
  variable
    ℓ : Level

-- Negation
infix 3 ¬_

¬_ : Type ℓ → Type ℓ
¬ A = A → ⊥

-- Decidable types (inspired by standard library)
data Dec (P : Type ℓ) : Type ℓ where
  yes : ( p :   P) → Dec P
  no  : (¬p : ¬ P) → Dec P

data IsYes {P : Type ℓ} : Dec P → Type ℓ where
  isYes : ∀ {x} → IsYes (yes x)

Discrete : Type ℓ → Type ℓ
Discrete A = ∀ x y → Dec (Path A x y)


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

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism

open import Cubical.Functions.FunExtEquiv

open import Cubical.Data.Nat
open import Cubical.Data.Vec

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

private
  variable
    ℓ ℓ' : Level

-- TODO: generalize to different target type?
nAryFunStructure : (n : ℕ) → Type (ℓ-max (ℓ-suc ℓ) (nAryLevel ℓ ℓ n))
nAryFunStructure {ℓ = ℓ} n = TypeWithStr _ (λ (X : Type ℓ) → nAryOp n X X)

-- iso for n-ary functions
nAryFunIso : (n : ℕ) → StrIso (λ (X : Type ℓ) → nAryOp n X X) ℓ
nAryFunIso n (X , fX) (Y , fY) f =
  (xs : Vec X n) → equivFun f (fX $ⁿ xs) ≡ fY $ⁿ map (equivFun f) xs

nAryFunSNS : (n : ℕ) → SNS {ℓ} _ (nAryFunIso n)
nAryFunSNS n = SNS-≡→SNS-PathP (nAryFunIso n) (nAryFunExtEquiv n)

-- Some specializations that are not used at the moment, but kept as
-- they might become useful later.
private

  -- unary
  unaryFunIso : StrIso  (λ (X : Type ℓ) → nAryOp 1 X X) ℓ
  unaryFunIso (A , f) (B , g) e =
    (x : A) → equivFun e (f x) ≡ g (equivFun e x)

  unaryFunSNS : SNS {ℓ} _ unaryFunIso
  unaryFunSNS = SNS-≡→SNS-PathP unaryFunIso (λ s t → compEquiv lem (nAryFunExtEquiv 1 s t))
    where
    lem : ∀ {X} → {s t : X → X} →
            ((x : X) → s x ≡ t x) ≃
            ((xs : Vec X 1) → (s $ⁿ xs) ≡ (t $ⁿ map (λ x → x) xs))
    lem {X} {s} {t} = isoToEquiv f
      where
      f : Iso ((x : X) → s x ≡ t x)
              ((xs : Vec X 1) → (s $ⁿ xs) ≡ (t $ⁿ map (λ x → x) xs))
      Iso.fun f p (x ∷ [])           = p x
      Iso.inv f p x                  = p (x ∷ [])
      Iso.rightInv f p _ xs@(x ∷ []) = p xs
      Iso.leftInv f p _              = p

  -- binary
  binaryFunIso : StrIso  (λ (X : Type ℓ) → nAryOp 2 X X) ℓ
  binaryFunIso (A , f) (B , g) e =
    (x y : A) → equivFun e (f x y) ≡ g (equivFun e x) (equivFun e y)

  binaryFunSNS : SNS {ℓ} _ binaryFunIso
  binaryFunSNS = SNS-≡→SNS-PathP binaryFunIso (λ s t → compEquiv lem (nAryFunExtEquiv 2 s t))
    where
    lem : ∀ {X} → {s t : X → X → X} →
            ((x y : X) → s x y ≡ t x y) ≃
            ((xs : Vec X 2) → (s $ⁿ xs) ≡ (t $ⁿ map (λ x → x) xs))
    lem {X} {s} {t} = isoToEquiv f
      where
      f : Iso ((x y : X) → s x y ≡ t x y)
              ((xs : Vec X 2) → (s $ⁿ xs) ≡ (t $ⁿ map (λ x → x) xs))
      Iso.fun f p (x ∷ y ∷ [])           = p x y
      Iso.inv f p x y                    = p (x ∷ y ∷ [])
      Iso.rightInv f p _ xs@(x ∷ y ∷ []) = p xs
      Iso.leftInv f p _                  = p


{-# OPTIONS --cubical --safe #-}
module Cubical.Algebra.BasicProp where

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

open import Cubical.Structures.Group

private
  variable
    ℓ ℓ' : Level

---------------------------------------------------------------------
-- Groups basic properties
---------------------------------------------------------------------

-- We will use the multiplicative notation for groups

module _ (G : Group {ℓ}) where

  open group-·syntax G

  private
    ₁· = group-lid G

    ·₁ = group-rid G

    ·-assoc = group-assoc G

    ⁻¹· = group-linv G

    ·⁻¹ = group-rinv G

  id-is-unique : isContr (Σ[ x ∈ ⟨ G ⟩ ] ∀ (y : ⟨ G ⟩) → (x · y ≡ y) × (y · x ≡ y))
  id-is-unique = (₁ , λ y → ₁· y , ·₁ y) ,
                 λ { (e , is-unit) → ΣProp≡ (λ x → isPropΠ λ y → isPropΣ (group-is-set G _ _)
                                                                    λ _ →    group-is-set G _ _)
                                              (₁     ≡⟨ sym (snd (is-unit ₁)) ⟩
                                               ₁ · e ≡⟨ ₁· e ⟩
                                               e ∎
                                              )}

  are-inverses : ∀ (x y : ⟨ G ⟩)
               → x · y ≡ ₁
               → (y ≡ x ⁻¹) × (x ≡ y ⁻¹)
  are-inverses x y eq = (y                ≡⟨ sym (₁· y) ⟩
                         ₁ · y            ≡⟨ sym (·-assoc _ _ _ ∙ cong (_· y) (⁻¹· _)) ⟩
                         (x ⁻¹) · (x · y) ≡⟨ cong ((x ⁻¹) ·_) eq ⟩
                         (x ⁻¹) · ₁       ≡⟨ ·₁ _ ⟩
                         x ⁻¹ ∎)
                     , (x                 ≡⟨ sym (·₁ x) ⟩
                        x · ₁             ≡⟨ cong (x ·_) (sym (·⁻¹ y)) ∙ ·-assoc _ _ _ ⟩
                        (x · y) · (y ⁻¹)  ≡⟨ cong (_· (y ⁻¹)) eq ⟩
                        ₁ · (y ⁻¹)        ≡⟨ ₁· _ ⟩
                        y ⁻¹ ∎)

  inv-involutive : ∀ (x : ⟨ G ⟩)
                 → (x ⁻¹) ⁻¹ ≡ x
  inv-involutive x = sym (snd (are-inverses x (x ⁻¹) (·⁻¹ x)))

  inv-distr : ∀ (x y : ⟨ G ⟩) → (x · y) ⁻¹ ≡ (y ⁻¹) · (x ⁻¹)
  inv-distr x y = sym (fst (are-inverses _ _ γ))
    where γ : (x · y) · ((y ⁻¹) · (x ⁻¹)) ≡ ₁
          γ = (x · y) · ((y ⁻¹) · (x ⁻¹)) ≡⟨ sym (cong (x ·_) (sym (·-assoc _ _ _)) ∙ ·-assoc _ _ _) ⟩
              x · ((y · (y ⁻¹)) · (x ⁻¹)) ≡⟨ cong (λ - → x · (- · (x ⁻¹))) (·⁻¹ y) ⟩
              x · (₁ · (x ⁻¹))            ≡⟨ cong (x ·_) (₁· (x ⁻¹)) ⟩
              x · (x ⁻¹)                  ≡⟨ ·⁻¹ x ⟩
              ₁ ∎

  left-cancel : ∀ (x y z : ⟨ G ⟩) → x · y ≡ x · z → y ≡ z
  left-cancel x y z eq = y                ≡⟨ sym (cong (_· y) (⁻¹· x) ∙ ₁· y) ⟩
                         ((x ⁻¹) · x) · y ≡⟨ sym (·-assoc _ _ _) ⟩
                         (x ⁻¹) · (x · y) ≡⟨ cong ((x ⁻¹) ·_) eq ⟩
                         (x ⁻¹) · (x · z) ≡⟨ ·-assoc _ _ _ ⟩
                         ((x ⁻¹) · x) · z ≡⟨ cong (_· z) (⁻¹· x) ∙ ₁· z ⟩
                         z ∎

  right-cancel : ∀ (x y z : ⟨ G ⟩) → x · z ≡ y · z → x ≡ y
  right-cancel x y z eq = x                ≡⟨ sym (cong (x ·_) (·⁻¹ z) ∙ ·₁ x) ⟩
                          x · (z · (z ⁻¹)) ≡⟨ ·-assoc _ _ _ ⟩
                          (x · z) · (z ⁻¹) ≡⟨ cong (_· (z ⁻¹)) eq ⟩
                          (y · z) · (z ⁻¹) ≡⟨ sym (·-assoc _ _ _) ⟩
                          y · (z · (z ⁻¹)) ≡⟨ cong (y ·_) (·⁻¹ z) ∙ ·₁ y ⟩
                          y ∎


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

open import HoTT

module Extensions where

  ExtensionOf : ∀ {ℓ} {A B : Type ℓ} (f : A → B) (P : B → Type ℓ) (φ : (a : A) → P (f a)) → Type ℓ
  ExtensionOf {A = A} {B = B} f P φ = Σ (Π B P) (λ ψ → (a : A) → ψ (f a) == φ a)

  syntax ExtensionOf f P φ = ⟨ P ⟩⟨ φ ↗ f ⟩

  path-extension : ∀ {ℓ} {A B : Type ℓ} {f : A → B}
                   {P : B → Type ℓ} {φ : (a : A) → P (f a)}
                   (e₀ e₁ : ⟨ P ⟩⟨ φ ↗ f ⟩) →
                   ⟨ (λ b → fst e₀ b == fst e₁ b) ⟩⟨ (λ a → snd e₀ a ∙ ! (snd e₁ a)) ↗ f ⟩ ≃ (e₀ == e₁)
  path-extension {f = f} (ψ₀ , ε₀) (ψ₁ , ε₁) = equiv to {!!} {!!} {!!}

    where to : ExtensionOf f (λ b → ψ₀ b == ψ₁ b) (λ a → ε₀ a ∙ ! (ε₁ a)) → (ψ₀ , ε₀) == (ψ₁ , ε₁)
          to (α , β) = pair= (λ= α) {!!}

          from : (ψ₀ , ε₀) == (ψ₁ , ε₁) → ExtensionOf f (λ b → ψ₀ b == ψ₁ b) (λ a → ε₀ a ∙ ! (ε₁ a))
          from p = {!!}

    --       from : (e₀ == e₁) → ⟨ (λ b → fst e₀ b == fst e₁ b) ⟩⟨ (λ a → snd e₀ a ∙ ! (snd e₁ a)) ↗ f ⟩
    --       from = {!!}

  -- Definition equiv_path_extension `{Funext} {A B : Type} {f : A -> B}
  --            {P : B -> Type} {d : forall x:A, P (f x)}
  --            (ext ext' : ExtensionAlong f P d)
  -- : (ExtensionAlong f
  --                   (fun y => pr1 ext y = pr1 ext' y)
  --                   (fun x => pr2 ext x @ (pr2 ext' x)^))
  --   <~> ext = ext'.


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

open import level
open import function.isomorphism.lift
open import hott.level.core
open import hott.level.closure.core

-- lifting preserves h-levels
↑-level : ∀ {i n} j {X : Set i}
        → h n X
        → h n (↑ j X)
↑-level j {X} = iso-level (lift-iso j X)


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

open import Base

{-
    This file contains the lemma that
    a point (1 -> A) has n-connected fibers
    if A is (S n)-connected.

    The other direction will be added whenever
    it is needed.
-}

module Homotopy.PointConnected {i} (A : Set i) (a : A) where

  open import Homotopy.Connected
  open import Homotopy.Truncation
  open import Homotopy.PathTruncation

  point : unit {i} → A
  point _ = a

  abstract
    point-has-connected-fibers : ∀ {n} →
      is-connected (S n) A → has-connected-fibers n point
    point-has-connected-fibers {n} A-is-conn a₂ = center [a≡a₂]n , path
      where
        [a≡a₂]n : τ n (a ≡ a₂)
        [a≡a₂]n = connected-has-all-τ-paths A-is-conn a a₂

        center : τ n (a ≡ a₂) → τ n (hfiber point a₂)
        center = τ-extend-nondep ⦃ τ-is-truncated n _ ⦄
          (λ shift → proj $ tt , shift)

        path′ : ∀ f → proj f ≡ center [a≡a₂]n
        path′ (tt , a≡a₂) = ap center $ contr-has-all-paths
          (connected-has-connected-paths A-is-conn a a₂) (proj a≡a₂) [a≡a₂]n

        path : ∀ f → f ≡ center [a≡a₂]n
        path = τ-extend ⦃ λ _ → ≡-is-truncated n $ τ-is-truncated n _ ⦄ path′


open import Data.Graph

module Data.Graph.Path.Search {ℓᵥ ℓₑ} (g : FiniteGraph ℓᵥ ℓₑ) where

open import Data.Graph.Path.Cut g
open import Data.Graph.Path.Finite g
open import Data.Product as Σ
open import Data.Sum as ⊎
open import Data.Vec as Vec
open import Finite
open import Function
open import Level
open import Relation.Binary
open import Relation.Binary.Construct.Closure.ReflexiveTransitive
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary hiding (module Dec)
open import Relation.Nullary.Decidable as Dec
open import Relation.Nullary.Negation as ¬

open FiniteGraph g
open IsFinite

pathSearchFrom : ∀ {ℓ} {P : Vertex → Set ℓ} →
  (∀ b → Dec (P b)) → ∀ a → Dec (∃ λ b → P b × ∃ (Path a b))
pathSearchFrom P? a =
  case ∃? (Path≤-finite (size vertexFinite) a) (P? ∘ proj₁) of λ where
    (yes ((_ , _ , _ , p) , pb)) → yes (-, pb , (-, p))
    (no ¬p) → no λ where (_ , pb , _ , p) → ¬p ((-, shortEnoughPath p) , pb)

pathSearchAcyclicFrom : ∀ {ℓ} {P : Vertex → Set ℓ} →
  (∀ b → Dec (P b)) → ∀ a →
  Dec (∃ λ b → P b × ∃₂ λ n (p : Path a b n) → Acyclic p)
pathSearchAcyclicFrom P? a =
  case ∃? (Path≤-finite (size vertexFinite) a) (P? ∘ proj₁) of λ where
    (yes ((_ , _ , _ , p) , pb)) →
      let (x , x≤n , p′) , ¬r′ = acyclicPath p in
        yes (-, pb , (-, (p′ , ¬r′)))
    (no ¬p) → no λ where (_ , pb , _ , p , r) → ¬p ((-, shortEnoughPath p) , pb)

pathSearchBetween : ∀ a b → Dec (∃ (Path a b))
pathSearchBetween a b =
  case pathSearchFrom (decEqVertex b) a of λ where
    (yes (_ , refl , p)) → yes p
    (no ¬p) → no λ where (n , p) → ¬p (-, refl , -, p)

searchFrom : ∀ {ℓ} {P : Vertex → Set ℓ} →
  (∀ b → Dec (P b)) →
  ∀ a → Dec (∃ λ b → P b × Star Edge a b)
searchFrom P? a =
  Dec.map′
    (Σ.map₂ (Σ.map₂ (toStar ∘ proj₂)))
    (Σ.map₂ (Σ.map₂ (-,_ ∘ fromStar)))
    (pathSearchFrom P? a)

searchBetween : ∀ a b → Dec (Star Edge a b)
searchBetween a b = Dec.map′ (toStar ∘ proj₂) (-,_ ∘ fromStar) (pathSearchBetween a b)

module _
  {ℓ ℓ≈ ℓ<}
  {P : Vertex → Set ℓ} (P? : ∀ a → Dec (P a))
  {_≈_ : ∀ {a} → Rel (∃ (Star Edge a)) ℓ≈}
  {_<_ : ∀ {a} → Rel (∃ (Star Edge a)) ℓ<}
  (<-po : ∀ {a} → IsDecStrictPartialOrder (_≈_ {a}) _<_)
  where

  record MaximalPath a : Set (ℓ ⊔ ℓᵥ ⊔ ℓₑ ⊔ ℓ<) where
    field
      destination : Vertex
      predicate : P destination
      path : Star Edge a destination
      acyclic : Acyclic (fromStar path)
      isMax : ∀
        {b} (p : Star Edge a b) (pb : P b) → Acyclic (fromStar p) →
        ¬ ((-, path) < (-, p))

  searchMaximalFrom : ∀ a → Dec (MaximalPath a)
  searchMaximalFrom a =
    case max of λ where
      (inj₁ ¬p) →
        no λ mp →
          let open MaximalPath mp in
            ¬p ((-, path , fromWitness acyclic) , fromWitness predicate)

      (inj₂ (((b , p , acp) , pb) , isMax)) →
        yes record
          { destination = b
          ; predicate = toWitness pb
          ; path = p
          ; acyclic = toWitness acp
          ; isMax = λ q pb acq → isMax ((-, q , fromWitness acq) , fromWitness pb)
          }
    where
      module DPO = IsDecStrictPartialOrder <-po

      _≈′_ = _≈_ on λ where ((b , p , acp) , pb) → b , p
      _<′_ = _<_ on λ where ((b , p , acp) , pb) → b , p

      <′-IsDecStrictPartialOrder : IsDecStrictPartialOrder _≈′_ _<′_
      <′-IsDecStrictPartialOrder = record
        { isStrictPartialOrder = record
          { isEquivalence = record
            { refl = IsEquivalence.refl DPO.isEquivalence
            ; sym = IsEquivalence.sym DPO.isEquivalence
            ; trans = IsEquivalence.trans DPO.isEquivalence
            }
          ; irrefl = DPO.irrefl
          ; trans = DPO.trans
          ; <-resp-≈ = proj₁ DPO.<-resp-≈ , proj₂ DPO.<-resp-≈
          }
        ; _≟_ = λ _ _ → _ DPO.≟ _
        ; _<?_ = λ _ _ → _ DPO.<? _
        }

      acyclicPaths = filter (AcyclicStar-finite a) (P? ∘ proj₁)

      open Ordered acyclicPaths <′-IsDecStrictPartialOrder


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.RingSolver.Examples where

open import Cubical.Foundations.Prelude

open import Cubical.Algebra.CommRing
open import Cubical.Algebra.RingSolver.ReflectionSolving

private
  variable
    ℓ : Level

module Test (R : CommRing {ℓ}) where
  open CommRingStr (snd R)

  _ :   1r · (1r + 0r)
      ≡ (1r · 0r) + 1r
  _ = solve R

  _ :   1r · 0r + (1r - 1r)
      ≡ 0r - 0r
  _ = solve R

  _ : (x : fst R) → x ≡ x
  _ = solve R

  _ : (x y : fst R) → x ≡ x
  _ = solve R

  _ : (x y : fst R) → x + y ≡ y + x
  _ = solve R

  _ : (x y : fst R) → (x + y) · (x - y) ≡ x · x - y · y
  _ = solve R

  {-
    A bigger example, copied from the other example files:
  -}
  _ : (x y z : (fst R)) → (x + y) · (x + y) · (x + y) · (x + y)
                ≡ x · x · x · x + (fromℤ R 4) · x · x · x · y + (fromℤ R 6) · x · x · y · y
                  + (fromℤ R 4) · x · y · y · y + y · y · y · y
  _ = solve R

  {-
    Keep in mind, that the solver can lead to wrong error locations.
    For example, the commented code below tries to solve an equation that does not hold,
    with the result of an error at the wrong location.

  _ : (x y : (fst R)) → x ≡ y
  _ = solve R
  -}


{-# OPTIONS --cubical --safe #-}
module Cubical.Data.Maybe.Properties where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Data.Empty
open import Cubical.Data.Unit
open import Cubical.Data.Nat
open import Cubical.Relation.Nullary
open import Cubical.Data.Sum

open import Cubical.Data.Maybe.Base

-- Path space of Maybe type
module MaybePath {ℓ} {A : Type ℓ} where
  Cover : Maybe A → Maybe A → Type ℓ
  Cover nothing  nothing   = Lift Unit
  Cover nothing  (just _)  = Lift ⊥
  Cover (just _) nothing   = Lift ⊥
  Cover (just a) (just a') = a ≡ a'

  reflCode : (c : Maybe A) → Cover c c
  reflCode nothing  = lift tt
  reflCode (just b) = refl

  encode : ∀ c c' → c ≡ c' → Cover c c'
  encode c _ = J (λ c' _ → Cover c c') (reflCode c)

  encodeRefl : ∀ c → encode c c refl ≡ reflCode c
  encodeRefl c = JRefl (λ c' _ → Cover c c') (reflCode c)

  decode : ∀ c c' → Cover c c' → c ≡ c'
  decode nothing  nothing  _ = refl
  decode (just _) (just _) p = cong just p

  decodeRefl : ∀ c → decode c c (reflCode c) ≡ refl
  decodeRefl nothing  = refl
  decodeRefl (just _) = refl

  decodeEncode : ∀ c c' → (p : c ≡ c') → decode c c' (encode c c' p) ≡ p
  decodeEncode c _ =
    J (λ c' p → decode c c' (encode c c' p) ≡ p)
      (cong (decode c c) (encodeRefl c) ∙ decodeRefl c)

  isOfHLevelCover : (n : ℕ)
    → isOfHLevel (suc (suc n)) A
    → ∀ c c' → isOfHLevel (suc n) (Cover c c')
  isOfHLevelCover n p nothing  nothing   = isOfHLevelLift (suc n) (isOfHLevelUnit (suc n))
  isOfHLevelCover n p nothing  (just a') = isOfHLevelLift (suc n)
    (subst (λ m → isOfHLevel m ⊥) (+-comm n 1) (hLevelLift n isProp⊥))
  isOfHLevelCover n p (just a) nothing   = isOfHLevelLift (suc n)
    (subst (λ m → isOfHLevel m ⊥) (+-comm n 1) (hLevelLift n isProp⊥))
  isOfHLevelCover n p (just a) (just a') = p a a'

isOfHLevelMaybe : ∀ {ℓ} (n : ℕ) {A : Type ℓ}
  → isOfHLevel (suc (suc n)) A
  → isOfHLevel (suc (suc n)) (Maybe A)
isOfHLevelMaybe n lA c c' =
  retractIsOfHLevel (suc n)
    (MaybePath.encode c c')
    (MaybePath.decode c c')
    (MaybePath.decodeEncode c c')
    (MaybePath.isOfHLevelCover n lA c c')

private
 variable
   ℓ : Level
   A : Type ℓ

fromJust-def : A → Maybe A → A
fromJust-def a nothing = a
fromJust-def _ (just a) = a

just-inj : (x y : A) → just x ≡ just y → x ≡ y
just-inj x _ eq = cong (fromJust-def x) eq

¬nothing≡just : ∀ {x : A} → ¬ (nothing ≡ just x)
¬nothing≡just {A = A} {x = x} p = lower (subst (caseMaybe (Maybe A) (Lift ⊥)) p (just x))

¬just≡nothing : ∀ {x : A} → ¬ (just x ≡ nothing)
¬just≡nothing {A = A} {x = x} p = lower (subst (caseMaybe (Lift ⊥) (Maybe A)) p (just x))

discreteMaybe : Discrete A → Discrete (Maybe A)
discreteMaybe eqA nothing nothing    = yes refl
discreteMaybe eqA nothing (just a')  = no ¬nothing≡just
discreteMaybe eqA (just a) nothing   = no ¬just≡nothing
discreteMaybe eqA (just a) (just a') with eqA a a'
... | yes p = yes (cong just p)
... | no ¬p = no (λ p → ¬p (just-inj _ _ p))

module SumUnit where
  Maybe→SumUnit : Maybe A → Unit ⊎ A
  Maybe→SumUnit nothing  = inl tt
  Maybe→SumUnit (just a) = inr a

  SumUnit→Maybe : Unit ⊎ A → Maybe A
  SumUnit→Maybe (inl _) = nothing
  SumUnit→Maybe (inr a) = just a

  Maybe→SumUnit→Maybe : (x : Maybe A) → SumUnit→Maybe (Maybe→SumUnit x) ≡ x
  Maybe→SumUnit→Maybe nothing  = refl
  Maybe→SumUnit→Maybe (just _) = refl

  SumUnit→Maybe→SumUnit : (x : Unit ⊎ A) → Maybe→SumUnit (SumUnit→Maybe x) ≡ x
  SumUnit→Maybe→SumUnit (inl _) = refl
  SumUnit→Maybe→SumUnit (inr _) = refl

Maybe≡SumUnit : Maybe A ≡ Unit ⊎ A
Maybe≡SumUnit = isoToPath (iso SumUnit.Maybe→SumUnit SumUnit.SumUnit→Maybe SumUnit.SumUnit→Maybe→SumUnit SumUnit.Maybe→SumUnit→Maybe)


module examplesPaperJFP.loadAllOOAgdaPart1 where

-- This file loads the files containing the code examples in the ooAgda paper
-- ordered by sections
-- The code is divided into files
--    loadAllOOAgdaPart1.agda and loadAllOOAgdaPart2.agda
-- loadAllOOAgdaPart1.agda loads code from Sect. 1 - 7
-- loadAllOOAgdaPart2.agda loads code from Sect. 8 - 12
--
-- The reason for splitting it into  two files is that because of some
--  Builtin the code from the first file cannot be loaded at the same
--  time as the code from the second one.
-- The difference is loading  NativeIOSafe.agda vs NativeIO.agda
--
-- Important changes due to updating it to current agda
-- ####################################################
--      * do is now a keyword and therefore replaced by exec
--      * some other small changes mainly because of changes in the
--           standard library have been made
--
-- Files from the Library
-- #########################
-- loadAllOOAgdaFilesAsInLibrary.agda
-- loads corresponding code from the library which is slightly different
--   from how it is represented in the paper

-- Source of paper, presentations, slides
-- #######################################
--  Andreas Abel, Stephan Adelsberger, Anton Setzer:
--    Interactive Programming in Agda - Objects and Graphical User Interfaces
--    Journal of Functional Programming, 27, 2017
--    doi: http://dx.doi.org/10.1145/2976022.2976032
--    authors copy: http://www.cs.swan.ac.uk/~csetzer/articles/ooAgda.pdf
--    bibtex: http://www.cs.swan.ac.uk/~csetzer/articles/ooAgda.bib

-- 1. Introdution
-- 2. Introduction to Agda

import examplesPaperJFP.finn
import examplesPaperJFP.exampleFinFun
import examplesPaperJFP.Equality

-- 3. Coalgebras in Agda
-- 3.1. Coalgebra by example: Colists

import examplesPaperJFP.Colists
import examplesPaperJFP.Collatz

-- 3.2. Coalgebras in General

import examplesPaperJFP.Coalgebra

-- 4. Interactive Programs in Agda
-- 4.1. Interaction interfaces

import examplesPaperJFP.NativeIOSafe
import examplesPaperJFP.BasicIO
import examplesPaperJFP.triangleRightOperator
import examplesPaperJFP.ConsoleInterface

-- 4.2. Interaction trees

import examplesPaperJFP.Console
import examplesPaperJFP.CatNonTerm
import examplesPaperJFP.CatTerm

-- 4.3. Running interactive programs

import examplesPaperJFP.IOExampleConsole

-- 5. Objects in Agda

-- code as in paper adapted to new Agda
import examplesPaperJFP.Object
-- code as in library see loadAllOOAgdaFilesAsInLibrary.agda
-- open import SizedIO.Object

-- 6. Sized Coinductive Types

import examplesPaperJFP.Sized

-- 7. Interface Extension and Delegation

-- code as in paper adapted to new Agda
import examplesPaperJFP.CounterCell
-- code as in library see loadAllOOAgdaFilesAsInLibrary.agda
-- open import Sized.CounterCell

--  *** Code from Sect 8 - 12 can be found in loadAllOOAgdaPart2.agda ***


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

open import PathInduction using (Type; _==_; idp; Square; !; _∙_; Coh; path-induction)

module ExPathInduction {i} where

{-<excoh>-}
coh :  {A : Type i} {a : A} →
       Coh  ({b : A} (p : a == b)
            {d : A} {s : d == b}
            {c : A} {r : b == c}
            {f : A} {u : f == c}
            {e : A} {t : e == c}
            {w : f == e} (ν : Square w idp t u)
            {v : d == e} (α : Square v s t r)
            {vw : d == f} (vw= : vw == v ∙ ! w)
            → Square (p ∙ ! s) p vw (r ∙ ! u))
coh = path-induction
{-</>-}


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

module HoTT-UF-Agda where

open import Universes public

variable
 𝓤 𝓥 𝓦 𝓣 : Universe

data 𝟙 : 𝓤₀ ̇  where
 ⋆ : 𝟙

𝟙-induction : (A : 𝟙 → 𝓤 ̇ ) → A ⋆ → (x : 𝟙) → A x
𝟙-induction A a ⋆ = a

𝟙-recursion : (B : 𝓤 ̇ ) → B → (𝟙 → B)
𝟙-recursion B b x = 𝟙-induction (λ _ → B) b x

!𝟙' : (X : 𝓤 ̇ ) → X → 𝟙
!𝟙' X x = ⋆

!𝟙 : {X : 𝓤 ̇ } → X → 𝟙
!𝟙 x = ⋆

data 𝟘 : 𝓤₀ ̇  where

𝟘-induction : (A : 𝟘 → 𝓤 ̇ ) → (x : 𝟘) → A x
𝟘-induction A ()

𝟘-recursion : (A : 𝓤 ̇ ) → 𝟘 → A
𝟘-recursion A a = 𝟘-induction (λ _ → A) a

!𝟘 : (A : 𝓤 ̇ ) → 𝟘 → A
!𝟘 = 𝟘-recursion

is-empty : 𝓤 ̇ → 𝓤 ̇
is-empty X = X → 𝟘

¬ : 𝓤 ̇ → 𝓤 ̇
¬ X = X → 𝟘

data ℕ : 𝓤₀ ̇  where
 zero : ℕ
 succ : ℕ → ℕ

{-# BUILTIN NATURAL ℕ #-}

ℕ-induction : (A : ℕ → 𝓤 ̇ )
            → A 0
            → ((n : ℕ) → A n → A (succ n))
            → (n : ℕ) → A n

ℕ-induction A a₀ f = h
 where
  h : (n : ℕ) → A n
  h 0        = a₀
  h (succ n) = f n (h n)

ℕ-recursion : (X : 𝓤 ̇ )
            → X
            → (ℕ → X → X)
            → ℕ → X

ℕ-recursion X = ℕ-induction (λ _ → X)

ℕ-iteration : (X : 𝓤 ̇ )
            → X
            → (X → X)
            → ℕ → X

ℕ-iteration X x f = ℕ-recursion X x (λ _ x → f x)

module Arithmetic where

  _+_  _×_ : ℕ → ℕ → ℕ

  x + 0      = x
  x + succ y = succ (x + y)

  x × 0      = 0
  x × succ y = x + x × y

  infixl 20 _+_
  infixl 21 _×_

module Arithmetic' where

  _+_  _×_ : ℕ → ℕ → ℕ

  x + y = h y
   where
    h : ℕ → ℕ
    h = ℕ-iteration ℕ x succ

  x × y = h y
   where
    h : ℕ → ℕ
    h = ℕ-iteration ℕ 0 (x +_)

  infixl 20 _+_
  infixl 21 _×_

module ℕ-order where

  _≤_ _≥_ : ℕ → ℕ → 𝓤₀ ̇
  0      ≤ y      = 𝟙
  succ x ≤ 0      = 𝟘
  succ x ≤ succ y = x ≤ y

  x ≥ y = y ≤ x

  infix 10 _≤_
  infix 10 _≥_

data _+_ {𝓤 𝓥} (X : 𝓤 ̇ ) (Y : 𝓥 ̇ ) : 𝓤 ⊔ 𝓥 ̇  where
 inl : X → X + Y
 inr : Y → X + Y

+-induction : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } (A : X + Y → 𝓦 ̇ )
            → ((x : X) → A (inl x))
            → ((y : Y) → A (inr y))
            → (z : X + Y) → A z

+-induction A f g (inl x) = f x
+-induction A f g (inr y) = g y

+-recursion : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } {A : 𝓦 ̇ } → (X → A) → (Y → A) → X + Y → A
+-recursion {𝓤} {𝓥} {𝓦} {X} {Y} {A} = +-induction (λ _ → A)

𝟚 : 𝓤₀ ̇
𝟚 = 𝟙 + 𝟙

pattern ₀ = inl ⋆
pattern ₁ = inr ⋆

𝟚-induction : (A : 𝟚 → 𝓤 ̇ ) → A ₀ → A ₁ → (n : 𝟚) → A n
𝟚-induction A a₀ a₁ ₀ = a₀
𝟚-induction A a₀ a₁ ₁ = a₁

𝟚-induction' : (A : 𝟚 → 𝓤 ̇ ) → A ₀ → A ₁ → (n : 𝟚) → A n
𝟚-induction' A a₀ a₁ = +-induction A
                         (𝟙-induction (λ (x : 𝟙) → A (inl x)) a₀)
                         (𝟙-induction (λ (y : 𝟙) → A (inr y)) a₁)

record Σ {𝓤 𝓥} {X : 𝓤 ̇ } (Y : X → 𝓥 ̇ ) : 𝓤 ⊔ 𝓥 ̇  where
  constructor
   _,_
  field
   x : X
   y : Y x

pr₁ : {X : 𝓤 ̇ } {Y : X → 𝓥 ̇ } → Σ Y → X
pr₁ (x , y) = x

pr₂ : {X : 𝓤 ̇ } {Y : X → 𝓥 ̇ } → (z : Σ Y) → Y (pr₁ z)
pr₂ (x , y) = y

-Σ : {𝓤 𝓥 : Universe} (X : 𝓤 ̇ ) (Y : X → 𝓥 ̇ ) → 𝓤 ⊔ 𝓥 ̇
-Σ X Y = Σ Y

syntax -Σ X (λ x → y) = Σ x ꞉ X , y

Σ-induction : {X : 𝓤 ̇ } {Y : X → 𝓥 ̇ } {A : Σ Y → 𝓦 ̇ }
            → ((x : X) (y : Y x) → A (x , y))
            → ((x , y) : Σ Y) → A (x , y)

Σ-induction g (x , y) = g x y

curry : {X : 𝓤 ̇ } {Y : X → 𝓥 ̇ } {A : Σ Y → 𝓦 ̇ }
      → (((x , y) : Σ Y) → A (x , y))
      → ((x : X) (y : Y x) → A (x , y))

curry f x y = f (x , y)

_×_ : 𝓤 ̇ → 𝓥 ̇ → 𝓤 ⊔ 𝓥 ̇
X × Y = Σ x ꞉ X , Y

Π : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) → 𝓤 ⊔ 𝓥 ̇
Π {𝓤} {𝓥} {X} A = (x : X) → A x

-Π : {𝓤 𝓥 : Universe} (X : 𝓤 ̇ ) (Y : X → 𝓥 ̇ ) → 𝓤 ⊔ 𝓥 ̇
-Π X Y = Π Y

syntax -Π A (λ x → b) = Π x ꞉ A , b

id : {X : 𝓤 ̇ } → X → X
id x = x

𝑖𝑑 : (X : 𝓤 ̇ ) → X → X
𝑖𝑑 X = id

_∘_ : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } {Z : Y → 𝓦 ̇ }
    → ((y : Y) → Z y)
    → (f : X → Y)
    → (x : X) → Z (f x)

g ∘ f = λ x → g (f x)

domain : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } → (X → Y) → 𝓤 ̇
domain {𝓤} {𝓥} {X} {Y} f = X

codomain : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } → (X → Y) → 𝓥 ̇
codomain {𝓤} {𝓥} {X} {Y} f = Y

type-of : {X : 𝓤 ̇ } → X → 𝓤 ̇
type-of {𝓤} {X} x = X

data Id {𝓤} (X : 𝓤 ̇ ) : X → X → 𝓤 ̇  where
 refl : (x : X) → Id X x x

_≡_ : {X : 𝓤 ̇ } → X → X → 𝓤 ̇
x ≡ y = Id _ x y

𝕁 : (X : 𝓤 ̇ ) (A : (x y : X) → x ≡ y → 𝓥 ̇ )
  → ((x : X) → A x x (refl x))
  → (x y : X) (p : x ≡ y) → A x y p
𝕁 X A f x x (refl x) = f x

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

𝕁' : (X : 𝓤 ̇ ) (A : (x y : X) → x ≡ y → 𝓥 ̇ )
   → ((x : X) → A x x (refl x))
   → (x y : X) (p : x ≡ y) → A x y p
𝕁' X A f x = ℍ x (A x) (f x)

𝕁s-agreement : (X : 𝓤 ̇ ) (A : (x y : X) → x ≡ y → 𝓥 ̇ )
               (f : (x : X) → A x x (refl x)) (x y : X) (p : x ≡ y)
             → 𝕁 X A f x y p ≡ 𝕁' X A f x y p
𝕁s-agreement X A f x x (refl x) = refl (f x)

transport : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) {x y : X}
          → x ≡ y → A x → A y
transport A (refl x) = 𝑖𝑑 (A x)

transport𝕁 : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) {x y : X}
           → x ≡ y → A x → A y
transport𝕁 {𝓤} {𝓥} {X} A {x} {y} = 𝕁 X (λ x y _ → A x → A y) (λ x → 𝑖𝑑 (A x)) x y

nondep-ℍ : {X : 𝓤 ̇ } (x : X) (A : X → 𝓥 ̇ )
         → A x → (y : X) → x ≡ y → A y
nondep-ℍ x A = ℍ x (λ y _ → A y)

transportℍ : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) {x y : X}
           → x ≡ y → A x → A y
transportℍ A {x} {y} p a = nondep-ℍ x A a y p

transports-agreement : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) {x y : X} (p : x ≡ y)
                     → (transportℍ A p ≡ transport A p)
                     × (transport𝕁 A p ≡ transport A p)
transports-agreement A (refl x) = refl (transport A (refl x)) ,
                                  refl (transport A (refl x))

lhs : {X : 𝓤 ̇ } {x y : X} → x ≡ y → X
lhs {𝓤} {X} {x} {y} p = x

rhs : {X : 𝓤 ̇ } {x y : X} → x ≡ y → X
rhs {𝓤} {X} {x} {y} p = y

_∙_ : {X : 𝓤 ̇ } {x y z : X} → x ≡ y → y ≡ z → x ≡ z
p ∙ q = transport (lhs p ≡_) q p

_≡⟨_⟩_ : {X : 𝓤 ̇ } (x : X) {y z : X} → x ≡ y → y ≡ z → x ≡ z
x ≡⟨ p ⟩ q = p ∙ q

_∎ : {X : 𝓤 ̇ } (x : X) → x ≡ x
x ∎ = refl x

_⁻¹ : {X : 𝓤 ̇ } → {x y : X} → x ≡ y → y ≡ x
p ⁻¹ = transport (_≡ lhs p) p (refl (lhs p))

_∙'_ : {X : 𝓤 ̇ } {x y z : X} → x ≡ y → y ≡ z → x ≡ z
p ∙' q = transport (_≡ rhs q) (p ⁻¹) q

∙agreement : {X : 𝓤 ̇ } {x y z : X} (p : x ≡ y) (q : y ≡ z)
          → (p ∙' q) ≡ (p ∙ q)
∙agreement (refl x) (refl x) = refl (refl x)

rdnel : {X : 𝓤 ̇ } {x y : X} (p : x ≡ y)
      → (p ∙ refl y) ≡ p

rdnel p = refl p

rdner : {X : 𝓤 ̇ } {y z : X} (q : y ≡ z)
      → (refl y  ∙' q) ≡ q

rdner q = refl q

ap : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } (f : X → Y) {x x' : X} → x ≡ x' → f x ≡ f x'
ap f {x} {x'} p = transport (λ - → f x ≡ f -) p (refl (f x))

_∼_ : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } → Π A → Π A → 𝓤 ⊔ 𝓥 ̇
f ∼ g = ∀ x → f x ≡ g x

¬¬ ¬¬¬ : 𝓤 ̇ → 𝓤 ̇
¬¬  A = ¬(¬ A)
¬¬¬ A = ¬(¬¬ A)

dni : (A : 𝓤 ̇ ) → A → ¬¬ A
dni A a u = u a

contrapositive : {A : 𝓤 ̇ } {B : 𝓥 ̇ } → (A → B) → (¬ B → ¬ A)
contrapositive f v a = v (f a)

tno : (A : 𝓤 ̇ ) → ¬¬¬ A → ¬ A
tno A = contrapositive (dni A)

_⇔_ : 𝓤 ̇ → 𝓥 ̇ → 𝓤 ⊔ 𝓥 ̇
X ⇔ Y = (X → Y) × (Y → X)

lr-implication : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } → (X ⇔ Y) → (X → Y)
lr-implication = pr₁

rl-implication : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } → (X ⇔ Y) → (Y → X)
rl-implication = pr₂

absurdity³-is-absurdity : {A : 𝓤 ̇ } → ¬¬¬ A ⇔ ¬ A
absurdity³-is-absurdity {𝓤} {A} = firstly , secondly
 where
  firstly : ¬¬¬ A → ¬ A
  firstly = contrapositive (dni A)

  secondly : ¬ A → ¬¬¬ A
  secondly = dni (¬ A)

_≢_ : {X : 𝓤 ̇ } → X → X → 𝓤 ̇
x ≢ y = ¬(x ≡ y)

≢-sym : {X : 𝓤 ̇ } {x y : X} → x ≢ y → y ≢ x
≢-sym {𝓤} {X} {x} {y} u = λ (p : y ≡ x) → u (p ⁻¹)

Id→Fun : {X Y : 𝓤 ̇ } → X ≡ Y → X → Y
Id→Fun {𝓤} = transport (𝑖𝑑 (𝓤 ̇ ))

Id→Fun' : {X Y : 𝓤 ̇ } → X ≡ Y → X → Y
Id→Fun' (refl X) = 𝑖𝑑 X

Id→Funs-agree : {X Y : 𝓤 ̇ } (p : X ≡ Y)
              → Id→Fun p ≡ Id→Fun' p

Id→Funs-agree (refl X) = refl (𝑖𝑑 X)

𝟙-is-not-𝟘 : 𝟙 ≢ 𝟘
𝟙-is-not-𝟘 p = Id→Fun p ⋆

₁-is-not-₀ : ₁ ≢ ₀
₁-is-not-₀ p = 𝟙-is-not-𝟘 q
 where
  f : 𝟚 → 𝓤₀ ̇
  f ₀ = 𝟘
  f ₁ = 𝟙

  q : 𝟙 ≡ 𝟘
  q = ap f p

₁-is-not-₀[not-an-MLTT-proof] : ¬(₁ ≡ ₀)
₁-is-not-₀[not-an-MLTT-proof] ()

decidable : 𝓤 ̇ → 𝓤 ̇
decidable A = A + ¬ A

has-decidable-equality : 𝓤 ̇ → 𝓤 ̇
has-decidable-equality X = (x y : X) → decidable (x ≡ y)

𝟚-has-decidable-equality : has-decidable-equality 𝟚
𝟚-has-decidable-equality ₀ ₀ = inl (refl ₀)
𝟚-has-decidable-equality ₀ ₁ = inr (≢-sym ₁-is-not-₀)
𝟚-has-decidable-equality ₁ ₀ = inr ₁-is-not-₀
𝟚-has-decidable-equality ₁ ₁ = inl (refl ₁)

not-zero-is-one : (n : 𝟚) → n ≢ ₀ → n ≡ ₁
not-zero-is-one ₀ f = !𝟘 (₀ ≡ ₁) (f (refl ₀))
not-zero-is-one ₁ f = refl ₁

inl-inr-disjoint-images : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } {x : X} {y : Y} → inl x ≢ inr y
inl-inr-disjoint-images {𝓤} {𝓥} {X} {Y} p = 𝟙-is-not-𝟘 q
 where
  f : X + Y → 𝓤₀ ̇
  f (inl x) = 𝟙
  f (inr y) = 𝟘

  q : 𝟙 ≡ 𝟘
  q = ap f p

right-fails-gives-left-holds : {P : 𝓤 ̇ } {Q : 𝓥 ̇ } → P + Q → ¬ Q → P
right-fails-gives-left-holds (inl p) u = p
right-fails-gives-left-holds (inr q) u = !𝟘 _ (u q)

module twin-primes where

 open Arithmetic renaming (_×_ to _*_ ; _+_ to _∔_)
 open ℕ-order

 is-prime : ℕ → 𝓤₀ ̇
 is-prime n = (n ≥ 2) × ((x y : ℕ) → x * y ≡ n → (x ≡ 1) + (x ≡ n))

 twin-prime-conjecture : 𝓤₀ ̇
 twin-prime-conjecture =
                       (n : ℕ) → -Σ ℕ (λ p → ((p ≥ n) × is-prime p) × is-prime (p ∔ 2))

positive-not-zero : (x : ℕ) → succ x ≢ 0
positive-not-zero x p = 𝟙-is-not-𝟘 q where
  f : ℕ →  𝓤₀ ̇
  f zero = 𝟘
  f (succ n) = 𝟙

  q : 𝟙 ≡ 𝟘
  q = ap f p

pred : ℕ → ℕ
pred 0        = 0
pred (succ n) = n

succ-lc : {x y : ℕ} → succ x ≡ succ y → x ≡ y
succ-lc = ap pred

ℕ-has-decidable-equality : has-decidable-equality ℕ
ℕ-has-decidable-equality 0 0               = inl (refl 0)
ℕ-has-decidable-equality 0 (succ y)        = inr (≢-sym (positive-not-zero y))
ℕ-has-decidable-equality (succ x) 0        = inr (positive-not-zero x)
ℕ-has-decidable-equality (succ x) (succ y) = f (ℕ-has-decidable-equality x y)
 where
  f : decidable (x ≡ y) → decidable (succ x ≡ succ y)
  f (inl p) = inl (ap succ p)
  f (inr k) = inr (λ (s : succ x ≡ succ y) → k (succ-lc s))

module basic-arithmetic-and-order where

  open ℕ-order public
  open Arithmetic renaming (_+_ to _∔_) hiding (_×_)

  +-assoc : (x y z : ℕ) → ((x ∔ y) ∔ z) ≡ (x ∔ (y ∔ z))
  +-assoc x y zero     =  ((x ∔ y) ∔ 0) ≡⟨ (refl _) ⟩
                          (x ∔ (y ∔ 0)) ∎

  +-assoc x y (succ z) = ((x ∔ y) ∔ succ z)   ≡⟨ (refl _)     ⟩
                         (succ ((x ∔ y) ∔ z)) ≡⟨ ap succ IH ⟩
                         (succ (x ∔ (y ∔ z))) ≡⟨ refl _     ⟩
                         (x ∔ (y ∔ succ z))   ∎
   where
    IH : ((x ∔ y) ∔ z) ≡ (x ∔ (y ∔ z))
    IH = +-assoc x y z

  +-base-on-first : (x : ℕ) → 0 ∔ x ≡ x
  +-base-on-first 0        = refl 0
  +-base-on-first (succ x) = 0 ∔ succ x   ≡⟨ refl _     ⟩
                             succ (0 ∔ x) ≡⟨ ap succ IH ⟩
                             succ x       ∎
   where
    IH : 0 ∔ x ≡ x
    IH = +-base-on-first x

  +-step-on-first : (x y : ℕ) → succ x ∔ y ≡ succ (x ∔ y)
  +-step-on-first x zero     = refl (succ x)
  +-step-on-first x (succ y) = succ x ∔ succ y   ≡⟨ refl _     ⟩
                               succ (succ x ∔ y) ≡⟨ ap succ IH ⟩
                               succ (x ∔ succ y) ∎
   where
    IH : succ x ∔ y ≡ succ (x ∔ y)
    IH = +-step-on-first x y

  +-comm : (x y : ℕ) → x ∔ y ≡ y ∔ x
  +-comm 0 y = 0 ∔ y ≡⟨ +-base-on-first y ⟩
               y     ≡⟨ refl _ ⟩
               y ∔ 0 ∎
  +-comm (succ x) y = succ x ∔ y  ≡⟨ +-step-on-first x y ⟩
                      succ(x ∔ y) ≡⟨ ap succ IH          ⟩
                      succ(y ∔ x) ≡⟨ refl _              ⟩
                      y ∔ succ x  ∎
    where
     IH : x ∔ y ≡ y ∔ x
     IH = +-comm x y

  +-lc : (x y z : ℕ) → x ∔ y ≡ x ∔ z → y ≡ z
  +-lc 0        y z p = y     ≡⟨ (+-base-on-first y)⁻¹ ⟩
                        0 ∔ y ≡⟨ p                     ⟩
                        0 ∔ z ≡⟨ +-base-on-first z     ⟩
                        z     ∎
  +-lc (succ x) y z p = IH
   where
    q = succ (x ∔ y) ≡⟨ (+-step-on-first x y)⁻¹ ⟩
        succ x ∔ y   ≡⟨ p                       ⟩
        succ x ∔ z   ≡⟨ +-step-on-first x z     ⟩
        succ (x ∔ z) ∎

    IH : y ≡ z
    IH = +-lc x y z (succ-lc q)

  _≼_ : ℕ → ℕ → 𝓤₀ ̇
  x ≼ y = Σ z ꞉ ℕ , x ∔ z ≡ y

  ≤-gives-≼ : (x y : ℕ) → x ≤ y → x ≼ y
  ≤-gives-≼ 0 0               l = 0 , refl 0
  ≤-gives-≼ 0 (succ y)        l = succ y , +-base-on-first (succ y)
  ≤-gives-≼ (succ x) 0        l = !𝟘 (succ x ≼ zero) l
  ≤-gives-≼ (succ x) (succ y) l = γ
   where
    IH : x ≼ y
    IH = ≤-gives-≼ x y l

    z : ℕ
    z = pr₁ IH

    p : x ∔ z ≡ y
    p = pr₂ IH

    γ : succ x ≼ succ y
    γ = z , (succ x ∔ z   ≡⟨ +-step-on-first x z ⟩
             succ (x ∔ z) ≡⟨ ap succ p           ⟩
             succ y       ∎)

  ≼-gives-≤ : (x y : ℕ) → x ≼ y → x ≤ y
  ≼-gives-≤ 0 0               (z , p) = ⋆
  ≼-gives-≤ 0 (succ y)        (z , p) = ⋆
  ≼-gives-≤ (succ x) 0        (z , p) = positive-not-zero (x ∔ z) q
   where
    q = succ (x ∔ z) ≡⟨ (+-step-on-first x z)⁻¹ ⟩
        succ x ∔ z   ≡⟨ p                       ⟩
        zero         ∎
  ≼-gives-≤ (succ x) (succ y) (z , p) = IH
   where
    q = succ (x ∔ z) ≡⟨ (+-step-on-first x z)⁻¹ ⟩
        succ x ∔ z   ≡⟨ p                       ⟩
        succ y       ∎

    IH : x ≤ y
    IH = ≼-gives-≤ x y (z , succ-lc q)

  ≤-refl : (n : ℕ) → n ≤ n
  ≤-refl zero     = ⋆
  ≤-refl (succ n) = ≤-refl n

  ≤-trans : (l m n : ℕ) → l ≤ m → m ≤ n → l ≤ n
  ≤-trans zero     m        n        p q = ⋆
  ≤-trans (succ l) zero     n        p q = !𝟘 (succ l ≤ n) p
  ≤-trans (succ l) (succ m) zero     p q = q
  ≤-trans (succ l) (succ m) (succ n) p q = ≤-trans l m n p q

  ≤-anti : (m n : ℕ) → m ≤ n → n ≤ m → m ≡ n
  ≤-anti zero     zero     p q = refl zero
  ≤-anti zero     (succ n) p q = !𝟘 (zero ≡ succ n) q
  ≤-anti (succ m) zero     p q = !𝟘 (succ m ≡ zero) p
  ≤-anti (succ m) (succ n) p q = ap succ (≤-anti m n p q)

  ≤-succ : (n : ℕ) → n ≤ succ n
  ≤-succ zero     = ⋆
  ≤-succ (succ n) = ≤-succ n

  zero-minimal : (n : ℕ) → zero ≤ n
  zero-minimal n = ⋆

  unique-minimal : (n : ℕ) → n ≤ zero → n ≡ zero
  unique-minimal zero     p = refl zero
  unique-minimal (succ n) p = !𝟘 (succ n ≡ zero) p

  ≤-split : (m n : ℕ) → m ≤ succ n → (m ≤ n) + (m ≡ succ n)
  ≤-split zero     n        l = inl l
  ≤-split (succ m) zero     l = inr (ap succ (unique-minimal m l))
  ≤-split (succ m) (succ n) l = +-recursion inl (inr ∘ ap succ) (≤-split m n l)

  _<_ : ℕ → ℕ → 𝓤₀ ̇
  x < y = succ x ≤ y

  infix 10 _<_

  not-<-gives-≥ : (m n : ℕ) → ¬(n < m) → m ≤ n
  not-<-gives-≥ zero     n        u = zero-minimal n
  not-<-gives-≥ (succ m) zero     u = dni (zero < succ m) (zero-minimal m) u
  not-<-gives-≥ (succ m) (succ n) u = not-<-gives-≥ m n u

  bounded-∀-next : (A : ℕ → 𝓤 ̇ ) (k : ℕ)
                 → A k
                 → ((n : ℕ) → n < k → A n)
                 → (n : ℕ) → n < succ k → A n
  bounded-∀-next A k a φ n l = +-recursion f g s
   where
    s : (n < k) + (succ n ≡ succ k)
    s = ≤-split (succ n) k l

    f : n < k → A n
    f = φ n

    g : succ n ≡ succ k → A n
    g p = transport A ((succ-lc p)⁻¹) a

  root : (ℕ → ℕ) → 𝓤₀ ̇
  root f = Σ n ꞉ ℕ , f n ≡ 0

  _has-no-root<_ : (ℕ → ℕ) → ℕ → 𝓤₀ ̇
  f has-no-root< k = (n : ℕ) → n < k → f n ≢ 0

  is-minimal-root : (ℕ → ℕ) → ℕ → 𝓤₀ ̇
  is-minimal-root f m = (f m ≡ 0) × (f has-no-root< m)

  at-most-one-minimal-root : (f : ℕ → ℕ) (m n : ℕ)
                           → is-minimal-root f m → is-minimal-root f n → m ≡ n

  at-most-one-minimal-root f m n (p , φ) (q , ψ) = c m n a b
   where
    a : ¬(m < n)
    a u = ψ m u p

    b : ¬(n < m)
    b v = φ n v q

    c : (m n : ℕ) → ¬(m < n) → ¬(n < m) → m ≡ n
    c m n u v = ≤-anti m n (not-<-gives-≥ m n v) (not-<-gives-≥ n m u)

  minimal-root : (ℕ → ℕ) → 𝓤₀ ̇
  minimal-root f = Σ m ꞉ ℕ , is-minimal-root f m

  minimal-root-is-root : ∀ f → minimal-root f → root f
  minimal-root-is-root f (m , p , _) = m , p

  bounded-ℕ-search : ∀ k f → (minimal-root f) + (f has-no-root< k)
  bounded-ℕ-search zero f = inr (λ n → !𝟘 (f n ≢ 0))
  bounded-ℕ-search (succ k) f = +-recursion φ γ (bounded-ℕ-search k f)
   where
    A : ℕ → (ℕ → ℕ) → 𝓤₀ ̇
    A k f = (minimal-root f) + (f has-no-root< k)

    φ : minimal-root f → A (succ k) f
    φ = inl

    γ : f has-no-root< k → A (succ k) f
    γ u = +-recursion γ₀ γ₁ (ℕ-has-decidable-equality (f k) 0)
     where
      γ₀ : f k ≡ 0 → A (succ k) f
      γ₀ p = inl (k , p , u)

      γ₁ : f k ≢ 0 → A (succ k) f
      γ₁ v = inr (bounded-∀-next (λ n → f n ≢ 0) k v u)

  root-gives-minimal-root : ∀ f → root f → minimal-root f
  root-gives-minimal-root f (n , p) = γ
   where
    g : ¬(f has-no-root< (succ n))
    g φ = φ n (≤-refl n) p

    γ : minimal-root f
    γ = right-fails-gives-left-holds (bounded-ℕ-search (succ n) f) g

is-singleton : 𝓤 ̇ → 𝓤 ̇
is-singleton X = Σ c ꞉ X , ((x : X) → c ≡ x)

is-center : (X : 𝓤 ̇ ) → X → 𝓤 ̇
is-center X c = (x : X) → c ≡ x

𝟙-is-singleton : is-singleton 𝟙
𝟙-is-singleton = ⋆ , λ x → 𝟙-induction (λ y → ⋆ ≡ y) (refl ⋆) x

center : (X : 𝓤 ̇ ) → is-singleton X → X
center X (c , φ) = c

centrality : (X : 𝓤 ̇ ) (i : is-singleton X) (x : X) → center X i ≡ x
centrality X (c , φ) = φ

is-subsingleton : 𝓤 ̇ → 𝓤 ̇
is-subsingleton X = (x y : X) → x ≡ y

𝟘-is-subsingleton : is-subsingleton 𝟘
𝟘-is-subsingleton x y = !𝟘 (x ≡ y) x

singletons-are-subsingletons : (X : 𝓤 ̇ ) → is-singleton X → is-subsingleton X
singletons-are-subsingletons X (c , φ) x y = x ≡⟨ (φ x)⁻¹ ⟩
                                             c ≡⟨ φ y     ⟩
                                             y ∎

𝟙-is-subsingleton : is-subsingleton 𝟙
𝟙-is-subsingleton = singletons-are-subsingletons 𝟙 𝟙-is-singleton

pointed-subsingletons-are-singletons : (X : 𝓤 ̇ )
                                     → X → is-subsingleton X → is-singleton X

pointed-subsingletons-are-singletons X x s = (x , s x)

singleton-iff-pointed-and-subsingleton : {X : 𝓤 ̇ }
                                       → is-singleton X ⇔ (X × is-subsingleton X)

singleton-iff-pointed-and-subsingleton {𝓤} {X} = (a , b)
 where
  a : is-singleton X → X × is-subsingleton X
  a s = center X s , singletons-are-subsingletons X s

  b : X × is-subsingleton X → is-singleton X
  b (x , t) = pointed-subsingletons-are-singletons X x t

is-prop is-truth-value : 𝓤 ̇ → 𝓤 ̇
is-prop        = is-subsingleton
is-truth-value = is-subsingleton

is-set : 𝓤 ̇ → 𝓤 ̇
is-set X = (x y : X) → is-subsingleton (x ≡ y)

EM EM' : ∀ 𝓤 → 𝓤 ⁺ ̇
EM  𝓤 = (X : 𝓤 ̇ ) → is-subsingleton X → X + ¬ X
EM' 𝓤 = (X : 𝓤 ̇ ) → is-subsingleton X → is-singleton X + is-empty X

EM-gives-EM' : EM 𝓤 → EM' 𝓤
EM-gives-EM' em X s = γ (em X s)
 where
  γ : X + ¬ X → is-singleton X + is-empty X
  γ (inl x) = inl (pointed-subsingletons-are-singletons X x s)
  γ (inr x) = inr x

EM'-gives-EM : EM' 𝓤 → EM 𝓤
EM'-gives-EM em' X s = γ (em' X s)
 where
  γ : is-singleton X + is-empty X → X + ¬ X
  γ (inl i) = inl (center X i)
  γ (inr x) = inr x

no-unicorns : ¬(Σ X ꞉ 𝓤 ̇ , is-subsingleton X × ¬(is-singleton X) × ¬(is-empty X))
no-unicorns (X , i , f , g) = c
 where
  e : is-empty X
  e x = f (pointed-subsingletons-are-singletons X x i)

  c : 𝟘
  c = g e

module magmas where

 Magma : (𝓤 : Universe) → 𝓤 ⁺ ̇
 Magma 𝓤 = Σ X ꞉ 𝓤 ̇ , is-set X × (X → X → X)

 ⟨_⟩ : Magma 𝓤 → 𝓤 ̇
 ⟨ X , i , _·_ ⟩ = X

 magma-is-set : (M : Magma 𝓤) → is-set ⟨ M ⟩
 magma-is-set (X , i , _·_) = i

 magma-operation : (M : Magma 𝓤) → ⟨ M ⟩ → ⟨ M ⟩ → ⟨ M ⟩
 magma-operation (X , i , _·_) = _·_

 syntax magma-operation M x y = x ·⟨ M ⟩ y

 is-magma-hom : (M N : Magma 𝓤) → (⟨ M ⟩ → ⟨ N ⟩) → 𝓤 ̇
 is-magma-hom M N f = (x y : ⟨ M ⟩) → f (x ·⟨ M ⟩ y) ≡ f x ·⟨ N ⟩ f y

 id-is-magma-hom : (M : Magma 𝓤) → is-magma-hom M M (𝑖𝑑 ⟨ M ⟩)
 id-is-magma-hom M = λ (x y : ⟨ M ⟩) → refl (x ·⟨ M ⟩ y)

 is-magma-iso : (M N : Magma 𝓤) → (⟨ M ⟩ → ⟨ N ⟩) → 𝓤 ̇
 is-magma-iso M N f = is-magma-hom M N f
                    × (Σ g ꞉ (⟨ N ⟩ → ⟨ M ⟩), is-magma-hom N M g
                                            × (g ∘ f ∼ 𝑖𝑑 ⟨ M ⟩)
                                            × (f ∘ g ∼ 𝑖𝑑 ⟨ N ⟩))

 id-is-magma-iso : (M : Magma 𝓤) → is-magma-iso M M (𝑖𝑑 ⟨ M ⟩)
 id-is-magma-iso M = id-is-magma-hom M ,
                     𝑖𝑑 ⟨ M ⟩ ,
                     id-is-magma-hom M ,
                     refl ,
                     refl

 Id→iso : {M N : Magma 𝓤} → M ≡ N → ⟨ M ⟩ → ⟨ N ⟩
 Id→iso p = transport ⟨_⟩ p

 Id→iso-is-iso : {M N : Magma 𝓤} (p : M ≡ N) → is-magma-iso M N (Id→iso p)
 Id→iso-is-iso (refl M) = id-is-magma-iso M

 _≅ₘ_ : Magma 𝓤 → Magma 𝓤 → 𝓤 ̇
 M ≅ₘ N = Σ f ꞉ (⟨ M ⟩ → ⟨ N ⟩), is-magma-iso M N f

 magma-Id→iso : {M N : Magma 𝓤} → M ≡ N → M ≅ₘ N
 magma-Id→iso p = Id→iso p , Id→iso-is-iso p

 ∞-Magma : (𝓤 : Universe) → 𝓤 ⁺ ̇
 ∞-Magma 𝓤 = Σ X ꞉ 𝓤 ̇ , (X → X → X)

module monoids where

 left-neutral : {X : 𝓤 ̇ } → X → (X → X → X) → 𝓤 ̇
 left-neutral e _·_ = ∀ x → e · x ≡ x

 right-neutral : {X : 𝓤 ̇ } → X → (X → X → X) → 𝓤 ̇
 right-neutral e _·_ = ∀ x → x · e ≡ x

 associative : {X : 𝓤 ̇ } → (X → X → X) → 𝓤 ̇
 associative _·_ = ∀ x y z → (x · y) · z ≡ x · (y · z)

 Monoid : (𝓤 : Universe) → 𝓤 ⁺ ̇
 Monoid 𝓤 = Σ X ꞉ 𝓤  ̇ , is-set X
                      × (Σ · ꞉ (X → X → X) , (Σ e ꞉ X , (left-neutral e ·)
                                                      × (right-neutral e ·)
                                                      × (associative ·)))

module groups where

 left-neutral : {X : 𝓤 ̇ } → X → (X → X → X) → 𝓤 ̇
 left-neutral e _·_ = ∀ x → e · x ≡ x

 right-neutral : {X : 𝓤 ̇ } → X → (X → X → X) → 𝓤 ̇
 right-neutral e _·_ = ∀ x → x · e ≡ x

 associative : {X : 𝓤 ̇ } → (X → X → X) → 𝓤 ̇
 associative _·_ = ∀ x y z → (x · y) · z ≡ x · (y · z)

 inverse : {X : 𝓤 ̇ } → X → (X → X → X) → 𝓤 ̇
 inverse e _·_ = ∀ x → Σ (λ x' → x · x' ≡ e)

 Monoid : (𝓤 : Universe) → 𝓤 ⁺ ̇
 Monoid 𝓤 = Σ X ꞉ 𝓤  ̇ , is-set X
                      × (Σ · ꞉ (X → X → X) , (Σ e ꞉ X , (left-neutral e ·)
                                                      × (right-neutral e ·)
                                                      × (associative ·)
                                                      × (inverse e ·)))

refl-left : {X : 𝓤 ̇ } {x y : X} {p : x ≡ y} → refl x ∙ p ≡ p
refl-left {𝓤} {X} {x} {x} {refl x} = refl (refl x)

refl-right : {X : 𝓤 ̇ } {x y : X} {p : x ≡ y} → p ∙ refl y ≡ p
refl-right {𝓤} {X} {x} {y} {p} = refl p

∙assoc : {X : 𝓤 ̇ } {x y z t : X} (p : x ≡ y) (q : y ≡ z) (r : z ≡ t)
       → (p ∙ q) ∙ r ≡ p ∙ (q ∙ r)
∙assoc p q (refl z) = refl (p ∙ q)

⁻¹-left∙ : {X : 𝓤 ̇ } {x y : X} (p : x ≡ y)
         → p ⁻¹ ∙ p ≡ refl y
⁻¹-left∙ (refl x) = refl (refl x)

⁻¹-right∙ : {X : 𝓤 ̇ } {x y : X} (p : x ≡ y)
          → p ∙ p ⁻¹ ≡ refl x
⁻¹-right∙ (refl x) = refl (refl x)

⁻¹-involutive : {X : 𝓤 ̇ } {x y : X} (p : x ≡ y)
              → (p ⁻¹)⁻¹ ≡ p
⁻¹-involutive (refl x) = refl (refl x)

ap-refl : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } (f : X → Y) (x : X)
        → ap f (refl x) ≡ refl (f x)
ap-refl f x = refl (refl (f x))

ap-∙ : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } (f : X → Y) {x y z : X} (p : x ≡ y) (q : y ≡ z)
     → ap f (p ∙ q) ≡ ap f p ∙ ap f q
ap-∙ f p (refl y) = refl (ap f p)

ap⁻¹ : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } (f : X → Y) {x y : X} (p : x ≡ y)
     → (ap f p)⁻¹ ≡ ap f (p ⁻¹)
ap⁻¹ f (refl x) = refl (refl (f x))

ap-id : {X : 𝓤 ̇ } {x y : X} (p : x ≡ y)
      → ap id p ≡ p
ap-id (refl x) = refl (refl x)

ap-∘ : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } {Z : 𝓦 ̇ }
       (f : X → Y) (g : Y → Z) {x y : X} (p : x ≡ y)
     → ap (g ∘ f) p ≡ (ap g ∘ ap f) p
ap-∘ f g (refl x) = refl (refl (g (f x)))

transport∙ : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) {x y z : X} (p : x ≡ y) (q : y ≡ z)
           → transport A (p ∙ q) ≡ transport A q ∘ transport A p
transport∙ A p (refl y) = refl (transport A p)

Nat : {X : 𝓤 ̇ } → (X → 𝓥 ̇ ) → (X → 𝓦 ̇ ) → 𝓤 ⊔ 𝓥 ⊔ 𝓦 ̇
Nat A B = (x : domain A) → A x → B x

Nats-are-natural : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) (B : X → 𝓦 ̇ ) (τ : Nat A B)
                 → {x y : X} (p : x ≡ y)
                 → τ y ∘ transport A p ≡ transport B p ∘ τ x
Nats-are-natural A B τ (refl x) = refl (τ x)

NatΣ : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } {B : X → 𝓦 ̇ } → Nat A B → Σ A → Σ B
NatΣ τ (x , a) = (x , τ x a)

transport-ap : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } (A : Y → 𝓦 ̇ )
               (f : X → Y) {x x' : X} (p : x ≡ x') (a : A (f x))
             → transport (A ∘ f) p a ≡ transport A (ap f p) a
transport-ap A f (refl x) a = refl a

data Color : 𝓤₀ ̇  where
 Black White : Color

apd : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } (f : (x : X) → A x) {x y : X}
      (p : x ≡ y) → transport A p (f x) ≡ f y
apd f (refl _) = refl (f _)

module Exercise where

  ≤ : ℕ → ℕ → 𝓤₀ ̇
  ≤ x = ℕ-induction (λ _ → ℕ → 𝓤₀ ̇) (λ _ → 𝟙)
                     (λ _ f x₂ → ℕ-induction (λ _ →  𝓤₀ ̇) 𝟘 (λ n _ → f n) x₂) x

  ℍ' : {X : 𝓤 ̇ } (x : X) (B : (y : X) → x ≡ y → 𝓥 ̇ )
    → B x (refl x)
    → (y : X) (p : x ≡ y) → B y p
  ℍ' {X} x B b y p = {!!}

  ℕ-has-decidable-equality' : has-decidable-equality ℕ
  ℕ-has-decidable-equality' = ℕ-induction (λ z → (x : ℕ) → Id ℕ z x + (z ≢ x))
                                          (λ m → ℕ-induction
                                                 (λ x → Id ℕ zero x + (zero ≢ x))
                                                 (inl (refl zero))
                                                 (λ n _ → inr (λ ())) m)
                                          λ n f → ℕ-induction (λ x → Id ℕ (succ n) x + (succ n ≢ x))
                                                    (inr (λ ()))
                                                    λ n₁ x → g (f n₁)
                              where
                              g : {x y : ℕ} → decidable (x ≡ y) → decidable (succ x ≡ succ y)
                              g (inl p) = inl (ap succ p)
                              g {x} {y} (inr k) = inr (λ (s : succ x ≡ succ y) → k (succ-lc s))

  Sub-EM Sub-EM' : ∀ 𝓤 → 𝓤 ⁺ ̇
  Sub-EM 𝓤 = (X : 𝓤 ̇ ) → is-subsingleton X → ¬¬(is-singleton X + is-empty X)
  Sub-EM' 𝓤 = ¬¬((X : 𝓤 ̇ ) → is-subsingleton X → is-singleton X + is-empty X)

  Sub-EM-gives-Sub-EM' : Sub-EM 𝓤 → Sub-EM' 𝓤
  Sub-EM-gives-Sub-EM' {𝓤} sub neg = {!!}

  Sub-EM'-gives-Sub-EM : Sub-EM' 𝓤 → Sub-EM 𝓤
  Sub-EM'-gives-Sub-EM sub' X subsing neg = sub' λ z → neg (z X subsing)

  ∙assoc' : {X : 𝓤 ̇ } {x y z t : X} (p : x ≡ y) (q : y ≡ z) (r : z ≡ t)
          → (p ∙ q) ∙ r ≡ p ∙ (q ∙ r)
  ∙assoc' p q r = {!𝕁!}

infix   0 _∼_
infixr 50 _,_
infixr 30 _×_
infixr 20 _+_
infixl 70 _∘_
infix   0 Id
infix   0 _≡_
infix  10 _⇔_
infixl 30 _∙_
infixr  0 _≡⟨_⟩_
infix   1 _∎
infix  40 _⁻¹
infix  10 _◁_
infixr  0 _◁⟨_⟩_
infix   1 _◀
infix  10 _≃_
infixl 30 _●_
infixr  0 _≃⟨_⟩_
infix   1 _■
infix  40 _∈_
infix  30 _[_,_]
infixr -1 -Σ
infixr -1 -Π
infixr -1 -∃!


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

module LogicalFramework.UniversalQuantifier where

postulate D : Set

-- The universal quantifier type on D.
data ForAll (A : D → Set) : Set where
  dfun : ((t : D) → A t) → ForAll A

dapp : {A : D → Set}(t : D) → ForAll A → A t
dapp t (dfun f) = f t


open import Common.Prelude
open import Common.Reflection
open import Common.Equality

data Dec {a} (A : Set a) : Set a where
  yes : A → Dec A
  no  : Dec A

record Eq {a} (A : Set a) : Set a where
  constructor eqDict
  field
    _==_ : (x y : A) → Dec (x ≡ y)

module M {a} {A : Set a} {{EqA : Eq A}} where
  _==_ : (x y : A) → Dec (x ≡ y)
  _==_ = Eq._==_ EqA

open Eq {{...}}

private
  eqNat : (x y : Nat) → Dec (x ≡ y)
  eqNat zero zero = yes refl
  eqNat zero (suc y) = no
  eqNat (suc x) zero = no
  eqNat (suc x) (suc y) with eqNat x y
  eqNat (suc x) (suc .x) | yes refl = yes refl
  ... | no     = no

  eqBool : (x y : Bool) → Dec (x ≡ y)
  eqBool true true = yes refl
  eqBool true false = no
  eqBool false true = no
  eqBool false false = yes refl

unquoteDecl EqNat = define (iArg EqNat)
  (funDef (def (quote Eq) (vArg (def (quote Nat) []) ∷ []))
          (clause [] (con (quote eqDict) (vArg (def (quote eqNat) []) ∷ [])) ∷ []))

instance
  EqBool : Eq Bool
  unquoteDef EqBool =
    defineFun EqBool (clause [] (con (quote eqDict) (vArg (def (quote eqBool) []) ∷ [])) ∷ [])

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

tm : QName → Term
tm eq = def (quote id) (vArg (def eq (vArg (lit (nat 0)) ∷ vArg (lit (nat 1)) ∷ [])) ∷ [])

tm₂ : QName → Term
tm₂ eq = def eq (iArg (def (quote EqNat) []) ∷ vArg (lit (nat 0)) ∷ vArg (lit (nat 1)) ∷ [])

_==′_ : ∀ {a} {A : Set a} {{EqA : Eq A}} (x y : A) → Dec (x ≡ y)
_==′_ = _==_

ok₁ : Dec (0 ≡ 1)
ok₁ = unquote (give (tm (quote _==′_)))

ok₂ : Dec (0 ≡ 1)
ok₂ = unquote (give (tm₂ (quote _==_)))

ok₃ : Dec (0 ≡ 1)
ok₃ = unquote (give (tm (quote M._==_)))

ok₄ : Dec (true ≡ false)
ok₄ = true == false

ok₅ : Dec (2 ≡ 2)
ok₅ = 2 == 2

-- Was bad.
bad : Dec (0 ≡ 1)
bad = unquote (give (tm (quote _==_)))


module Testing where

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

{-# BUILTIN NATURAL Nat #-}

plus : Nat -> Nat -> Nat
plus zero n = n
plus (suc m) n = suc (plus m n)

times : Nat -> Nat -> Nat
times zero n = zero
times (suc m) n = plus n (times m n)

data List (A : Set) : Nat -> Set where
    nil : List A 0
    cons : {n : Nat} -> A -> List A n -> List A (suc n)

f : Nat -> (b : Nat) -> (a : Nat) -> Nat
f x = plus

-- Push argument doesn't work with implicit
-- Toggle implicit generates code that the tool can't handle
-- also, want to include {something = x} in language

map : {n : Nat} -> {A : Set} -> {B : Set} -> {renameMe0 : A -> B} -> List A n ->
    List B n
map {renameMe0 = f} nil = nil
map {renameMe0 = f} (cons x xs) = cons (f x) (map {_} {_} {_} {f} xs)

map2 : {n : Nat} -> {A : Set} -> {B : Set} -> (A -> B) -> List A n ->
    List B n
map2 f nil = nil
map2 f (cons x xs) = cons (f x) (map2 f xs)
{-
data Eq {A : Set} (x : A) : A -> Set where
  refl : Eq x x

subst : {A : Set} -> (P : A -> Set) ->
        {x : A} -> {y : A} -> Eq x y -> P x -> P y
subst P refl px = px

data Foo : Set where
  foo : Foo
  bar : Foo

-- Refactoring to introduce these!
{-# FOREIGN GHC data Foo = Foo | Bar #-}
{-# COMPILE GHC Foo = data Foo (Foo | Bar) #-}
-}


module Issue628 where

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

{-# BUILTIN NATURAL ℕ #-}
{-# BUILTIN SUC suc #-}
{-# BUILTIN ZERO zero #-}

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

data ⊥ : Set where

0≢1+n : ∀ {n} -> 0 ≡ suc n → ⊥
0≢1+n ()

divSucAux : (k m n j : ℕ) -> ℕ
divSucAux k m zero j = k
divSucAux k m (suc n) zero = divSucAux (suc k) m n m
divSucAux k m (suc n) (suc j) = divSucAux k m n j
{-# BUILTIN NATDIVSUCAUX divSucAux #-}

oh-noes : ⊥
oh-noes = 0≢1+n {divSucAux 0 0 0 1} refl


module Pat (BaseType : Set) where

data Ty : Set where
  ι   : BaseType -> Ty
  _⟶_ : Ty -> Ty -> Ty

data Bwd (A : Set) : Set where
  •   : Bwd A
  _◄_ : Bwd A -> A -> Bwd A

infixl 30 _◄_

Ctx = Bwd Ty

data Take {A : Set} : Bwd A -> A -> Bwd A -> Set where
  hd : forall {x xs} -> Take (xs ◄ x) x xs
  tl : forall {x y xs ys} -> Take xs x ys -> Take (xs ◄ y) x (ys ◄ y)

data Pat : Ctx -> Ctx -> Ty -> Ctx -> Set

data Pats : Ctx -> Ty -> Ctx -> Ty -> Set where
  ε : forall {Θ τ} -> Pats Θ τ Θ τ
  _,_ : forall {Θ₁ Θ₂ Θ₃ ρ σ τ} ->
        Pat • Θ₁ ρ Θ₂ -> Pats Θ₂ σ Θ₃ τ ->
        Pats Θ₁ (ρ ⟶ σ) Θ₃ τ

data Pat where
  ƛ    : forall {Δ Θ Θ' σ τ} -> Pat (Δ ◄ σ) Θ τ Θ' ->
         Pat Δ Θ (σ ⟶ τ) Θ'
  _[_] : forall {Θ Θ' Δ σ τ} ->
         Take Θ σ Θ' -> Pats Δ σ • τ -> Pat Δ Θ τ Θ'