------------------------------------------------------------------------
-- A container for finite binary trees with information in internal
-- nodes
------------------------------------------------------------------------

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

open import Equality

module Container.Tree
  {c⁺} (eq : ∀ {a p} → Equality-with-J a p c⁺) where

open Derived-definitions-and-properties eq

open import Prelude hiding (id; _∘_; List; []; _∷_)

open import Bijection eq using (_↔_; module _↔_)
open import Container eq hiding (Shape; Position)
open import Container.List eq hiding (fold; fold-lemma)
open import Function-universe eq
import Tree eq as Tree

------------------------------------------------------------------------
-- The type

-- Shapes.

data Shape : Type where
  lf : Shape
  nd : Shape → Shape → Shape

-- Positions.

data Position : Shape → Type where
  root  : ∀ {l r} → Position (nd l r)
  left  : ∀ {l r} → Position l → Position (nd l r)
  right : ∀ {l r} → Position r → Position (nd l r)

-- Trees.

Tree : Container lzero
Tree = Shape ▷ Position

------------------------------------------------------------------------
-- An isomorphism

-- The type of shapes is isomorphic to Tree.Tree ⊤.
--
-- This lemma is included because it was mentioned in the paper "Bag
-- Equivalence via a Proof-Relevant Membership Relation".

Shape↔Tree-⊤ : Shape ↔ Tree.Tree ⊤
Shape↔Tree-⊤ = record
  { surjection = record
    { logical-equivalence = record
      { to   = to
      ; from = from
      }
    ; right-inverse-of = to∘from
    }
  ; left-inverse-of = from∘to
  }
  where
  to : Shape → Tree.Tree ⊤
  to lf       = Tree.leaf
  to (nd l r) = Tree.node (to l) tt (to r)

  from : Tree.Tree ⊤ → Shape
  from Tree.leaf          = lf
  from (Tree.node l tt r) = nd (from l) (from r)

  to∘from : ∀ t → to (from t) ≡ t
  to∘from Tree.leaf          = refl _
  to∘from (Tree.node l tt r) =
    cong₂ (λ l r → Tree.node l tt r) (to∘from l) (to∘from r)

  from∘to : ∀ s → from (to s) ≡ s
  from∘to lf       = refl _
  from∘to (nd l r) = cong₂ nd (from∘to l) (from∘to r)

------------------------------------------------------------------------
-- Constructors

-- Leaves.

leaf : {A : Type} → ⟦ Tree ⟧ A
leaf = (lf , λ ())

-- Internal nodes.

node : {A : Type} → ⟦ Tree ⟧ A → A → ⟦ Tree ⟧ A → ⟦ Tree ⟧ A
node (l , lkup-l) x (r , lkup-r) =
  ( nd l r
  , λ { root      → x
      ; (left  p) → lkup-l p
      ; (right p) → lkup-r p
      }
  )

-- Even if we don't assume extensionality we can prove that
-- intensionally distinct implementations of the constructors are bag
-- equivalent.

leaf≈ : {A : Type} {lkup : _ → A} →
        _≈-bag_ {C₂ = Tree} leaf (lf , lkup)
leaf≈ _ = record
  { surjection = record
    { logical-equivalence = record
      { to   = λ { (() , _) }
      ; from = λ { (() , _) }
      }
    ; right-inverse-of = λ { (() , _) }
    }
  ; left-inverse-of = λ { (() , _) }
  }

node≈ : ∀ {A : Type} {l r} {lkup : _ → A} →
        _≈-bag_ {C₂ = Tree}
                (node (l , lkup ∘ left) (lkup root) (r , lkup ∘ right))
                (nd l r , lkup)
node≈ _ = record
  { surjection = record
    { logical-equivalence = record
      { to   = λ { (root    , eq) → (root    , eq)
                 ; (left p  , eq) → (left p  , eq)
                 ; (right p , eq) → (right p , eq)
                 }
      ; from = λ { (root    , eq) → (root    , eq)
                 ; (left p  , eq) → (left p  , eq)
                 ; (right p , eq) → (right p , eq)
                 }
      }
    ; right-inverse-of = λ { (root    , eq) → refl _
                           ; (left p  , eq) → refl _
                           ; (right p , eq) → refl _
                           }
    }
  ; left-inverse-of = λ { (root    , eq) → refl _
                        ; (left p  , eq) → refl _
                        ; (right p , eq) → refl _
                        }
  }

-- Any lemmas for the constructors.

Any-leaf : ∀ {A : Type} (P : A → Type) →
           Any P leaf ↔ ⊥₀
Any-leaf _ = record
  { surjection = record
    { logical-equivalence = record
      { to   = λ { (() , _) }
      ; from = λ ()
      }
    ; right-inverse-of = λ ()
    }
  ; left-inverse-of = λ { (() , _) }
  }

Any-node : ∀ {A : Type} (P : A → Type) {l x r} →
           Any P (node l x r) ↔ Any P l ⊎ P x ⊎ Any P r
Any-node _ {l = _ , _} {r = _ , _} = record
  { surjection = record
    { logical-equivalence = record
      { to   = λ { (root    , eq) → inj₂ (inj₁ eq)
                 ; (left p  , eq) → inj₁ (p , eq)
                 ; (right p , eq) → inj₂ (inj₂ (p , eq))
                 }
      ; from = λ { (inj₁ (p , eq))        → (left p  , eq)
                 ; (inj₂ (inj₁ eq))       → (root    , eq)
                 ; (inj₂ (inj₂ (p , eq))) → (right p , eq)
                 }
      }
    ; right-inverse-of = λ { (inj₁ (p , eq))        → refl _
                           ; (inj₂ (inj₁ eq))       → refl _
                           ; (inj₂ (inj₂ (p , eq))) → refl _
                           }
    }
  ; left-inverse-of = λ { (root    , eq) → refl _
                        ; (left p  , eq) → refl _
                        ; (right p , eq) → refl _
                        }
  }

------------------------------------------------------------------------
-- More functions

-- Singleton trees.

singleton : {A : Type} → A → ⟦ Tree ⟧ A
singleton x = node leaf x leaf

-- Any lemma for singleton.

Any-singleton : ∀ {A : Type} (P : A → Type) {x} →
                Any P (singleton x) ↔ P x
Any-singleton P {x} =
  Any P (singleton x)            ↔⟨⟩
  Any P (node leaf x leaf)       ↔⟨ Any-node P ⟩
  Any P leaf ⊎ P x ⊎ Any P leaf  ↔⟨ Any-leaf P ⊎-cong id ⊎-cong Any-leaf P ⟩
  ⊥ ⊎ P x ⊎ ⊥                    ↔⟨ ⊎-left-identity ⟩
  P x ⊎ ⊥                        ↔⟨ ⊎-right-identity ⟩
  P x                            □

-- For the design considerations underlying the inclusion of fold and
-- fold-lemma, see Container.List.fold/fold-lemma.

-- A fold for trees. (Well, this is not a catamorphism, it is a
-- paramorphism.)

fold : {A B : Type} →
       B → (⟦ Tree ⟧ A → A → ⟦ Tree ⟧ A → B → B → B) → ⟦ Tree ⟧ A → B
fold {A} {B} fl fn = uncurry fold′
  where
  fold′ : (s : Shape) → (Position s → A) → B
  fold′ lf       lkup = fl
  fold′ (nd l r) lkup =
    fn (l , lkup ∘ left )
       (lkup root)
       (r , lkup ∘ right)
       (fold′ l (lkup ∘ left ))
       (fold′ r (lkup ∘ right))

-- A lemma which can be used to prove properties about fold.
--
-- The "respects bag equivalence" argument could be omitted if
-- equality of functions were extensional.

fold-lemma : ∀ {A B : Type}
               {fl : B} {fn : ⟦ Tree ⟧ A → A → ⟦ Tree ⟧ A → B → B → B}
             (P : ⟦ Tree ⟧ A → B → Type) →
             (∀ t₁ t₂ → t₁ ≈-bag t₂ → ∀ b → P t₁ b → P t₂ b) →
             P leaf fl →
             (∀ l x r b₁ b₂ →
                P l b₁ → P r b₂ → P (node l x r) (fn l x r b₁ b₂)) →
             ∀ t → P t (fold fl fn t)
fold-lemma {A} {fl = fl} {fn} P resp P-le P-no = uncurry fold-lemma′
  where
  fold-lemma′ : (s : Shape) (lkup : Position s → A) →
                P (s , lkup) (fold fl fn (s , lkup))
  fold-lemma′ lf       lkup = resp _ _ leaf≈ _ P-le
  fold-lemma′ (nd l r) lkup = resp _ _ node≈ _ $
    P-no _ _ _ _ _
       (fold-lemma′ l (lkup ∘ left ))
       (fold-lemma′ r (lkup ∘ right))

-- Inorder flattening of a tree.

flatten : {A : Type} → ⟦ Tree ⟧ A → ⟦ List ⟧ A
flatten = fold [] (λ _ x _ xs ys → xs ++ x ∷ ys)

-- Flatten does not add or remove any elements.

flatten≈ : {A : Type} (t : ⟦ Tree ⟧ A) → flatten t ≈-bag t
flatten≈ = fold-lemma
  (λ t xs → xs ≈-bag t)

  (λ t₁ t₂ t₁≈t₂ xs xs≈t₁ z →
     z ∈ xs  ↔⟨ xs≈t₁ z ⟩
     z ∈ t₁  ↔⟨ t₁≈t₂ z ⟩
     z ∈ t₂  □)

  (λ z →
   z ∈ []    ↔⟨ Any-[] (λ x → z ≡ x) ⟩
   ⊥         ↔⟨ inverse $ Any-leaf (λ x → z ≡ x) ⟩
   z ∈ leaf  □)

  (λ l x r xs ys xs≈l ys≈r z →
     z ∈ xs ++ x ∷ ys         ↔⟨ Any-++ (λ x → z ≡ x) _ _ ⟩
     z ∈ xs ⊎ z ∈ x ∷ ys      ↔⟨ id ⊎-cong Any-∷ (λ x → z ≡ x) ⟩
     z ∈ xs ⊎ z ≡ x ⊎ z ∈ ys  ↔⟨ xs≈l z ⊎-cong id ⊎-cong ys≈r z ⟩
     z ∈ l ⊎ z ≡ x ⊎ z ∈ r    ↔⟨ inverse $ Any-node (λ x → z ≡ x) ⟩
     z ∈ node l x r           □)


-- Andreas, 2017-01-20, issue #1817 is fixed

open import Agda.Builtin.Size
open import Agda.Builtin.Nat renaming (Nat to ℕ)

-- Function

_$_ : ∀{a b}{A : Set a}{B : Set b} →(A → B) → A →  B
f $ x = f x

case_of_ : ∀{a b}{A : Set a}{B : Set b} → A → (A → B) → B
case x of f = f x

-- Size

data SizeLt (i : Size) : Set where
  size : (j : Size< i) → SizeLt i

getSize : ∀{i} → SizeLt i → Size
getSize (size j) = j

-- List

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

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

-- BT

data Var : (n : ℕ) → Set where
  vz : ∀{n} → Var (suc n)
  vs : ∀{n} → (x : Var n) → Var (suc n)

mutual
  record BT (i : Size) (n : ℕ) : Set where
    inductive; constructor Λ
    field nabs : ℕ
          var  : Var (nabs + n)
          args : List (BT' i (nabs + n))

  record BT' (i : Size) (n : ℕ) : Set where
    coinductive; constructor delay
    field force : ∀{j : SizeLt i} → BT (getSize j) n

open BT'

-- Renaming

data Ope : (n m : ℕ) → Set where
  id   : ∀{n} → Ope n n
  weak : ∀{n m} (ρ : Ope n m) → Ope (1 + n) m
  lift : ∀{n m} (ρ : Ope n m) → Ope (1 + n) (1 + m)

lifts : ∀ k {n m} (ρ : Ope n m) → Ope (k + n) (k + m)
lifts 0       ρ = ρ
lifts (suc k) ρ = lift (lifts k ρ)

renVar : ∀{n m} (ρ : Ope n m) (x : Var m) → Var n
renVar id       x      = x
renVar (weak ρ) x      = vs (renVar ρ x)
renVar (lift ρ) vz     = vz
renVar (lift ρ) (vs x) = vs (renVar ρ x)

ren  : ∀{i n m} (ρ : Ope n m) (t : BT i m) → BT i n
ren {i} ρ₀ (Λ n x ts) = Λ n (renVar ρ x) $ for ts \ t → delay
   \{ {size j} → ren {j} ρ $ force t {size j} }
  where ρ = lifts n ρ₀


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

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

open import Algebra

module Algebra.Properties.Lattice {l₁ l₂} (L : Lattice l₁ l₂) where

open Lattice L
open import Algebra.Structures
open import Algebra.FunctionProperties _≈_
import Algebra.Properties.Semilattice as SL
open import Relation.Binary
import Relation.Binary.Lattice as R
open import Relation.Binary.Reasoning.Setoid  setoid
open import Function
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence using (_⇔_; module Equivalence)
open import Data.Product using (_,_; swap)

------------------------------------------------------------------------
-- Every lattice contains two semilattices.

∧-idempotent : Idempotent _∧_
∧-idempotent x = begin
  x ∧ x            ≈⟨ refl ⟨ ∧-cong ⟩ sym (∨-absorbs-∧ _ _) ⟩
  x ∧ (x ∨ x ∧ x)  ≈⟨ ∧-absorbs-∨ _ _ ⟩
  x                ∎

∨-idempotent : Idempotent _∨_
∨-idempotent x = begin
  x ∨ x      ≈⟨ refl ⟨ ∨-cong ⟩ sym (∧-idempotent _) ⟩
  x ∨ x ∧ x  ≈⟨ ∨-absorbs-∧ _ _ ⟩
  x          ∎

∧-isSemilattice : IsSemilattice _≈_ _∧_
∧-isSemilattice = record
  { isBand = record
    { isSemigroup = record
      { isMagma = record
        { isEquivalence = isEquivalence
        ; ∙-cong        = ∧-cong
        }
      ; assoc         = ∧-assoc
      }
    ; idem = ∧-idempotent
    }
  ; comm   = ∧-comm
  }

∧-semilattice : Semilattice l₁ l₂
∧-semilattice = record { isSemilattice = ∧-isSemilattice }

∨-isSemilattice : IsSemilattice _≈_ _∨_
∨-isSemilattice = record
  { isBand = record
    { isSemigroup = record
      { isMagma = record
        { isEquivalence = isEquivalence
        ; ∙-cong        = ∨-cong
        }
      ; assoc         = ∨-assoc
      }
    ; idem = ∨-idempotent
    }
  ; comm   = ∨-comm
  }

∨-semilattice : Semilattice l₁ l₂
∨-semilattice = record { isSemilattice = ∨-isSemilattice }

open SL ∧-semilattice public using (poset)
open Poset poset using (_≤_; isPartialOrder)

------------------------------------------------------------------------
-- The dual construction is also a lattice.

∧-∨-isLattice : IsLattice _≈_ _∧_ _∨_
∧-∨-isLattice = record
  { isEquivalence = isEquivalence
  ; ∨-comm        = ∧-comm
  ; ∨-assoc       = ∧-assoc
  ; ∨-cong        = ∧-cong
  ; ∧-comm        = ∨-comm
  ; ∧-assoc       = ∨-assoc
  ; ∧-cong        = ∨-cong
  ; absorptive    = swap absorptive
  }

∧-∨-lattice : Lattice _ _
∧-∨-lattice = record { isLattice = ∧-∨-isLattice }

------------------------------------------------------------------------
-- Every algebraic lattice can be turned into an order-theoretic one.

isOrderTheoreticLattice : R.IsLattice _≈_ _≤_ _∨_ _∧_
isOrderTheoreticLattice = record
  { isPartialOrder = isPartialOrder
  ; supremum       = supremum
  ; infimum        = infimum
  }
  where
  ∧-meetSemilattice = SL.orderTheoreticMeetSemilattice ∧-semilattice
  ∨-joinSemilattice = SL.orderTheoreticJoinSemilattice ∨-semilattice
  open R.MeetSemilattice ∧-meetSemilattice using (infimum)
  open R.JoinSemilattice ∨-joinSemilattice using ()
    renaming (supremum to supremum′; _≤_ to _≤′_)

  -- An alternative but equivalent interpretation of the order _≤_.

  sound : ∀ {x y} → x ≤′ y → x ≤ y
  sound {x} {y} y≈y∨x = sym $ begin
    x ∧ y        ≈⟨ ∧-congˡ y≈y∨x ⟩
    x ∧ (y ∨ x)  ≈⟨ ∧-congˡ (∨-comm y x) ⟩
    x ∧ (x ∨ y)  ≈⟨ ∧-absorbs-∨ x y ⟩
    x            ∎

  complete : ∀ {x y} → x ≤ y → x ≤′ y
  complete {x} {y} x≈x∧y = sym $ begin
    y ∨ x        ≈⟨ ∨-congˡ x≈x∧y ⟩
    y ∨ (x ∧ y)  ≈⟨ ∨-congˡ (∧-comm x y) ⟩
    y ∨ (y ∧ x)  ≈⟨ ∨-absorbs-∧ y x ⟩
    y            ∎

  supremum : R.Supremum _≤_ _∨_
  supremum x y =
    let x∨y≥x , x∨y≥y , greatest = supremum′ x y
    in sound x∨y≥x , sound x∨y≥y ,
       λ z x≤z y≤z → sound (greatest z (complete x≤z) (complete y≤z))

orderTheoreticLattice : R.Lattice _ _ _
orderTheoreticLattice = record { isLattice = isOrderTheoreticLattice }

------------------------------------------------------------------------
-- One can replace the underlying equality with an equivalent one.

replace-equality : {_≈′_ : Rel Carrier l₂} →
                   (∀ {x y} → x ≈ y ⇔ (x ≈′ y)) → Lattice _ _
replace-equality {_≈′_} ≈⇔≈′ = record
  { _≈_       = _≈′_
  ; _∧_       = _∧_
  ; _∨_       = _∨_
  ; isLattice = record
    { isEquivalence = record
      { refl  = to ⟨$⟩ refl
      ; sym   = λ x≈y → to ⟨$⟩ sym (from ⟨$⟩ x≈y)
      ; trans = λ x≈y y≈z → to ⟨$⟩ trans (from ⟨$⟩ x≈y) (from ⟨$⟩ y≈z)
      }
    ; ∨-comm     = λ x y → to ⟨$⟩ ∨-comm x y
    ; ∨-assoc    = λ x y z → to ⟨$⟩ ∨-assoc x y z
    ; ∨-cong     = λ x≈y u≈v → to ⟨$⟩ ∨-cong (from ⟨$⟩ x≈y) (from ⟨$⟩ u≈v)
    ; ∧-comm     = λ x y → to ⟨$⟩ ∧-comm x y
    ; ∧-assoc    = λ x y z → to ⟨$⟩ ∧-assoc x y z
    ; ∧-cong     = λ x≈y u≈v → to ⟨$⟩ ∧-cong (from ⟨$⟩ x≈y) (from ⟨$⟩ u≈v)
    ; absorptive = (λ x y → to ⟨$⟩ ∨-absorbs-∧ x y)
                 , (λ x y → to ⟨$⟩ ∧-absorbs-∨ x y)
    }
  } where open module E {x y} = Equivalence (≈⇔≈′ {x} {y})


module nfa136 where

open import logic
open import nfa
open import automaton
open import Data.List
open import finiteSet
open import Data.Fin
open import  Relation.Binary.PropositionalEquality hiding ( [_] )

data  StatesQ   : Set  where
   q1 : StatesQ
   q2 : StatesQ
   q3 : StatesQ

data  A2   : Set  where
   a0 : A2
   b0 : A2

finStateQ : FiniteSet StatesQ
finStateQ = record {
        Q←F = Q←F
      ; F←Q  = F←Q
      ; finiso→ = finiso→
      ; finiso← = finiso←
   } where
       Q←F : Fin 3 → StatesQ
       Q←F zero = q1
       Q←F (suc zero) = q2
       Q←F (suc (suc zero)) = q3
       F←Q : StatesQ → Fin 3
       F←Q q1 = zero
       F←Q q2 = suc zero
       F←Q q3 = suc (suc zero)
       finiso→ : (q : StatesQ) → Q←F (F←Q q) ≡ q
       finiso→ q1 = refl
       finiso→ q2 = refl
       finiso→ q3 = refl
       finiso← : (f : Fin 3) → F←Q (Q←F f) ≡ f
       finiso← zero = refl
       finiso← (suc zero) = refl
       finiso← (suc (suc zero)) = refl
       finiso← (suc (suc (suc ())))

transition136 : StatesQ  → A2  → StatesQ → Bool
transition136 q1 b0 q2 = true
transition136 q1 a0 q1 = true  -- q1 → ep → q3
transition136 q2 a0 q2 = true
transition136 q2 a0 q3 = true
transition136 q2 b0 q3 = true
transition136 q3 a0 q1 = true
transition136 _ _ _ = false

end136 : StatesQ → Bool
end136  q1 = true
end136  _ = false

start136 : StatesQ → Bool
start136 q1 = true
start136 _ = false

exists136 : (StatesQ → Bool) → Bool
exists136 f = f q1 \/ f q2 \/ f q3

to-list-136 : (StatesQ → Bool) → List StatesQ
to-list-136 f = tl1 where
   tl3 : List StatesQ
   tl3 with f q3
   ... | true = q3 ∷  []
   ... | false = []
   tl2 : List StatesQ
   tl2 with f q2
   ... | true = q2 ∷ tl3
   ... | false = tl3
   tl1 : List StatesQ
   tl1 with f q1
   ... | true = q1 ∷ tl2
   ... | false = tl2

nfa136 :  NAutomaton  StatesQ A2
nfa136 =  record { Nδ = transition136; Nend = end136 }

example136-1 = Naccept nfa136 exists136 start136( a0  ∷ b0  ∷ a0 ∷ a0 ∷ [] )

t146-1 = Ntrace nfa136 exists136 to-list-136 start136( a0  ∷ b0  ∷ a0 ∷ a0 ∷ [] )

example136-0 = Naccept nfa136 exists136 start136( a0 ∷ [] )

example136-2 = Naccept nfa136 exists136 start136( b0  ∷ a0  ∷ b0 ∷ a0 ∷ b0 ∷ [] )
t146-2 = Ntrace nfa136 exists136 to-list-136 start136( b0  ∷ a0  ∷ b0 ∷ a0 ∷ b0 ∷ [] )

open FiniteSet

nx : (StatesQ → Bool) → (List A2 ) → StatesQ → Bool
nx now [] = now
nx now ( i ∷ ni ) = (Nmoves nfa136 exists136 (nx now ni) i )

example136-3 = to-list-136 start136
example136-4 = to-list-136 (nx start136  ( a0  ∷ b0 ∷ a0 ∷ [] ))

open import sbconst2

fm136 : Automaton ( StatesQ → Bool  )  A2
fm136  = subset-construction exists136 nfa136

open NAutomaton

lemma136 : ( x : List A2 ) → Naccept nfa136 exists136 start136 x  ≡ accept fm136 start136 x
lemma136 x = lemma136-1 x start136 where
    lemma136-1 : ( x : List A2 ) → ( states : StatesQ → Bool )
        → Naccept nfa136 exists136 states x  ≡ accept fm136 states x
    lemma136-1 [] _ = refl
    lemma136-1 (h ∷ t) states = lemma136-1 t (δconv exists136 (Nδ nfa136) states h)


{-# OPTIONS --cubical #-}

module Type.Cubical.Quotient where

open import Functional
import      Lvl
open import Structure.Type.Identity
open import Type.Cubical
open import Type.Cubical.Path.Equality
open import Type
open import Syntax.Function

private variable ℓ ℓₗ : Lvl.Level
private variable T A B : Type{ℓ}
private variable x y : T
private variable P : T → Type{ℓ}
private variable _▫_ : T → T → Type{ℓ}

data Quotient(_▫_ : T → T → Type{ℓ}) : Type{Lvl.of(T) Lvl.⊔ ℓ} where
  class : T → Quotient(_▫_)
  class-extensionalityₗ : (class x ≡ class y) ← (x ▫ y)

open import Type.Cubical.Path
open import Type.Cubical.Univalence
open import Type.Properties.MereProposition
open import Structure.Relator.Equivalence
open import Structure.Relator.Properties

module _ (P : Quotient(_▫_) → Type{ℓ}) ⦃ prop-P : ∀{c} → MereProposition(P(c)) ⦄ where
  Quotient-property-pathP : ∀{x y}{px : P(x)}{py : P(y)} → (xy : x ≡ y) → PathP(\i → P(xy i)) px py
  Quotient-property-pathP {x}{y}{px}{py} xy = IdentityEliminator.elim Path-identity-eliminator (xy ↦ (∀{px}{py} → PathP(\i → P(xy i)) px py)) (\{c} → uniqueness(P(c))) {x}{y} xy {px}{py}

  class-property : (∀{a} → P(class a)) → (∀{c} → P(c))
  class-property p {class a} = p{a}
  class-property p {class-extensionalityₗ {x} {y} xy i} = Quotient-property-pathP {px = p{x}}{py = p{y}} (class-extensionalityₗ xy) i

-- TODO: Use Structuve.Function.Surjective when it is generalized to support Type.Cubical.Logic.∃. The difference is that Type.Cubical.Logic.∃ is a mere propositions while surjective uses existence defined as Σ which is not
open import Type.Cubical.Logic
class-surjective : ∀{y} → ∃(x ↦ class{_▫_ = _▫_} x ≡ y)
class-surjective{_▫_ = _▫_} = class-property(y ↦ ∃(x ↦ class{_▫_ = _▫_} x ≡ y)) (\{a} → [∃]-intro a ⦃ reflexivity(_≡_) ⦄)

-- Note: The following holds by definition: ∀{P : (A → B) → Type{ℓ}}{f}{p} → P(f) → P(Quotient-recursion f p ∘ class).
Quotient-recursion : (f : A → B) → (∀{a b} → (a ▫ b) → (f(a) ≡ f(b))) → (Quotient(_▫_) → B)
Quotient-recursion f _ (class x) = f(x)
Quotient-recursion _ p (class-extensionalityₗ xy i) = p xy i

module _ where
  open import Structure.Function
  open import Structure.Setoid

  Quotient-function : ∀{ℓₑ₁ ℓₑ₂}{equiv-A : Equiv{ℓₑ₁}(A)}{equiv-B : Equiv{ℓₑ₂}(B)} ⦃ sub : (Equiv._≡_ equiv-B) ⊆₂ Path ⦄ (f : A → B) ⦃ func : Function ⦃ equiv-A ⦄ ⦃ equiv-B ⦄ f ⦄ → (Quotient(Equiv._≡_ equiv-A) → B)
  Quotient-function {equiv-B = equiv-B} f(x) = Quotient-recursion f (sub₂(Equiv._≡_ equiv-B)(Path) ∘ congruence₁ ⦃ _ ⦄ ⦃ _ ⦄ (f)) x

module _ ⦃ equivalence : Equivalence(_▫_) ⦄ ⦃ prop : ∀{x y} → MereProposition(x ▫ y) ⦄ where
  class-extensionalityᵣ : (class{_▫_ = _▫_} x ≡ class y) → (x ▫ y)
  class-extensionalityᵣ {x = x} {y = y} p = sub₂(_≡_)(_→ᶠ_) ⦃ Path-coercion ⦄ xx-xy (reflexivity(_▫_)) where
    xx-xy : (x ▫ x) ≡ (x ▫ y)
    xx-xy i = Quotient-recursion (x ▫_) (\ab → propositional-extensionalityₗ ([↔]-intro (swap(transitivity(_▫_)) (symmetry(_▫_) ab)) (swap(transitivity(_▫_)) ab))) (p i)

  class-extensionality : (class{_▫_ = _▫_} x ≡ class y) ↔ (x ▫ y)
  class-extensionality = [↔]-intro class-extensionalityₗ class-extensionalityᵣ

module Syntax where
  _/_ : (T : Type{ℓ}) → (T → T → Type{ℓₗ}) → Type
  _ / (_▫_) = Quotient(_▫_)

  [_] : T → (T / (_▫_))
  [_] = class


-- Andreas, 2014-06-27, issue raised by fsfbugs
-- {-# OPTIONS -v interaction.give:10 -v tc:20 -v tc.conv.sort:30 #-}

open import Common.Level

record R (p r : Level) : Set (lsuc (p ⊔ r)) where
  field
    P   : Set p
    _~_ : P -> P -> Set r
    f   : (p p' : P) -> {!p ~ p'!}  -- Give (p ~ p') here!

-- PROBLEM WAS:
-- When issuing C-c C-SPC, Agda complains
--   Set (r ⊔ p) != Set (suc r ⊔ suc p)
-- even though removing the hole manually (by removing '{!' and '!}')
-- gives a well-typed definition.

-- REASON WAS:
-- Conversion.leqSort produced equality rather than subtyping constraint
-- upon postponement:
--   does (f : (p p' : P) → ?0 p r P _~_ p p') → f
--   of sort Setω
--   fit in Set (lsuc r ⊔ lsuc p) ?
--   adding constraint [0] dLub (Set p)
--                       (λ p → dLub (Set p) (λ p' → Set (_4 p r P _~_ p p')))
--                       == Set (lsuc r ⊔ lsuc p)

-- WORKS NOW


{-

Constant structure: _ ↦ A

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Structures.Relational.Constant where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure
open import Cubical.Foundations.RelationalStructure
open import Cubical.HITs.PropositionalTruncation
open import Cubical.HITs.SetQuotients

open import Cubical.Structures.Constant

private
  variable
    ℓ ℓ' : Level

-- Structured relations

module _ (A : hSet ℓ') where

  ConstantRelStr : StrRel {ℓ = ℓ} (ConstantStructure (A .fst)) ℓ'
  ConstantRelStr _ a₀ a₁ = a₀ ≡ a₁

  constantSuitableRel : SuitableStrRel {ℓ = ℓ} (ConstantStructure (A .fst)) ConstantRelStr
  constantSuitableRel .quo _ _ _ = isContrSingl _
  constantSuitableRel .symmetric _ = sym
  constantSuitableRel .transitive _ _ = _∙_
  constantSuitableRel .set _ = A .snd
  constantSuitableRel .prop _ = A .snd

  constantRelMatchesEquiv : StrRelMatchesEquiv {ℓ = ℓ} ConstantRelStr (ConstantEquivStr (A .fst))
  constantRelMatchesEquiv _ _ _ = idEquiv _

  constantRelAction : StrRelAction {ℓ = ℓ} ConstantRelStr
  constantRelAction .actStr _ a = a
  constantRelAction .actStrId _ = refl
  constantRelAction .actRel _ a a' p = p

  constantPositiveRel : PositiveStrRel {ℓ = ℓ} constantSuitableRel
  constantPositiveRel .act = constantRelAction
  constantPositiveRel .reflexive a = refl
  constantPositiveRel .detransitive R R' p = ∣ _ , p , refl ∣
  constantPositiveRel .quo R = isoToIsEquiv isom
    where
    open Iso
    isom : Iso _ _
    isom .fun = _
    isom .inv = [_]
    isom .rightInv _ = refl
    isom .leftInv = elimProp (λ _ → squash/ _ _) (λ a → refl)


------------------------------------------------------------------------------
--  Properties related with lists (using induction on the FOTC lists type)
------------------------------------------------------------------------------

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

module FOTC.Data.List.PropertiesByInductionI where

open import Common.FOL.Relation.Binary.EqReasoning

open import FOTC.Base
open import FOTC.Base.List
open import FOTC.Base.List.PropertiesI
open import FOTC.Data.List
open import FOTC.Data.Nat.Type

------------------------------------------------------------------------------
-- Congruence properties

++-leftCong : ∀ {xs ys zs} → xs ≡ ys → xs ++ zs ≡ ys ++ zs
++-leftCong refl = refl

------------------------------------------------------------------------------
-- Totality properties

lengthList-N : ∀ {xs} → List xs → N (length xs)
lengthList-N = List-ind A A[] h
  where
  A : D → Set
  A ds = N (length ds)

  A[] : A []
  A[] = subst N (sym length-[]) nzero

  h : ∀ a {as} → A as → A (a ∷ as)
  h a {as} Aas = subst N (sym (length-∷ a as)) (nsucc Aas)

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

++-leftIdentity : ∀ xs → [] ++ xs ≡ xs
++-leftIdentity = ++-[]

++-assoc : ∀ {xs} → List xs → ∀ ys zs → (xs ++ ys) ++ zs ≡ xs ++ ys ++ zs
++-assoc Lxs ys zs = List-ind A A[] h Lxs
  where
  A : D → Set
  A as = (as ++ ys) ++ zs ≡ as ++ ys ++ zs

  A[] : A []
  A[] = ([] ++ ys) ++ zs ≡⟨ ++-leftCong (++-leftIdentity ys) ⟩
        ys ++ zs         ≡⟨ sym (++-leftIdentity (ys ++ zs)) ⟩
        [] ++ ys ++ zs   ∎

  h : ∀ a {as} → A as → A (a ∷ as)
  h a {as} Aas =
    ((a ∷ as) ++ ys) ++ zs ≡⟨ ++-leftCong (++-∷ a as ys) ⟩
    (a ∷ (as ++ ys)) ++ zs ≡⟨ ++-∷ a (as ++ ys) zs ⟩
    a ∷ ((as ++ ys) ++ zs) ≡⟨ ∷-rightCong Aas ⟩
    a ∷ (as ++ ys ++ zs)   ≡⟨ sym (++-∷ a as (ys ++ zs)) ⟩
    (a ∷ as) ++ ys ++ zs   ∎


open import Level using (_⊔_)
open import Function using (_$_)

open import Data.Empty using (⊥)

open import Relation.Nullary using (yes; no)
open import Relation.Nullary.Negation using (contradiction)
open import Relation.Binary using (Rel; Reflexive; Transitive; Antisymmetric; _Respects₂_; _Respectsʳ_; _Respectsˡ_; Symmetric; Decidable; Irrelevant)
open import Relation.Binary.PropositionalEquality using (_≡_) renaming (refl to ≡-refl; cong to ≡-cong)

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

open import Algebra.Bundles using (CommutativeSemiring)

module AKS.Algebra.Divisibility {c ℓ} (S : CommutativeSemiring c ℓ) where

open import AKS.Nat using (ℕ; _<_; <-irrelevant)
open import AKS.Nat.WellFounded using (Acc; acc; <-well-founded)

open CommutativeSemiring S using (_+_; _*_; 0#; 1#) renaming (Carrier to C)
open CommutativeSemiring S using (_≈_; setoid; refl; sym; trans)
open import Relation.Binary.Reasoning.Setoid setoid
open CommutativeSemiring S using (+-cong; +-congˡ; +-congʳ; +-identityʳ; +-comm; +-assoc)
open CommutativeSemiring S using (*-assoc; *-identityˡ; *-identityʳ; *-congˡ; *-congʳ; zeroˡ; zeroʳ; distribʳ; distribˡ; *-comm)
open import Algebra.Core using (Op₂)
open import Algebra.Definitions _≈_ using (Commutative; Congruent₂; LeftCongruent; RightCongruent)

open import AKS.Algebra.Structures C _≈_ using (module Divisibility; module Modulus)
open Divisibility _*_ using (_∣_; _∤_; divides; IsGCD) public

infix 4 _≉_
_≉_ : Rel C ℓ
x ≉ y = x ≈ y → ⊥

∣-refl : Reflexive _∣_
∣-refl {x} = divides 1# (sym (*-identityˡ x))

∣-trans : Transitive _∣_
∣-trans {x} {y} {z} (divides q₁ y≈q₁*x) (divides q₂ z≈q₂*y) = divides (q₂ * q₁) $ begin
  z ≈⟨ z≈q₂*y ⟩
  q₂ * y ≈⟨ *-congˡ y≈q₁*x ⟩
  q₂ * (q₁ * x) ≈⟨ sym (*-assoc q₂ q₁ x) ⟩
  (q₂ * q₁) * x ∎

∣-respʳ : _∣_ Respectsʳ _≈_
∣-respʳ {y} {x₁} {x₂} x₁≈x₂ (divides q x₁≈q*y) = divides q $ begin
  x₂    ≈⟨ sym x₁≈x₂ ⟩
  x₁    ≈⟨ x₁≈q*y ⟩
  q * y ∎

∣-respˡ : _∣_ Respectsˡ _≈_
∣-respˡ {y} {x₁} {x₂} x₁≈x₂ (divides q y≈q*x₁) = divides q $ begin
  y      ≈⟨ y≈q*x₁ ⟩
  q * x₁ ≈⟨ *-congˡ x₁≈x₂ ⟩
  q * x₂ ∎

∣-resp : _∣_ Respects₂ _≈_
∣-resp = ∣-respʳ , ∣-respˡ

infix 10 1∣_ _∣0

1∣_ : ∀ n → 1# ∣ n
1∣ n = divides n (sym (*-identityʳ n))

_∣0 : ∀ n → n ∣ 0#
n ∣0 = divides 0# (sym (zeroˡ n))

0∣n⇒n≈0 : ∀ {n} → 0# ∣ n → n ≈ 0#
0∣n⇒n≈0 {n} (divides q n≈q*0) = begin
  n      ≈⟨ n≈q*0 ⟩
  q * 0# ≈⟨ zeroʳ q ⟩
  0#     ∎

∣n⇒∣m*n : ∀ i n m → i ∣ n → i ∣ m * n
∣n⇒∣m*n i n m (divides q n≈q*i) = divides (m * q) $ begin
  m * n       ≈⟨ *-congˡ n≈q*i ⟩
  m * (q * i) ≈⟨ sym (*-assoc m q i) ⟩
  m * q * i   ∎

∣n⇒∣n*m : ∀ i n m → i ∣ n → i ∣ n * m
∣n⇒∣n*m i n m i∣n = ∣-respʳ (*-comm m n) (∣n⇒∣m*n i n m i∣n)

module GCD {gcd : Op₂ C} (isGCD : IsGCD gcd) (∣-antisym : Antisymmetric _≈_ _∣_) where
  open IsGCD isGCD

  ∣1⇒≈1 : ∀ {n} → n ∣ 1# → n ≈ 1#
  ∣1⇒≈1 {n} n∣1 = ∣-antisym n∣1 (1∣ n)

  gcd[0,0]≈0 : gcd 0# 0# ≈ 0#
  gcd[0,0]≈0 = ∣-antisym (gcd 0# 0# ∣0) (gcd-greatest ∣-refl ∣-refl)

  gcd-comm : Commutative gcd
  gcd-comm a b = ∣-antisym
    (gcd-greatest (gcd[a,b]∣b a b) (gcd[a,b]∣a a b))
    (gcd-greatest (gcd[a,b]∣b b a) (gcd[a,b]∣a b a))

  gcd[0,a]≈a : ∀ a → gcd 0# a ≈ a
  gcd[0,a]≈a a = ∣-antisym (gcd[a,b]∣b 0# a) (gcd-greatest (a ∣0) ∣-refl)

  gcd[a,0]≈a : ∀ a → gcd a 0# ≈ a
  gcd[a,0]≈a a = ∣-antisym (gcd[a,b]∣a a 0#) (gcd-greatest ∣-refl (a ∣0))

  gcd[0,a]≈1⇒a≈1 : ∀ a → gcd 0# a ≈ 1# → a ≈ 1#
  gcd[0,a]≈1⇒a≈1 a gcd[0,a]≈1 = ∣1⇒≈1 (∣-respʳ gcd[0,a]≈1 (gcd-greatest (a ∣0) ∣-refl))

  gcd[a,0]≈1⇒a≈1 : ∀ a → gcd a 0# ≈ 1# → a ≈ 1#
  gcd[a,0]≈1⇒a≈1 a gcd[a,0]≈1 = ∣1⇒≈1 (∣-respʳ gcd[a,0]≈1 (gcd-greatest ∣-refl (a ∣0)))

  gcd[a,b]≈0⇒a≈0 : ∀ {a b} → gcd a b ≈ 0# → a ≈ 0#
  gcd[a,b]≈0⇒a≈0 {a} {b} gcd[a,b]≈0 = 0∣n⇒n≈0 (∣-respˡ gcd[a,b]≈0 (gcd[a,b]∣a a b))

  gcd[a,b]≈0⇒b≈0 : ∀ {a b} → gcd a b ≈ 0# → b ≈ 0#
  gcd[a,b]≈0⇒b≈0 {a} {b} gcd[a,b]≈0 = 0∣n⇒n≈0 (∣-respˡ gcd[a,b]≈0 (gcd[a,b]∣b a b))

  gcd[a,1]≈1 : ∀ a → gcd a 1# ≈ 1#
  gcd[a,1]≈1 a = ∣-antisym (gcd[a,b]∣b a 1#) (gcd-greatest (1∣ a) ∣-refl)

  gcd[1,a]≈1 : ∀ a → gcd 1# a ≈ 1#
  gcd[1,a]≈1 a = ∣-antisym (gcd[a,b]∣a 1# a) (gcd-greatest ∣-refl (1∣ a))

  -- gcd[d*a,d*b]≈d*gcd[a,b] : ∀ a b d → gcd (d * a) (d * b) ≈ d * gcd a b
  -- gcd[d*a,d*b]≈d*gcd[a,b] = ?

  a≉0⇒gcd[a,b]≉0 : ∀ a b → a ≉ 0# → gcd a b ≉ 0#
  a≉0⇒gcd[a,b]≉0 a b a≉0 gcd[a,b]≈0 = a≉0 (gcd[a,b]≈0⇒a≈0 gcd[a,b]≈0)

  b≉0⇒gcd[a,b]≉0 : ∀ a b → b ≉ 0# → gcd a b ≉ 0#
  b≉0⇒gcd[a,b]≉0 a b b≉0 gcd[a,b]≈0 = b≉0 (gcd[a,b]≈0⇒b≈0 gcd[a,b]≈0)

  gcd-cong : Congruent₂ gcd
  gcd-cong {a} {b} {c} {d} a≈b c≈d = ∣-antisym
    (gcd-greatest (∣-respʳ a≈b (gcd[a,b]∣a a c)) (∣-respʳ c≈d (gcd[a,b]∣b a c)))
    (gcd-greatest (∣-respʳ (sym a≈b) (gcd[a,b]∣a b d)) (∣-respʳ (sym c≈d) (gcd[a,b]∣b b d)))

  gcd-congˡ : LeftCongruent gcd
  gcd-congˡ c≈d = gcd-cong refl c≈d

  gcd-congʳ : RightCongruent gcd
  gcd-congʳ a≈b = gcd-cong a≈b refl

  infix 4 _⊥_
  _⊥_ : C → C → Set ℓ
  n ⊥ m = gcd n m ≈ 1#

  ⊥-sym : Symmetric _⊥_
  ⊥-sym {x} {y} gcd[x,y]≡1 = begin
    gcd y x ≈⟨ gcd-comm y x ⟩
    gcd x y ≈⟨ gcd[x,y]≡1 ⟩
    1# ∎

  ⊥-respʳ : _⊥_ Respectsʳ _≈_
  ⊥-respʳ {y} {x₁} {x₂} x₁≈x₂ gcd[y,x₁]≈1 = begin
    gcd y x₂ ≈⟨ gcd-congˡ (sym x₁≈x₂) ⟩
    gcd y x₁ ≈⟨ gcd[y,x₁]≈1 ⟩
    1# ∎

  ⊥-respˡ : _⊥_ Respectsˡ _≈_
  ⊥-respˡ {y} {x₁} {x₂} x₁≈x₂ gcd[x₁,y]≈1 = begin
    gcd x₂ y ≈⟨ gcd-congʳ (sym x₁≈x₂) ⟩
    gcd x₁ y ≈⟨ gcd[x₁,y]≈1 ⟩
    1# ∎

  ⊥-resp : _⊥_ Respects₂ _≈_
  ⊥-resp = ⊥-respʳ , ⊥-respˡ

module _
  (∣_∣ : ∀ n {n≉0 : n ≉ 0#} → ℕ)
  (_div_ : ∀ (n m : C) {m≉0 : m ≉ 0#} → C)
  (_mod_ : ∀ (n m : C) {m≉0 : m ≉ 0#} → C)
  where
  open Modulus 0# ∣_∣ _mod_

  module Euclidean
    (_≈?_ : Decidable _≈_)
    (≈-irrelevant : Irrelevant _≈_)
    (≉-irrelevant : Irrelevant _≉_)
    (division : ∀ n m {m≉0 : m ≉ 0#} → n ≈ m * (n div m) {m≉0} + (n mod m) {m≉0})
    (modulus : ∀ n m {m≉0 : m ≉ 0#} → Remainder n m {m≉0})
    (mod-cong : ∀ {x₁ x₂} {y₁ y₂} → x₁ ≈ x₂ → y₁ ≈ y₂ → ∀ {y₁≉0 y₂≉0} → (x₁ mod y₁) {y₁≉0} ≈ (x₂ mod y₂) {y₂≉0})
    (mod-distribʳ-* : ∀ c a b {b≉0} {b*c≉0} → ((a * c) mod (b * c)) {b*c≉0} ≈ (a mod b) {b≉0} * c)
    where

    gcdₕ : ∀ (n m : C) {m≉0 : m ≉ 0#} → Acc _<_ (∣ m ∣ {m≉0}) → C
    gcdₕ n m {m≉0} (acc downward) with modulus n m {m≉0}
    ... | 0≈ r≈0 = m
    ... | 0≉ r≉0 r<m = gcdₕ m (n mod m) (downward r<m)

    gcd : C → C → C
    gcd n m with m ≈? 0#
    ... | yes m≈0 = n
    ... | no  m≉0 = gcdₕ n m {m≉0} <-well-founded

    ∣b∣a%b⇒∣a : ∀ {c a b} {b≉0 : b ≉ 0#} → c ∣ b → c ∣ (a mod b) {b≉0} → c ∣ a
    ∣b∣a%b⇒∣a {c} {a} {b} {b≉0} (divides q₁ b≈q₁*c) (divides q₂ a%b≈q₂*c) = divides ((a div b) {b≉0} * q₁ + q₂) $ begin
      a                             ≈⟨ division a b {b≉0} ⟩
      b * (a div b) + a mod b       ≈⟨ +-cong (*-congʳ b≈q₁*c) a%b≈q₂*c ⟩
      (q₁ * c) * (a div b) + q₂ * c ≈⟨ +-congʳ (*-comm (q₁ * c) (a div b)) ⟩
      (a div b) * (q₁ * c) + q₂ * c ≈⟨ +-congʳ (sym (*-assoc (a div b) q₁ c)) ⟩
      ((a div b) * q₁) * c + q₂ * c ≈⟨ sym (distribʳ c ((a div b) * q₁) q₂) ⟩
      ((a div b) * q₁ + q₂) * c     ∎

    gcd[a,b]∣a×gcd[a,b]∣b : ∀ a b → (gcd a b ∣ a) × (gcd a b ∣ b)
    gcd[a,b]∣a×gcd[a,b]∣b a b with b ≈? 0#
    ... | yes b≈0 = ∣-refl , (∣-respʳ (sym b≈0) (a ∣0))
    ... | no  b≉0 = loop a b {b≉0} <-well-founded
      where
      loop : ∀ a b {b≉0} (rec : Acc _<_ (∣ b ∣ {b≉0})) → (gcdₕ a b rec ∣ a) × (gcdₕ a b rec ∣ b)
      loop a b {b≉0} (acc downward) with modulus a b {b≉0}
      ... | 0≈ r≈0 = ∣b∣a%b⇒∣a ∣-refl (∣-respʳ (sym r≈0) (b ∣0)) , ∣-refl
      ... | 0≉ r≉0 r<m with loop b (a mod b) (downward r<m)
      ...   | gcd∣b , gcd∣a%b = ∣b∣a%b⇒∣a gcd∣b gcd∣a%b , gcd∣b

    ∣a∣b⇒∣a%b : ∀ {c a b} {b≉0 : b ≉ 0#} → c ∣ a → c ∣ b → c ∣ (a mod b) {b≉0}
    ∣a∣b⇒∣a%b {c} {a} {b} {b≉0} (divides q₁ a≈q₁*c) (divides q₂ b≈q₂*c) = divides ((q₁ mod q₂) {q≉0}) $ begin
      a mod b ≈⟨ mod-cong a≈q₁*c b≈q₂*c {b≉0} {q₂*c≉0} ⟩
      (q₁ * c) mod (q₂ * c) ≈⟨ mod-distribʳ-* c q₁ q₂ ⟩
      (q₁ mod q₂) * c ∎
      where
      q≉0 : q₂ ≉ 0#
      q≉0 q₂≈0 = b≉0 $ begin
        b      ≈⟨ b≈q₂*c ⟩
        q₂ * c ≈⟨ *-congʳ q₂≈0 ⟩
        0# * c ≈⟨ zeroˡ c ⟩
        0#     ∎
      q₂*c≉0 : q₂ * c ≉ 0#
      q₂*c≉0 q₂*c≈0 = b≉0 $ begin
        b ≈⟨ b≈q₂*c ⟩
        q₂ * c ≈⟨ q₂*c≈0 ⟩
        0# ∎

    gcd-greatest : ∀ {c a b} → c ∣ a → c ∣ b → c ∣ gcd a b
    gcd-greatest {c} {a} {b} c∣a c∣b with b ≈? 0#
    ... | yes b≈0 = c∣a
    ... | no  b≉0 = loop c a b <-well-founded c∣a c∣b
      where
      loop : ∀ c a b {b≉0} (rec : Acc _<_ (∣ b ∣ {b≉0})) → c ∣ a → c ∣ b → c ∣ gcdₕ a b rec
      loop c a b {b≉0} (acc downward) c∣a c∣b with modulus a b {b≉0}
      ... | 0≈ r≈0 = c∣b
      ... | 0≉ r≉0 r<m = loop c b (a mod b) (downward r<m) c∣b (∣a∣b⇒∣a%b c∣a c∣b)

    gcd-isGCD : IsGCD gcd
    gcd-isGCD = record
      { gcd[a,b]∣a = λ a b → proj₁ (gcd[a,b]∣a×gcd[a,b]∣b a b)
      ; gcd[a,b]∣b = λ a b → proj₂ (gcd[a,b]∣a×gcd[a,b]∣b a b)
      ; gcd-greatest = gcd-greatest
      }

    -- open GCD gcd-isGCD ∣-antisym public

    data Identity (d : C) (a : C) (b : C) : Set (c ⊔ ℓ) where
      +ʳ : ∀ (x y : C) → d + x * a ≈ y * b → Identity d a b
      +ˡ : ∀ (x y : C) → d + y * b ≈ x * a → Identity d a b

    identity-sym : ∀ {d} → Symmetric (Identity d)
    identity-sym (+ʳ x y pf) = +ˡ y x pf
    identity-sym (+ˡ x y pf) = +ʳ y x pf

    identity-base : ∀ {d a} → Identity d d a
    identity-base {d} {a} = +ˡ 1# 0# $ begin
      d + 0# * a  ≈⟨ +-congˡ (zeroˡ a) ⟩
      d + 0#      ≈⟨ +-identityʳ d ⟩
      d           ≈⟨ sym (*-identityˡ d) ⟩
      1# * d      ∎

    stepʳ
      : ∀ d x y a b {b≉0}
      → d + x * b ≈ y * (a mod b) {b≉0}
      → d + (x + y * (a div b) {b≉0}) * b ≈ y * a
    stepʳ d x y a b {b≉0} d+x*b≈y*[a%b] = begin
      d + (x + y * a div b) * b       ≈⟨ +-congˡ (distribʳ b x (y * (a div b) {b≉0})) ⟩
      d + (x * b + y * a div b * b)   ≈⟨ sym (+-assoc d (x * b) (y * a div b * b)) ⟩
      (d + x * b) + y * a div b * b   ≈⟨ +-cong d+x*b≈y*[a%b] (*-assoc y (a div b) b) ⟩
      y * a mod b + y * (a div b * b) ≈⟨ sym (distribˡ y (a mod b) (a div b * b)) ⟩
      y * (a mod b + a div b * b)     ≈⟨ *-congˡ (+-comm (a mod b) (a div b * b)) ⟩
      y * (a div b * b + a mod b)     ≈⟨ *-congˡ (+-congʳ (*-comm (a div b) b)) ⟩
      y * (b * a div b + a mod b)     ≈⟨ *-congˡ (sym (division a b)) ⟩
      y * a                           ∎

    stepˡ
      : ∀ d x y a b {b≉0}
      → d + y * (a mod b) {b≉0} ≈ x * b
      → d + y * a ≈ (x + y * (a div b) {b≉0}) * b
    stepˡ d x y a b {b≉0} d+x*b≈y*[a%b] = begin
      d + y * a                               ≈⟨ +-congˡ (*-congˡ (division a b {b≉0})) ⟩
      d + y * (b * a div b + a mod b)         ≈⟨ +-congˡ (*-congˡ (+-comm (b * a div b) (a mod b))) ⟩
      d + y * (a mod b + b * a div b)         ≈⟨ +-congˡ (distribˡ y (a mod b) (b * a div b)) ⟩
      d + (y * (a mod b) + y * (b * a div b)) ≈⟨ sym (+-assoc d (y * (a mod b)) (y * (b * a div b))) ⟩
      (d + y * (a mod b)) + y * (b * a div b) ≈⟨ +-cong d+x*b≈y*[a%b] (*-congˡ (*-comm b (a div b))) ⟩
      x * b + y * (a div b * b)               ≈⟨ +-congˡ (sym (*-assoc y (a div b) b)) ⟩
      x * b + (y * a div b) * b               ≈⟨ sym (distribʳ b x (y * a div b)) ⟩
      (x + y * (a div b)) * b                 ∎

    identity-step : ∀ {d a b} {b≉0} → Identity d b ((a mod b) {b≉0}) → Identity d a b
    identity-step {d} {a} {b} {b≉0} (+ʳ x y d+x*b≈y*[a%b]) = +ˡ y (x + y * (a div b)) (stepʳ d x y a b {b≉0} d+x*b≈y*[a%b])
    identity-step {d} {a} {b} {b≉0} (+ˡ x y d+y*[a%b]≈x*b) = +ʳ y (x + y * (a div b)) (stepˡ d x y a b {b≉0} d+y*[a%b]≈x*b)

    data Bézoutₕ (a : C) (b : C) {b≉0 : b ≉ 0#} (rec : Acc _<_ (∣ b ∣ {b≉0})) : Set (c ⊔ ℓ) where
      lemmaₕ : ∀ d → gcdₕ a b rec ≈ d → Identity d a b → Bézoutₕ a b rec

    gcdₕ-base : ∀ {a b} {b≉0} {rec : Acc _<_ (∣ b ∣ {b≉0})} (r≈0 : (a mod b) {b≉0} ≈ 0#) → gcdₕ a b rec ≈ b
    gcdₕ-base {a} {b} {b≉0} {acc downward} [r≈0]₁ with modulus a b {b≉0}
    ... | 0≈ [r≈0]₂ rewrite ≈-irrelevant [r≈0]₁ [r≈0]₂ = refl
    ... | 0≉ r≉0 _  = contradiction [r≈0]₁ r≉0

    gcdₕ-step
      : ∀ {d a b} {b≉0} {r≉0 : (a mod b) {b≉0} ≉ 0#}
          {r<m : ∣ a mod b ∣ {r≉0} < ∣ b ∣ {b≉0}}
          {downward : ∀ {x} → x < ∣ b ∣ {b≉0} → Acc _<_ x}
      → gcdₕ b (a mod b) (downward {∣ a mod b ∣} r<m) ≈ d → gcdₕ a b (acc downward) ≈ d
    gcdₕ-step {d} {a} {b} {b≉0} {[r≉0]₁} {[r<m]₁} gcdₕ[b,a%b]≈d with modulus a b {b≉0}
    ... | 0≈ r≈0 = contradiction r≈0 [r≉0]₁
    ... | 0≉ [r≉0]₂ [r<m]₂ rewrite ≉-irrelevant [r≉0]₁ [r≉0]₂ | <-irrelevant [r<m]₁ [r<m]₂ = gcdₕ[b,a%b]≈d

    bézoutₕ : ∀ a b {b≉0} (rec : Acc _<_ (∣ b ∣ {b≉0})) → Bézoutₕ a b rec
    bézoutₕ a b {b≉0} (acc downward) with modulus a b {b≉0}
    ... | 0≈ r≈0 = lemmaₕ b (gcdₕ-base r≈0) (identity-sym identity-base)
    ... | 0≉ r≉0 r<m with bézoutₕ b (a mod b) {r≉0} (downward r<m)
    ...   | lemmaₕ d gcdₕ[b,a%b]≈d ident = lemmaₕ d (gcdₕ-step gcdₕ[b,a%b]≈d) (identity-step ident)

    data Bézout (a : C) (b : C) : Set (c ⊔ ℓ) where
      lemma : ∀ d → gcd a b ≈ d → Identity d a b → Bézout a b

    b≈0⇒gcd[a,b]≈a : ∀ a b → b ≈ 0# → gcd a b ≈ a
    b≈0⇒gcd[a,b]≈a a b b≈0 with b ≈? 0#
    ... | yes _  = refl
    ... | no b≉0 = contradiction b≈0 b≉0

    gcdₕ⇒gcd : ∀ {d a b} {b≉0} → gcdₕ a b {b≉0} <-well-founded ≈ d → gcd a b ≈ d
    gcdₕ⇒gcd {d} {a} {b} {[b≉0]₁} gcdₕ[a,b]≈d with b ≈? 0#
    ... | yes b≈0 = contradiction b≈0 [b≉0]₁
    ... | no [b≉0]₂ rewrite ≉-irrelevant [b≉0]₁ [b≉0]₂ = gcdₕ[a,b]≈d

    bézout : ∀ a b → Bézout a b
    bézout a b with b ≈? 0#
    ... | yes b≈0 = lemma a (b≈0⇒gcd[a,b]≈a a b b≈0) identity-base
    ... | no  b≉0 with bézoutₕ a b {b≉0} <-well-founded
    ...   | lemmaₕ d gcdₕ[a,b]≈d ident = lemma d (gcdₕ⇒gcd gcdₕ[a,b]≈d) ident


module Experimental.Finite where

data ℕ : Set where
  Z : ℕ
  S : ℕ → ℕ

data Fin : ℕ → Set where
  Fin-S : ∀ {n} → Fin n → Fin (S n)
  Fin-Z : ∀ {n} → Fin (S n)


open import Data.Product using ( _×_ ; _,_ )
open import Web.Semantic.DL.ABox.Model using ( _⊨a_ ; ⊨a-resp-≲ )
open import Web.Semantic.DL.ABox.Interp using ( Interp ; ⌊_⌋ )
open import Web.Semantic.DL.ABox.Interp.Morphism using ( _≃_ ; ≃⌊_⌋ ; ≃-impl-≲ )
open import Web.Semantic.DL.KB using ( KB ; tbox ; abox )
open import Web.Semantic.DL.Signature using ( Signature )
open import Web.Semantic.DL.TBox.Model using ( _⊨t_ ; ⊨t-resp-≃ )

module Web.Semantic.DL.KB.Model {Σ : Signature} {X : Set} where

infixr 2 _⊨_

_⊨_ : Interp Σ X → KB Σ X → Set
I ⊨ K = (⌊ I ⌋ ⊨t tbox K) × (I ⊨a abox K)

Interps : KB Σ X → Interp Σ X → Set
Interps K I = I ⊨ K

⊨-resp-≃ : ∀ {I J} → (I ≃ J) → ∀ K → (I ⊨ K) → (J ⊨ K)
⊨-resp-≃ I≃J K (I⊨T , I⊨A) =
  (⊨t-resp-≃ ≃⌊ I≃J ⌋ (tbox K) I⊨T , ⊨a-resp-≲ (≃-impl-≲ I≃J) (abox K) I⊨A)


module #11 where

{-
  Show that for any type A, we have ¬¬¬A → ¬A.
-}

open import Data.Empty
open import Relation.Nullary

tripleNeg : ∀{x}{A : Set x} → ¬ (¬ (¬ A)) → ¬ A
tripleNeg = λ z z₁ → z (λ z₂ → z₂ z₁)


------------------------------------------------------------------------
-- An LTS from Section 6.2.5 of "Enhancements of the bisimulation
-- proof method" by Pous and Sangiorgi
------------------------------------------------------------------------

{-# OPTIONS --safe #-}

open import Prelude

module Labelled-transition-system.6-2-5 (Name : Type) where

open import Labelled-transition-system

infixr 12 _·_
infix   5 _[_]
infix   4 _[_]⟶_

-- Processes.

data Proc : Type where
  op  : Proc → Proc
  _·_ : Name → Proc → Proc
  ∅   : Proc

-- Transitions.

data _[_]⟶_ : Proc → Name → Proc → Type where
  action : ∀ {a P} → a · P [ a ]⟶ P
  op     : ∀ {a P P′ P″} → P [ a ]⟶ P′ → P′ [ a ]⟶ P″ → op P [ a ]⟶ P″

-- The LTS.

6-2-5 : LTS lzero
6-2-5 = record
  { Proc      = Proc
  ; Label     = Name
  ; _[_]⟶_    = _[_]⟶_
  ; is-silent = λ _ → false
  }

open LTS 6-2-5 public hiding (Proc; _[_]⟶_)

-- Polyadic contexts.

data Context (n : ℕ) : Type where
  hole : (x : Fin n) → Context n
  op   : Context n → Context n
  _·_  : (a : Name) → Context n → Context n
  ∅    : Context n

-- Hole filling.

_[_] : ∀ {n} → Context n → (Fin n → Proc) → Proc
hole x [ ps ] = ps x
op C   [ ps ] = op (C [ ps ])
a · C  [ ps ] = a · (C [ ps ])
∅      [ ps ] = ∅


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

-- a categorical (i.e. non-skeletal) version of Lawvere Theory,
-- as per https://ncatlab.org/nlab/show/Lawvere+theory

module Categories.Theory.Lawvere where

open import Data.Nat using (ℕ)
open import Data.Product using (Σ; _,_)
open import Level

open import Categories.Category.Cartesian.Structure
open import Categories.Category using (Category; _[_,_])
open import Categories.Category.Instance.Setoids
open import Categories.Category.Monoidal.Instance.Setoids using (Setoids-CartesianCategory)
open import Categories.Category.Product
open import Categories.Functor using (Functor; _∘F_) renaming (id to idF)
open import Categories.Functor.Cartesian
open import Categories.Functor.Cartesian.Properties
import Categories.Morphism as Mor
open import Categories.NaturalTransformation using (NaturalTransformation)

private
  variable
    o ℓ e o′ ℓ′ e′ o″ ℓ″ e″ : Level

record FiniteProduct (o ℓ e : Level) : Set (suc (o ⊔ ℓ ⊔ e)) where
  field
    T : CartesianCategory o ℓ e

  module T = CartesianCategory T
  open Mor T.U

  field
    generic : T.Obj

  field
    obj-iso-to-generic-power : ∀ x → Σ ℕ (λ n → x ≅ T.power generic n)

record LT-Hom (T₁ : FiniteProduct o ℓ e) (T₂ : FiniteProduct o′ ℓ′ e′) : Set (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′) where
  private
    module T₁ = FiniteProduct T₁
    module T₂ = FiniteProduct T₂

  field
    cartF : CartesianF T₁.T T₂.T

  module cartF = CartesianF cartF

LT-id : {A : FiniteProduct o ℓ e} → LT-Hom A A
LT-id = record { cartF = idF-CartesianF _ }

LT-∘ : {A : FiniteProduct o ℓ e} {B : FiniteProduct o′ ℓ′ e′} {C : FiniteProduct o″ ℓ″ e″} →
       LT-Hom B C → LT-Hom A B → LT-Hom A C
LT-∘ G H = record { cartF = ∘-CartesianF (cartF G) (cartF H) }
  where open LT-Hom

record T-Algebra (FP : FiniteProduct o ℓ e) : Set (o ⊔ ℓ ⊔ e ⊔ suc (ℓ′ ⊔ e′)) where
  private
    module FP = FiniteProduct FP
  field
    cartF : CartesianF FP.T (Setoids-CartesianCategory ℓ′ e′)

  module cartF = CartesianF cartF

  mod : Functor FP.T.U (Setoids ℓ′ e′)
  mod = cartF.F


-- https://github.com/idris-lang/Idris-dev/blob/4e704011fb805fcb861cc9a1bd68a2e727cefdde/libs/contrib/Data/Nat/Fib.idr

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

-- agda-stdlib
open import Algebra

module Math.NumberTheory.Fibonacci.Generic
  {c e} (CM : CommutativeMonoid c e)
  (v0 v1 : CommutativeMonoid.Carrier CM)
  where

-- agda-stdlib
open import Data.Nat
open import Function
import Relation.Binary.PropositionalEquality as ≡
import Relation.Binary.Reasoning.Setoid as SetoidReasoning

open CommutativeMonoid CM
  renaming
  ( Carrier to A
  )

open SetoidReasoning setoid

fibRec : ℕ → A
fibRec 0             = v0
fibRec 1             = v1
fibRec (suc (suc n)) = fibRec (suc n) ∙ fibRec n

fibAcc : ℕ → A → A → A
fibAcc 0       a b = a
fibAcc (suc n) a b = fibAcc n b (a ∙ b)

fib : ℕ → A
fib n = fibAcc n v0 v1

lemma : ∀ m n o p → (m ∙ n) ∙ (o ∙ p) ≈ (m ∙ o) ∙ (n ∙ p)
lemma m n o p = begin
  (m ∙ n) ∙ (o ∙ p) ≈⟨ assoc m n (o ∙ p)  ⟩
  m ∙ (n ∙ (o ∙ p)) ≈⟨ sym $ ∙-congˡ $ assoc n o p ⟩
  m ∙ ((n ∙ o) ∙ p) ≈⟨ ∙-congˡ $ ∙-congʳ $ comm n o ⟩
  m ∙ ((o ∙ n) ∙ p) ≈⟨ ∙-congˡ $ assoc o n p ⟩
  m ∙ (o ∙ (n ∙ p)) ≈⟨ sym $ assoc m o (n ∙ p) ⟩
  (m ∙ o) ∙ (n ∙ p) ∎

fibAcc-cong : ∀ {m n o p q r} →
  m ≡.≡ n → o ≈ p → q ≈ r → fibAcc m o q ≈ fibAcc n p r
fibAcc-cong {zero}  {.0}       {o} {p} {q} {r} ≡.refl o≈p q≈r = o≈p
fibAcc-cong {suc m} {.(suc m)} {o} {p} {q} {r} ≡.refl o≈p q≈r =
  fibAcc-cong {m = m} ≡.refl q≈r (∙-cong o≈p q≈r)

fibAdd : ∀ m n o p q → fibAcc m n o ∙ fibAcc m p q ≈ fibAcc m (n ∙ p) (o ∙ q)
fibAdd 0             n o p q = refl
fibAdd 1             n o p q = refl
fibAdd (suc (suc m)) n o p q = begin
  fibAcc (2 + m) n o ∙ fibAcc (2 + m) p q                         ≡⟨⟩
  fibAcc (1 + m) o (n ∙ o) ∙ fibAcc (1 + m) q (p ∙ q)             ≡⟨⟩
  fibAcc m (n ∙ o) (o ∙ (n ∙ o)) ∙ fibAcc m (p ∙ q) (q ∙ (p ∙ q)) ≈⟨ fibAdd m (n ∙ o) (o ∙ (n ∙ o)) (p ∙ q) (q ∙ (p ∙ q)) ⟩
  fibAcc m ((n ∙ o) ∙ (p ∙ q)) ((o ∙ (n ∙ o)) ∙ (q ∙ (p ∙ q)))    ≈⟨ fibAcc-cong {m = m} ≡.refl (lemma n o p q) (lemma o (n ∙ o) q (p ∙ q)) ⟩
  fibAcc m ((n ∙ p) ∙ (o ∙ q)) ((o ∙ q) ∙ ((n ∙ o) ∙ (p ∙ q)))    ≈⟨ fibAcc-cong {m = m} ≡.refl refl (∙-congˡ $ lemma n o p q) ⟩
  fibAcc m ((n ∙ p) ∙ (o ∙ q)) ((o ∙ q) ∙ ((n ∙ p) ∙ (o ∙ q)))    ≡⟨⟩
  fibAcc (1 + m) (o ∙ q) ((n ∙ p) ∙ (o ∙ q))                      ≡⟨⟩
  fibAcc (2 + m) (n ∙ p) (o ∙ q)                                  ∎

fibRec≈fib : ∀ n → fibRec n ≈ fib n
fibRec≈fib 0             = refl
fibRec≈fib 1             = refl
fibRec≈fib (suc (suc n)) = begin
  fibRec (2 + n)                         ≡⟨⟩
  fibRec (1 + n) ∙ fibRec n              ≈⟨ ∙-cong (fibRec≈fib (suc n)) (fibRec≈fib n) ⟩
  fib (1 + n) ∙ fib n                    ≡⟨⟩
  fibAcc (1 + n) v0 v1 ∙ fibAcc n v0 v1  ≡⟨⟩
  fibAcc n v1 (v0 ∙ v1) ∙ fibAcc n v0 v1 ≈⟨ fibAdd n v1 (v0 ∙ v1) v0 v1 ⟩
  fibAcc n (v1 ∙ v0) ((v0 ∙ v1) ∙ v1)    ≈⟨ fibAcc-cong {m = n} ≡.refl (comm v1 v0) (trans (∙-congʳ (comm v0 v1)) (assoc v1 v0 v1)) ⟩
  fibAcc n (v0 ∙ v1) (v1 ∙ (v0 ∙ v1))    ≡⟨⟩
  fib (2 + n)                            ∎

fib[2+n]≈fib[1+n]∙fib[n] : ∀ n → fib (suc (suc n)) ≈ fib (suc n) ∙ fib n
fib[2+n]≈fib[1+n]∙fib[n] n =
  trans (sym $ fibRec≈fib (suc (suc n)))
        (∙-cong (fibRec≈fib (suc n)) (fibRec≈fib n))

fib[1+n]∙fib[n]≈fib[2+n] : ∀ n → fib (suc n) ∙ fib n ≈ fib (suc (suc n))
fib[1+n]∙fib[n]≈fib[2+n] n = sym $ fib[2+n]≈fib[1+n]∙fib[n] n

fib[n]∙fib[1+n]≈fib[2+n] : ∀ n → fib n ∙ fib (suc n) ≈ fib (suc (suc n))
fib[n]∙fib[1+n]≈fib[2+n] n = trans (comm (fib n) (fib (suc n))) (fib[1+n]∙fib[n]≈fib[2+n] n)


open import Data.Fin using (Fin)
open import Data.Nat using (ℕ; _+_)
open import Data.Vec using (Vec; []; _∷_; _++_)
open import Dipsy.Polarity

module Dipsy.Base
  (FOp : {n : ℕ} (as : Vec Polarity n) (b : Polarity) → Set)
  (SOp : {n : ℕ} (as : Vec Polarity n) (b : Polarity) → Set)
  where

open import Dipsy.Form FOp public
open import Dipsy.Struct FOp SOp public

Res : Set
Res = {n₁ n₂ : ℕ}
    → {as₁ : Vec Polarity n₁}
    → {as₂ : Vec Polarity n₂}
    → {b : Polarity}
    → SOp (as₁ ++ flip b ∷ as₂) b
    → Context (flip b) b

-- we need contexts with n holes if we want to encode structuralisation properly..
-- those are functions...


module RewriteAndWhere where

open import Common.Equality

data ℕ : Set where
  zero : ℕ

good : (a b : ℕ) → a ≡ b → b ≡ a
good a b eq with a | eq
... | .b | refl = foo
  where
    foo : b ≡ b
    foo = refl

mutual
  aux : (a b : ℕ)(w : ℕ) → w ≡ b → b ≡ w
  aux a b .b refl = foo
    where
     foo : b ≡ b
     foo = refl

  good₂ : (a b : ℕ) → a ≡ b → b ≡ a
  good₂ a b eq = aux a b a eq

bad : (a b : ℕ) → a ≡ b → b ≡ a
bad a b eq rewrite eq = foo
  where
    foo : b ≡ b
    foo rewrite sym eq = bar
      where
        bar : a ≡ a
        bar = refl


{-# OPTIONS --cubical --safe #-}

module Data.Sigma.Base where

open import Agda.Builtin.Sigma
  using (Σ; _,_; fst; snd)
  public
open import Level
open import Path

∃ : ∀ {a b} {A : Type a} (B : A → Type b) → Type (a ℓ⊔ b)
∃ {A = A} = Σ A

infixr 4.5 ∃-syntax
∃-syntax : ∀ {a b} {A : Type a} (B : A → Type b) → Type (a ℓ⊔ b)
∃-syntax = ∃

syntax ∃-syntax (λ x → e) = ∃[ x ] e

infixr 4.5 Σ⦂-syntax
Σ⦂-syntax : (A : Type a) (B : A → Type b) → Type (a ℓ⊔ b)
Σ⦂-syntax = Σ

syntax Σ⦂-syntax t (λ x → e) = Σ[ x ⦂ t ] e

infixr 4.5 _×_
_×_ : (A : Type a) → (B : Type b) → Type (a ℓ⊔ b)
A × B = Σ A λ _ → B

curry : ∀ {A : Type a} {B : A → Type b} {C : Σ A B → Type c} →
          ((p : Σ A B) → C p) →
          ((x : A) → (y : B x) → C (x , y))
curry f x y = f (x , y)

uncurry : ∀ {A : Type a} {B : A → Type b} {C : Σ A B → Type c} →
            ((x : A) → (y : B x) → C (x , y)) →
            ((p : Σ A B) → C p)
uncurry f (x , y) = f x y

map-Σ : ∀ {p q} {P : A → Set p} {Q : B → Set q} →
        (f : A → B) → (∀ {x} → P x → Q (f x)) →
        Σ A P → Σ B Q
map-Σ f g (x , y) = (f x , g y)

map₁ : (A → B) → A × C → B × C
map₁ f = map-Σ f (λ x → x)

map₁-Σ : ∀ {A : Set a} {B : Set b} {C : B → Set b}
       → (f : A → B) → Σ A (λ x → C (f x)) → Σ B C
map₁-Σ f (x , y) = f x , y

map₂ : ∀ {A : Set a} {B : A → Set b} {C : A → Set c} →
        (∀ {x} → B x → C x) → Σ A B → Σ A C
map₂ f = map-Σ (λ x → x) f

∃! : ∀ {a b} {A : Type a} → (A → Type b) → Type (a ℓ⊔ b)
∃! B = ∃ λ x → B x × (∀ {y} → B y → x ≡ y)

infixr 4.5 ∃!-syntax
∃!-syntax : ∀ {a b} {A : Type a} (B : A → Type b) → Type (a ℓ⊔ b)
∃!-syntax = ∃!

syntax ∃!-syntax (λ x → e) = ∃![ x ] e


------------------------------------------------------------------------
-- Some properties imply others
------------------------------------------------------------------------

module Relation.Binary.Consequences where

open import Relation.Binary.Core hiding (refl)
open import Relation.Nullary.Core
open import Relation.Binary.PropositionalEquality.Core
open import Data.Function
open import Data.Sum
open import Data.Product
open import Data.Empty

-- Some of the definitions can be found in the following module:

open import Relation.Binary.Consequences.Core public

trans∧irr⟶asym :
  ∀ {a} → {≈ < : Rel a} →
  Reflexive ≈ →
  Transitive < → Irreflexive ≈ < → Asymmetric <
trans∧irr⟶asym refl trans irrefl = λ x<y y<x →
  irrefl refl (trans x<y y<x)

irr∧antisym⟶asym :
  ∀ {a} → {≈ < : Rel a} →
  Irreflexive ≈ < → Antisymmetric ≈ < → Asymmetric <
irr∧antisym⟶asym irrefl antisym = λ x<y y<x →
  irrefl (antisym x<y y<x) x<y

asym⟶antisym :
  ∀ {a} → {≈ < : Rel a} →
  Asymmetric < → Antisymmetric ≈ <
asym⟶antisym asym x<y y<x = ⊥-elim (asym x<y y<x)

asym⟶irr :
  ∀ {a} → {≈ < : Rel a} →
  < Respects₂ ≈ → Symmetric ≈ →
  Asymmetric < → Irreflexive ≈ <
asym⟶irr {< = _<_} resp sym asym {x} {y} x≈y x<y = asym x<y y<x
  where
  y<y : y < y
  y<y = proj₂ resp x≈y x<y
  y<x : y < x
  y<x = proj₁ resp (sym x≈y) y<y

total⟶refl :
  ∀ {a} → {≈ ∼ : Rel a} →
  ∼ Respects₂ ≈ → Symmetric ≈ →
  Total ∼ → ≈ ⇒ ∼
total⟶refl {≈ = ≈} {∼ = ∼} resp sym total = refl
  where
  refl : ≈ ⇒ ∼
  refl {x} {y} x≈y with total x y
  ...              | inj₁ x∼y = x∼y
  ...              | inj₂ y∼x =
    proj₁ resp x≈y (proj₂ resp (sym x≈y) y∼x)

total+dec⟶dec :
  ∀ {a} → {≈ ≤ : Rel a} →
  ≈ ⇒ ≤ → Antisymmetric ≈ ≤ →
  Total ≤ → Decidable ≈ → Decidable ≤
total+dec⟶dec {≈ = ≈} {≤ = ≤} refl antisym total _≟_ = dec
  where
  dec : Decidable ≤
  dec x y with total x y
  ... | inj₁ x≤y = yes x≤y
  ... | inj₂ y≤x with x ≟ y
  ...   | yes  x≈y = yes (refl x≈y)
  ...   | no  ¬x≈y = no (λ x≤y → ¬x≈y (antisym x≤y y≤x))

tri⟶asym :
  ∀ {a} → {≈ < : Rel a} →
  Trichotomous ≈ < → Asymmetric <
tri⟶asym tri {x} {y} x<y x>y with tri x y
... | tri< _   _ x≯y = x≯y x>y
... | tri≈ _   _ x≯y = x≯y x>y
... | tri> x≮y _ _   = x≮y x<y

tri⟶irr :
  ∀ {a} → {≈ < : Rel a} →
  < Respects₂ ≈ → Symmetric ≈ →
  Trichotomous ≈ < → Irreflexive ≈ <
tri⟶irr resp sym tri = asym⟶irr resp sym (tri⟶asym tri)

tri⟶dec≈ :
  ∀ {a} → {≈ < : Rel a} →
  Trichotomous ≈ < → Decidable ≈
tri⟶dec≈ compare x y with compare x y
... | tri< _ x≉y _ = no  x≉y
... | tri≈ _ x≈y _ = yes x≈y
... | tri> _ x≉y _ = no  x≉y

tri⟶dec< :
  ∀ {a} → {≈ < : Rel a} →
  Trichotomous ≈ < → Decidable <
tri⟶dec< compare x y with compare x y
... | tri< x<y _ _ = yes x<y
... | tri≈ x≮y _ _ = no  x≮y
... | tri> x≮y _ _ = no  x≮y

subst⟶cong :
  {≈ : ∀ {a} → Rel a} →
  (∀ {a} → Reflexive {a} ≈) →
  (∀ {a} → Substitutive {a} ≈) →
  Congruential ≈
subst⟶cong {≈ = _≈_} refl subst f {x} x≈y =
  subst (λ y → f x ≈ f y) x≈y refl

cong+trans⟶cong₂ :
  {≈ : ∀ {a} → Rel a} →
  Congruential  ≈ → (∀ {a} → Transitive {a} ≈) →
  Congruential₂ ≈
cong+trans⟶cong₂ cong trans f {x = x} {v = v} x≈y u≈v =
  cong (f x) u≈v ⟨ trans ⟩ cong (flip f v) x≈y

map-NonEmpty : ∀ {I} {P Q : Rel I} →
               P ⇒ Q → NonEmpty P → NonEmpty Q
map-NonEmpty f x = nonEmpty (f (NonEmpty.proof x))


module Function.Inverse where

open import Data.Tuple as Tuple using (_⨯_ ; _,_)
import      Lvl
open import Logic
open import Logic.Propositional
open import Logic.Predicate
open import Functional
open import Function.Equals
open import Function.Equals.Proofs
open import Function.Inverseₗ
open import Function.Inverseᵣ
open import Structure.Setoid
open import Structure.Setoid.Uniqueness
open import Structure.Function
open import Structure.Function.Domain
open import Structure.Function.Domain.Proofs
open import Structure.Operator
open import Structure.Relator.Properties
open import Syntax.Transitivity
open import Type

module _ {ℓ₁ ℓ₂ ℓₑ₁ ℓₑ₂} {A : Type{ℓ₁}} ⦃ eqA : Equiv{ℓₑ₁}(A) ⦄ {B : Type{ℓ₂}} ⦃ eqB : Equiv{ℓₑ₂}(B) ⦄ where
  private variable f : A → B

  -- The inverse function of a bijective function f.
  inv : (f : A → B) → ⦃ inver : Invertible(f) ⦄ → (B → A)
  inv(f) ⦃ inver ⦄ = [∃]-witness inver

  module _ {f : A → B} ⦃ inver : Invertible(f) ⦄ where
    inv-inverse : Inverse(f)(inv f)
    inv-inverse = [∧]-elimᵣ([∃]-proof inver)

    inv-inverseₗ : Inverseₗ(f)(inv f)
    inv-inverseₗ = [∧]-elimₗ inv-inverse

    inv-inverseᵣ : Inverseᵣ(f)(inv f)
    inv-inverseᵣ = [∧]-elimᵣ inv-inverse

    inv-function : Function(inv f)
    inv-function = [∧]-elimₗ([∃]-proof inver)

    inv-surjective : Surjective(inv f)
    inv-surjective = inverse-surjective ⦃ inver = [∧]-elimᵣ([∃]-proof inver) ⦄

    module _ ⦃ func : Function(f) ⦄ where
      inv-injective : Injective(inv f)
      inv-injective = inverse-injective ⦃ inver = [∧]-elimᵣ([∃]-proof inver) ⦄

      inv-bijective : Bijective(inv f)
      inv-bijective = inverse-bijective ⦃ inver = [∧]-elimᵣ([∃]-proof inver) ⦄

{-
  module _ {f : A → B} ⦃ inver : Invertible(f) ⦄ ⦃ inv-func : Function(inv f) ⦄ where
    inv-sides-equality : (invₗ(f) ⊜ invᵣ(f))
    inv-sides-equality =
      invₗ(f)                 🝖[ _⊜_ ]-[]
      invₗ(f) ∘ id            🝖[ _⊜_ ]-[ [⊜][∘]-binaryOperator-raw {f₁ = invₗ(f)} ⦃ func₂ = {!!} ⦄ (reflexivity(_⊜_)) (intro(inverseᵣ(f)(invᵣ f) ⦃ inv-inverseᵣ ⦄)) ]-sym
      invₗ(f) ∘ (f ∘ invᵣ(f)) 🝖[ _⊜_ ]-[]
      (invₗ(f) ∘ f) ∘ invᵣ(f) 🝖[ _⊜_ ]-[ {!!} ]
      id ∘ invᵣ(f)            🝖[ _⊜_ ]-[]
      invᵣ(f)                 🝖-end

-- congruence₂ᵣ(_∘_)(invₗ(f)) ?

    -- x₁ ≡ x₂
    -- inv f(y₁) ≡ inv f(y₂)

    --f(x₁) ≡ f(x₂)
    --invᵣ f(f(x₁)) ≡ invᵣ f(f(x₂))
    --invᵣ f(f(x₁))

-}

{-
    -- inv is a left inverse function to a bijective f.
    inv-inverseₗ : Inverseₗ(f)(inv f)
    inv-inverseₗ = invᵣ-inverseₗ ⦃ inj = {!invertibleₗ-to-injective!} ⦄
    -- [∃!]-existence-eq-any (bijective(f)) (reflexivity(_≡_))

    inv-injective : Injective(inv f)
    inv-injective = {!invᵣ-injective!}-}

{-
    -- inv(f) is surjective when f is bijective.
    inv-surjective : Surjective(inv(f))
    Surjective.proof(inv-surjective) {x} = [∃]-intro(f(x)) ⦃ inv-inverseₗ ⦄

    inv-unique-inverseᵣ : ∀{f⁻¹} → (f ∘ f⁻¹ ⊜ id) → (f⁻¹ ⊜ inv(f))
    inv-unique-inverseᵣ = invᵣ-unique-inverseᵣ ⦃ surj = bijective-to-surjective(f) ⦄ ⦃ inj = bijective-to-injective(f) ⦄

    inv-unique-inverseₗ : ∀{f⁻¹} → ⦃ _ : Function(f⁻¹) ⦄ → (f⁻¹ ∘ f ⊜ id) → (f⁻¹ ⊜ inv(f))
    inv-unique-inverseₗ = invᵣ-unique-inverseₗ ⦃ surj = bijective-to-surjective(f) ⦄

    -- inv(f) is a function when f is a function.
    inv-function : Function(inv(f))
    inv-function = invᵣ-function ⦃ surj = bijective-to-surjective(f) ⦄ ⦃ inj = bijective-to-injective(f) ⦄

    module _ ⦃ func : Function(f) ⦄ where
      -- inv(f) is injective when f is a function and is bijective.
      inv-injective : Injective(inv f)
      inv-injective = invᵣ-injective ⦃ surj = bijective-to-surjective(f) ⦄

      -- inv(f) is bijective when f is a function and is bijective.
      inv-bijective : Bijective(inv(f))
      inv-bijective = injective-surjective-to-bijective(inv(f)) ⦃ inv-injective ⦄ ⦃ inv-surjective ⦄
-}


------------------------------------------------------------------------
-- The Agda standard library
--
-- Equality over lists using propositional equality
------------------------------------------------------------------------

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

open import Relation.Binary

module Data.List.Relation.Binary.Equality.Propositional {a} {A : Set a} where

open import Data.List
import Data.List.Relation.Binary.Equality.Setoid as SetoidEquality
open import Relation.Binary.PropositionalEquality

------------------------------------------------------------------------
-- Publically re-export everything from setoid equality

open SetoidEquality (setoid A) public

------------------------------------------------------------------------
-- ≋ is propositional

≋⇒≡ : _≋_ ⇒ _≡_
≋⇒≡ []             = refl
≋⇒≡ (refl ∷ xs≈ys) = cong (_ ∷_) (≋⇒≡ xs≈ys)

≡⇒≋ : _≡_ ⇒ _≋_
≡⇒≋ refl = ≋-refl


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

open import lib.Basics
open import lib.NType
open import lib.types.Cospan
open import lib.types.Pointed
open import lib.types.Sigma

module lib.types.Pullback where

module _ {i j k} (D : Cospan {i} {j} {k}) where

  open Cospan D

  record Pullback : Type (lmax i (lmax j k)) where
    constructor pullback
    field
      a : A
      b : B
      h : f a == g b

  pullback= : {a a' : A} (p : a == a') {b b' : B} (q : b == b')
    {h : f a == g b} {h' : f a' == g b'} (r : h ∙ ap g q == ap f p ∙ h')
    → pullback a b h == pullback a' b' h'
  pullback= idp idp r =
    ap (pullback _ _) (! (∙-unit-r _) ∙ r)

  pullback-aβ : {a a' : A} (p : a == a') {b b' : B} (q : b == b')
    {h : f a == g b} {h' : f a' == g b'} (r : h ∙ ap g q == ap f p ∙ h')
    → ap Pullback.a (pullback= p q {h = h} {h' = h'} r) == p
  pullback-aβ idp idp r =
    ap Pullback.a (ap (pullback _ _) (! (∙-unit-r _) ∙ r))
      =⟨ ∘-ap Pullback.a (pullback _ _) _ ⟩
    ap (λ _ → _) (! (∙-unit-r _) ∙ r)
      =⟨ ap-cst _ _ ⟩
    idp =∎

  pullback-bβ : {a a' : A} (p : a == a') {b b' : B} (q : b == b')
    {h : f a == g b} {h' : f a' == g b'} (r : h ∙ ap g q == ap f p ∙ h')
    → ap Pullback.b (pullback= p q {h = h} {h' = h'} r) == q
  pullback-bβ idp idp r =
    ap Pullback.b (ap (pullback _ _) (! (∙-unit-r _) ∙ r))
      =⟨ ∘-ap Pullback.b (pullback _ _) _ ⟩
    ap (λ _ → _) (! (∙-unit-r _) ∙ r)
      =⟨ ap-cst _ _ ⟩
    idp =∎

module _ {i j k} (D : ⊙Cospan {i} {j} {k}) where

  ⊙Pullback : Ptd (lmax i (lmax j k))
  ⊙Pullback =
    ⊙[ Pullback (⊙cospan-out D) ,
       pullback (pt X) (pt Y) (snd f ∙ ! (snd g)) ]
    where open ⊙Cospan D

module _ {i j k} (D : Cospan {i} {j} {k}) where
  open Cospan D

  pullback-decomp-equiv : Pullback D ≃ Σ (A × B) (λ {(a , b) → f a == g b})
  pullback-decomp-equiv = equiv
    (λ {(pullback a b h) → ((a , b) , h)})
    (λ {((a , b) , h) → pullback a b h})
    (λ _ → idp)
    (λ _ → idp)

module _ {i j k} (n : ℕ₋₂) {D : Cospan {i} {j} {k}} where
  open Cospan D

  pullback-level : has-level n A → has-level n B → has-level n C
    → has-level n (Pullback D)
  pullback-level pA pB pC =
    equiv-preserves-level ((pullback-decomp-equiv D)⁻¹) $
      Σ-level (×-level pA pB) (λ _ → =-preserves-level pC)


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

open import lib.Basics
open import lib.NType2
open import lib.types.Int
open import lib.types.Group
open import lib.types.List
open import lib.types.Word
open import lib.groups.Homomorphism
open import lib.groups.Isomorphism
open import lib.groups.FreeAbelianGroup
open import lib.groups.GeneratedGroup
open import lib.types.SetQuotient

module lib.groups.Int where

ℤ-group-structure : GroupStructure ℤ
ℤ-group-structure = record
  { ident = 0
  ; inv = ℤ~
  ; comp = _ℤ+_
  ; unit-l = ℤ+-unit-l
  ; assoc = ℤ+-assoc
  ; inv-l = ℤ~-inv-l
  }

ℤ-group : Group₀
ℤ-group = group _ ℤ-group-structure

ℤ-group-is-abelian : is-abelian ℤ-group
ℤ-group-is-abelian = ℤ+-comm

ℤ-abgroup : AbGroup₀
ℤ-abgroup = ℤ-group , ℤ-group-is-abelian

private
  module OneGeneratorFreeAbGroup = FreeAbelianGroup Unit

OneGenFreeAbGroup : AbGroup lzero
OneGenFreeAbGroup = OneGeneratorFreeAbGroup.FreeAbGroup

private
  module OneGenFreeAbGroup = AbGroup OneGenFreeAbGroup

ℤ-iso-FreeAbGroup-Unit : ℤ-group ≃ᴳ OneGenFreeAbGroup.grp
ℤ-iso-FreeAbGroup-Unit = ≃-to-≃ᴳ (equiv to from to-from from-to) to-pres-comp where
  open OneGeneratorFreeAbGroup
  module F = Freeness ℤ-abgroup
  to : Group.El ℤ-group → OneGenFreeAbGroup.El
  to = OneGenFreeAbGroup.exp qw[ inl unit :: nil ]
  from : OneGenFreeAbGroup.El → Group.El ℤ-group
  from = GroupHom.f (F.extend (λ _ → 1))
  abstract
    to-pres-comp = OneGenFreeAbGroup.exp-+ qw[ inl unit :: nil ]

    to-from' : ∀ l → to (Word-extendᴳ ℤ-group (λ _ → 1) l) == qw[ l ]
    to-from' nil = idp
    to-from' (inl unit :: nil) = idp
    to-from' (inl unit :: l@(_ :: _)) =
        OneGenFreeAbGroup.exp-succ qw[ inl unit :: nil ] (Word-extendᴳ ℤ-group (λ _ → 1) l)
      ∙ ap (OneGenFreeAbGroup.comp qw[ inl unit :: nil ]) (to-from' l)
    to-from' (inr unit :: nil) = idp
    to-from' (inr unit :: l@(_ :: _)) =
        OneGenFreeAbGroup.exp-pred qw[ inl unit :: nil ] (Word-extendᴳ ℤ-group (λ _ → 1) l)
      ∙ ap (OneGenFreeAbGroup.comp qw[ inr unit :: nil ]) (to-from' l)

    to-from : ∀ fs → to (from fs) == fs
    to-from = QuotWord-elim to-from' (λ _ → prop-has-all-paths-↓)

    from-to : ∀ z → from (to z) == z
    from-to (pos 0) = idp
    from-to (pos 1) = idp
    from-to (negsucc 0) = idp
    from-to (pos (S (S n))) =
        GroupHom.pres-comp (F.extend (λ _ → 1))
          qw[ inl unit :: nil ] (OneGenFreeAbGroup.exp qw[ inl unit :: nil ] (pos (S n)))
      ∙ ap succ (from-to (pos (S n)))
    from-to (negsucc (S n)) =
        GroupHom.pres-comp (F.extend (λ _ → 1))
          qw[ inr unit :: nil ] (OneGenFreeAbGroup.exp qw[ inl unit :: nil ] (negsucc n))
      ∙ ap pred (from-to (negsucc n))

exp-shom : ∀ {i} {GEl : Type i} (GS : GroupStructure GEl) (g : GEl) → ℤ-group-structure →ᴳˢ GS
exp-shom GS g = group-structure-hom (GroupStructure.exp GS g) (GroupStructure.exp-+ GS g)

exp-hom : ∀ {i} (G : Group i) (g : Group.El G) → ℤ-group →ᴳ G
exp-hom G g = group-hom (Group.exp G g) (Group.exp-+ G g)


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

syntax TLC | Λ

type
  N   : 0-ary
  _↣_ : 2-ary | r30
  𝟙   : 0-ary
  _⊗_ : 2-ary | l40
  𝟘   : 0-ary
  _⊕_ : 2-ary | l30

term
  app   : α ↣ β  α  ->  β | _$_ l20
  lam   : α.β  ->  α ↣ β | ƛ_ r10
  unit  : 𝟙
  pair  : α  β  ->  α ⊗ β | ⟨_,_⟩
  fst   : α ⊗ β  ->  α
  snd   : α ⊗ β  ->  β
  abort : 𝟘  ->  α
  inl   : α  ->  α ⊕ β
  inr   : β  ->  α ⊕ β
  case  : α ⊕ β  α.γ  β.γ  ->  γ
  ze    : N
  su    : N  ->  N
  nrec  : N  α  (α,N).α  ->  α

theory
  (ƛβ) b : α.β  a : α |> app (lam(x.b[x]), a) = b[a]
  (ƛη) f : α ↣ β      |> lam (x. app(f, x))   = f
  (𝟙η) u : 𝟙 |> u = unit
  (fβ) a : α  b : β |> fst (pair(a, b))      = a
  (sβ) a : α  b : β |> snd (pair(a, b))      = b
  (pη) p : α ⊗ β    |> pair (fst(p), snd(p)) = p
  (𝟘η) e : 𝟘  c : α |> abort(e) = c
  (lβ) a : α   f : α.γ  g : β.γ |> case (inl(a), x.f[x], y.g[y])      = f[a]
  (rβ) b : β   f : α.γ  g : β.γ |> case (inr(b), x.f[x], y.g[y])      = g[b]
  (cη) s : α ⊕ β  c : (α ⊕ β).γ |> case (s, x.c[inl(x)], y.c[inr(y)]) = c[s]
  (zeβ) z : α   s : (α,N).α        |> nrec (ze,       z, r m. s[r,m]) = z
  (suβ) z : α   s : (α,N).α  n : N |> nrec (su (n), z, r m. s[r,m]) = s[nrec (n, z, r m. s[r,m]), n]
  (ift) t f : α |> if (true, t, f) = t
  (iff) t f : α |> if (false, t, f) = f
-}

module TLC.Signature where

open import SOAS.Context

-- Type declaration
data ΛT : Set where
  N   : ΛT
  _↣_ : ΛT → ΛT → ΛT
  𝟙   : ΛT
  _⊗_ : ΛT → ΛT → ΛT
  𝟘   : ΛT
  _⊕_ : ΛT → ΛT → ΛT
infixr 30 _↣_
infixl 40 _⊗_
infixl 30 _⊕_

-- Derived types
B : ΛT
B = 𝟙 ⊕ 𝟙

open import SOAS.Syntax.Signature ΛT public
open import SOAS.Syntax.Build ΛT public

-- Operator symbols
data Λₒ : Set where
  appₒ lamₒ pairₒ fstₒ sndₒ inlₒ inrₒ : {α β : ΛT} → Λₒ
  unitₒ zeₒ suₒ : Λₒ
  abortₒ nrecₒ : {α : ΛT} → Λₒ
  caseₒ : {α β γ : ΛT} → Λₒ

-- Term signature
Λ:Sig : Signature Λₒ
Λ:Sig = sig λ
  { (appₒ   {α}{β})    → (⊢₀ α ↣ β) , (⊢₀ α) ⟼₂ β
  ; (lamₒ   {α}{β})    → (α ⊢₁ β) ⟼₁ α ↣ β
  ;  unitₒ             → ⟼₀ 𝟙
  ; (pairₒ  {α}{β})    → (⊢₀ α) , (⊢₀ β) ⟼₂ α ⊗ β
  ; (fstₒ   {α}{β})    → (⊢₀ α ⊗ β) ⟼₁ α
  ; (sndₒ   {α}{β})    → (⊢₀ α ⊗ β) ⟼₁ β
  ; (abortₒ {α})       → (⊢₀ 𝟘) ⟼₁ α
  ; (inlₒ   {α}{β})    → (⊢₀ α) ⟼₁ α ⊕ β
  ; (inrₒ   {α}{β})    → (⊢₀ β) ⟼₁ α ⊕ β
  ; (caseₒ  {α}{β}{γ}) → (⊢₀ α ⊕ β) , (α ⊢₁ γ) , (β ⊢₁ γ) ⟼₃ γ
  ;  zeₒ               → ⟼₀ N
  ;  suₒ               → (⊢₀ N) ⟼₁ N
  ; (nrecₒ  {α})       → (⊢₀ N) , (⊢₀ α) , (α , N ⊢₂ α) ⟼₃ α
  }

open Signature Λ:Sig public


module Lec7 where

open import Lec1Done

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

foldrL : {X T : Set} -> (X -> T -> T) -> T -> List X -> T
foldrL c n [] = n
foldrL c n (x ,- xs) = c x (foldrL c n xs)

data Bwd (X : Set) : Set where
  []   : Bwd X
  _-,_ : Bwd X -> X -> Bwd X
infixl 3 _-,_

data _<=_ {X : Set} : (xz yz : Bwd X) -> Set where
  oz : [] <= []
  os : {xz yz : Bwd X}{y : X} -> xz <= yz -> (xz -, y) <= (yz -, y)
  o' : {xz yz : Bwd X}{y : X} -> xz <= yz ->  xz       <= (yz -, y)

oe : {X : Set}{xz : Bwd X} -> [] <= xz
oe {_} {[]}      = oz
oe {_} {xz -, _} = o' oe

oi : {X : Set}{xz : Bwd X} -> xz <= xz
oi {_} {[]}      = oz
oi {_} {xz -, _} = os oi       -- look here...

_<o<_ : {X : Set}{xz yz zz : Bwd X} -> xz <= yz -> yz <= zz -> xz <= zz
th <o< o' ph = o' (th <o< ph)
oz <o< oz = oz
os th <o< os ph = os (th <o< ph)   -- ...and here
o' th <o< os ph = o' (th <o< ph)

Elem : {X : Set} -> X -> Bwd X -> Set
Elem x yz = ([] -, x) <= yz

data Ty : Set where
  one  : Ty
  list : Ty -> Ty
  _=>_ : Ty -> Ty -> Ty
infixr 4 _=>_

Val : Ty -> Set
Val one      = One
Val (list T) = List (Val T)
Val (S => T) = Val S -> Val T

data Tm (Tz : Bwd Ty) : Ty -> Set where

  var : {T : Ty} -> Elem T Tz -> Tm Tz T

  <> : Tm Tz one

  []   : {T : Ty} -> Tm Tz (list T)
  _,-_ : {T : Ty} -> Tm Tz T -> Tm Tz (list T) -> Tm Tz (list T)
  foldr : {S T : Ty} ->
          Tm Tz (S => T => T) ->
          Tm Tz T ->
          Tm Tz (list S)
          -> Tm Tz T

  lam : {S T : Ty} ->
        Tm (Tz -, S) T
        -> Tm Tz (S => T)
  _$$_ : {S T : Ty} ->
         Tm Tz (S => T) ->
         Tm Tz S
         -> Tm Tz T

infixl 3 _$$_

All : {X : Set} -> (X -> Set) -> Bwd X -> Set
All P []        = One
All P (xz -, x) = All P xz * P x

all : {X : Set}{P Q : X -> Set}(f : (x : X) -> P x -> Q x) -> (xz : Bwd X) -> All P xz -> All Q xz
all f [] <> = <>
all f (xz -, x) (pz , p) = all f xz pz , f x p

Env : Bwd Ty -> Set
Env = All Val

select : {X : Set}{P : X -> Set}{Sz Tz : Bwd X} -> Sz <= Tz -> All P Tz -> All P Sz
select oz     <>       = <>
select (os x) (vz , v) = select x vz , v
select (o' x) (vz , v) = select x vz

eval : {Tz : Bwd Ty}{T : Ty} -> Env Tz -> Tm Tz T -> Val T
eval vz (var x) with select x vz
eval vz (var x) | <> , v = v
eval vz <> = <>
eval vz []               = []
eval vz (t ,- ts)        = eval vz t ,- eval vz ts
eval vz (foldr c n ts)   = foldrL (eval vz c) (eval vz n) (eval vz ts)
eval vz (lam t)          = \ s -> eval (vz , s) t
eval vz (f $$ s)         = eval vz f (eval vz s)

append : {Tz : Bwd Ty}{T : Ty} ->
         Tm Tz (list T => list T => list T)
append = lam (lam (foldr (lam (lam (var (o' (os oe)) ,- var (os oe))))
           (var (os oe)) (var (o' (os oe)))))

test : Val (list one)
test = eval {[]} <> (append $$ (<> ,- []) $$ (<> ,- []))

thin : {Sz Tz : Bwd Ty} -> Sz <= Tz -> {S : Ty} -> Tm Sz S -> Tm Tz S
thin th (var x) = var (x <o< th)
thin th <> = <>
thin th [] = []
thin th (t ,- ts) = thin th t ,- thin th ts
thin th (foldr c n ts) = foldr (thin th c) (thin th n) (thin th ts)
thin th (lam t) = lam (thin (os th) t)
thin th (f $$ s) = thin th f $$ thin th s

Subst : Bwd Ty -> Bwd Ty -> Set
Subst Sz Tz = All (Tm Tz) Sz

subst : {Sz Tz : Bwd Ty} -> Subst Sz Tz -> {S : Ty} -> Tm Sz S -> Tm Tz S
subst tz (var x) with select x tz
subst tz (var x) | <> , t = t
subst tz <> = <>
subst tz [] = []
subst tz (t ,- ts) = subst tz t ,- subst tz ts
subst tz (foldr c n ts) = foldr (subst tz c) (subst tz n) (subst tz ts)
subst tz (lam t) = lam (subst (all (\ T -> thin (o' oi)) _ tz , (var (os oe))) t)
subst tz (f $$ s) = subst tz f $$ subst tz s

record Action (M : Bwd Ty -> Bwd Ty -> Set) : Set where
  field
    varA : forall {S Sz Tz} -> M Sz Tz -> Elem S Sz -> Tm Tz S
    lamA : forall {S Sz Tz} -> M Sz Tz -> M (Sz -, S) (Tz -, S)
  act : {Sz Tz : Bwd Ty} -> M Sz Tz -> {S : Ty} -> Tm Sz S -> Tm Tz S
  act m (var x) = varA m x
  act m <> = <>
  act m [] = []
  act m (t ,- ts) = act m t ,- act m ts
  act m (foldr c n ts) = foldr (act m c) (act m n) (act m ts)
  act m (lam t) = lam (act (lamA m) t)
  act m (f $$ s) = act m f $$ act m s

THIN : Action _<=_
Action.varA THIN th x = var (x <o< th)
Action.lamA THIN = os

SUBST : Action Subst
Action.varA SUBST tz x with select x tz
... | <> , t = t
Action.lamA SUBST tz = all (\ T -> Action.act THIN (o' oi)) _ tz , (var (os oe))

-- substitution
-- thinning
-- abstr-action


module Holes.Util where

open import Holes.Prelude

private
  Rel : ∀ {a} → Set a → ∀ ℓ → Set (a ⊔ lsuc ℓ)
  Rel A ℓ = A → A → Set ℓ

module CongSplit {ℓ x} {X : Set x} (_≈_ : Rel X ℓ) (reflexive : ∀ {x} → x ≈ x) where

  two→one₁ : {_+_ : X → X → X}
            → (∀ {x x′ y y′} → x ≈ x′ → y ≈ y′ → (x + y) ≈ (x′ + y′))
            → (∀ x y {x′} → x ≈ x′ → (x + y) ≈ (x′ + y))
  two→one₁ cong² _ _ eq = cong² eq reflexive

  two→one₂ : {_+_ : X → X → X}
           → (∀ {x x′ y y′} → x ≈ x′ → y ≈ y′ → (x + y) ≈ (x′ + y′))
           → (∀ x y {y′} → y ≈ y′ → (x + y) ≈ (x + y′))
  two→one₂ cong² _ _ eq = cong² reflexive eq


{-# OPTIONS --safe --experimental-lossy-unification #-}
module Cubical.Algebra.Polynomials.Multivariate.EquivCarac.Poly0-A where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.HLevels

open import Cubical.Data.Nat renaming (_+_ to _+n_; _·_ to _·n_)
open import Cubical.Data.Vec

open import Cubical.Algebra.DirectSum.DirectSumHIT.Base
open import Cubical.Algebra.Ring
open import Cubical.Algebra.CommRing

open import Cubical.Algebra.CommRing.Instances.Polynomials.MultivariatePoly

private variable
  ℓ : Level

module Equiv-Poly0-A
  (Acr@(A , Astr) : CommRing ℓ) where

  private
    PA = PolyCommRing Acr 0

  open CommRingStr

-----------------------------------------------------------------------------
-- Equivalence

  Poly0→A : Poly Acr 0 → A
  Poly0→A = DS-Rec-Set.f _ _ _ _ (is-set Astr)
             (0r Astr)
             (λ v a → a)
             (_+_ Astr)
             (+Assoc Astr)
             (+IdR Astr)
             (+Comm Astr)
             (λ _ → refl)
             λ _ a b → refl

  A→Poly0 : A → Poly Acr 0
  A→Poly0 a = base [] a

  e-sect : (a : A) → Poly0→A (A→Poly0 a) ≡ a
  e-sect a = refl

  e-retr : (P : Poly Acr 0) → A→Poly0 (Poly0→A P) ≡ P
  e-retr = DS-Ind-Prop.f _ _ _ _ (λ _ → trunc _ _)
           (base-neutral [])
           (λ { [] a → refl })
           λ {U V} ind-U ind-V → (sym (base-add _ _ _)) ∙ (cong₂ (snd PA ._+_ ) ind-U ind-V)

-----------------------------------------------------------------------------
-- Ring homomorphism

  Poly0→A-pres1 : Poly0→A (snd PA .1r) ≡ 1r Astr
  Poly0→A-pres1 = refl

  Poly0→A-pres+ : (P Q : Poly Acr 0) → Poly0→A (snd PA ._+_ P Q) ≡ Astr ._+_ (Poly0→A P) (Poly0→A Q)
  Poly0→A-pres+ P Q = refl

  Poly0→A-pres· : (P Q : Poly Acr 0) → Poly0→A ( snd PA ._·_ P Q) ≡ Astr ._·_ (Poly0→A P) (Poly0→A Q)
  Poly0→A-pres· = DS-Ind-Prop.f _ _ _ _ (λ _ → isPropΠ λ _ → is-set Astr _ _)
                    (λ Q → sym (RingTheory.0LeftAnnihilates (CommRing→Ring Acr) (Poly0→A Q)))
                    (λ v a → DS-Ind-Prop.f _ _ _ _ (λ _ → is-set Astr _ _)
                              (sym (RingTheory.0RightAnnihilates (CommRing→Ring Acr) (Poly0→A (base v a))))
                              (λ v' a' → refl)
                              λ {U V} ind-U ind-V → (cong₂ (Astr ._+_) ind-U ind-V) ∙ sym (·DistR+ Astr _ _ _))
                    λ {U V} ind-U ind-V Q → (cong₂ (Astr ._+_) (ind-U Q) (ind-V Q)) ∙ sym (·DistL+ Astr _ _ _)

-----------------------------------------------------------------------------
-- Ring Equivalence

module _ (A' : CommRing ℓ) where

  open Equiv-Poly0-A A'

  CRE-Poly0-A : CommRingEquiv (PolyCommRing A' 0) A'
  fst CRE-Poly0-A = isoToEquiv is
    where
    is : Iso (Poly A' 0) (A' .fst)
    Iso.fun is = Poly0→A
    Iso.inv is = A→Poly0
    Iso.rightInv is = e-sect
    Iso.leftInv is = e-retr
  snd CRE-Poly0-A = makeIsRingHom Poly0→A-pres1 Poly0→A-pres+ Poly0→A-pres·


{-# OPTIONS --safe #-}
module Cubical.Homotopy.WedgeConnectivity where

open import Cubical.Foundations.Everything
open import Cubical.Data.Nat
open import Cubical.Data.Sigma
open import Cubical.HITs.Susp
open import Cubical.HITs.Truncation as Trunc
open import Cubical.Homotopy.Connected

module WedgeConnectivity {ℓ ℓ' ℓ''} (n m : ℕ)
  (A : Pointed ℓ) (connA : isConnected (suc n) (typ A))
  (B : Pointed ℓ') (connB : isConnected (suc m) (typ B))
  (P : typ A → typ B → TypeOfHLevel ℓ'' (n + m))
  (f : (a : typ A) → P a (pt B) .fst)
  (g : (b : typ B) → P (pt A) b .fst)
  (p : f (pt A) ≡ g (pt B))
  where

  private
    Q : typ A → TypeOfHLevel _ n
    Q a =
      ( (Σ[ k ∈ ((b : typ B) → P a b .fst) ] k (pt B) ≡ f a)
      , isOfHLevelRetract n
          (λ {(h , q) → h , funExt λ _ → q})
          (λ {(h , q) → h , funExt⁻ q _})
          (λ _ → refl)
          (isOfHLevelPrecomposeConnected n m (P a) (λ _ → pt B)
            (isConnectedPoint m connB (pt B)) (λ _ → f a))
      )

    main : isContr (fiber (λ s _ → s (pt A)) (λ _ → g , p ⁻¹))
    main =
      elim.isEquivPrecompose (λ _ → pt A) n Q
        (isConnectedPoint n connA (pt A))
        .equiv-proof (λ _ → g , p ⁻¹)

  extension : ∀ a b → P a b .fst
  extension a b = main .fst .fst a .fst b

  left : ∀ a → extension a (pt B) ≡ f a
  left a = main .fst .fst a .snd

  right : ∀ b → extension (pt A) b ≡ g b
  right = funExt⁻ (cong fst (funExt⁻ (main .fst .snd) _))

  hom : left (pt A) ⁻¹ ∙ right (pt B) ≡ p
  hom i j = hcomp (λ k → λ { (i = i1) → p j
                           ; (j = i0) → (cong snd (funExt⁻ (main .fst .snd) tt)) i (~ j)
                           ; (j = i1) → right (pt B) (i ∨ k)})
                  (cong snd (funExt⁻ (main .fst .snd) tt) i (~ j))

  hom' : left (pt A) ≡ right (pt B) ∙ sym p
  hom' = (lUnit (left _) ∙ cong (_∙ left (pt A)) (sym (rCancel (right (pt B)))))
       ∙∙ sym (assoc _ _ _)
       ∙∙ cong (right (pt B) ∙_) (sym (symDistr (left (pt A) ⁻¹) (right (pt B))) ∙ (cong sym hom))

  homSquare : PathP (λ i → extension (pt A) (pt B) ≡ p i) (left (pt A)) (right (pt B))
  homSquare i j = hcomp (λ k → λ { (i = i0) → left (pt A) j
                                 ; (i = i1) → compPath-filler (right (pt B)) (sym p) (~ k) j
                                 ; (j = i0) → extension (pt A) (pt B)
                                 ; (j = i1) → p (i ∧ k) })
                        (hom' i j)


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

open import Numbers.ClassicalReals.RealField
open import LogicalFormulae
open import Setoids.Subset
open import Setoids.Setoids
open import Sets.EquivalenceRelations
open import Rings.Orders.Total.Definition
open import Rings.Orders.Partial.Definition
open import Rings.Definition
open import Fields.Fields
open import Groups.Definition
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Numbers.Naturals.Order.Lemmas
open import Setoids.Orders.Partial.Definition
open import Setoids.Orders.Total.Definition

module Numbers.ClassicalReals.Examples (ℝ : RealField) where

open RealField ℝ
open Setoid S
open Equivalence eq
open Ring R
open Field F
open SetoidPartialOrder pOrder
open import Fields.Orders.LeastUpperBounds.Definition pOrder
open import Rings.Orders.Total.Lemmas orderedRing
open import Rings.Orders.Partial.Lemmas pOrderedRing
open Group additiveGroup
open PartiallyOrderedRing pOrderedRing
open SetoidTotalOrder (TotallyOrderedRing.total orderedRing)
open import Rings.InitialRing R
open import Fields.Orders.Lemmas oField
open import Rings.Lemmas R
open import Groups.Lemmas additiveGroup
open import Numbers.Intervals.Definition pOrderedRing
open import Numbers.Intervals.Arithmetic pOrderedRing
open import Fields.Lemmas F

squarePositive : (a : A) → (((a ∼ 0R) → False) && (0R < (a * a))) || (a ∼ 0R)
squarePositive a with totality 0R a
squarePositive a | inl (inl x) = inl ((λ a=0 → irreflexive (<WellDefined reflexive a=0 x)) ,, orderRespectsMultiplication x x)
squarePositive a | inl (inr x) = inl ((λ a=0 → irreflexive (<WellDefined a=0 reflexive x)) ,, <WellDefined reflexive twoNegativesTimes (orderRespectsMultiplication (<WellDefined invIdent reflexive (ringSwapNegatives' x)) (<WellDefined invIdent reflexive (ringSwapNegatives' x))))
squarePositive a | inr 0=a = inr (symmetric 0=a)

fraction<1 : (n m : ℕ) → n <N m → (0<m : fromN m ∼ 0G → False) → ((fromN n) * underlying (allInvertible (fromN m) 0<m)) < 1R
fraction<1 n m n<m 0<m with allInvertible (fromN m) 0<m
... | 1/m , prM = <WellDefined reflexive (transitive *Commutative prM) (ringCanMultiplyByPositive (inversePositiveIsPositive prM (fromNPreservesOrder (0<1 nontrivial) {0} {m} (zeroLeast n<m))) (fromNPreservesOrder (0<1 nontrivial) n<m))

1/2 : A
1/2 = underlying (allInvertible (1R + 1R) (orderedImpliesCharNot2 nontrivial))

pr1/2 : (1/2 * (1R + 1R)) ∼ 1R
pr1/2 with allInvertible (1R + 1R) (orderedImpliesCharNot2 nontrivial)
... | x , pr = pr

pr1/2' : (1/2 + 1/2) ∼ 1R
pr1/2' = transitive (symmetric (transitive *DistributesOver+ (+WellDefined (transitive *Commutative identIsIdent) (transitive *Commutative identIsIdent)))) pr1/2

1/2<1 : 1/2 < 1R
1/2<1 = <WellDefined (transitive (*WellDefined identRight (allInvertibleWellDefined (+WellDefined reflexive identRight))) identIsIdent) reflexive (fraction<1 1 2 (le 0 refl) λ p → charZero 1 (symmetric p))

3/2<2 : (fromN 3 * 1/2) < (1R + 1R)
3/2<2 = <WellDefined (transitive (+WellDefined reflexive (transitive (symmetric pr1/2) (transitive *Commutative (*WellDefined (+WellDefined reflexive (symmetric identRight)) reflexive)))) (symmetric *DistributesOver+')) reflexive (orderRespectsAddition (<WellDefined (symmetric identIsIdent) reflexive 1/2<1) 1R)

2<9/4 : (1R + 1R) < ((fromN 3 * 1/2) * (fromN 3 * 1/2))
2<9/4 = <WellDefined reflexive (symmetric *Associative) (halveInequality _ _ 1/2 pr1/2' (<WellDefined reflexive (transitive (symmetric *Associative) *Commutative) (halveInequality _ _ 1/2 pr1/2' (<WellDefined (transitive (fromNPreserves* 4 2) (transitive (*WellDefined (+WellDefined reflexive (+WellDefined reflexive (+WellDefined reflexive identRight))) (+WellDefined reflexive identRight)) (transitive *DistributesOver+ (+WellDefined (transitive *Commutative (transitive identIsIdent +Associative)) (transitive *Commutative (transitive identIsIdent +Associative)))))) (fromNPreserves* 3 3) (fromNPreservesOrder (0<1 nontrivial) (le {8} 0 refl))))))

0<2 : 0R < (1R + 1R)
0<2 = <WellDefined identLeft reflexive (ringAddInequalities (0<1 nontrivial) (0<1 nontrivial))

0<3/2 : 0R < (fromN 3 * 1/2)
0<3/2 = orderRespectsMultiplication (fromNPreservesOrder (0<1 nontrivial) (le {0} {3} 2 refl)) (inversePositiveIsPositive pr1/2 0<2)

3/2ub : {r : A} → (r * r) < (1R + 1R) → (r < (fromN 3 * 1/2))
3/2ub {r} r^2<2 with totality r (fromN 3 * 1/2)
3/2ub {r} r^2<2 | inl (inl r<3/2) = r<3/2
3/2ub {r} r^2<2 | inl (inr 3/2<r) = exFalso (irreflexive (<Transitive r^2<2 (<Transitive 2<9/4 (ringMultiplyPositives 0<3/2 0<3/2 3/2<r 3/2<r))))
3/2ub {r} r^2<2 | inr r=3/2 = exFalso (irreflexive (<Transitive r^2<2 (<WellDefined reflexive (symmetric (*WellDefined r=3/2 r=3/2)) 2<9/4)))

2/6<1 : ((1R + 1R) * underlying (allInvertible (fromN 6) (charZero' 5))) < 1R
2/6<1 with allInvertible (fromN 6) (charZero' 5)
2/6<1 | 1/6 , pr1/6 = <WellDefined reflexive (transitive *Commutative pr1/6) (ringCanMultiplyByPositive (inversePositiveIsPositive pr1/6 (fromNPreservesOrder (0<1 nontrivial) {0} {6} (le 5 refl))) (<WellDefined (+WellDefined reflexive identRight) reflexive (fromNPreservesOrder (0<1 nontrivial) {2} {6} (le 3 refl))))

2<2*2 : (1R + 1R) < ((1R + 1R) * (1R + 1R))
2<2*2 = (<WellDefined (+WellDefined reflexive identRight) (transitive (fromNPreserves* 2 2) (*WellDefined (+WellDefined reflexive identRight) (+WellDefined reflexive identRight))) (fromNPreservesOrder (0<1 nontrivial) {2} {4} (le 1 refl)))

square<2Means<2 : (u : A) → (u * u) < (1R + 1R) → u < (1R + 1R)
square<2Means<2 u u^2<2 with totality u (1R + 1R)
square<2Means<2 u u^2<2 | inl (inl x) = x
square<2Means<2 u u^2<2 | inl (inr x) = exFalso (irreflexive (<Transitive u^2<2 (<Transitive 2<2*2 (ringMultiplyPositives 0<2 0<2 x x))))
square<2Means<2 u u^2<2 | inr u=2 = exFalso (irreflexive (<Transitive (<WellDefined (*WellDefined u=2 u=2) reflexive u^2<2) 2<2*2))

2=2*2-2 : (fromN 2) ∼ (((1R + 1R) * (1R + 1R)) + inverse (fromN 2))
2=2*2-2 = transitive (+WellDefined reflexive identRight) (transitive (transitive (transitive (transitive (symmetric identRight) (+WellDefined reflexive (symmetric invRight))) +Associative) (+WellDefined (symmetric (+WellDefined (+WellDefined identIsIdent identIsIdent) (+WellDefined identIsIdent identIsIdent))) reflexive)) (+WellDefined (transitive (+WellDefined (symmetric *DistributesOver+') (symmetric *DistributesOver+')) (symmetric *DistributesOver+)) (inverseWellDefined (symmetric (+WellDefined reflexive identRight)))))

sqrtRespectsInequality : {x y : A} → (x * x) < (y * y) → 0R < y → x < y
sqrtRespectsInequality {x} {y} x^2<y^2 _ with totality x y
sqrtRespectsInequality {x} {y} x^2<y^2 _ | inl (inl x<y) = x<y
sqrtRespectsInequality {x} {y} x^2<y^2 0<y | inl (inr y<x) = exFalso (irreflexive (<Transitive x^2<y^2 (ringMultiplyPositives 0<y 0<y y<x y<x)))
sqrtRespectsInequality {x} {y} x^2<y^2 _ | inr x=y = exFalso (irreflexive (<WellDefined (*WellDefined x=y x=y) reflexive x^2<y^2))

sqrt2 : Sg A (λ i → (i * i) ∼ (1R + 1R))
sqrt2 = sqrt2' , sqrt2IsSqrt2
  where
    pred : A → Set c
    pred a = (a * a) < (1R + 1R)
    sub : subset S pred
    sub {y} x=y x^2<2 = <WellDefined (*WellDefined x=y x=y) reflexive x^2<2
    abstract
      2ub : UpperBound sub (1R + 1R)
      2ub y y^2<2 with totality y (1R + 1R)
      2ub y y^2<2 | inl (inl y<2) = inl y<2
      2ub y y^2<2 | inl (inr 2<y) = exFalso (irreflexive (<Transitive y^2<2 (<Transitive s r)))
        where
          r : ((1R + 1R) * (1R + 1R)) < (y * y)
          r = ringMultiplyPositives 0<2 0<2 2<y 2<y
          s : (1R + 1R) < ((1R + 1R) * (1R + 1R))
          s = <WellDefined reflexive (symmetric *DistributesOver+) (<WellDefined reflexive (+WellDefined (transitive (symmetric identIsIdent) *Commutative) (transitive (symmetric identIsIdent) *Commutative)) (<WellDefined identLeft reflexive (orderRespectsAddition 0<2 (1R + 1R))))
      2ub y y^2<2 | inr y=2 = inr y=2
    abstract
      sup : Sg A (LeastUpperBound sub)
      sup = lub sub (0R , <Transitive (<WellDefined (symmetric timesZero) (symmetric identLeft) (0<1 nontrivial)) (orderRespectsAddition (0<1 nontrivial) 1R)) ((1R + 1R) , 2ub)
    sqrt2' : A
    sqrt2' = underlying sup
    sqrt2IsSqrt2 : (sqrt2' * sqrt2') ∼ (1R + 1R)
    sqrt2IsSqrt2 with totality (sqrt2' * sqrt2') (1R + 1R)
    sqrt2IsSqrt2 | inl (inl sup^2<2) with sup
    sqrt2IsSqrt2 | inl (inl sup^2<2) | sqrt2' , record { upperBound = upperBound ; leastUpperBound = leastUpperBound } = exFalso bad
      where
        abstract
          t : A
          t = ((fromN 2) + inverse (sqrt2' * sqrt2')) * (underlying (allInvertible (fromN 6) (charZero' 5)))
          pr' : (underlying (allInvertible (fromN 6) (charZero' 5)) * fromN 6) ∼ 1R
          pr' with allInvertible (fromN 6) (charZero' 5)
          ... | x , p = p
          crudeBound : isInInterval (sqrt2' * sqrt2') record { minBound = 0R ; maxBound = 1R + 1R }
          crudeBound with squarePositive sqrt2'
          crudeBound | inl (_ ,, snd) = snd ,, sup^2<2
          crudeBound | inr sqrt2=0 with upperBound 1R (<WellDefined (transitive identRight (symmetric identIsIdent)) (+WellDefined reflexive identRight) (fromNPreservesOrder (0<1 nontrivial) {1} {2} (le 0 refl)))
          crudeBound | inr sqrt2=0 | inl 1<sqrt2 = exFalso (irreflexive (<Transitive 1<sqrt2 (<WellDefined (symmetric sqrt2=0) reflexive (0<1 nontrivial))))
          crudeBound | inr sqrt2=0 | inr 1=sqrt2 = exFalso (nontrivial (transitive (symmetric sqrt2=0) (symmetric 1=sqrt2)))
          crudeBound' : isInInterval (inverse (sqrt2' * sqrt2')) record { minBound = inverse (1R + 1R) ; maxBound = inverse 0R }
          crudeBound' = intervalInverseContains crudeBound
          numeratorBound : isInInterval (inverse (sqrt2' * sqrt2') + fromN 2) record { minBound = 0R ; maxBound = 1R + 1R }
          numeratorBound = intervalWellDefined (transitive groupIsAbelian (transferToRight'' (transitive +Associative identRight)) ,, transitive (+WellDefined invIdent reflexive) (transitive identLeft (+WellDefined reflexive identRight))) (intervalConstantSumContains (fromN 2) crudeBound')
          numeratorBound' : isInInterval (fromN 2 + inverse (sqrt2' * sqrt2')) record { minBound = 0R ; maxBound = 1R + 1R }
          numeratorBound' = intervalWellDefined' groupIsAbelian numeratorBound
          tBound : isInInterval t record { minBound = 0R ; maxBound = (1R + 1R) * (underlying (allInvertible (fromN 6) (charZero' 5))) }
          tBound = intervalWellDefined (transitive *Commutative timesZero ,, reflexive) (intervalConstantProductContains (inversePositiveIsPositive pr' (fromNPreservesOrder (0<1 nontrivial) {0} {6} (le 5 refl))) numeratorBound')
          u : ((((fromN 5) * ((fromN 2) + inverse (sqrt2' * sqrt2'))) * underlying (allInvertible (fromN 6) (charZero' 5))) + (sqrt2' * sqrt2')) < ((fromN 2 + inverse (sqrt2' * sqrt2')) + (sqrt2' * sqrt2'))
          u = orderRespectsAddition (<WellDefined (transitive (symmetric *Associative) (transitive (*WellDefined reflexive *Commutative) *Associative)) identIsIdent (ringCanMultiplyByPositive {(fromN 5) * underlying (allInvertible (fromN 6) (charZero' 5))} {1R} {fromN 2 + inverse (sqrt2' * sqrt2')} (moveInequality (<WellDefined reflexive (transitive (symmetric identRight) (symmetric +Associative)) sup^2<2)) (fraction<1 5 6 (le zero refl) λ pr → charZero' 5 pr))) (sqrt2' * sqrt2')
          tBound' : (((fromN 5) * t) + (sqrt2' * sqrt2')) < (1R + 1R)
          tBound' = <WellDefined (+WellDefined (symmetric *Associative) reflexive) (transitive (symmetric +Associative) (transitive (+WellDefined reflexive invLeft) (transitive identRight (+WellDefined reflexive identRight)))) u
          sqrt2<2 : sqrt2' < (1R + 1R)
          sqrt2<2 with leastUpperBound (fromN 3 * 1/2) (λ r s → inl (3/2ub s))
          sqrt2<2 | inl x = <Transitive x 3/2<2
          sqrt2<2 | inr x = <WellDefined (symmetric x) reflexive 3/2<2
          2sqrt2<4 : (sqrt2' + sqrt2') < fromN 4
          2sqrt2<4 = <WellDefined (transitive *DistributesOver+ (+WellDefined (transitive *Commutative identIsIdent) (transitive *Commutative identIsIdent))) (transitive (transitive (*WellDefined (symmetric identRight) (symmetric identRight)) (*WellDefined (symmetric +Associative) (symmetric +Associative))) (symmetric (fromNPreserves* 2 2))) (ringCanMultiplyByPositive {sqrt2'} {1R + 1R} {1R + 1R} (<WellDefined identLeft reflexive (ringAddInequalities (0<1 nontrivial) (0<1 nontrivial))) sqrt2<2)
          t<1 : t < 1R
          t<1 = <Transitive (_&&_.snd tBound) 2/6<1
          newElementIsElement : ((sqrt2' + t) * (sqrt2' + t)) < (1R + 1R)
          newElementIsElement = <WellDefined (symmetric *DistributesOver+') reflexive (<WellDefined (+WellDefined (symmetric *DistributesOver+) reflexive) reflexive (<WellDefined (transitive groupIsAbelian +Associative) reflexive (<Transitive (orderRespectsAddition (<WellDefined (+WellDefined *Commutative reflexive) reflexive (<WellDefined (transitive *Commutative *DistributesOver+) reflexive (ringCanMultiplyByPositive (_&&_.fst tBound) (<WellDefined (symmetric +Associative) reflexive (<Transitive (orderRespectsAddition 2sqrt2<4 t) (<WellDefined groupIsAbelian reflexive (<WellDefined reflexive (reflexive {fromN 5}) (orderRespectsAddition t<1 (fromN 4))))))))) (sqrt2' * sqrt2')) tBound')))
        bad : False
        bad with upperBound (sqrt2' + t) newElementIsElement
        bad | inl x = irreflexive (<Transitive x (<WellDefined identLeft groupIsAbelian (orderRespectsAddition (_&&_.fst tBound) sqrt2')))
        bad | inr x = irreflexive (<WellDefined identLeft (transitive groupIsAbelian x) (orderRespectsAddition (_&&_.fst tBound) sqrt2'))
    sqrt2IsSqrt2 | inl (inr 2<sup^2) with sup
    sqrt2IsSqrt2 | inl (inr 2<sup^2) | sqrt2' , record { upperBound = upperBound ; leastUpperBound = leastUpperBound } = exFalso bad
      where
        abstract
          1<sqrt2 : 1R < sqrt2'
          1<sqrt2 with upperBound 1R (<WellDefined (transitive identRight (symmetric identIsIdent)) (+WellDefined reflexive identRight) (fromNPreservesOrder (0<1 nontrivial) {1} {2} (le zero refl)))
          1<sqrt2 | inl x = x
          1<sqrt2 | inr x = exFalso (irreflexive (<Transitive 2<sup^2 (<WellDefined (transitive identRight (transitive (symmetric identIsIdent) (*WellDefined x x))) (+WellDefined reflexive identRight) (fromNPreservesOrder (0<1 nontrivial) {1} {2} (le 0 refl)))))
          0<sqrt2 : 0R < sqrt2'
          0<sqrt2 = <Transitive (0<1 nontrivial) 1<sqrt2
          sqrt2<2 : sqrt2' < (1R + 1R)
          sqrt2<2 with leastUpperBound (fromN 3 * 1/2) (λ r s → inl (3/2ub s))
          sqrt2<2 | inl x = <Transitive x 3/2<2
          sqrt2<2 | inr x = <WellDefined (symmetric x) reflexive 3/2<2
          2sqrt2<4 : (sqrt2' + sqrt2') < fromN 4
          2sqrt2<4 = <WellDefined (transitive *DistributesOver+ (+WellDefined (transitive *Commutative identIsIdent) (transitive *Commutative identIsIdent))) (transitive (transitive (*WellDefined (symmetric identRight) (symmetric identRight)) (*WellDefined (symmetric +Associative) (symmetric +Associative))) (symmetric (fromNPreserves* 2 2))) (ringCanMultiplyByPositive {sqrt2'} {1R + 1R} {1R + 1R} (<WellDefined identLeft reflexive (ringAddInequalities (0<1 nontrivial) (0<1 nontrivial))) sqrt2<2)
          t : A
          t = ((sqrt2' * sqrt2') + inverse (fromN 2)) * underlying (allInvertible (fromN 4) (charZero' 3))
          pr1 : inverse (fromN 4 * t) ∼ (inverse (sqrt2' * sqrt2') + (fromN 2))
          pr1 with allInvertible (fromN 4) (charZero' 3)
          ... | 1/4 , pr1/4 = transitive (transitive (transitive (transitive (symmetric ringMinusExtracts) (transitive (transitive (*WellDefined reflexive (transitive (symmetric ringMinusExtracts') (transitive *Commutative (*WellDefined reflexive (transitive invContravariant (transitive groupIsAbelian (+WellDefined reflexive invInv))))))) *Associative) *Commutative)) (*WellDefined reflexive (transitive *Commutative pr1/4))) *Commutative) identIsIdent
          t<sqrt2 : t < sqrt2'
          t<sqrt2 with allInvertible (fromN 4) (charZero' 3)
          ... | 1/4 , pr4 = <WellDefined reflexive (transitive (symmetric *Associative) (transitive (*WellDefined reflexive (transitive *Commutative pr4)) (transitive *Commutative identIsIdent))) (ringCanMultiplyByPositive (inversePositiveIsPositive pr4 (fromNPreservesOrder (0<1 nontrivial) {0} {4} (le 3 refl))) (<Transitive (orderRespectsAddition (ringMultiplyPositives 0<sqrt2 0<sqrt2 sqrt2<2 sqrt2<2) (inverse (1R + (1R + 0G)))) (<WellDefined {fromN 2} 2=2*2-2 reflexive (<Transitive {fromN 2} {sqrt2' * fromN 2} (<WellDefined identIsIdent reflexive (ringCanMultiplyByPositive (fromNPreservesOrder (0<1 nontrivial) {0} (le 1 refl)) 1<sqrt2)) (<WellDefined *Commutative *Commutative (ringCanMultiplyByPositive 0<sqrt2 (fromNPreservesOrder (0<1 nontrivial) {2} (le 1 refl))))))))
          0<t : 0R < t
          0<t with allInvertible (fromN 4) (charZero' 3)
          ... | 1/4 , pr4 = orderRespectsMultiplication (<WellDefined reflexive (+WellDefined reflexive (inverseWellDefined (+WellDefined reflexive (symmetric identRight)))) (moveInequality 2<sup^2)) (inversePositiveIsPositive pr4 (fromNPreservesOrder (0<1 nontrivial) {0} {4} (le 3 refl)))
        anotherUpperBound : A
        anotherUpperBound = (sqrt2' + inverse t) * (sqrt2' + inverse t)
        abstract
          u : anotherUpperBound ∼ ((sqrt2' * sqrt2') + (inverse ((t * sqrt2') + (t * sqrt2')) + (t * t)))
          u = transitive *DistributesOver+' (transitive (+WellDefined *DistributesOver+ reflexive) (transitive (symmetric +Associative) (+WellDefined reflexive (transitive (+WellDefined ringMinusExtracts *DistributesOver+) (transitive +Associative (+WellDefined (transitive (+WellDefined (inverseWellDefined *Commutative) ringMinusExtracts') (symmetric invContravariant)) twoNegativesTimes))))))
          w : ((sqrt2' * sqrt2') + inverse ((fromN 4) * t)) < anotherUpperBound
          w = <WellDefined reflexive (symmetric u) (<WellDefined groupIsAbelian groupIsAbelian (orderRespectsAddition (<WellDefined (ringMinusExtracts') (+WellDefined (inverseWellDefined (*DistributesOver+)) reflexive) (<WellDefined reflexive (+WellDefined ringMinusExtracts reflexive) (<WellDefined reflexive *DistributesOver+ (<WellDefined reflexive *Commutative (ringCanMultiplyByPositive 0<t (<WellDefined identRight reflexive (ringAddInequalities (ringSwapNegatives' (<WellDefined reflexive (transitive (+WellDefined (+WellDefined reflexive (symmetric identRight)) (+WellDefined reflexive (symmetric identRight))) (symmetric (fromNPreserves+ 2 2))) (ringAddInequalities sqrt2<2 sqrt2<2))) 0<t))))))) (sqrt2' * sqrt2')))
          w' : ((sqrt2' * sqrt2') + inverse ((fromN 4) * t)) ∼ (1R + 1R)
          w' = transitive (+WellDefined reflexive pr1) (transitive +Associative (transitive (+WellDefined invRight reflexive) (transitive identLeft (+WellDefined reflexive identRight))))
          anotherUpperBoundBounds : (1R + 1R) < anotherUpperBound
          anotherUpperBoundBounds = <WellDefined w' reflexive w
        aubIsBound : UpperBound sub (sqrt2' + inverse t)
        aubIsBound y y^2<2 with totality y (sqrt2' + inverse t)
        aubIsBound y y^2<2 | inl (inl x) = inl x
        aubIsBound y y^2<2 | inl (inr x) = exFalso (irreflexive (<Transitive (<Transitive anotherUpperBoundBounds (ringMultiplyPositives (moveInequality t<sqrt2) (moveInequality t<sqrt2) x x)) y^2<2))
        aubIsBound y y^2<2 | inr x = inr x
        bad : False
        bad with leastUpperBound (sqrt2' + inverse t) aubIsBound
        bad | inl x = irreflexive (<Transitive x (<WellDefined groupIsAbelian identLeft (orderRespectsAddition (ringMinusFlipsOrder 0<t) sqrt2')))
        bad | inr x = irreflexive (<WellDefined (symmetric (transitive x groupIsAbelian)) identLeft (orderRespectsAddition (ringMinusFlipsOrder 0<t) sqrt2'))
    sqrt2IsSqrt2 | inr x = x


------------------------------------------------------------------------
-- INCREMENTAL λ-CALCULUS
--
-- Sets of variables
------------------------------------------------------------------------

module Base.Syntax.Vars
     (Type : Set)
  where

-- The notion of sets of variables
--
-- This module is calculus-independent.

open import Base.Syntax.Context Type

open import Relation.Binary.PropositionalEquality
open import Data.Unit
open import Data.Sum
open import Data.Bool

-- Sets of variables

open import Base.Data.DependentList

Free : Type → Set
Free _ = Bool

Vars : Context → Set
Vars = DependentList Free

none : {Γ : Context} → Vars Γ
none = tabulate (λ _ → false)

singleton : ∀ {τ Γ} → Var Γ τ → Vars Γ
singleton {Γ = τ • Γ₀} this = true • none
singleton (that x) = false • singleton x

-- Union of variable sets
infixl 6 _∪_ -- just like _+_
_∪_ : ∀ {Γ} → Vars Γ → Vars Γ → Vars Γ
_∪_ = zipWith _∨_

-- Test if a set of variables is empty
empty? : ∀ {Γ} → (vs : Vars Γ) → (vs ≡ none) ⊎ ⊤
empty? ∅ = inj₁ refl
empty? (true • vs) = inj₂ tt
empty? (false • vs) with empty? vs
... | inj₁ vs=∅ = inj₁ (cong₂ _•_ refl vs=∅)
... | inj₂ _ = inj₂ tt


module Data.Either where

import      Lvl
open import Data.Boolean using (Bool ; 𝑇 ; 𝐹)
open import Functional using (id ; _∘_)
open import Type

infixr 100 _‖_

private variable ℓ ℓ₁ ℓ₂ ℓ₃ ℓ₄ : Lvl.Level
private variable A B C A₁ A₂ B₁ B₂ : Type{ℓ}

data _‖_ (A : Type{ℓ₁}) (B : Type{ℓ₂}) : Type{ℓ₁ Lvl.⊔ ℓ₂} where
  Left  : A → (A ‖ B)
  Right : B → (A ‖ B)
{-# FOREIGN GHC type AgdaEither ℓ₁ ℓ₂ = Either #-}
{-# COMPILE GHC _‖_ = data AgdaEither (Left | Right) #-}

elim : ∀{P : (A ‖ B) → Type{ℓ}} → ((a : A) → P(Left a)) → ((b : B) → P(Right b)) → ((e : (A ‖ B)) → P(e))
elim fa _ (Left  a) = fa(a)
elim _ fb (Right b) = fb(b)

map1 : let _ = A ; _ = B ; _ = C in (A → C) → (B → C) → (A ‖ B) → C
map1 = elim

swap : (A ‖ B) → (B ‖ A)
swap (Left t) = Right t
swap (Right t) = Left t

extract : (A ‖ A) → A
extract = map1 id id

map : (A₁ → A₂) → (B₁ → B₂) → (A₁ ‖ B₁) → (A₂ ‖ B₂)
map fa fb = map1 (Left ∘ fa) (Right ∘ fb)

mapLeft : let _ = A₁ ; _ = A₂ ; _ = B in (A₁ → A₂) → (A₁ ‖ B) → (A₂ ‖ B)
mapLeft f = map f id

mapRight : let _ = A ; _ = B₁ ; _ = B₂ in (B₁ → B₂) → (A ‖ B₁) → (A ‖ B₂)
mapRight f = map id f

isLeft : (A ‖ B) → Bool
isLeft(Left  _) = 𝑇
isLeft(Right _) = 𝐹

isRight : (A ‖ B) → Bool
isRight(Left  _) = 𝐹
isRight(Right _) = 𝑇


{-# OPTIONS -v tc.with.display:30 #-}
-- {-# OPTIONS -v tc.with.strip:30 #-}

open import Common.Product
open import Common.Prelude
open import Common.Equality

postulate
  p : Nat → Nat

-- g : Nat → Nat × Nat
-- g x .proj₁ with p x
-- g x .proj₁ | 0 = 1
-- g x .proj₁ | suc y = 0
-- g x .proj₂ = suc x

-- h : Nat → Nat × Nat
-- h x .proj₁ with p x
-- h x .proj₁ | 0 = 1
-- proj₁ (h x) | suc y = 0
-- h x .proj₂ = suc x

f : Nat → Nat × Nat
f x .proj₁ with p x
... | 0 = 1
... | suc y = 0
f x .proj₂ = suc x

test : f 0 ≡ (0 , 1)
test = refl

-- EXPECTED ERROR:
-- f 0 .proj₁ | p 0 != zero of type Nat
-- when checking that the expression refl has type f 0 ≡ (0 , 1)