-- This module explains how to combine elimination of empty types with pattern
-- match style definitions without running into problems with decidability.

module Introduction.Data.Empty where

-- First we introduce an empty and a singleton type.
data Zero : Set where
data One  : Set where
  one : One

-- There is a special pattern () which matches any element of an (obviously)
-- empty type. If there is a ()-pattern in a left-hand side the right-hand side
-- can be omitted.
elim-Zero : {A : Set} -> Zero -> A
elim-Zero ()

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

-- The algorithm for checking if a type is empty is very naive. In this example
-- you cannot replace pair () _ with () because the type checker cannot see
-- that Zero × B is empty.
elim-EmptyPair : {A B : Set} -> Zero × B -> A
elim-EmptyPair (pair () _)

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

-- For some empty types finite unfolding is not enough.
ConstZero : Nat -> Set
ConstZero  zero   = Zero
ConstZero (suc n) = ConstZero n

-- We can still define the elimination function but we have to do it
-- recursively over the n.
elim-ConstZero : (n : Nat) -> ConstZero n -> {A : Set} -> A
elim-ConstZero  zero   ()
elim-ConstZero (suc n)  x = elim-ConstZero n x


module Lib.Bool where

open import Lib.Logic

data Bool : Set where
  true  : Bool
  false : Bool

{-# BUILTIN BOOL Bool #-}
{-# BUILTIN TRUE true #-}
{-# BUILTIN FALSE false #-}

{-# COMPILED_DATA Bool Bool True False #-}

isTrue : Bool -> Set
isTrue true  = True
isTrue false = False

isFalse : Bool -> Set
isFalse true  = False
isFalse false = True

data Inspect (b : Bool) : Set where
  itsTrue  : .(isTrue b)  -> Inspect b
  itsFalse : .(isFalse b) -> Inspect b

inspect : (b : Bool) -> Inspect b
inspect true  = itsTrue _
inspect false = itsFalse _

infix 5 if_then_else_

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

not : Bool -> Bool
not true  = false
not false = true

infixr 25 _&&_
infixr 22 _||_

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

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


module Human.List where

open import Human.Nat

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

{-# BUILTIN LIST List #-}

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

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

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

-- TODO --
-- filter
-- reduce

-- Receives a function that transforms each element of A, a function A and a new list, B.
map : ∀ {A : Set} {B : Set} → (f : A → B) → List A → List B
map f end      = end
map f (x , xs) = (f x) , (map f xs) -- f transforms element x, return map to do a new transformation

-- Sum all numbers in a list
sum : List Nat → Nat
sum end     = zero
sum (x , l) = x + (sum l)

remove-last : ∀ {A : Set} → List A → List A
remove-last end     = end
remove-last (x , l) = l


{-# OPTIONS --without-K #-}
module AC {a b c} {A : Set a} {B : A → Set b} {C : (x : A) → B x → Set c} where

open import Equivalence
open import FunExt
open import Types

left : Set _
left = (x : A) → Σ (B x) λ y → C x y

right : Set _
right = Σ ((x : A) → B x) λ f → (x : A) → C x (f x)

to : left → right
to f = π₁ ∘ f , π₂ ∘ f

from : right → left
from f x = π₁ f x , π₂ f x

AC∞ : right ≃ left
AC∞
  = from
  , (to , λ _ → refl)
  , (to , λ _ → refl)


module Thesis.SIRelBigStep.OpSem where

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

data Val : Type → Set

import Base.Denotation.Environment
open Base.Denotation.Environment Type Val public
open import Base.Data.DependentList public

data Val where
  closure : ∀ {Γ σ τ} → (t : Term (σ • Γ) τ) → (ρ : ⟦ Γ ⟧Context) → Val (σ ⇒ τ)
  natV : ∀ (n : ℕ) → Val nat
  pairV : ∀ {σ τ} → Val σ → Val τ → Val (pair σ τ)

eval-const : ∀ {τ} → Const τ → Val τ
eval-const (lit n) = natV n

eval : ∀ {Γ τ} (sv : SVal Γ τ) (ρ : ⟦ Γ ⟧Context) → Val τ
eval (var x) ρ = ⟦ x ⟧Var ρ
eval (abs t) ρ = closure t ρ
eval (cons sv1 sv2) ρ = pairV (eval sv1 ρ) (eval sv2 ρ)
eval (const c) ρ = eval-const c

eval-primitive : ∀ {σ τ} → Primitive (σ ⇒ τ) → Val σ → Val τ
eval-primitive succ (natV n) = natV (suc n)
eval-primitive add (pairV (natV n1) (natV n2)) = natV (n1 + n2)

-- Yann's idea.
data HasIdx : Set where
  true : HasIdx
  false : HasIdx
data Idx : HasIdx → Set where
  i' : ℕ → Idx true
  no : Idx false

i : {hasIdx : HasIdx} → ℕ → Idx hasIdx
i {false} j = no
i {true} j = i' j

module _ {hasIdx : HasIdx} where
  data _⊢_↓[_]_ {Γ} (ρ : ⟦ Γ ⟧Context) : ∀ {τ} → Term Γ τ → Idx hasIdx → Val τ → Set where
    val : ∀ {τ} (sv : SVal Γ τ) →
      ρ ⊢ val sv ↓[ i 0 ] eval sv ρ
    primapp : ∀ {σ τ} (p : Primitive (σ ⇒ τ)) (sv : SVal Γ σ) →
      ρ ⊢ primapp p sv ↓[ i 1 ] eval-primitive p (eval sv ρ)
    app : ∀ n {Γ′ σ τ ρ′} vtv {v} {vs : SVal Γ (σ ⇒ τ)} {vt : SVal Γ σ} {t : Term (σ • Γ′) τ} →
      ρ ⊢ val vs ↓[ i 0 ] closure t ρ′ →
      ρ ⊢ val vt ↓[ i 0 ] vtv →
      (vtv • ρ′) ⊢ t ↓[ i n ] v →
      ρ ⊢ app vs vt ↓[ i (suc n) ] v
    lett :
      ∀ n1 n2 {σ τ} vsv {v} (s : Term Γ σ) (t : Term (σ • Γ) τ) →
      ρ ⊢ s ↓[ i n1 ] vsv →
      (vsv • ρ) ⊢ t ↓[ i n2 ] v →
      ρ ⊢ lett s t ↓[ i (suc n1 + n2) ] v


module Haskell.Prim.Functor where

open import Haskell.Prim
open import Haskell.Prim.Either
open import Haskell.Prim.List
open import Haskell.Prim.Maybe
open import Haskell.Prim.Tuple

--------------------------------------------------
-- Functor

record Functor (f : Set → Set) : Set₁ where
  field
    fmap : (a → b) → f a → f b

  infixl 1 _<&>_
  infixl 4 _<$>_ _<$_ _$>_

  _<$>_ : (a → b) → f a → f b
  _<$>_ = fmap

  _<&>_ : f a → (a → b) → f b
  m <&> f = fmap f m

  _<$_ : a → f b → f a
  x <$ m = fmap (const x) m

  _$>_ : f a → b → f b
  m $> x = x <$ m

  void : f a → f (Tuple [])
  void = [] <$_

open Functor ⦃ ... ⦄ public

instance
  iFunctorList : Functor List
  iFunctorList .fmap = map

  iFunctorMaybe : Functor Maybe
  iFunctorMaybe .fmap f Nothing  = Nothing
  iFunctorMaybe .fmap f (Just x) = Just (f x)

  iFunctorEither : Functor (Either a)
  iFunctorEither .fmap f (Left  x) = Left x
  iFunctorEither .fmap f (Right y) = Right (f y)

  iFunctorFun : Functor (λ b → a → b)
  iFunctorFun .fmap = _∘_

  iFunctorTuple₂ : Functor (a ×_)
  iFunctorTuple₂ .fmap f (x , y) = x , f y

  iFunctorTuple₃ : Functor (a × b ×_)
  iFunctorTuple₃ .fmap f (x , y , z) = x , y , f z

  iFunctorTuple₄ : Functor (λ d → Tuple (a ∷ b ∷ c ∷ d ∷ []))
  iFunctorTuple₄ .fmap f (x ∷ y ∷ z ∷ w ∷ []) = x ∷ y ∷ z ∷ f w ∷ []


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

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

module Fields.FieldOfFractions.Ring {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ : A → A → A} {_*_ : A → A → A} {R : Ring S _+_ _*_} (I : IntegralDomain R) where

open import Fields.FieldOfFractions.Setoid I
open import Fields.FieldOfFractions.Addition I
open import Fields.FieldOfFractions.Group I
open import Fields.FieldOfFractions.Multiplication I

fieldOfFractionsRing : Ring fieldOfFractionsSetoid fieldOfFractionsPlus fieldOfFractionsTimes
Ring.additiveGroup fieldOfFractionsRing = fieldOfFractionsGroup
Ring.*WellDefined fieldOfFractionsRing {a} {b} {c} {d} = fieldOfFractionsTimesWellDefined {a} {b} {c} {d}
Ring.1R fieldOfFractionsRing = record { num = Ring.1R R ; denom = Ring.1R R ; denomNonzero = IntegralDomain.nontrivial I }
Ring.groupIsAbelian fieldOfFractionsRing {record { num = a ; denom = b }} {record { num = c ; denom = d }} = Equivalence.transitive (Setoid.eq S) (Ring.*Commutative R) (Ring.*WellDefined R (Ring.*Commutative R) (Equivalence.transitive (Setoid.eq S) (Group.+WellDefined (Ring.additiveGroup R) (Ring.*Commutative R) (Ring.*Commutative R)) (Ring.groupIsAbelian R)))
Ring.*Associative fieldOfFractionsRing {record { num = a ; denom = b }} {record { num = c ; denom = d }} {record { num = e ; denom = f }} = Equivalence.transitive (Setoid.eq S) (Ring.*WellDefined R (Ring.*Associative R) (Ring.*Associative' R)) (Ring.*Commutative R)
Ring.*Commutative fieldOfFractionsRing {record { num = a ; denom = b }} {record { num = c ; denom = d }} = Equivalence.transitive (Setoid.eq S) (Ring.*Commutative R) (Ring.*WellDefined R (Ring.*Commutative R) (Ring.*Commutative R))
Ring.*DistributesOver+ fieldOfFractionsRing {record { num = a ; denom = b }} {record { num = c ; denom = d }} {record { num = e ; denom = f }} = need
  where
    open Setoid S
    open Ring R
    open Equivalence eq
    inter : b * (a * ((c * f) + (d * e))) ∼ (((a * c) * (b * f)) + ((b * d) * (a * e)))
    inter = transitive *Associative (transitive *DistributesOver+ (Group.+WellDefined additiveGroup (transitive *Associative (transitive (*WellDefined (transitive (*WellDefined (*Commutative) reflexive) (transitive (symmetric *Associative) (transitive (*WellDefined reflexive *Commutative) *Associative))) reflexive) (symmetric *Associative))) (transitive *Associative (transitive (*WellDefined (transitive (symmetric *Associative) (transitive (*WellDefined reflexive *Commutative) *Associative)) reflexive) (symmetric *Associative)))))
    need : ((a * ((c * f) + (d * e))) * ((b * d) * (b * f))) ∼ ((b * (d * f)) * (((a * c) * (b * f)) + ((b * d) * (a * e))))
    need = transitive (Ring.*WellDefined R reflexive (Ring.*WellDefined R reflexive (Ring.*Commutative R))) (transitive (Ring.*WellDefined R reflexive (Ring.*Associative R)) (transitive (Ring.*Commutative R) (transitive (Ring.*WellDefined R (Ring.*WellDefined R (symmetric (Ring.*Associative R)) reflexive) reflexive) (transitive (symmetric (Ring.*Associative R)) (Ring.*WellDefined R reflexive inter)))))
Ring.identIsIdent fieldOfFractionsRing {record { num = a ; denom = b }} = need
  where
    open Setoid S
    open Equivalence eq
    need : (((Ring.1R R) * a) * b) ∼ (((Ring.1R R * b)) * a)
    need = transitive (Ring.*WellDefined R (Ring.identIsIdent R) reflexive) (transitive (Ring.*Commutative R) (Ring.*WellDefined R (symmetric (Ring.identIsIdent R)) reflexive))


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

module Cubical.Algebra.Group.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma
open import Cubical.Algebra.Semigroup
open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Group.Base

private
  variable
    ℓ ℓ' ℓ'' : Level

module GroupLemmas (G : Group {ℓ}) where
  open Group G public
  abstract
    simplL : (a : Carrier) {b c : Carrier} → a + b ≡ a + c → b ≡ c
    simplL a {b} {c} p =
      b
        ≡⟨ sym (lid b) ∙ cong (_+ b) (sym (invl a)) ∙ sym (assoc _ _ _) ⟩
      - a + (a + b)
        ≡⟨ cong (- a +_) p ⟩
      - a + (a + c)
        ≡⟨ assoc _ _ _ ∙ cong (_+ c) (invl a) ∙ lid c ⟩
      c ∎

    simplR : {a b : Carrier} (c : Carrier) → a + c ≡ b + c → a ≡ b
    simplR {a} {b} c p =
      a
        ≡⟨ sym (rid a) ∙ cong (a +_) (sym (invr c)) ∙ assoc _ _ _ ⟩
      (a + c) - c
        ≡⟨ cong (_- c) p ⟩
      (b + c) - c
        ≡⟨ sym (assoc _ _ _) ∙ cong (b +_) (invr c) ∙ rid b ⟩
      b ∎

    invInvo : (a : Carrier) → - (- a) ≡ a
    invInvo a = simplL (- a) (invr (- a) ∙ sym (invl a))

    invId : - 0g ≡ 0g
    invId = simplL 0g (invr 0g ∙ sym (lid 0g))

    idUniqueL : {e : Carrier} (x : Carrier) → e + x ≡ x → e ≡ 0g
    idUniqueL {e} x p = simplR x (p ∙ sym (lid _))

    idUniqueR : (x : Carrier) {e : Carrier} → x + e ≡ x → e ≡ 0g
    idUniqueR x {e} p = simplL x (p ∙ sym (rid _))

    invUniqueL : {g h : Carrier} → g + h ≡ 0g → g ≡ - h
    invUniqueL {g} {h} p = simplR h (p ∙ sym (invl h))

    invUniqueR : {g h : Carrier} → g + h ≡ 0g → h ≡ - g
    invUniqueR {g} {h} p = simplL g (p ∙ sym (invr g))

    invDistr : (a b : Carrier) → - (a + b) ≡ - b - a
    invDistr a b = sym (invUniqueR γ) where
      γ : (a + b) + (- b - a) ≡ 0g
      γ = (a + b) + (- b - a)
            ≡⟨ sym (assoc _ _ _) ⟩
          a + b + (- b) + (- a)
            ≡⟨ cong (a +_) (assoc _ _ _ ∙ cong (_+ (- a)) (invr b)) ⟩
          a + (0g - a)
            ≡⟨ cong (a +_) (lid (- a)) ∙ invr a ⟩
          0g ∎

isPropIsGroup : {G : Type ℓ} (0g : G) (_+_ : G → G → G) (-_ : G → G)
             → isProp (IsGroup 0g _+_ -_)
IsGroup.isMonoid (isPropIsGroup 0g _+_ -_ g1 g2 i) = isPropIsMonoid _ _ (IsGroup.isMonoid g1) (IsGroup.isMonoid g2) i
IsGroup.inverse (isPropIsGroup 0g _+_ -_ g1 g2 i) = isPropInv (IsGroup.inverse g1) (IsGroup.inverse g2) i
  where
  isSetG : isSet _
  isSetG = IsSemigroup.is-set (IsMonoid.isSemigroup (IsGroup.isMonoid g1))

  isPropInv : isProp ((x : _) → ((x + (- x)) ≡ 0g) × (((- x) + x) ≡ 0g))
  isPropInv = isPropΠ λ _ → isProp× (isSetG _ _) (isSetG _ _)


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

open import lib.Basics
open import lib.types.Span
open import lib.types.Pushout
open import lib.types.PushoutFlattening
open import lib.types.Unit
open import lib.types.Pointed

-- Cofiber is defined as a particular case of pushout

module lib.types.Cofiber where

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

  cofiber-span : Span
  cofiber-span = span Unit B A (λ _ → tt) f

  Cofiber : Type (lmax i j)
  Cofiber = Pushout cofiber-span

  cfbase' : Cofiber
  cfbase' = left tt

  cfcod' : B → Cofiber
  cfcod' b = right b

  cfglue' : (a : A) → cfbase' == cfcod' (f a)
  cfglue' a = glue a

module _ {i j} {A : Type i} {B : Type j} {f : A → B} where

  cfbase : Cofiber f
  cfbase = cfbase' f

  cfcod : B → Cofiber f
  cfcod = cfcod' f

  cfglue : (a : A) → cfbase == cfcod (f a)
  cfglue = cfglue' f

  module CofiberElim {k} {P : Cofiber f → Type k}
    (b : P cfbase) (c : (y : B) → P (cfcod y))
    (p : (x : A) → b == c (f x) [ P ↓ cfglue x ])
    = PushoutElim (λ _ → b) c p

  open CofiberElim public using () renaming (f to Cofiber-elim)

  module CofiberRec {k} {C : Type k} (b : C) (c : B → C)
    (p : (x : A) → b == c (f x))
    = PushoutRec {d = cofiber-span f} (λ _ → b) c p

  module CofiberRecType {k} (b : Type k) (c : B → Type k)
    (p : (x : A) → b ≃ c (f x))
    = PushoutRecType {d = cofiber-span f} (λ _ → b) c p

module _ {i j} {X : Ptd i} {Y : Ptd j} (F : fst (X ⊙→ Y)) where

  ⊙cof-span : ⊙Span
  ⊙cof-span = ⊙span ⊙Unit Y X ((λ _ → tt) , idp) F

  ⊙Cof : Ptd (lmax i j)
  ⊙Cof = ⊙Pushout ⊙cof-span

  ⊙cfcod' : fst (Y ⊙→ ⊙Cof)
  ⊙cfcod' = cfcod , ap cfcod (! (snd F)) ∙ ! (cfglue (snd X))

  ⊙cfglue' : ⊙cst == ⊙cfcod' ⊙∘ F
  ⊙cfglue' = ⊙λ= cfglue (lemma cfcod (cfglue (snd X)) (snd F))
    where
    lemma : ∀ {i j} {A : Type i} {B : Type j} (f : A → B)
      {x y : A} {z : B} (p : z == f x) (q : x == y)
      → idp == p ∙ ap f q ∙ ap f (! q) ∙ ! p
    lemma f idp idp = idp

module _ {i j} {X : Ptd i} {Y : Ptd j} {F : fst (X ⊙→ Y)} where

  ⊙cfcod : fst (Y ⊙→ ⊙Cof F)
  ⊙cfcod = ⊙cfcod' F

  ⊙cfglue : ⊙cst == ⊙cfcod ⊙∘ F
  ⊙cfglue = ⊙cfglue' F


module Pos where

  import Prelude
  import Equiv
  import Datoid
  import Nat

  open Prelude
  open Equiv
  open Datoid

  abstract

    Pos : Set
    Pos = Nat.Nat

    one : Pos
    one = Nat.zero

    suc : Pos -> Pos
    suc = Nat.suc

    suc' : Nat.Nat -> Pos
    suc' n = n

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

    -- Returns Nothing if input is 1.
    pred : Pos -> Maybe Pos
    pred Nat.zero    = Nothing
    pred (Nat.suc n) = Just n

    toNat : Pos -> Nat.Nat
    toNat = suc

    decidableEquiv : DecidableEquiv Pos
    decidableEquiv = Nat.decidableEquiv

  posDatoid : Datoid
  posDatoid = datoid Pos decidableEquiv

  sucPred : Maybe Pos -> Pos
  sucPred Nothing  = one
  sucPred (Just p) = suc p

  data Pred (p : Pos) (mP : Maybe Pos) : Set where
    ok : datoidRel posDatoid (sucPred mP) p -> Pred p mP

  abstract

    -- Returns Nothing if input is 1.
    predOK : (p : Pos) -> Pred p (pred p)
    predOK Nat.zero    = ok (dRefl posDatoid {one})
    predOK (Nat.suc n) = ok (dRefl posDatoid {n})


------------------------------------------------------------------------------
-- Well-founded relation on lists based on their length
------------------------------------------------------------------------------

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

module FOTC.Data.List.WF-Relation.LT-Length where

open import FOTC.Base
open import FOTC.Data.List
open import FOTC.Data.Nat.Inequalities

------------------------------------------------------------------------------
-- Well-founded relation on lists based on their length.
LTL : D → D → Set
LTL xs ys = length xs < length ys


module bool-thms2 where

open import bool
open import eq
open import product
open import sum

ff-imp : ∀ (b : 𝔹) → (ff imp b) ≡ tt
ff-imp ff = refl
ff-imp tt = refl

imp-tt : ∀ (b : 𝔹) → (b imp tt) ≡ tt
imp-tt ff = refl
imp-tt tt = refl

imp-ff : ∀ (b : 𝔹) → (b imp ff) ≡ ~ b
imp-ff tt = refl
imp-ff ff = refl

tt-imp : ∀ (b : 𝔹) → (tt imp b) ≡ b
tt-imp tt = refl
tt-imp ff = refl

&&-tt : ∀ (b : 𝔹) → b && tt ≡ b
&&-tt tt = refl
&&-tt ff = refl

||-ff : ∀ (b : 𝔹) → b || ff ≡ b
||-ff tt = refl
||-ff ff = refl

&&-contra : ∀ (b : 𝔹) → b && ~ b ≡ ff
&&-contra ff = refl
&&-contra tt = refl

&&-comm : ∀ (b1 b2 : 𝔹) → b1 && b2 ≡ b2 && b1
&&-comm ff ff = refl
&&-comm ff tt = refl
&&-comm tt ff = refl
&&-comm tt tt = refl

||-comm : ∀ (b1 b2 : 𝔹) → b1 || b2 ≡ b2 || b1
||-comm ff ff = refl
||-comm ff tt = refl
||-comm tt ff = refl
||-comm tt tt = refl

&&-assoc : ∀ (b1 b2 b3 : 𝔹) → b1 && (b2 && b3) ≡ (b1 && b2) && b3
&&-assoc ff _ _ = refl
&&-assoc tt _ _ = refl

||-assoc : ∀ (b1 b2 b3 : 𝔹) → b1 || (b2 || b3) ≡ (b1 || b2) || b3
||-assoc tt _ _ = refl
||-assoc ff _ _ = refl

~-over-&& : ∀ (b1 b2 : 𝔹) → ~ ( b1 && b2 ) ≡ (~ b1 || ~ b2)
~-over-&& tt _ = refl
~-over-&& ff _ = refl

~-over-|| : ∀ (b1 b2 : 𝔹) → ~ ( b1 || b2 ) ≡ (~ b1 && ~ b2)
~-over-|| tt _ = refl
~-over-|| ff _ = refl

&&-over-||-l : ∀ (a b c : 𝔹) → a && (b || c) ≡ (a && b) || (a && c)
&&-over-||-l tt _ _ = refl
&&-over-||-l ff _ _ = refl

&&-over-||-r : ∀ (a b c : 𝔹) → (a || b) && c ≡ (a && c) || (b && c)
&&-over-||-r tt tt tt = refl
&&-over-||-r tt tt ff = refl
&&-over-||-r tt ff tt = refl
&&-over-||-r tt ff ff = refl
&&-over-||-r ff tt tt = refl
&&-over-||-r ff tt ff = refl
&&-over-||-r ff ff tt = refl
&&-over-||-r ff ff ff = refl

||-over-&&-l : ∀ (a b c : 𝔹) → a || (b && c) ≡ (a || b) && (a || c)
||-over-&&-l tt _ _ = refl
||-over-&&-l ff _ _ = refl

||-over-&&-r : ∀ (a b c : 𝔹) → (a && b) || c ≡ (a || c) && (b || c)
||-over-&&-r tt _ _ = refl
||-over-&&-r ff _ ff = refl
||-over-&&-r ff tt tt = refl
||-over-&&-r ff ff tt = refl

&&-cong₁ : ∀ {b1 b1' b2 : 𝔹} → b1 ≡ b1' → b1 && b2 ≡ b1' && b2
&&-cong₁ refl = refl

&&-cong₂ : ∀ {b1 b2 b2' : 𝔹} → b2 ≡ b2' → b1 && b2 ≡ b1 && b2'
&&-cong₂ refl = refl

&&-intro : ∀ {b1 b2 : 𝔹} → b1 ≡ tt → b2 ≡ tt → b1 && b2 ≡ tt
&&-intro{tt}{tt} _ _ = refl
&&-intro{tt}{ff} _ ()
&&-intro{ff}{tt} () _
&&-intro{ff}{ff} () _

||-intro1 : ∀ {b1 b2 : 𝔹} → b1 ≡ tt → b1 || b2 ≡ tt
||-intro1 {tt} p = refl
||-intro1 {ff} ()

&&-elim : ∀ {b1 b2 : 𝔹} → b1 && b2 ≡ tt → b1 ≡ tt ∧ b2 ≡ tt
&&-elim{tt}{tt} _ = refl , refl
&&-elim{ff}{_} ()
&&-elim{tt}{ff} ()

&&-elim1 : ∀ {b1 b2 : 𝔹} → b1 && b2 ≡ tt → b1 ≡ tt
&&-elim1 p with &&-elim p
&&-elim1 _ | p , _ = p

&&-elim2 : ∀ {b1 b2 : 𝔹} → b1 && b2 ≡ tt → b2 ≡ tt
&&-elim2{b1} p with &&-elim{b1} p
&&-elim2 _ | _ , p = p

||-elim : ∀ {b1 b2 : 𝔹} → b1 || b2 ≡ tt → b1 ≡ tt ∨ b2 ≡ tt
||-elim {tt} refl = inj₁ refl
||-elim {ff} refl = inj₂ refl

~-cong : ∀ {b b' : 𝔹} → b ≡ b' → ~ b ≡ ~ b'
~-cong refl = refl

ite-cong₁ : ∀{ℓ}{A : Set ℓ} {b b' : 𝔹}(x y : A) → b ≡ b' → (if b then x else y) ≡ (if b' then x else y)
ite-cong₁ x y refl = refl

ite-cong₂ : ∀{ℓ}{A : Set ℓ} (b : 𝔹){x x' : A}(y : A) → x ≡ x' → (if b then x else y) ≡ (if b then x' else y)
ite-cong₂ b y refl = refl

ite-cong₃ : ∀{ℓ}{A : Set ℓ} (b : 𝔹)(x : A){y y' : A} → y ≡ y' → (if b then x else y) ≡ (if b then x else y')
ite-cong₃ b x refl = refl

&&-split : ∀ {b b' : 𝔹} → b || b' ≡ ff → b ≡ ff ⊎ b' ≡ ff
&&-split {tt} ()
&&-split {ff}{tt} ()
&&-split {ff}{ff} p = inj₁ refl

-----------------------------------
-- Theorems about imp
-----------------------------------
imp-same : ∀ (b : 𝔹) → (b imp b) ≡ tt
imp-same ff = refl
imp-same tt = refl

imp-to-|| : ∀ (b1 b2 : 𝔹) → (b1 imp b2) ≡ (~ b1 || b2)
imp-to-|| ff _ = refl
imp-to-|| tt _ = refl

imp-mp : ∀ {b b' : 𝔹} → (b imp b') ≡ tt → b ≡ tt → b' ≡ tt
imp-mp {tt} {tt} p refl = refl
imp-mp {ff} {ff} p q = q
imp-mp {tt} {ff} p q = p
imp-mp {ff} {tt} p q = refl

imp-antisymm : ∀ {b1 b2 : 𝔹} → (b1 imp b2) ≡ tt → (b2 imp b1) ≡ tt → b1 ≡ b2
imp-antisymm{tt}{tt} p q = refl
imp-antisymm{tt}{ff} () q
imp-antisymm{ff}{tt} p ()
imp-antisymm{ff}{ff} p q = refl

-----------------------------------
-- Theorems about xor
-----------------------------------
ff-xor : ∀ (b : 𝔹) → ff xor b ≡ b
ff-xor tt = refl
ff-xor ff = refl

tt-xor : ∀ (b : 𝔹) → tt xor b ≡ ~ b
tt-xor tt = refl
tt-xor ff = refl

~-xor-distrb : ∀ (a b : 𝔹) → ~ (a xor b) ≡ ~ a xor b
~-xor-distrb tt tt = refl
~-xor-distrb tt ff = refl
~-xor-distrb ff tt = refl
~-xor-distrb ff ff = refl

xor-distrib-&& : ∀ (x y : 𝔹) → x xor (y && x) ≡ ~ y && x
xor-distrib-&& tt tt = refl
xor-distrib-&& tt ff = refl
xor-distrib-&& ff tt = refl
xor-distrib-&& ff ff = refl

xor~hop : ∀ (a b : 𝔹) → ~ a xor b ≡ a xor ~ b
xor~hop tt tt = refl
xor~hop tt ff = refl
xor~hop ff tt = refl
xor~hop ff ff = refl

xor-comm : ∀ (b1 b2 : 𝔹) → b1 xor b2 ≡ b2 xor b1
xor-comm tt tt = refl
xor-comm tt ff = refl
xor-comm ff tt = refl
xor-comm ff ff = refl

xor-assoc : (b1 b2 b3 : 𝔹) → b1 xor (b2 xor b3) ≡ (b1 xor b2) xor b3
xor-assoc tt tt tt = refl
xor-assoc tt tt ff = refl
xor-assoc tt ff tt = refl
xor-assoc tt ff ff = refl
xor-assoc ff tt tt = refl
xor-assoc ff tt ff = refl
xor-assoc ff ff tt = refl
xor-assoc ff ff ff = refl

xor-anti-idem : (b : 𝔹) → b xor b ≡ ff
xor-anti-idem tt = refl
xor-anti-idem ff = refl

xor-≡ : {b1 b2 : 𝔹} → b1 xor b2 ≡ ff → b1 ≡ b2
xor-≡ {tt} {tt} p = refl
xor-≡ {tt} {ff} ()
xor-≡ {ff} {tt} ()
xor-≡ {ff} {ff} p = refl

-----------------------------------
-- Theorems about nor, nand
-----------------------------------

nor-not : ∀ (b : 𝔹) → b nor b ≡ ~ b
nor-not tt = refl
nor-not ff = refl

nor-or : ∀ (b1 b2 : 𝔹) → (b1 nor b2) nor (b1 nor b2) ≡ b1 || b2
nor-or tt b2 = refl
nor-or ff tt = refl
nor-or ff ff = refl

nor-and : ∀ (b1 b2 : 𝔹) → (b1 nor b1) nor (b2 nor b2) ≡ b1 && b2
nor-and tt tt = refl
nor-and tt ff = refl
nor-and ff b2 = refl

nor-comm : ∀ (b1 b2 : 𝔹) → b1 nor b2 ≡ b2 nor b1
nor-comm tt tt = refl
nor-comm tt ff = refl
nor-comm ff tt = refl
nor-comm ff ff = refl

nand-comm : ∀ (b1 b2 : 𝔹) → b1 nand b2 ≡ b2 nand b1
nand-comm tt tt = refl
nand-comm tt ff = refl
nand-comm ff tt = refl
nand-comm ff ff = refl


module Sets.IterativeSet.Oper where

import      Lvl
open import Data
open import Data.Boolean
open import Data.Boolean.Stmt
open import Data.Either as Either using (_‖_)
open import Data.Tuple as Tuple using ()
open import Functional
open import Logic
open import Numeral.Natural
open import Relator.Equals using () renaming (_≡_ to Id ; [≡]-intro to intro)
open import Sets.IterativeSet
open import Syntax.Function
open import Type.Dependent

module _ where
  private variable {ℓ ℓ₁ ℓ₂} : Lvl.Level
  open Iset

  -- The empty set, consisting of no elements.
  -- Index is the empty type, which means that there are no objects pointing to elements in the set.
  ∅ : Iset{ℓ}
  ∅ = set{Index = Empty} empty

  -- The singleton set, consisting of one element.
  -- Index is the unit type, which means that there are a single object pointing to a single element in the set.
  singleton : Iset{ℓ} → Iset{ℓ}
  singleton = set{Index = Unit} ∘ const

  -- The pair set, consisting of two elements.
  -- Index is the boolean type, which means that there are two objects pointing to two elements in the set.
  pair : Iset{ℓ} → Iset{ℓ} → Iset{ℓ}
  pair A B = set{Index = Lvl.Up(Bool)} ((if_then B else A) ∘ Lvl.Up.obj)

  -- The union operator.
  -- Index(A ∪ B) is the either type of two indices, which means that both objects from the A and the B index point to elements in the set.
  _∪_ : Iset{ℓ} → Iset{ℓ} → Iset{ℓ}
  A ∪ B = set{Index = Index(A) ‖ Index(B)} (Either.map1 (elem(A)) (elem(B)))

  _,_ : Iset{ℓ} → Iset{ℓ} → Iset{ℓ}
  A , B = pair (singleton A) (pair A B)

  _⨯_ : Iset{ℓ} → Iset{ℓ} → Iset{ℓ}
  A ⨯ B = set{Index = Index(A) Tuple.⨯ Index(B)} \{(ia Tuple., ib) → (elem(A)(ia) , elem(B)(ib))}

  -- The big union operator.
  -- Index(⋃ A) is the dependent sum type of an Index(A) and the index of the element this index points to.
  ⋃ : Iset{ℓ} → Iset{ℓ}
  ⋃ A = set{Index = Σ(Index(A)) (ia ↦ Index(elem(A)(ia)))} (\{(intro ia i) → elem(elem(A)(ia))(i)})

  indexFilter : (A : Iset{ℓ}) → (Index(A) → Stmt{ℓ}) → Iset{ℓ}
  indexFilter A P = set{Index = Σ(Index(A)) P} (elem(A) ∘ Σ.left)

  filter : (A : Iset{ℓ}) → (Iset{ℓ} → Stmt{ℓ}) → Iset{ℓ}
  filter{ℓ} A P = indexFilter A (P ∘ elem(A))

  indexFilterBool : (A : Iset{ℓ}) → (Index(A) → Bool) → Iset{ℓ}
  indexFilterBool A f = indexFilter A (Lvl.Up ∘ IsTrue ∘ f)

  filterBool : (A : Iset{ℓ}) → (Iset{ℓ} → Bool) → Iset{ℓ}
  filterBool A f = indexFilterBool A (f ∘ elem(A))

  mapSet : (Iset{ℓ} → Iset{ℓ}) → (Iset{ℓ} → Iset{ℓ})
  mapSet f(A) = set{Index = Index(A)} (f ∘ elem(A))

  -- The power set operator.
  -- Index(℘(A)) is a function type. An instance of such a function represents a subset, and essentially maps every element in A to a boolean which is interpreted as "in the subset of not".
  -- Note: This only works properly in a classical setting. Trying to use indexFilter instead result in universe level problems.
  ℘ : Iset{ℓ} → Iset{ℓ}
  ℘(A) = set{Index = Index(A) → Bool} (indexFilterBool A)

  -- The set of ordinal numbers of the first order.
  ω : Iset{ℓ}
  ω = set{Index = Lvl.Up ℕ} (N ∘ Lvl.Up.obj) where
    N : ℕ → Iset{ℓ}
    N(𝟎)    = ∅
    N(𝐒(n)) = N(n) ∪ singleton(N(n))


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

open import LogicalFormulae
open import Groups.Lemmas
open import Groups.Definition
open import Setoids.Orders.Partial.Definition
open import Setoids.Orders.Total.Definition
open import Setoids.Setoids
open import Functions.Definition
open import Sets.EquivalenceRelations
open import Rings.Definition
open import Rings.Orders.Total.Definition
open import Rings.Orders.Partial.Definition
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Orders.Total.Definition
open import Rings.IntegralDomains.Definition

module Rings.Orders.Total.AbsoluteValue {n m p : _} {A : Set n} {S : Setoid {n} {m} A} {_+_ : A → A → A} {_*_ : A → A → A} {R : Ring S _+_ _*_} {_<_ : Rel {_} {p} A} {pOrder : SetoidPartialOrder S _<_} {pOrderRing : PartiallyOrderedRing R pOrder} (order : TotallyOrderedRing pOrderRing) where

open Ring R
open Group additiveGroup
open Setoid S
open SetoidPartialOrder pOrder
open TotallyOrderedRing order
open SetoidTotalOrder total
open PartiallyOrderedRing pOrderRing
open import Rings.Lemmas R
open import Rings.Orders.Partial.Lemmas pOrderRing
open import Rings.Orders.Total.Lemmas order

abs : A → A
abs a with totality 0R a
abs a | inl (inl 0<a) = a
abs a | inl (inr a<0) = inverse a
abs a | inr 0=a = a

absWellDefined : (a b : A) → a ∼ b → abs a ∼ abs b
absWellDefined a b a=b with totality 0R a
absWellDefined a b a=b | inl (inl 0<a) with totality 0R b
absWellDefined a b a=b | inl (inl 0<a) | inl (inl 0<b) = a=b
absWellDefined a b a=b | inl (inl 0<a) | inl (inr b<0) = exFalso (irreflexive {0G} (<Transitive 0<a (<WellDefined (Equivalence.symmetric eq a=b) (Equivalence.reflexive eq) b<0)))
absWellDefined a b a=b | inl (inl 0<a) | inr 0=b = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq a=b (Equivalence.symmetric eq 0=b)) 0<a))
absWellDefined a b a=b | inl (inr a<0) with totality 0R b
absWellDefined a b a=b | inl (inr a<0) | inl (inl 0<b) = exFalso (irreflexive {0G} (<Transitive 0<b (<WellDefined a=b (Equivalence.reflexive eq) a<0)))
absWellDefined a b a=b | inl (inr a<0) | inl (inr b<0) = inverseWellDefined additiveGroup a=b
absWellDefined a b a=b | inl (inr a<0) | inr 0=b = exFalso (irreflexive {0G} (<WellDefined (Equivalence.transitive eq a=b (Equivalence.symmetric eq 0=b)) (Equivalence.reflexive eq) a<0))
absWellDefined a b a=b | inr 0=a with totality 0R b
absWellDefined a b a=b | inr 0=a | inl (inl 0<b) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq (Equivalence.transitive eq 0=a a=b)) 0<b))
absWellDefined a b a=b | inr 0=a | inl (inr b<0) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.symmetric eq (Equivalence.transitive eq 0=a a=b)) (Equivalence.reflexive eq) b<0))
absWellDefined a b a=b | inr 0=a | inr 0=b = a=b

triangleInequality : (a b : A) → ((abs (a + b)) < ((abs a) + (abs b))) || (abs (a + b) ∼ (abs a) + (abs b))
triangleInequality a b with totality 0R (a + b)
triangleInequality a b | inl (inl 0<a+b) with totality 0R a
triangleInequality a b | inl (inl 0<a+b) | inl (inl 0<a) with totality 0R b
triangleInequality a b | inl (inl 0<a+b) | inl (inl 0<a) | inl (inl 0<b) = inr (Equivalence.reflexive eq)
triangleInequality a b | inl (inl 0<a+b) | inl (inl 0<a) | inl (inr b<0) = inl (<WellDefined groupIsAbelian groupIsAbelian (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder b<0 (lemm2 b b<0)) a))
triangleInequality a b | inl (inl 0<a+b) | inl (inl 0<a) | inr 0=b = inr (Equivalence.reflexive eq)
triangleInequality a b | inl (inl 0<a+b) | inl (inr a<0) with totality 0R b
triangleInequality a b | inl (inl 0<a+b) | inl (inr a<0) | inl (inl 0<b) = inl (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder a<0 (lemm2 a a<0)) b)
triangleInequality a b | inl (inl 0<a+b) | inl (inr a<0) | inl (inr b<0) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder 0<a+b (<WellDefined (Equivalence.reflexive eq) identLeft (ringAddInequalities a<0 b<0))))
triangleInequality a b | inl (inl 0<a+b) | inl (inr a<0) | inr 0=b = inl (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder a<0 (lemm2 a a<0)) b)
triangleInequality a b | inl (inl 0<a+b) | inr 0=a with totality 0R b
triangleInequality a b | inl (inl 0<a+b) | inr 0=a | inl (inl 0<b) = inr (Equivalence.reflexive eq)
triangleInequality a b | inl (inl 0<a+b) | inr 0=a | inl (inr b<0) = inl (<WellDefined groupIsAbelian groupIsAbelian (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder b<0 (lemm2 b b<0)) a))
triangleInequality a b | inl (inl 0<a+b) | inr 0=a | inr 0=b = inr (Equivalence.reflexive eq)
triangleInequality a b | inl (inr a+b<0) with totality 0G a
triangleInequality a b | inl (inr a+b<0) | inl (inl 0<a) with totality 0G b
triangleInequality a b | inl (inr a+b<0) | inl (inl 0<a) | inl (inl 0<b) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder (<WellDefined identLeft (Equivalence.reflexive eq) (ringAddInequalities 0<a 0<b)) a+b<0))
triangleInequality a b | inl (inr a+b<0) | inl (inl 0<a) | inl (inr b<0) = inl (<WellDefined (Equivalence.transitive eq (Equivalence.symmetric eq (invContravariant additiveGroup)) (inverseWellDefined additiveGroup groupIsAbelian)) (Equivalence.reflexive eq) (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder (lemm2' _ 0<a) 0<a) (inverse b)))
triangleInequality a b | inl (inr a+b<0) | inl (inl 0<a) | inr 0=b = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder 0<a (<WellDefined (Equivalence.transitive eq (+WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) identRight) (Equivalence.reflexive eq) a+b<0)))
triangleInequality a b | inl (inr a+b<0) | inl (inr a<0) with totality 0G b
triangleInequality a b | inl (inr a+b<0) | inl (inr a<0) | inl (inl 0<b) = inl (<WellDefined (Equivalence.symmetric eq (invContravariant additiveGroup)) groupIsAbelian (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder (lemm2' _ 0<b) 0<b) (inverse a)))
triangleInequality a b | inl (inr a+b<0) | inl (inr a<0) | inl (inr b<0) = inr (Equivalence.transitive eq (invContravariant additiveGroup) groupIsAbelian)
triangleInequality a b | inl (inr a+b<0) | inl (inr a<0) | inr 0=b = inr (Equivalence.transitive eq (invContravariant additiveGroup) (Equivalence.transitive eq (Equivalence.transitive eq (Equivalence.transitive eq (+WellDefined (Equivalence.transitive eq (inverseWellDefined additiveGroup (Equivalence.symmetric eq 0=b)) (invIdent additiveGroup)) (Equivalence.reflexive eq)) identLeft) (Equivalence.symmetric eq identRight)) (+WellDefined (Equivalence.reflexive eq) 0=b)))
triangleInequality a b | inl (inr a+b<0) | inr 0=a with totality 0G b
triangleInequality a b | inl (inr a+b<0) | inr 0=a | inl (inl 0<b) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder 0<b (<WellDefined (Equivalence.transitive eq (+WellDefined (Equivalence.symmetric eq 0=a) (Equivalence.reflexive eq)) identLeft) (Equivalence.reflexive eq) a+b<0)))
triangleInequality a b | inl (inr a+b<0) | inr 0=a | inl (inr b<0) = inr (Equivalence.transitive eq (invContravariant additiveGroup) (Equivalence.transitive eq groupIsAbelian (+WellDefined (Equivalence.transitive eq (Equivalence.transitive eq (Equivalence.symmetric eq (inverseWellDefined additiveGroup 0=a)) (invIdent additiveGroup)) 0=a) (Equivalence.reflexive eq))))
triangleInequality a b | inl (inr a+b<0) | inr 0=a | inr 0=b = exFalso (irreflexive {0G} (<WellDefined (Equivalence.transitive eq (+WellDefined (Equivalence.symmetric eq 0=a) (Equivalence.symmetric eq 0=b)) identLeft) (Equivalence.reflexive eq) a+b<0))
triangleInequality a b | inr 0=a+b with totality 0G a
triangleInequality a b | inr 0=a+b | inl (inl 0<a) with totality 0G b
triangleInequality a b | inr 0=a+b | inl (inl 0<a) | inl (inl 0<b) = exFalso (irreflexive {0G} (<WellDefined identLeft (Equivalence.symmetric eq 0=a+b) (ringAddInequalities 0<a 0<b)))
triangleInequality a b | inr 0=a+b | inl (inl 0<a) | inl (inr b<0) = inl (<WellDefined groupIsAbelian groupIsAbelian (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder b<0 (lemm2 _ b<0)) a))
triangleInequality a b | inr 0=a+b | inl (inl 0<a) | inr 0=b = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq (lemm3 _ _ (Equivalence.transitive eq 0=a+b groupIsAbelian) 0=b)) 0<a))
triangleInequality a b | inr 0=a+b | inl (inr a<0) with totality 0G b
triangleInequality a b | inr 0=a+b | inl (inr a<0) | inl (inl 0<b) = inl (orderRespectsAddition (SetoidPartialOrder.<Transitive pOrder a<0 (lemm2 _ a<0)) b)
triangleInequality a b | inr 0=a+b | inl (inr a<0) | inl (inr b<0) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.symmetric eq 0=a+b) identLeft (ringAddInequalities a<0 b<0)))
triangleInequality a b | inr 0=a+b | inl (inr a<0) | inr 0=b = exFalso (irreflexive {0G} (<WellDefined (Equivalence.symmetric eq (lemm3 _ _ (Equivalence.transitive eq 0=a+b groupIsAbelian) 0=b)) (Equivalence.reflexive eq) a<0))
triangleInequality a b | inr 0=a+b | inr 0=a with totality 0G b
triangleInequality a b | inr 0=a+b | inr 0=a | inl (inl 0<b) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq (lemm3 a b 0=a+b 0=a)) 0<b))
triangleInequality a b | inr 0=a+b | inr 0=a | inl (inr b<0) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.symmetric eq (lemm3 a b 0=a+b 0=a)) (Equivalence.reflexive eq) b<0))
triangleInequality a b | inr 0=a+b | inr 0=a | inr 0=b = inr (Equivalence.reflexive eq)

absZero : abs (Ring.0R R) ≡ Ring.0R R
absZero with totality (Ring.0R R) (Ring.0R R)
absZero | inl (inl x) = exFalso (irreflexive x)
absZero | inl (inr x) = exFalso (irreflexive x)
absZero | inr x = refl

absNegation : (a : A) → (abs a) ∼ (abs (inverse a))
absNegation a with totality 0R a
absNegation a | inl (inl 0<a) with totality 0G (inverse a)
absNegation a | inl (inl 0<a) | inl (inl 0<-a) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder 0<-a (lemm2' a 0<a)))
absNegation a | inl (inl 0<a) | inl (inr -a<0) = Equivalence.symmetric eq (invTwice additiveGroup a)
absNegation a | inl (inl 0<a) | inr 0=-a = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (Equivalence.transitive eq (Equivalence.symmetric eq (invTwice additiveGroup a)) (inverseWellDefined additiveGroup (Equivalence.symmetric eq 0=-a))) (invIdent additiveGroup)) 0<a))
absNegation a | inl (inr a<0) with totality 0G (inverse a)
absNegation a | inl (inr a<0) | inl (inl 0<-a) = Equivalence.reflexive eq
absNegation a | inl (inr a<0) | inl (inr -a<0) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder (<WellDefined (Equivalence.reflexive eq) (invTwice additiveGroup a) (lemm2 (inverse a) -a<0)) a<0))
absNegation a | inl (inr a<0) | inr 0=-a = exFalso (irreflexive {0G} (<WellDefined (Equivalence.transitive eq (Equivalence.symmetric eq (Equivalence.transitive eq (inverseWellDefined additiveGroup 0=-a) (invTwice additiveGroup a))) (invIdent additiveGroup)) (Equivalence.reflexive eq) a<0))
absNegation a | inr 0=a with totality 0G (inverse a)
absNegation a | inr 0=a | inl (inl 0<-a) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (inverseWellDefined additiveGroup (Equivalence.symmetric eq 0=a)) (invIdent additiveGroup)) 0<-a))
absNegation a | inr 0=a | inl (inr -a<0) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.transitive eq (inverseWellDefined additiveGroup (Equivalence.symmetric eq 0=a)) (invIdent additiveGroup)) (Equivalence.reflexive eq) -a<0))
absNegation a | inr 0=a | inr 0=-a = Equivalence.transitive eq (Equivalence.symmetric eq 0=a) 0=-a

absRespectsTimes : (a b : A) → abs (a * b) ∼ (abs a) * (abs b)
absRespectsTimes a b with totality 0R a
absRespectsTimes a b | inl (inl 0<a) with totality 0R b
absRespectsTimes a b | inl (inl 0<a) | inl (inl 0<b) with totality 0R (a * b)
absRespectsTimes a b | inl (inl 0<a) | inl (inl 0<b) | inl (inl 0<ab) = Equivalence.reflexive eq
absRespectsTimes a b | inl (inl 0<a) | inl (inl 0<b) | inl (inr ab<0) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder (orderRespectsMultiplication 0<a 0<b) ab<0))
absRespectsTimes a b | inl (inl 0<a) | inl (inl 0<b) | inr 0=ab = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=ab) (orderRespectsMultiplication 0<a 0<b)))
absRespectsTimes a b | inl (inl 0<a) | inl (inr b<0) with totality 0R (a * b)
absRespectsTimes a b | inl (inl 0<a) | inl (inr b<0) | inl (inl 0<ab) with <WellDefined (Equivalence.reflexive eq) ringMinusExtracts (orderRespectsMultiplication 0<a (lemm2 b b<0))
... | bl = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder 0<ab (<WellDefined (invTwice additiveGroup _) (Equivalence.reflexive eq) (lemm2' _ bl))))
absRespectsTimes a b | inl (inl 0<a) | inl (inr b<0) | inl (inr ab<0) = Equivalence.symmetric eq ringMinusExtracts
absRespectsTimes a b | inl (inl 0<a) | inl (inr b<0) | inr 0=ab = exFalso (irreflexive {0G} (<WellDefined (Equivalence.symmetric eq 0=ab) (Equivalence.reflexive eq) (posTimesNeg a b 0<a b<0)))
absRespectsTimes a b | inl (inl 0<a) | inr 0=b with totality 0R (a * b)
absRespectsTimes a b | inl (inl 0<a) | inr 0=b | inl (inl 0<ab) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) (timesZero {a})) 0<ab))
absRespectsTimes a b | inl (inl 0<a) | inr 0=b | inl (inr ab<0) = exFalso ((irreflexive {0G} (<WellDefined (Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) (timesZero {a})) (Equivalence.reflexive eq) ab<0)))
absRespectsTimes a b | inl (inl 0<a) | inr 0=b | inr 0=ab = Equivalence.reflexive eq
absRespectsTimes a b | inl (inr a<0) with totality 0R b
absRespectsTimes a b | inl (inr a<0) | inl (inl 0<b) with totality 0R (a * b)
absRespectsTimes a b | inl (inr a<0) | inl (inl 0<b) | inl (inl 0<ab) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder 0<ab (<WellDefined *Commutative (Equivalence.reflexive eq) (posTimesNeg b a 0<b a<0))))
absRespectsTimes a b | inl (inr a<0) | inl (inl 0<b) | inl (inr ab<0) = Equivalence.symmetric eq ringMinusExtracts'
absRespectsTimes a b | inl (inr a<0) | inl (inl 0<b) | inr 0=ab = exFalso (irreflexive {0G} (<WellDefined (Equivalence.symmetric eq (Equivalence.transitive eq 0=ab *Commutative)) (Equivalence.reflexive eq) (posTimesNeg b a 0<b a<0)))
absRespectsTimes a b | inl (inr a<0) | inl (inr b<0) with totality 0R (a * b)
absRespectsTimes a b | inl (inr a<0) | inl (inr b<0) | inl (inl 0<ab) = Equivalence.symmetric eq twoNegativesTimes
absRespectsTimes a b | inl (inr a<0) | inl (inr b<0) | inl (inr ab<0) = exFalso (irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder (negTimesPos a b a<0 b<0) ab<0))
absRespectsTimes a b | inl (inr a<0) | inl (inr b<0) | inr 0=ab = exFalso (exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=ab) (negTimesPos a b a<0 b<0))))
absRespectsTimes a b | inl (inr a<0) | inr 0=b with totality 0R (a * b)
absRespectsTimes a b | inl (inr a<0) | inr 0=b | inl (inl 0<ab) = exFalso (irreflexive {0R} (<WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) (timesZero {a})) 0<ab))
absRespectsTimes a b | inl (inr a<0) | inr 0=b | inl (inr ab<0) = exFalso (irreflexive {0R} (<WellDefined (Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) timesZero) (Equivalence.reflexive eq) ab<0))
absRespectsTimes a b | inl (inr a<0) | inr 0=b | inr 0=ab = Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) (Equivalence.transitive eq (Equivalence.transitive eq timesZero (Equivalence.symmetric eq timesZero)) (*WellDefined (Equivalence.reflexive eq) 0=b))
absRespectsTimes a b | inr 0=a with totality 0R b
absRespectsTimes a b | inr 0=a | inl (inl 0<b) with totality 0R (a * b)
absRespectsTimes a b | inr 0=a | inl (inl 0<b) | inl (inl 0<ab) = Equivalence.reflexive eq
absRespectsTimes a b | inr 0=a | inl (inl 0<b) | inl (inr ab<0) = Equivalence.transitive eq (Equivalence.transitive eq (Equivalence.transitive eq (inverseWellDefined additiveGroup (Equivalence.transitive eq (*WellDefined (Equivalence.symmetric eq 0=a) (Equivalence.reflexive eq)) (Equivalence.transitive eq *Commutative timesZero))) (invIdent additiveGroup)) (Equivalence.transitive eq (Equivalence.symmetric eq timesZero) *Commutative)) (*WellDefined 0=a (Equivalence.reflexive eq))
absRespectsTimes a b | inr 0=a | inl (inl 0<b) | inr 0=ab = Equivalence.reflexive eq
absRespectsTimes a b | inr 0=a | inl (inr b<0) with totality 0R (a * b)
absRespectsTimes a b | inr 0=a | inl (inr b<0) | inl (inl 0<ab) = Equivalence.transitive eq (Equivalence.transitive eq (*WellDefined (Equivalence.symmetric eq 0=a) (Equivalence.reflexive eq)) *Commutative) (Equivalence.transitive eq timesZero (Equivalence.transitive eq (Equivalence.symmetric eq (Equivalence.transitive eq *Commutative timesZero)) (*WellDefined 0=a (Equivalence.reflexive eq))))
absRespectsTimes a b | inr 0=a | inl (inr b<0) | inl (inr ab<0) = Equivalence.symmetric eq ringMinusExtracts
absRespectsTimes a b | inr 0=a | inl (inr b<0) | inr 0=ab = Equivalence.transitive eq (Equivalence.transitive eq (*WellDefined (Equivalence.symmetric eq 0=a) (Equivalence.reflexive eq)) *Commutative) (Equivalence.transitive eq timesZero (Equivalence.transitive eq (Equivalence.symmetric eq (Equivalence.transitive eq *Commutative timesZero)) (*WellDefined 0=a (Equivalence.reflexive eq))))
absRespectsTimes a b | inr 0=a | inr 0=b with totality 0R (a * b)
absRespectsTimes a b | inr 0=a | inr 0=b | inl (inl 0<ab) = exFalso (irreflexive {0R} (<WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) timesZero) 0<ab))
absRespectsTimes a b | inr 0=a | inr 0=b | inl (inr ab<0) = exFalso (irreflexive {0R} (<WellDefined (Equivalence.transitive eq (*WellDefined (Equivalence.reflexive eq) (Equivalence.symmetric eq 0=b)) timesZero) (Equivalence.reflexive eq) ab<0))
absRespectsTimes a b | inr 0=a | inr 0=b | inr 0=ab = Equivalence.reflexive eq

absNonnegative : {a : A} → (abs a < 0R) → False
absNonnegative {a} pr with totality 0R a
absNonnegative {a} pr | inl (inl x) = irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder x pr)
absNonnegative {a} pr | inl (inr x) = irreflexive {0G} (SetoidPartialOrder.<Transitive pOrder (<WellDefined (Equivalence.reflexive eq) (invTwice additiveGroup a) (lemm2 (inverse a) pr)) x)
absNonnegative {a} pr | inr x = irreflexive {0G} (<WellDefined (Equivalence.symmetric eq x) (Equivalence.reflexive eq) pr)

absZeroImpliesZero : {a : A} → abs a ∼ 0R → a ∼ 0R
absZeroImpliesZero {a} a=0 with totality 0R a
absZeroImpliesZero {a} a=0 | inl (inl 0<a) = exFalso (irreflexive {0G} (<WellDefined (Equivalence.reflexive eq) a=0 0<a))
absZeroImpliesZero {a} a=0 | inl (inr a<0) = Equivalence.symmetric eq (lemm3 (inverse a) a (Equivalence.symmetric eq invLeft) (Equivalence.symmetric eq a=0))
absZeroImpliesZero {a} a=0 | inr 0=a = a=0

addingAbsCannotShrink : {a b : A} → 0G < b → 0G < ((abs a) + b)
addingAbsCannotShrink {a} {b} 0<b with totality 0G a
addingAbsCannotShrink {a} {b} 0<b | inl (inl x) = <WellDefined identLeft (Equivalence.reflexive eq) (ringAddInequalities x 0<b)
addingAbsCannotShrink {a} {b} 0<b | inl (inr x) = <WellDefined identLeft (Equivalence.reflexive eq) (ringAddInequalities (lemm2 a x) 0<b)
addingAbsCannotShrink {a} {b} 0<b | inr x = <WellDefined (Equivalence.reflexive eq) (Equivalence.transitive eq (Equivalence.symmetric eq identLeft) (+WellDefined x (Equivalence.reflexive eq))) 0<b

greaterZeroImpliesEqualAbs : {a : A} → 0R < a → a ∼ abs a
greaterZeroImpliesEqualAbs {a} 0<a with totality 0R a
... | inl (inl _) = Equivalence.reflexive eq
... | inl (inr a<0) = exFalso (irreflexive (SetoidPartialOrder.<Transitive pOrder a<0 0<a))
... | inr 0=a = exFalso (irreflexive (<WellDefined 0=a (Equivalence.reflexive eq) 0<a))

lessZeroImpliesEqualNegAbs : {a : A} → a < 0R → abs a ∼ inverse a
lessZeroImpliesEqualNegAbs {a} a<0 with totality 0R a
... | inl (inr _) = Equivalence.reflexive eq
... | inl (inl 0<a) = exFalso (irreflexive (SetoidPartialOrder.<Transitive pOrder a<0 0<a))
... | inr 0=a = exFalso (irreflexive (<WellDefined (Equivalence.reflexive eq) 0=a a<0))

absZeroIsZero : abs 0R ∼ 0R
absZeroIsZero with totality 0R 0R
... | inl (inl bad) = exFalso (irreflexive bad)
... | inl (inr bad) = exFalso (irreflexive bad)
... | inr _ = Equivalence.reflexive eq

greaterThanAbsImpliesGreaterThan0 : {a b : A} → (abs a) < b → 0R < b
greaterThanAbsImpliesGreaterThan0 {a} {b} a<b with totality 0R a
greaterThanAbsImpliesGreaterThan0 {a} {b} a<b | inl (inl 0<a) = SetoidPartialOrder.<Transitive pOrder 0<a a<b
greaterThanAbsImpliesGreaterThan0 {a} {b} a<b | inl (inr a<0) = SetoidPartialOrder.<Transitive pOrder (lemm2 _ a<0) a<b
greaterThanAbsImpliesGreaterThan0 {a} {b} a<b | inr 0=a = <WellDefined (Equivalence.symmetric eq 0=a) (Equivalence.reflexive eq) a<b

abs1Is1 : abs 1R ∼ 1R
abs1Is1 with totality 0R 1R
abs1Is1 | inl (inl 0<1) = Equivalence.reflexive eq
abs1Is1 | inl (inr 1<0) = exFalso (1<0False 1<0)
abs1Is1 | inr 0=1 = Equivalence.reflexive eq

absBoundedImpliesBounded : {a b : A} → abs a < b → a < b
absBoundedImpliesBounded {a} {b} a<b with totality 0G a
absBoundedImpliesBounded {a} {b} a<b | inl (inl x) = a<b
absBoundedImpliesBounded {a} {b} a<b | inl (inr x) = SetoidPartialOrder.<Transitive pOrder x (SetoidPartialOrder.<Transitive pOrder (lemm2 a x) a<b)
absBoundedImpliesBounded {a} {b} a<b | inr x = a<b

a-bPos : {a b : A} → ((a ∼ b) → False) → 0R < abs (a + inverse b)
a-bPos {a} {b} a!=b with totality 0R (a + inverse b)
a-bPos {a} {b} a!=b | inl (inl x) = x
a-bPos {a} {b} a!=b | inl (inr x) = lemm2 _ x
a-bPos {a} {b} a!=b | inr x = exFalso (a!=b (transferToRight additiveGroup (Equivalence.symmetric eq x)))


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

open import Polynomial.Parameters

module Polynomial.Solver
  {c r₁ r₂ r₃}
  (homo : Homomorphism c r₁ r₂ r₃)
  where

open import Data.Vec as Vec using (Vec)
open import Polynomial.Expr public
open import Algebra.Solver.Ring.AlmostCommutativeRing

open Homomorphism homo
open Eval homo

open import Polynomial.NormalForm.Definition coeffs
  using (Poly)
open import Polynomial.NormalForm.Operations coeffs
  using (_⊞_; _⊠_; ⊟_; _⊡_; κ; ι)

norm : ∀ {n} → Expr Raw.Carrier n → Poly n
norm (Κ x) = κ x
norm (Ι x) = ι x
norm (x ⊕ y) = norm x ⊞ norm y
norm (x ⊗ y) = norm x ⊠ norm y
norm (x ⊛ i) = norm x ⊡ i
norm (⊝ x) = ⊟ norm x

open import Polynomial.NormalForm.Semantics homo
  renaming (⟦_⟧ to ⟦_⟧ₚ)

⟦_⇓⟧ : ∀ {n} → Expr Raw.Carrier n → Vec Carrier n → Carrier
⟦ x ⇓⟧ = ⟦ norm x ⟧ₚ

import Polynomial.Homomorphism homo
  as Hom
open import Function

correct : ∀ {n} (e : Expr Raw.Carrier n) ρ → ⟦ e ⇓⟧ ρ ≈ ⟦ e ⟧ ρ
correct (Κ x) ρ = Hom.κ-hom x ρ
correct (Ι x) ρ = Hom.ι-hom x ρ
correct (x ⊕ y) ρ = Hom.⊞-hom (norm x) (norm y) ρ ⟨ trans ⟩ (correct x ρ ⟨ +-cong ⟩ correct y ρ)
correct (x ⊗ y) ρ = Hom.⊠-hom (norm x) (norm y) ρ ⟨ trans ⟩ (correct x ρ ⟨ *-cong ⟩ correct y ρ)
correct (x ⊛ i) ρ = Hom.⊡-hom (norm x) i ρ ⟨ trans ⟩ (Hom.pow-cong i (correct x ρ))
correct (⊝ x) ρ = Hom.⊟-hom (norm x) ρ ⟨ trans ⟩ -‿cong (correct x ρ)

open import Relation.Binary.Reflection setoid Ι ⟦_⟧ ⟦_⇓⟧ correct public


--
-- open import Relation.Binary using (Rel; Setoid; IsEquivalence)
-- open import Level as Lvl using ()

module Structures
  {G F : Set}
  (_≈G_ : G → G → Set)
  (_≈F_ : F → F → Set)
  where

-- import M as M’
open import Algebra.Structures _≈G_
  using (IsAbelianGroup)

open import Algebra.Structures _≈F_
  using (IsCommutativeRing)

open import Relation.Nullary

open import Algebra.FunctionProperties _≈F_ using (Inverse)

record IsField (+ * : F → F → F) (𝟘 𝟙 : F) (- : F → F) (⁻¹ : (a : F) → ¬ (a ≈F 𝟘) → F) : Set where
  field
    isCommutativeRing : IsCommutativeRing + * - 𝟘 𝟙
    *-inverse : Inverse {!   !} {!  ⁻¹  !} {!   !}

record IsVectorSpace

  (+ᵍ : G → G → G)
  (𝟘ᵍ : G)
  (-ᵍ : G → G)

  : Set where

  -- module G =
  field
    G-isAbelianGroup : IsAbelianGroup +ᵍ 𝟘ᵍ -ᵍ
    F-isField : {! Rel  !}
      -- IsAbelianGroup {! +G  !} {!   !} {!   !} {!   !}


------------------------------------------------------------------------
-- Unary relations
------------------------------------------------------------------------

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

-- Adapted from the Agda standard library.

module Common.Relation.Unary where

infix 4 _∈_ _⊆_

------------------------------------------------------------------------
-- Unary relations
Pred : Set → Set₁
Pred A = A → Set

_∈_ : ∀ {A} → A → Pred A → Set
x ∈ P = P x

-- P ⊆ Q means that P is a subset of Q.
_⊆_ : ∀ {A} → Pred A → Pred A → Set
P ⊆ Q = ∀ {x} → x ∈ P → x ∈ Q


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

open import LogicalFormulae
open import Lists.Lists
open import Setoids.Setoids
open import Functions.Definition
open import Sets.EquivalenceRelations

module Setoids.Lists where

listEquality : {a b : _} {A : Set a} (S : Setoid {a} {b} A) → Rel {a} {b} (List A)
listEquality S [] [] = True'
listEquality S [] (x :: w2) = False'
listEquality S (x :: w1) [] = False'
listEquality S (x :: w1) (y :: w2) = (Setoid._∼_ S x y) && listEquality S w1 w2

listEqualityReflexive : {a b : _} {A : Set a} (S : Setoid {a} {b} A) (w : List A) → listEquality S w w
listEqualityReflexive S [] = record {}
listEqualityReflexive S (x :: w) = Equivalence.reflexive (Setoid.eq S) ,, listEqualityReflexive S w

listEqualitySymmetric : {a b : _} {A : Set a} (S : Setoid {a} {b} A) {w1 w2 : List A} → listEquality S w1 w2 → listEquality S w2 w1
listEqualitySymmetric S {w1 = []} {[]} pr = record {}
listEqualitySymmetric S {[]} {x :: xs} ()
listEqualitySymmetric S {x :: xs} {[]} ()
listEqualitySymmetric S {w1 = x :: w1} {y :: w2} (pr1 ,, pr2) = Equivalence.symmetric (Setoid.eq S) pr1 ,, listEqualitySymmetric S pr2

listEqualityTransitive : {a b : _} {A : Set a} (S : Setoid {a} {b} A) {w1 w2 w3 : List A} → listEquality S w1 w2 → listEquality S w2 w3 → listEquality S w1 w3
listEqualityTransitive S {w1 = []} {[]} {[]} w1=w2 w2=w3 = record {}
listEqualityTransitive S {w1 = []} {[]} {x :: xs} w1=w2 ()
listEqualityTransitive S {w1 = []} {x :: xs} {w3} () w2=w3
listEqualityTransitive S {w1 = x :: w1} {[]} {w3} () w2=w3
listEqualityTransitive S {w1 = x :: w1} {y :: ys} {[]} w1=w2 ()
listEqualityTransitive S {w1 = x :: w1} {y :: w2} {z :: w3} (pr1 ,, pr2) (pr3 ,, pr4) = Equivalence.transitive (Setoid.eq S) pr1 pr3 ,, listEqualityTransitive S pr2 pr4

listEqualityRespectsMap : {a b c d : _} {A : Set a} {B : Set b} (S : Setoid {a} {c} A) (T : Setoid {b} {d} B) (f : A → B) (fWD : {x y : A} → Setoid._∼_ S x y → Setoid._∼_ T (f x) (f y)) → {w1 w2 : List A} (w1=w2 : listEquality S w1 w2) → listEquality T (map f w1) (map f w2)
listEqualityRespectsMap S T f fWD {[]} {[]} w1=w2 = record {}
listEqualityRespectsMap S T f fWD {[]} {x :: w2} ()
listEqualityRespectsMap S T f fWD {x :: w1} {[]} ()
listEqualityRespectsMap S T f fWD {x :: w1} {y :: w2} (x=y ,, w1=w2) = fWD x=y ,, listEqualityRespectsMap S T f fWD {w1} {w2} w1=w2

listSetoid : {a b : _} {A : Set a} (S : Setoid {a} {b} A) → Setoid (List A)
Setoid._∼_ (listSetoid S) word1 word2 = listEquality S word1 word2
Equivalence.reflexive (Setoid.eq (listSetoid S)) {word} = listEqualityReflexive S word
Equivalence.symmetric (Setoid.eq (listSetoid S)) pr = listEqualitySymmetric S pr
Equivalence.transitive (Setoid.eq (listSetoid S)) pr1 pr2 = listEqualityTransitive S pr1 pr2

consWellDefined : {a b : _} {A : Set a} {S : Setoid {a} {b} A} (xs : List A) {x y : A} (x=y : Setoid._∼_ S x y) → Setoid._∼_ (listSetoid S) (x :: xs) (y :: xs)
consWellDefined {S = S} xs x=y = x=y ,, Equivalence.reflexive (Setoid.eq (listSetoid S))

appendWellDefined : {a b : _} {A : Set a} {S : Setoid {a} {b} A} {xs ys as bs : List A} (xs=as : Setoid._∼_ (listSetoid S) xs as) → (ys=bs : Setoid._∼_ (listSetoid S) ys bs) → Setoid._∼_ (listSetoid S) (xs ++ ys) (as ++ bs)
appendWellDefined {S = S} {[]} {[]} {[]} {[]} record {} record {} = record {}
appendWellDefined {S = S} {[]} {[]} {[]} {x :: bs} record {} ()
appendWellDefined {S = S} {[]} {x :: ys} {[]} {[]} record {} ys=bs = ys=bs
appendWellDefined {S = S} {[]} {x :: ys} {[]} {x₁ :: bs} record {} ys=bs = ys=bs
appendWellDefined {S = S} {[]} {ys} {x :: as} {bs} () ys=bs
appendWellDefined {S = S} {x :: xs} {ys} {[]} {bs} () ys=bs
appendWellDefined {S = S} {x :: xs} {[]} {x₁ :: as} {[]} xs=as record {} = _&&_.fst xs=as ,, identityOfIndiscernablesRight (listEquality S) (identityOfIndiscernablesLeft (listEquality S) (_&&_.snd xs=as) (equalityCommutative (appendEmptyList xs))) (equalityCommutative (appendEmptyList as))
appendWellDefined {S = S} {x :: xs} {[]} {x₁ :: as} {x₂ :: bs} xs=as ()
appendWellDefined {S = S} {x :: xs} {x₂ :: ys} {x₁ :: as} {[]} xs=as ()
appendWellDefined {S = S} {x :: xs} {x₂ :: ys} {x₁ :: as} {x₃ :: bs} (fst ,, snd) ys=bs = fst ,, appendWellDefined snd ys=bs


module CombinatoryLogic.Syntax where

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

-- Kapitel 1, Abschnitt C, §4 (Symbolische Festsetzungen), Def. 1
infixl 6 _∙_

data Combinator : Set where
  -- Kapitel 1, Abschnitt C, §3 (Die formalen Grundbegriffe)
  B C W K Q Π P ∧ : Combinator
  -- Kapitel 1, Abschnitt C, §2, c (Anwendung)
  _∙_ : (X Y : Combinator) → Combinator

-- NOTE: for the (intensional) equality defined by Kapitel 1, Abschnitt C, §4
-- (Symbolische Festsetzungen), Festsetzung 2, we use the propositional equality
-- _≡_.

toString : Combinator → String
toString (X ∙ Y@(_ ∙ _)) = toString X ++ "(" ++ toString Y ++ ")"
toString (X ∙ Y) = toString X ++ toString Y
toString B = "B"
toString C = "C"
toString W = "W"
toString K = "K"
toString Q = "Q"
toString Π = "Π"
toString P = "P"
toString ∧ = "∧"

_ : toString (K ∙ Q ∙ (W ∙ C)) ≡ "KQ(WC)"
_ = refl

_ : toString (K ∙ ∧ ∙ (Q ∙ Π) ∙ (W ∙ C)) ≡ "K∧(QΠ)(WC)"
_ = refl

_ : toString (K ∙ ∧ ∙ ((Q ∙ Π) ∙ (W ∙ C))) ≡ "K∧(QΠ(WC))"
_ = refl

_ : toString (K ∙ K ∙ K) ≡ "KKK"
_ = refl

infix 5 _==_

-- Kapitel 1, Abschnitt C, §4 (Symbolische Festsetzungen), Def. 2
_==_ : (X Y : Combinator) → Combinator
X == Y = Q ∙ X ∙ Y

-- Kapitel 1, Abschnitt C, §4 (Symbolische Festsetzungen), Def. 3
I : Combinator
I = W ∙ K


module Auxiliary where

open import Agda.Primitive
open import Data.List
open import Data.Nat renaming (_+_ to _+ᴺ_ ; _≤_ to _≤ᴺ_ ; _≥_ to _≥ᴺ_ ; _<_ to _<ᴺ_ ; _>_ to _>ᴺ_)
open import Data.Nat.Properties
open import Data.Integer renaming (_+_ to _+ᶻ_ ; _≤_ to _≤ᶻ_ ; _≥_ to _≥ᶻ_ ; _<_ to _<ᶻ_ ; _>_ to _>ᶻ_)
import Data.Integer.Properties
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary
open import Relation.Nullary.Negation
open import Data.Product
open import Data.Sum

-- natural numbers

n≢m⇒sucn≢sucm : {n m : ℕ} → n ≢ m → ℕ.suc n ≢ ℕ.suc m
n≢m⇒sucn≢sucm {n} {m} neq = λ x → contradiction (cong Data.Nat.pred x) neq

sucn≢sucm⇒n≢m : {n m : ℕ} → ℕ.suc n ≢ ℕ.suc m → n ≢ m
sucn≢sucm⇒n≢m {n} {m} neq = λ x → contradiction (cong ℕ.suc x) neq

n+1≡sucn : {n : ℕ} → n +ᴺ 1 ≡ ℕ.suc n
n+1≡sucn {zero} = refl
n+1≡sucn {ℕ.suc n} = cong ℕ.suc (n+1≡sucn{n})

n≤sucn : {n : ℕ} → n ≤ᴺ ℕ.suc n
n≤sucn {zero} = z≤n
n≤sucn {ℕ.suc n} = s≤s n≤sucn

n<sucn : {n : ℕ} → n <ᴺ ℕ.suc n
n<sucn {zero} = s≤s z≤n
n<sucn {ℕ.suc n} = s≤s n<sucn

m<n⇒m+o<n+o : {m n o : ℕ} → m <ᴺ n → m +ᴺ o <ᴺ n +ᴺ o
m<n⇒m+o<n+o {zero} {n} {o} le = m<n+m o le
m<n⇒m+o<n+o {ℕ.suc m} {ℕ.suc n} {o} (s≤s le) = s≤s (m<n⇒m+o<n+o le)

m≤n⇒m+o≤n+o : {m n o : ℕ} → m ≤ᴺ n → m +ᴺ o ≤ᴺ n +ᴺ o
m≤n⇒m+o≤n+o {zero} {n} {o} le = m≤n+m o n
m≤n⇒m+o≤n+o {ℕ.suc m} {ℕ.suc n} {o} (s≤s le) = s≤s (m≤n⇒m+o≤n+o le)

≤-refl-+-comm : {m n : ℕ} → m +ᴺ n ≤ᴺ n +ᴺ m
≤-refl-+-comm {m} {n} rewrite (+-comm m n) = ≤-refl

a<b≤c⇒a<c : {a b c : ℕ} → a <ᴺ b → b ≤ᴺ c → a <ᴺ c
a<b≤c⇒a<c {a} {b} {c} lt le = ≤-trans lt le

a≤b<c⇒a<c : {a b c : ℕ} → a ≤ᴺ b → b <ᴺ c → a <ᴺ c
a≤b<c⇒a<c {.0} {zero} {c} z≤n lt = lt
a≤b<c⇒a<c {.0} {ℕ.suc b} {ℕ.suc c} z≤n (s≤s lt) = s≤s z≤n
a≤b<c⇒a<c {.(ℕ.suc _)} {.(ℕ.suc _)} {ℕ.suc c} (s≤s le) (s≤s lt) = s≤s (a≤b<c⇒a<c le lt)

m≤n∧m≡q⇒q≤n : {m n q : ℕ} → m ≤ᴺ n → m ≡ q → q ≤ᴺ n
m≤n∧m≡q⇒q≤n {m} {n} {q} le eq rewrite eq = le

m≤n∧n≡q⇒m≤q : {m n q : ℕ} → m ≤ᴺ n → n ≡ q → m ≤ᴺ q
m≤n∧n≡q⇒m≤q le eq rewrite eq = le

n≤m⇒n≤sucm : {n m : ℕ} → n ≤ᴺ m → n ≤ᴺ ℕ.suc m
n≤m⇒n≤sucm {.0} {m} z≤n = z≤n
n≤m⇒n≤sucm {.(ℕ.suc _)} {.(ℕ.suc _)} (s≤s le) = s≤s (n≤m⇒n≤sucm le)

n≤m⇒n<sucm : {n m : ℕ} → n ≤ᴺ m → n <ᴺ ℕ.suc m
n≤m⇒n<sucm {n} {m} le = s≤s le

sucn≤m⇒n≤m : {n m : ℕ} → ℕ.suc n ≤ᴺ m → n ≤ᴺ m
sucn≤m⇒n≤m {n} {.(ℕ.suc _)} (s≤s le) = ≤-trans le n≤sucn

[k<x]⇒[k<x+1] : {x : ℕ} {k : ℕ} → (k <ᴺ x) → (k <ᴺ x +ᴺ 1)
[k<x]⇒[k<x+1]{x} {k} le = <-trans le (m<m+n x (s≤s z≤n))

[k<x]⇒[k<sucx] : {x : ℕ} {k : ℕ} → (k <ᴺ x) → (k <ᴺ ℕ.suc (x))
[k<x]⇒[k<sucx] {x} {k} le = <-trans le (s≤s ≤-refl)

¬[x≤k]⇒¬[sucx≤k] : {x : ℕ} {k : ℕ} → ¬ (x ≤ᴺ k) → ¬ ((x +ᴺ 1) ≤ᴺ k)
¬[x≤k]⇒¬[sucx≤k] {x} {k} nle = <⇒≱ ([k<x]⇒[k<x+1] (≰⇒> nle))

n+m≤n+q+m : {n m q : ℕ} → n +ᴺ m ≤ᴺ n +ᴺ (q +ᴺ m)
n+m≤n+q+m {n} {m} {q} rewrite (+-comm q m) | (sym (+-assoc n m q)) = m≤m+n (n +ᴺ m) q

m>n⇒m∸n≥1 : {m n : ℕ} → n <ᴺ m → m ∸ n ≥ᴺ 1
m>n⇒m∸n≥1 {ℕ.suc m} {zero} le = s≤s z≤n
m>n⇒m∸n≥1 {ℕ.suc m} {ℕ.suc n} (s≤s le) = m>n⇒m∸n≥1 le

m∸n≥q⇒m≥q : {m n q : ℕ} → m ∸ n ≥ᴺ q → m ≥ᴺ q
m∸n≥q⇒m≥q {m} {n} {q} ge = ≤-trans ge (m∸n≤m m n)

-- lists & length

++-assoc : {a : Level} {s : Set a} {Δ ∇ Γ : List s} → ((Δ ++ ∇) ++ Γ) ≡ (Δ ++ (∇ ++ Γ))
++-assoc {a} {s} {[]} {∇} {Γ} = refl
++-assoc {a} {s} {x ∷ Δ} {∇} {Γ} = cong (_∷_ x) (++-assoc{a}{s}{Δ}{∇}{Γ})

length[A]≥0 : {a : Level} {s : Set a} {A : List s} → length A ≥ᴺ 0
length[A]≥0 {a} {s} {A} = z≤n

A++[]≡A : {a : Level} {s : Set a} {A : List s} → A ++ [] ≡ A
A++[]≡A {a} {s} {[]} = refl
A++[]≡A {a} {s} {x ∷ A} = cong (_∷_ x) (A++[]≡A {a} {s} {A})

n+length[]≡n : {a : Level} {A : Set a} {n : ℕ} → n +ᴺ length{a}{A} [] ≡ n
n+length[]≡n {a} {A} {zero} = refl
n+length[]≡n {a} {A} {ℕ.suc n} = cong ℕ.suc (n+length[]≡n{a}{A})

length[A∷B]≡suc[length[B]] : {a : Level} {s : Set a} {A : s} {B : List s} → length (A ∷ B) ≡ ℕ.suc (length B)
length[A∷B]≡suc[length[B]] {a} {s} {A} {B} = refl

length[A∷B]≥1 : {a : Level} {s : Set a} {A : s} {B : List s} → length (A ∷ B) ≥ᴺ 1
length[A∷B]≥1 {a} {s} {A} {B} = s≤s z≤n

length[A++B]≡length[A]+length[B] : {a : Level} {s : Set a} {A B : List s} → length (A ++ B) ≡ length A +ᴺ length B
length[A++B]≡length[A]+length[B] {a} {s} {[]} {B} = refl
length[A++B]≡length[A]+length[B] {a} {s} {x ∷ A} {B} rewrite length[A∷B]≡suc[length[B]]{a}{s}{x}{A ++ B} = cong ℕ.suc (length[A++B]≡length[A]+length[B]{a}{s}{A}{B})

length[A++B∷[]]≡suc[length[A]] : {a : Level} {s : Set a} {A : List s} {B : s} → length (A ++ B ∷ []) ≡ ℕ.suc (length A)
length[A++B∷[]]≡suc[length[A]] {a} {s} {A} {B} rewrite (length[A++B]≡length[A]+length[B]{a}{s}{A}{B ∷ []}) = n+1≡sucn

A++B∷[]++C≡A++B∷C : {a : Level} {s : Set a} {A C : List s} {B : s} → ((A ++ B ∷ []) ++ C) ≡ (A ++ B ∷ C)
A++B∷[]++C≡A++B∷C {a} {s} {[]} {C} {B} = refl
A++B∷[]++C≡A++B∷C {a} {s} {x ∷ A} {C} {B} = cong (_∷_ x) A++B∷[]++C≡A++B∷C

A++B++D∷[]++C≡A++B++D∷C : {a : Level} {s : Set a} { A B C : List s} {D : s} → (A ++ B ++ D ∷ []) ++ C ≡ (A ++ B ++ D ∷ C)
A++B++D∷[]++C≡A++B++D∷C {a} {s} {[]} {B} {C} {D} = A++B∷[]++C≡A++B∷C
A++B++D∷[]++C≡A++B++D∷C {a} {s} {x ∷ A} {B} {C} {D} = cong (_∷_ x) (A++B++D∷[]++C≡A++B++D∷C{a}{s}{A}{B}{C}{D})

-- integers

m≥0⇒n+m≥0 : {n : ℕ} {m : ℤ} → m ≥ᶻ +0 → + n +ᶻ m ≥ᶻ +0
m≥0⇒n+m≥0 {n} {+_ m} ge = +≤+ z≤n

n>0⇒n>∣n⊖1∣ : {n : ℕ} → n ≥ᴺ 1 → n >ᴺ ∣ n ⊖ 1 ∣
n>0⇒n>∣n⊖1∣ {.(ℕ.suc _)} (s≤s le) = n<sucn

∣nℕ+1⊖1∣≡n : {n : ℕ} → ∣ n +ᴺ 1 ⊖ 1 ∣ ≡ n
∣nℕ+1⊖1∣≡n {zero} = refl
∣nℕ+1⊖1∣≡n {ℕ.suc n} = n+1≡sucn

m≥0⇒∣n+m∣≥n : {n : ℕ} {m : ℤ} → m ≥ᶻ +0 → ∣ +_ n +ᶻ m ∣ ≥ᴺ n
m≥0⇒∣n+m∣≥n {n} {+_ m} ge = m≤m+n n m

m>0⇒∣n+m∣>n : {n : ℕ} {m : ℤ} → m >ᶻ +0 → ∣ +_ n +ᶻ m ∣ >ᴺ n
m>0⇒∣n+m∣>n {n} {(+ m)} (+<+ m<n) = m<m+n n m<n

∣n∣≥n : {n : ℤ} → + ∣ n ∣ ≥ᶻ n
∣n∣≥n {+_ n} = +≤+ ≤-refl
∣n∣≥n { -[1+_] n} = -≤+

+a≤b⇒a≤∣b∣ : {a : ℕ} {b : ℤ} → + a ≤ᶻ b → a ≤ᴺ ∣ b ∣
+a≤b⇒a≤∣b∣ {zero} {b} le = z≤n
+a≤b⇒a≤∣b∣ {ℕ.suc a} {(+ b)} (+≤+ m≤n) = m≤n

+[1+q]≡q+1 : {q : ℕ} → +[1+ q ] ≡ + q +ᶻ + 1
+[1+q]≡q+1 {zero} = refl
+[1+q]≡q+1 {ℕ.suc q} = cong +[1+_] (sym n+1≡sucn)

+q≤+c+l⇒+1q≤+1c+l : {q c : ℕ} {l : ℤ} → + q ≤ᶻ + c +ᶻ l → +[1+ q ] ≤ᶻ +[1+ c ] +ᶻ l
+q≤+c+l⇒+1q≤+1c+l {q} {c} {l} le
  rewrite (+[1+q]≡q+1{q})
        | (+[1+q]≡q+1{c})
        | (Data.Integer.Properties.+-assoc (+ c) (+ 1) l)
        | (Data.Integer.Properties.+-comm (+ 1) l)
        | (sym (Data.Integer.Properties.+-assoc (+ c) (l) (+ 1)))
        = Data.Integer.Properties.+-monoˡ-≤ (+ 1) le

ℤ-m≤n⇒m+o≤n+o : {m n o : ℤ} → m ≤ᶻ n → m +ᶻ o ≤ᶻ n +ᶻ o
ℤ-m≤n⇒m+o≤n+o {m} {n} {o} le = Data.Integer.Properties.+-monoˡ-≤ o le

minus-1 : {y x : ℕ} {lt : x <ᴺ y} → ∣ y ∸ x ⊖ 1 ∣ +ᴺ x ≡ ∣ y ⊖ 1 ∣
minus-1 {y} {x} {lt}
  rewrite (Data.Integer.Properties.⊖-≥{y ∸ x}{1} (m>n⇒m∸n≥1 lt))
        | (sym (+-∸-comm {y ∸ x} x {1} (m>n⇒m∸n≥1 lt)))
        | (m∸n+n≡m {y} {x} (sucn≤m⇒n≤m lt))
        | (Data.Integer.Properties.⊖-≥{y}{1} ((m∸n≥q⇒m≥q{y}{x} (m>n⇒m∸n≥1{y}{x} lt))))
        = refl

k≥0⇒∣+x+k∣≡x+k : {x k : ℕ} → ∣ + x +ᶻ + k ∣ ≡ x +ᴺ k
k≥0⇒∣+x+k∣≡x+k {x} {k} = refl

-- products & sums

-- deMorgan on products and sums
dm1 : {P Q : Set} → (¬ P × ¬ Q) → ¬ (P ⊎ Q)
dm1 {P} {Q} (fst , snd) (inj₁ x) = contradiction x fst
dm1 {P} {Q} (fst , snd) (inj₂ y) = contradiction y snd

dm2 : {P Q : Set} → ¬ (P ⊎ Q) → (¬ P × ¬ Q)
dm2 {P} {Q} d = (λ x → contradiction (inj₁ x) d) , λ x → contradiction (inj₂ x) d


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Relation.Binary.Base where

open import Cubical.Core.Everything

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function using (_on_)
open import Cubical.Foundations.HLevels

open import Cubical.Classes using (Cast; [_]) public

private
  variable
    a b ℓ : Level
    A : Type a
    B : Type b

RawREL : Type a → Type b → (ℓ : Level) → Type _
RawREL A B ℓ = A → B → Type ℓ

RawRel : Type a → (ℓ : Level) → Type _
RawRel A ℓ = RawREL A A ℓ

REL : Type a → Type b → (ℓ : Level) → Type _
REL A B ℓ = A → B → hProp ℓ

Rel : Type a → (ℓ : Level) → Type _
Rel A ℓ = REL A A ℓ

isPropValued : RawREL A B ℓ → Type _
isPropValued R = ∀ a b → isProp (R a b)

instance
  RelCast : Cast (REL A B ℓ) (RawREL A B ℓ)
  RelCast = record { cast = λ R a b → R a b .fst }

isProp[_] : (R : REL A B ℓ) → isPropValued [ R ]
isProp[ R ] a b = R a b .snd

fromRaw : (R : RawREL A B ℓ) → isPropValued R → REL A B ℓ
fromRaw R isPropR a b .fst = R a b
fromRaw R isPropR a b .snd = isPropR a b


module Numeral.Sign.Oper0 where

open import Numeral.Sign

-- Negation
−_ : (+|0|−) → (+|0|−)
− (➕) = (➖)
− (𝟎) = (𝟎)
− (➖) = (➕)

-- Bounded addition
_+_ : (+|0|−) → (+|0|−) → (+|0|−)
(➕) + (➕) = (➕)
(➕) + (➖) = (𝟎)
(➕) + (𝟎) = (➕)
(➖) + (➕) = (𝟎)
(➖) + (➖) = (➖)
(➖) + (𝟎) = (➖)
(𝟎) + (➕) = (➕)
(𝟎) + (➖) = (➖)
(𝟎) + (𝟎) = (𝟎)

-- Multiplication
_⨯_ : (+|0|−) → (+|0|−) → (+|0|−)
(➕) ⨯ (➕) = (➕)
(➕) ⨯ (➖) = (➖)
(➕) ⨯ (𝟎) = (𝟎)
(➖) ⨯ (➕) = (➖)
(➖) ⨯ (➖) = (➕)
(➖) ⨯ (𝟎) = (𝟎)
(𝟎) ⨯ (➕) = (𝟎)
(𝟎) ⨯ (➖) = (𝟎)
(𝟎) ⨯ (𝟎) = (𝟎)

_⋚_ : (+|0|−) → (+|0|−) → (+|0|−)
➕ ⋚ 𝟎 = ➕
➕ ⋚ ➖ = ➕
𝟎 ⋚ ➖ = ➕
➕ ⋚ ➕ = 𝟎
𝟎 ⋚ 𝟎 = 𝟎
➖ ⋚ ➖ = 𝟎
𝟎 ⋚ ➕ = ➖
➖ ⋚ ➕ = ➖
➖ ⋚ 𝟎 = ➖


------------------------------------------------------------------------------
-- First-order logic
------------------------------------------------------------------------------

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

module FOL.README where

------------------------------------------------------------------------------
-- Description

-- Formalization of first-order logic using Agda's inductive notions.

------------------------------------------------------------------------------
-- Definition of the connectives and quantifiers
open import FOL.Base

-- Propositional logic theorems
open import FOL.ExclusiveDisjunction.TheoremsATP
open import FOL.ExclusiveDisjunction.TheoremsI
open import FOL.PropositionalLogic.TheoremsATP
open import FOL.PropositionalLogic.TheoremsI

-- First-order logic theorems
open import FOL.TheoremsATP
open import FOL.TheoremsI

-- Logical schemata
open import FOL.SchemataATP

-- Non-empty domains
open import FOL.NonEmptyDomain.TheoremsATP
open import FOL.NonEmptyDomain.TheoremsI

-- Non-intuitionistic logic theorems
open import FOL.NonIntuitionistic.TheoremsATP
open import FOL.NonIntuitionistic.TheoremsI


{-# OPTIONS --without-K #-}
module NTypes.Id where

open import GroupoidStructure
open import NTypes
open import PathOperations
open import Transport
open import Types

-- This should also be derivable from hLevel-suc from
-- HomotopyTypes.HLevel module.
Id-isSet : ∀ {a} {A : Set a} {x y : A} →
  isSet A → isSet (x ≡ y)
Id-isSet {x = x} {y = y} A-set _ _ pp qq
  = path pp ⁻¹ · path qq
  where
  split-path : {p q : x ≡ y} (pp : p ≡ q) →
    A-set _ _ p q ≡ pp · A-set _ _ q q
  split-path pp = J
    (λ p q pp → A-set _ _ p q ≡ pp · A-set _ _ q q)
    (λ _ → refl) _ _ pp

  path : {p q : x ≡ y} (pp : p ≡ q) →
    A-set _ _ p q ≡ pp
  path pp = J
    (λ p q pp → A-set _ _ p q ≡ pp)
    (λ p → split-path (A-set _ _ p p ⁻¹) · p⁻¹·p (A-set _ _ p p))
    _ _ pp

-- From the lectures.
Id-isSet-alt : ∀ {a} {A : Set a} {u v : A} →
  isSet A → isSet (u ≡ v)
Id-isSet-alt {u = u} {v = v} H r s α β
  = id·p α ⁻¹
  · ap (λ z → z · α)
    (p⁻¹·p (H′ r)) ⁻¹
  · p·q·r (H′ r ⁻¹) (H′ r) α ⁻¹
  · ap (λ z → H′ r ⁻¹ · z)
    ( tr-post r α (H′ r) ⁻¹
    · apd H′ α
    · apd H′ β ⁻¹
    · tr-post r β (H′ r)
    )
  · p·q·r (H′ r ⁻¹) (H′ r) β
  · ap (λ z → z · β)
    (p⁻¹·p (H′ r))
  · id·p β
  where
    H′ = λ q → H u v r q


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

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Pointed
open import Cubical.Foundations.HLevels
open import Cubical.HITs.S1
open import Cubical.HITs.Sn

record HSpace {ℓ : Level} (A : Pointed ℓ) : Type ℓ where
  constructor HSp
  field
    μ : typ A → typ A → typ A
    μₗ : (x : typ A) → μ (pt A) x ≡ x
    μᵣ : (x : typ A) → μ x (pt A) ≡ x
    μₗᵣ : μₗ (pt A) ≡ μᵣ (pt A)

record AssocHSpace {ℓ : Level} {A : Pointed ℓ} (e : HSpace A) : Type ℓ where
  constructor AssocHSp
  field
    μ-assoc : (x y z : _)
      → HSpace.μ e (HSpace.μ e x y) z ≡ HSpace.μ e x (HSpace.μ e y z)

    μ-assoc-filler : (y z : typ A)
      → PathP (λ i → HSpace.μ e (HSpace.μₗ e y i) z
                    ≡ HSpace.μₗ e (HSpace.μ e y z) i)
               (μ-assoc (pt A) y z)
               refl

-- Instances
open HSpace
open AssocHSpace

-- S¹
S1-HSpace : HSpace (S₊∙ 1)
μ S1-HSpace = _·_
μₗ S1-HSpace x = refl
μᵣ S1-HSpace base = refl
μᵣ S1-HSpace (loop i) = refl
μₗᵣ S1-HSpace x = refl

S1-AssocHSpace : AssocHSpace S1-HSpace
μ-assoc S1-AssocHSpace base _ _ = refl
μ-assoc S1-AssocHSpace (loop i) x y j = h x y j i
  where
  h : (x y : S₊ 1) → cong (_· y) (rotLoop x) ≡ rotLoop (x · y)
  h = wedgeconFun _ _ (λ _ _ → isOfHLevelPath 2 (isGroupoidS¹ _ _) _ _)
        (λ x → refl)
        (λ { base → refl ; (loop i) → refl})
        refl
μ-assoc-filler S1-AssocHSpace _ _ = refl


{-# OPTIONS --cubical #-}

open import Agda.Primitive.Cubical

postulate
  Id    : ∀ {ℓ} {A : Set ℓ}     → A    → A    → Set ℓ
  Path  : ∀ {ℓ} {A : Set ℓ}     → A    → A    → Set ℓ
  PathP : ∀ {ℓ} (A : I → Set ℓ) → A i0 → A i1 → Set ℓ

{-# BUILTIN PATH  Path  #-}
{-# BUILTIN PATHP PathP #-}
{-# BUILTIN ID    Id    #-}
{-# BUILTIN CONID conid #-}

reflPath : ∀ {ℓ} {A : Set ℓ} {x : A} → Path x x
reflPath {x = x} = λ i → x

reflId : ∀ {ℓ} {A : Set ℓ} {x : A} → Id x x
reflId {x = x} = conid i1 reflPath

primitive
 primIdJ : ∀ {ℓ ℓ'} {A : Set ℓ} {x : A} (P : ∀ y → Id x y → Set ℓ')
         → P x reflId → {y : A} (p : Id x y) → P y p

Id-comp-Id : ∀ {ℓ ℓ'} {A : Set ℓ} {x : A} (P : ∀ y → Id x y → Set ℓ')
           → (b : P x reflId) → Id (primIdJ P b reflId) b
Id-comp-Id P b = reflId

Id-comp-Path : ∀ {ℓ ℓ'} {A : Set ℓ} {x : A} (P : ∀ y → Id x y → Set ℓ')
             → (b : P x reflId) → Path (primIdJ P b reflId) b
Id-comp-Path P b = λ i → b


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

open import lib.Basics
open import lib.Equivalences2
open import lib.NType2
open import lib.types.Group
open import lib.types.Pi
open import lib.types.Sigma
open import lib.types.Truncation

module lib.groups.Homomorphisms where

record GroupHom {i j} (G : Group i) (H : Group j)
  : Type (lsucc (lmax i j)) where
  constructor group-hom

  field
    f : Group.El G → Group.El H
    pres-comp  : ∀ g1 g2 → f (Group.comp G g1 g2) == Group.comp H (f g1) (f g2)

  abstract
    pres-ident : f (Group.ident G) == Group.ident H
    pres-ident = group-cancel-l H (f (Group.ident G)) $
      Group.comp H (f (Group.ident G)) (f (Group.ident G))
        =⟨ ! (pres-comp (Group.ident G) (Group.ident G)) ⟩
      f (Group.comp G (Group.ident G) (Group.ident G))
        =⟨ ap f (Group.unitl G (Group.ident G)) ⟩
      f (Group.ident G)
        =⟨ ! (Group.unitr H (f (Group.ident G))) ⟩
      Group.comp H (f (Group.ident G)) (Group.ident H) ∎

    pres-inv : (g : Group.El G) → f (Group.inv G g) == Group.inv H (f g)
    pres-inv g =
      f (Group.inv G g)
        =⟨ ! (Group.unitr H (f (Group.inv G g))) ⟩
      Group.comp H (f (Group.inv G g)) (Group.ident H)
        =⟨ ! (Group.invr H (f g))
           |in-ctx (λ w → Group.comp H (f (Group.inv G g)) w) ⟩
      Group.comp H (f (Group.inv G g)) (Group.comp H (f g) (Group.inv H (f g)))
        =⟨ ! (Group.assoc H (f (Group.inv G g)) (f g) (Group.inv H (f g))) ⟩
      Group.comp H (Group.comp H (f (Group.inv G g)) (f g)) (Group.inv H (f g))
        =⟨ ! (pres-comp (Group.inv G g) g) ∙ ap f (Group.invl G g) ∙ pres-ident
           |in-ctx (λ w → Group.comp H w (Group.inv H (f g))) ⟩
      Group.comp H (Group.ident H) (Group.inv H (f g))
        =⟨ Group.unitl H (Group.inv H (f g)) ⟩
      Group.inv H (f g) ∎

  ⊙f : Σ (Group.El G → Group.El H)
            (λ f → f (Group.ident G) == Group.ident H)
  ⊙f = (f , pres-ident)

infix 0 _→ᴳ_
_→ᴳ_ = GroupHom

GroupIso : ∀ {i j} (G : Group i) (H : Group j) → Type (lsucc (lmax i j))
GroupIso G H = Σ (G →ᴳ H) (λ φ → is-equiv (GroupHom.f φ))

infix 30 _≃ᴳ_
_≃ᴳ_ = GroupIso

idhom : ∀ {i} (G : Group i) → (G →ᴳ G)
idhom G = group-hom (idf _) (λ _ _ → idp)

idiso : ∀ {i} (G : Group i) → (G ≃ᴳ G)
idiso G = (idhom G , idf-is-equiv _)

infixr 80 _∘ᴳ_

_∘ᴳ_ : ∀ {i j k} {G : Group i} {H : Group j} {K : Group k}
  → (H →ᴳ K) → (G →ᴳ H) → (G →ᴳ K)
(group-hom g g-comp) ∘ᴳ (group-hom f f-comp) =
  record {
    f = g ∘ f;
    pres-comp = λ x₁ x₂ → ap g (f-comp x₁ x₂) ∙ g-comp (f x₁) (f x₂)}

infixr 80 _∘eᴳ_

_∘eᴳ_ : ∀ {i j k} {G : Group i} {H : Group j} {K : Group k}
  → H ≃ᴳ K → G ≃ᴳ H → G ≃ᴳ K
(φ₂ , ie₂) ∘eᴳ (φ₁ , ie₁) = (φ₂ ∘ᴳ φ₁ , ie₂ ∘ise ie₁)

infixl 120 _⁻¹ᴳ

_⁻¹ᴳ : ∀ {i j} {G : Group i} {H : Group j} → G ≃ᴳ H → H ≃ᴳ G
_⁻¹ᴳ {G = G} {H = H} (φ , ie) =
  (record {
     f = is-equiv.g ie;
     pres-comp = λ h₁ h₂ →
       ap2 (λ w₁ w₂ → is-equiv.g ie (Group.comp H w₁ w₂))
         (! (is-equiv.f-g ie h₁)) (! (is-equiv.f-g ie h₂))
       ∙ ! (ap (is-equiv.g ie)
               (GroupHom.pres-comp φ (is-equiv.g ie h₁) (is-equiv.g ie h₂)))
       ∙ is-equiv.g-f ie (Group.comp G (is-equiv.g ie h₁) (is-equiv.g ie h₂))} ,
   snd ((_ , ie) ⁻¹))

{- a homomorphism which is an equivalence gives a path between groups -}
module _ {i} {G H : Group i} (iso : G ≃ᴳ H) where
  private
    module G = Group G
    module H = Group H
    module φ = GroupHom (fst iso)
    ie = snd iso

  private
    ap3-lemma : ∀ {i j k l} {C : Type i} {D : C → Type j} {E : C → Type k}
      {F : Type l} {c₁ c₂ : C} {d₁ : D c₁} {d₂ : D c₂} {e₁ : E c₁} {e₂ : E c₂}
      (f : (c : C) → D c → E c → F) (p : c₁ == c₂)
      → (d₁ == d₂ [ D ↓ p ]) → (e₁ == e₂ [ E ↓ p ])
      → (f c₁ d₁ e₁ == f c₂ d₂ e₂)
    ap3-lemma f idp idp idp = idp

    ap3-lemma-el : ∀ {i} {G H : Group i}
      (p : Group.El G == Group.El H)
      (q : Group.El-level G == Group.El-level H [ _ ↓ p ])
      (r : Group.group-struct G == Group.group-struct H [ _ ↓ p ])
      → ap Group.El (ap3-lemma group p q r) == p
    ap3-lemma-el idp idp idp = idp

  abstract
    group-ua : G == H
    group-ua =
      ap3-lemma group
        (ua (φ.f , ie))
        (prop-has-all-paths-↓ has-level-is-prop)
        (↓-group-structure= (G.El-level) (ua (φ.f , ie)) ident= inv= comp=)
      where
      ident= : G.ident == H.ident [ (λ C → C) ↓ ua (φ.f , ie) ]
      ident= = ↓-idf-ua-in _ φ.pres-ident

      inv= : G.inv == H.inv [ (λ C → C → C) ↓ ua (φ.f , ie) ]
      inv= =
        ↓-→-from-transp $ λ= $ λ a →
          transport (λ C → C) (ua (φ.f , ie)) (G.inv a)
            =⟨ to-transp (↓-idf-ua-in _ idp) ⟩
          φ.f (G.inv a)
            =⟨ φ.pres-inv a ⟩
          H.inv (φ.f a)
            =⟨ ap H.inv (! (to-transp (↓-idf-ua-in _ idp))) ⟩
          H.inv (transport (λ C → C) (ua (φ.f , ie)) a) ∎

      comp=' : (a : G.El)
        → G.comp a == H.comp (φ.f a) [ (λ C → C → C) ↓ ua (φ.f , ie) ]
      comp=' a =
        ↓-→-from-transp $ λ= $ λ b →
          transport (λ C → C) (ua (φ.f , ie)) (G.comp a b)
            =⟨ to-transp (↓-idf-ua-in _ idp) ⟩
          φ.f (G.comp a b)
            =⟨ φ.pres-comp a b ⟩
          H.comp (φ.f a) (φ.f b)
            =⟨ ! (to-transp (↓-idf-ua-in _ idp))
               |in-ctx (λ w → H.comp (φ.f a) w) ⟩
          H.comp (φ.f a) (transport (λ C → C) (ua (φ.f , ie)) b) ∎

      comp= : G.comp == H.comp [ (λ C → C → C → C) ↓ ua (φ.f , ie) ]
      comp= =
        ↓-→-from-transp $ λ= $ λ a →
          transport (λ C → C → C) (ua (φ.f , ie)) (G.comp a)
            =⟨ to-transp (comp=' a) ⟩
          H.comp (φ.f a)
            =⟨ ! (to-transp (↓-idf-ua-in _ idp)) |in-ctx (λ w → H.comp w) ⟩
          H.comp (transport (λ C → C) (ua (φ.f , ie)) a) ∎

    group-ua-el : ap Group.El group-ua == ua (φ.f , ie)
    group-ua-el = ap3-lemma-el (ua (φ.f , ie)) _ _

{- equality of homomorphisms -}
abstract
  hom= : ∀ {i j} {G : Group i} {H : Group j} (φ ψ : (G →ᴳ H))
    → GroupHom.f φ == GroupHom.f ψ → φ == ψ
  hom= {H = H} _ _ p =
   ap (uncurry group-hom)
      (pair= p (prop-has-all-paths-↓
                 (Π-level (λ _ → Π-level (λ _ → Group.El-level H _ _)))))

  hom=-↓ : ∀ {i j k} {A : Type i} {G : A → Group j} {H : A → Group k} {x y : A}
    {p : x == y} (φ : G x →ᴳ H x) (ψ : G y →ᴳ H y)
    → GroupHom.f φ == GroupHom.f ψ
      [ (λ a → Group.El (G a) → Group.El (H a)) ↓ p ]
    → φ == ψ [ (λ a → G a →ᴳ H a) ↓ p ]
  hom=-↓ {p = idp} = hom=

{- homomorphism from equality of groups -}
coeᴳ : ∀ {i} {G H : Group i} → G == H → (G →ᴳ H)
coeᴳ idp = idhom _

coe!ᴳ : ∀ {i} {G H : Group i} → G == H → (H →ᴳ G)
coe!ᴳ idp = idhom _

coeᴳ-fun : ∀ {i} {G H : Group i} (p : G == H)
  → GroupHom.f (coeᴳ p) == coe (ap Group.El p)
coeᴳ-fun idp = idp

coe!ᴳ-fun : ∀ {i} {G H : Group i} (p : G == H)
  → GroupHom.f (coe!ᴳ p) == coe! (ap Group.El p)
coe!ᴳ-fun idp = idp

coeᴳ-β : ∀ {i} {G H : Group i} (iso : G ≃ᴳ H)
  → coeᴳ (group-ua iso) == fst iso
coeᴳ-β (φ , ie) = hom= _ _ $
  coeᴳ-fun (group-ua (φ , ie))
  ∙ ap coe (group-ua-el (φ , ie))
  ∙ λ= (coe-β (GroupHom.f φ , ie))

{- algebraic properties -}

∘ᴳ-unit-r : ∀ {i j} {G : Group i} {H : Group j} (φ : G →ᴳ H)
  → φ ∘ᴳ idhom G == φ
∘ᴳ-unit-r φ = idp

∘ᴳ-unit-l : ∀ {i j} {G : Group i} {H : Group j} (φ : G →ᴳ H)
  → idhom H ∘ᴳ φ == φ
∘ᴳ-unit-l φ = hom= _ _ $ idp

∘ᴳ-assoc : ∀ {i j k l} {G : Group i} {H : Group j} {K : Group k} {L : Group l}
  (χ : K →ᴳ L) (ψ : H →ᴳ K) (φ : G →ᴳ H)
  → (χ ∘ᴳ ψ) ∘ᴳ φ == χ ∘ᴳ ψ ∘ᴳ φ
∘ᴳ-assoc χ ψ φ = hom= _ _ $ idp

{- homomorphism with kernel zero is injective -}
module _ {i j} {G : Group i} {H : Group j} (φ : (G →ᴳ H)) where

  private
    module G = Group G
    module H = Group H
    module φ = GroupHom φ

  zero-kernel-injective : ((g : G.El) → φ.f g == H.ident → g == G.ident)
    → ((g₁ g₂ : G.El) → φ.f g₁ == φ.f g₂ → g₁ == g₂)
  zero-kernel-injective f g₁ g₂ p =
    ! (group-inv-inv G g₁) ∙ group-inv-unique-r G (G.inv g₁) g₂ (f _ $
      φ.f (G.comp (G.inv g₁) g₂)
        =⟨ φ.pres-comp (G.inv g₁) g₂ ⟩
      H.comp (φ.f (G.inv g₁)) (φ.f g₂)
        =⟨ φ.pres-inv g₁ |in-ctx (λ w → H.comp w (φ.f g₂)) ⟩
      H.comp (H.inv (φ.f g₁)) (φ.f g₂)
        =⟨ p |in-ctx (λ w → H.comp (H.inv w) (φ.f g₂)) ⟩
      H.comp (H.inv (φ.f g₂)) (φ.f g₂)
        =⟨ H.invl (φ.f g₂) ⟩
      H.ident ∎)

{- constant homomorphism -}
module _ where
  cst-hom : ∀ {i j} {G : Group i} {H : Group j} → (G →ᴳ H)
  cst-hom {H = H} = group-hom (cst ident) (λ _ _ → ! (unitl _))
    where open Group H

  pre∘-cst-hom : ∀ {i j k} {G : Group i} {H : Group j} {K : Group k}
    (φ : H →ᴳ K)
    → φ ∘ᴳ cst-hom {G = G} {H = H} == cst-hom
  pre∘-cst-hom φ = hom= _ _ (λ= (λ g → GroupHom.pres-ident φ))

{- if an injective homomorphism is merely surjective, then it is
 - fully surjective -}
module _ {i j} {G : Group i} {H : Group j} (φ : G →ᴳ H) where

  private
    module G = Group G
    module H = Group H
    module φ = GroupHom φ

  module _ (inj : (g₁ g₂ : G.El) → φ.f g₁ == φ.f g₂ → g₁ == g₂)
    (msurj : (h : H.El) → Trunc -1 (Σ G.El (λ g → φ.f g == h))) where

{- a surjective and injective homomorphism is an isomorphism -}
module _ {i j} {G : Group i} {H : Group j} (φ : G →ᴳ H) where

  private
    module G = Group G
    module H = Group H
    module φ = GroupHom φ

  module _ (inj : (g₁ g₂ : G.El) → φ.f g₁ == φ.f g₂ → g₁ == g₂)
    (surj : (h : H.El) → Trunc -1 (Σ G.El (λ g → φ.f g == h))) where

    private
      image-prop : (h : H.El) → is-prop (Σ G.El (λ g → φ.f g == h))
      image-prop h = all-paths-is-prop $ λ {(g₁ , p₁) (g₂ , p₂) →
        pair= (inj g₁ g₂ (p₁ ∙ ! p₂)) (prop-has-all-paths-↓ (H.El-level _ _))}

    surj-inj-is-equiv : is-equiv φ.f
    surj-inj-is-equiv = contr-map-is-equiv
      (λ h → let (g₁ , p₁) = Trunc-rec (image-prop h) (idf _) (surj h) in
        ((g₁ , p₁) , (λ {(g₂ , p₂) →
          pair= (inj g₁ g₂ (p₁ ∙ ! p₂))
                (prop-has-all-paths-↓ (H.El-level _ _))})))

module _ {i} {G H : Group i} (φ : G →ᴳ H) where

  private
    module G = Group G
    module H = Group H
    module φ = GroupHom φ

  module _ (inj : (g₁ g₂ : G.El) → φ.f g₁ == φ.f g₂ → g₁ == g₂)
    (surj : (h : H.El) → Trunc -1 (Σ G.El (λ g → φ.f g == h))) where

    surj-inj-iso : G ≃ᴳ H
    surj-inj-iso = (φ , surj-inj-is-equiv φ inj surj)

    surj-inj-path : G == H
    surj-inj-path = group-ua surj-inj-iso

{- negation is a homomorphism in an abelian gruop -}
inv-hom : ∀ {i} (G : Group i) (G-abelian : is-abelian G) → GroupHom G G
inv-hom G G-abelian = record {
  f = Group.inv G;
  pres-comp = λ g₁ g₂ →
    group-inv-comp G g₁ g₂ ∙ G-abelian (Group.inv G g₂) (Group.inv G g₁)}

inv-hom-natural : ∀ {i j} {G : Group i} {H : Group j}
  (G-abelian : is-abelian G) (H-abelian : is-abelian H) (φ : G →ᴳ H)
  → φ ∘ᴳ inv-hom G G-abelian == inv-hom H H-abelian ∘ᴳ φ
inv-hom-natural _ _ φ = hom= _ _ $ λ= $ GroupHom.pres-inv φ

{- two homomorphisms into an abelian group can be composed with
 - the group operation -}
module _ {i} {G H : Group i} (H-abelian : is-abelian H)
  (φ ψ : G →ᴳ H) where

  private
    module G = Group G
    module H = Group H
    module φ = GroupHom φ
    module ψ = GroupHom ψ

  comp-hom : G →ᴳ H
  comp-hom = record {
    f = λ g → H.comp (φ.f g) (ψ.f g);
    pres-comp = λ g₁ g₂ →
      H.comp (φ.f (G.comp g₁ g₂)) (ψ.f (G.comp g₁ g₂))
        =⟨ ap2 H.comp (φ.pres-comp g₁ g₂) (ψ.pres-comp g₁ g₂) ⟩
      H.comp (H.comp (φ.f g₁) (φ.f g₂)) (H.comp (ψ.f g₁) (ψ.f g₂))
        =⟨ lemma (φ.f g₁) (φ.f g₂) (ψ.f g₁) (ψ.f g₂) ⟩
      H.comp (H.comp (φ.f g₁) (ψ.f g₁)) (H.comp (φ.f g₂) (ψ.f g₂)) ∎}

    where
    lemma : (h₁ h₂ h₃ h₄ : H.El) →
      H.comp (H.comp h₁ h₂) (H.comp h₃ h₄)
      == H.comp (H.comp h₁ h₃) (H.comp h₂ h₄)
    lemma h₁ h₂ h₃ h₄ =
      (h₁ □ h₂) □ (h₃ □ h₄)
         =⟨ H.assoc h₁ h₂ (h₃ □ h₄) ⟩
       h₁ □ (h₂ □ (h₃ □ h₄))
         =⟨ H-abelian h₃ h₄ |in-ctx (λ w → h₁ □ (h₂ □ w)) ⟩
       h₁ □ (h₂ □ (h₄ □ h₃))
         =⟨ ! (H.assoc h₂ h₄ h₃) |in-ctx (λ w → h₁ □ w) ⟩
       h₁ □ ((h₂ □ h₄) □ h₃)
         =⟨ H-abelian (h₂ □ h₄) h₃ |in-ctx (λ w → h₁ □ w) ⟩
       h₁ □ (h₃ □ (h₂ □ h₄))
         =⟨ ! (H.assoc h₁ h₃ (h₂ □ h₄)) ⟩
       (h₁ □ h₃) □ (h₂ □ h₄) ∎
       where
        infix 80 _□_
        _□_ = H.comp


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

-- The category of relations is cartesian and (by self-duality) co-cartesian.
-- Perhaps slightly counter-intuitively if you're used to categories which act
-- like Sets, the product acts on objects as the disjoint union.

open import Data.Empty.Polymorphic using (⊥; ⊥-elim)
import Data.Product as ×
open × using (_,_)
open import Data.Sum using (_⊎_; inj₁; inj₂; [_,_]′)
open import Function using (case_of_; flip)
open import Level using (Lift; lift)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)

open import Categories.Category.Cartesian using (Cartesian; module CartesianMonoidal)
open import Categories.Category.Core using (Category)
open import Categories.Category.Cocartesian using (Cocartesian)
open import Categories.Category.Instance.Rels using (Rels)

module _ {o ℓ} where

  Rels-Cartesian : Cartesian (Rels o ℓ)
  Rels-Cartesian = record
    { terminal = record
      { ⊤ = ⊥
      ; ⊤-is-terminal = record
        { ! = λ { _ (lift ()) }
        ; !-unique = λ _ → (λ { {_} {lift ()} }) , (λ { {_} {lift ()} })
        }
      }
    ; products = record
      { product = λ {A} {B} → record
        { A×B = A ⊎ B
        ; π₁ = [ (λ x y → Lift ℓ (x ≡ y) ) , (λ _ _ → ⊥) ]′
        ; π₂ = [ (λ _ _ → ⊥) , (λ x y → Lift ℓ (x ≡ y)) ]′
        ; ⟨_,_⟩ = λ L R c → [ L c , R c ]′
        ; project₁ = (λ { (inj₁ x , r , lift refl) → r})
          , λ r → inj₁ _ , r , lift refl
        ; project₂ = (λ { (inj₂ _ , r , lift refl) → r })
          , (λ r → inj₂ _ , r , lift refl)
        ; unique =
            λ { (p , q) (p′ , q′) → (λ { {_} {inj₁ a} r → case (q {_} {a} r) of λ { (inj₁ .a , s , lift refl) → s}
                                       ; {_} {inj₂ b} r → case (q′ {_} {b} r) of λ { (inj₂ .b , s , lift refl) → s} })
                                   , λ { {_} {inj₁ a} hxa → p (inj₁ a , hxa , lift refl)
                                       ; {_} {inj₂ b} hxb → p′ (inj₂ b , hxb , lift refl) } }
        }
      }
    }

  module Rels-CartesianMonoidal = CartesianMonoidal _ Rels-Cartesian
  open Rels-CartesianMonoidal renaming (monoidal to Rels-Monoidal) public

  -- because Rels is dual to itself, the proof that it is cocartesian resembles the proof that it's cartesian
  -- Rels is not self-dual 'on the nose', so we can't use duality proper.
  Rels-Cocartesian : Cocartesian (Rels o ℓ)
  Rels-Cocartesian = record
    { initial = record
      { ⊥ = ⊥
      ; ⊥-is-initial = record
        { ! = λ ()
        ; !-unique = λ _ → (λ { {()} }) , (λ { {()} })
        }
      }
    ; coproducts = record
      { coproduct = λ {A} {B} → record
        { A+B = A ⊎ B
        ; i₁ = λ a → [ (λ a′ → Lift ℓ (a ≡ a′)) , (λ _ → ⊥) ]′
        ; i₂ = λ b → [ (λ _ → ⊥) , (λ b′ → Lift ℓ (b ≡ b′)) ]′
        ; [_,_] = λ L R a+b c → [ flip L c , flip R c ]′ a+b
        ; inject₁ = (λ { (inj₁ x , lift refl , fxy) → fxy})
          , λ r → inj₁ _ , lift refl , r
        ; inject₂ = (λ { (inj₂ _ , lift refl , r) → r })
          , (λ r → inj₂ _ , lift refl , r)
        ; unique = λ { (p , q) (p′ , q′) → (λ { {inj₁ a} r → case (q {a} r) of λ { (inj₁ .a , lift refl , s) → s}
                                              ; {inj₂ b} r → case (q′ {b} r) of λ { (inj₂ .b , lift refl , s) → s} })
                                          , λ { {inj₁ a} hxa → p (inj₁ a , lift refl , hxa)
                                              ; {inj₂ b} hxb → p′ (inj₂ b , lift refl , hxb) } }
        }
      }
    }


{-

This file contains:

- Properties of 2-groupoid truncations

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.HITs.2GroupoidTruncation.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Univalence

open import Cubical.HITs.2GroupoidTruncation.Base

private
  variable
    ℓ : Level
    A : Type ℓ

rec : ∀ {B : Type ℓ} → is2Groupoid B → (A → B) → ∥ A ∥₄ → B
rec gB f ∣ x ∣₄ = f x
rec gB f (squash₄ _ _ _ _ _ _ t u i j k l) =
  gB _ _ _ _ _ _ (λ m n o → rec gB f (t m n o)) (λ m n o → rec gB f (u m n o))
     i j k l

elim : {B : ∥ A ∥₄ → Type ℓ}
       (bG : (x : ∥ A ∥₄) → is2Groupoid (B x))
       (f : (x : A) → B ∣ x ∣₄) (x : ∥ A ∥₄) → B x
elim bG f ∣ x ∣₄ = f x
elim bG f (squash₄ x y p q r s u v i j k l) =
  isOfHLevel→isOfHLevelDep 4 bG _ _ _ _ _ _
    (λ j k l → elim bG f (u j k l)) (λ j k l → elim bG f (v j k l))
    (squash₄ x y p q r s u v)
    i j k l

elim2 : {B : ∥ A ∥₄ → ∥ A ∥₄ → Type ℓ}
        (gB : ((x y : ∥ A ∥₄) → is2Groupoid (B x y)))
        (g : (a b : A) → B ∣ a ∣₄ ∣ b ∣₄)
        (x y : ∥ A ∥₄) → B x y
elim2 gB g = elim (λ _ → is2GroupoidΠ (λ _ → gB _ _))
                  (λ a → elim (λ _ → gB _ _) (g a))

elim3 : {B : (x y z : ∥ A ∥₄) → Type ℓ}
        (gB : ((x y z : ∥ A ∥₄) → is2Groupoid (B x y z)))
        (g : (a b c : A) → B ∣ a ∣₄ ∣ b ∣₄ ∣ c ∣₄)
        (x y z : ∥ A ∥₄) → B x y z
elim3 gB g = elim2 (λ _ _ → is2GroupoidΠ (λ _ → gB _ _ _))
                   (λ a b → elim (λ _ → gB _ _ _) (g a b))

2GroupoidTruncIs2Groupoid : is2Groupoid ∥ A ∥₄
2GroupoidTruncIs2Groupoid a b p q r s = squash₄ a b p q r s

2GroupoidTruncIdempotent≃ : is2Groupoid A → ∥ A ∥₄ ≃ A
2GroupoidTruncIdempotent≃ {A = A} hA = isoToEquiv f
  where
  f : Iso ∥ A ∥₄ A
  Iso.fun f = rec hA (idfun A)
  Iso.inv f x = ∣ x ∣₄
  Iso.rightInv f _ = refl
  Iso.leftInv f = elim (λ _ → isOfHLevelSuc 4 2GroupoidTruncIs2Groupoid _ _) (λ _ → refl)

2GroupoidTruncIdempotent : is2Groupoid A → ∥ A ∥₄ ≡ A
2GroupoidTruncIdempotent hA = ua (2GroupoidTruncIdempotent≃ hA)


-- {-# OPTIONS --show-implicit #-}
-- {-# OPTIONS -v tc.meta:25 #-}
module NoBlockOnLevel where

open import Common.Level
open import Common.Product

BSetoid : ∀ c → Set (lsuc c)
BSetoid c = Set c

infixr 0 _⟶_

postulate
  _⟶_ : ∀ {f t} → BSetoid f → BSetoid t → Set (f ⊔ t)
  →-to-⟶ : ∀ {a b} {A : Set a} {B : BSetoid b} →
           (A → B) → A ⟶ B

postulate
  a b p : Level
  A : Set a
  B : Set b
  P : A → B → Set p

-- This will leave unsolved metas if we give up on an unsolved level constraint
-- when checking argument spines. Since we can't match on levels it's safe to keep
-- checking later constraints even if they depend on the unsolved levels.
f : (∃ λ x → ∃ λ y → P x y) ⟶ (∃ λ y → ∃ λ x → P x y)
f = →-to-⟶ λ p → proj₁ (proj₂ p) , proj₁ p , proj₂ (proj₂ p)


{-

This file contains:

- Definition of set truncations

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.HITs.SetTruncation.Base where

open import Cubical.Core.Primitives

-- set truncation as a higher inductive type:

data ∥_∥₂ {ℓ} (A : Type ℓ) : Type ℓ where
  ∣_∣₂ : A → ∥ A ∥₂
  squash₂ : ∀ (x y : ∥ A ∥₂) (p q : x ≡ y) → p ≡ q


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

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

open import Cubical.Algebra.Ring
open import Cubical.Algebra.Algebra

open import Cubical.Categories.Category

open Category
open AlgebraHoms

private
 variable
  ℓ ℓ' : Level

module _ (R : Ring ℓ) where
  AlgebrasCategory : Category (ℓ-suc (ℓ-max ℓ ℓ')) (ℓ-max ℓ ℓ')
  ob AlgebrasCategory       = Algebra R _
  Hom[_,_] AlgebrasCategory = AlgebraHom
  id AlgebrasCategory {A}   = idAlgebraHom A
  _⋆_ AlgebrasCategory      = compAlgebraHom
  ⋆IdL AlgebrasCategory     = compIdAlgebraHom
  ⋆IdR AlgebrasCategory     = idCompAlgebraHom
  ⋆Assoc AlgebrasCategory   = compAssocAlgebraHom
  isSetHom AlgebrasCategory = isSetAlgebraHom _ _


open import Oscar.Prelude
open import Oscar.Data.𝟘

module Oscar.Data.Decidable where

data Decidable {a} (A : Ø a) : Ø a where
  ↑_ : A → Decidable A
  ↓_ : ¬ A → Decidable A


{-# OPTIONS --universe-polymorphism #-}
module Categories.Support.EqReasoning where

open import Categories.Support.Equivalence using (Setoid; module Setoid)
open import Relation.Binary.PropositionalEquality using () renaming (_≡_ to _≣_; trans to ≣-trans; sym to ≣-sym; refl to ≣-refl)

module SetoidReasoning {s₁ s₂} (S : Setoid s₁ s₂) where
  open Setoid S

  infix  4 _IsRelatedTo_
  infix  1 begin_
  infixr 2 _≈⟨_⟩_ _↓⟨_⟩_ _↑⟨_⟩_ _↓≣⟨_⟩_ _↑≣⟨_⟩_ _↕_
  infix  3 _∎

  -- This seemingly unnecessary type is used to make it possible to
  -- infer arguments even if the underlying equality evaluates.

  data _IsRelatedTo_ (x y : Carrier) : Set s₂ where
    relTo : (x∼y : x ≈ y) → x IsRelatedTo y

  .begin_ : ∀ {x y} → x IsRelatedTo y → x ≈ y
  begin relTo x∼y = x∼y

  ._↓⟨_⟩_ : ∀ x {y z} → x ≈ y → y IsRelatedTo z → x IsRelatedTo z
  _ ↓⟨ x∼y ⟩ relTo y∼z = relTo (trans x∼y y∼z)
    -- where open IsEquivalence isEquivalence

  ._↑⟨_⟩_ : ∀ x {y z} → y ≈ x → y IsRelatedTo z → x IsRelatedTo z
  _ ↑⟨ y∼x ⟩ relTo y∼z = relTo (trans (sym y∼x) y∼z)
    -- where open IsEquivalence isEquivalence

  -- the syntax of the ancients, for compatibility
  ._≈⟨_⟩_ : ∀ x {y z} → x ≈ y → y IsRelatedTo z → x IsRelatedTo z
  _≈⟨_⟩_ = _↓⟨_⟩_

  ._↓≣⟨_⟩_ : ∀ x {y z} → x ≣ y → y IsRelatedTo z → x IsRelatedTo z
  _ ↓≣⟨ ≣-refl ⟩ y∼z = y∼z

  ._↑≣⟨_⟩_ : ∀ x {y z} → y ≣ x → y IsRelatedTo z → x IsRelatedTo z
  _ ↑≣⟨ ≣-refl ⟩ y∼z = y∼z

  ._↕_ : ∀ x {z} → x IsRelatedTo z → x IsRelatedTo z
  _ ↕ x∼z = x∼z

  ._∎ : ∀ x → x IsRelatedTo x
  _∎ _ = relTo refl
    -- where open IsEquivalence isEquivalence

module ≣-reasoning {ℓ} (S : Set ℓ) where
  infix  4 _IsRelatedTo_
  infix  2 _∎
  infixr 2 _≈⟨_⟩_
  infixr 2 _↓⟨_⟩_
  infixr 2 _↑⟨_⟩_
  infixr 2 _↕_
  infix  1 begin_

  -- This seemingly unnecessary type is used to make it possible to
  -- infer arguments even if the underlying equality evaluates.

  data _IsRelatedTo_ (x y : S) : Set ℓ where
    relTo : (x∼y : x ≣ y) → x IsRelatedTo y

  begin_ : ∀ {x y} → x IsRelatedTo y → x ≣ y
  begin relTo x∼y = x∼y

  -- the syntax of the ancients, for compatibility
  _≈⟨_⟩_ : ∀ x {y z} → x ≣ y → y IsRelatedTo z → x IsRelatedTo z
  _ ≈⟨ x∼y ⟩ relTo y∼z = relTo (≣-trans x∼y y∼z)

  _↓⟨_⟩_ : ∀ x {y z} → x ≣ y → y IsRelatedTo z → x IsRelatedTo z
  _ ↓⟨ x∼y ⟩ relTo y∼z = relTo (≣-trans x∼y y∼z)

  _↑⟨_⟩_ : ∀ x {y z} → y ≣ x → y IsRelatedTo z → x IsRelatedTo z
  _ ↑⟨ y∼x ⟩ relTo y∼z = relTo (≣-trans (≣-sym y∼x) y∼z)

  _↕_ : ∀ x {z} → x IsRelatedTo z → x IsRelatedTo z
  _ ↕ x∼z = x∼z

  _∎ : ∀ x → x IsRelatedTo x
  _∎ _ = relTo ≣-refl


module 060-commutative-group where

-- We need groups.

open import 050-group

record CommutativeGroup
  {M : Set}
  (_==_ : M -> M -> Set)
  (_*_ : M -> M -> M)
  (id : M)
  (invert : M -> M)
  : Set1 where

  field
    group : Group _==_ _*_ id invert
    comm : ∀ {r s} -> (r * s) == (s * r)

  open Group group public

  -- Nothing proven here yet.


-- Andreas, 2017-09-09, re issue #2732
-- eta-contraction needed in termination checker

-- {-# OPTIONS -v term:30 #-}

open import Agda.Builtin.Equality

data O (A : Set) : Set where
  leaf : O A
  node : (A → O A) → O A

postulate
  A : Set
  a : A

test1 : (t u : O A) → O A
test1 leaf     leaf     = leaf
test1 leaf     (node g) = test1 leaf (g a)
test1 (node f) leaf     = test1 (f a) (node f)
test1 (node f) (node g) = test1 (node λ x → f x) (g a)
-- Should pass even with the eta-expansion.

data Q (A : Set) : Set where
  leaf : Q A
  node : (f g : A → Q A) (p : f ≡ g) → Q A

-- Having various call arguments in eta-expanded form.
test : (t u : Q A) → Q A
test leaf leaf = leaf
test leaf (node f g p) = test leaf (f a)
test (node f g p) leaf = test (g a) (node f g p)
test (node f .f refl) (node g g' p) = test (node (λ x → f x) _ refl) (g' a)


{-

This module converts between the path equality
and the inductively define equality types.

- _≡c_ stands for "c"ubical equality.
- _≡p_ stands for "p"ropositional equality.

TODO: reconsider naming scheme.
-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}

module Cubical.Data.Equality where

open import Cubical.Foundations.Prelude
  renaming ( _≡_ to _≡c_ ; refl to reflc )
  public
open import Agda.Builtin.Equality
  renaming ( _≡_ to _≡p_ ; refl to reflp )
  public

open import Cubical.Foundations.Isomorphism

private
 variable
  ℓ : Level
  A : Type ℓ
  x y z : A

ptoc : x ≡p y → x ≡c y
ptoc reflp = reflc

ctop : x ≡c y → x ≡p y
ctop p = transport (cong (λ u → _ ≡p u) p) reflp

ptoc-ctop : (p : x ≡c y) → ptoc (ctop p) ≡c p
ptoc-ctop p =
  J (λ _ h → ptoc (ctop h) ≡c h) (cong ptoc (transportRefl reflp)) p

ctop-ptoc : (p : x ≡p y) → ctop (ptoc p) ≡c p
ctop-ptoc {x = x} reflp = transportRefl reflp

p≅c : {x y : A} → Iso (x ≡c y) (x ≡p y)
p≅c = iso ctop ptoc ctop-ptoc ptoc-ctop

p-c : {x y : A} → (x ≡c y) ≡c (x ≡p y)
p-c = isoToPath p≅c

p=c : {x y : A} → (x ≡c y) ≡p (x ≡p y)
p=c = ctop p-c