module Termination.Sized.DeBruijnBase where

open import Data.Maybe
open import Data.Maybe.Effectful
open import Function -- composition, identity
open import Relation.Binary.PropositionalEquality hiding ( subst )
open ≡-Reasoning

open import Effect.Functor

fmap : {A B : Set} -> (A -> B) -> Maybe A -> Maybe B
fmap = RawFunctor._<$>_ functor

-- OR:
-- open RawFunctor MaybeFunctor using () renaming (_<$>_ to fmap)

fmapExt : {A B : Set}{f g : A -> B} ->
          (forall a -> f a ≡ g a) -> forall m -> fmap f m ≡ fmap g m
fmapExt f≡g nothing  = refl
fmapExt f≡g (just a) = cong just (f≡g a)

fmapLaw1 : {A : Set}(a : Maybe A) -> fmap id a ≡ a
fmapLaw1 nothing  = refl
fmapLaw1 (just a) = refl

fmapLaw2 : {A B C : Set}(f : B -> C)(g : A -> B) ->
          forall m -> fmap f (fmap g m) ≡ fmap (f ∘ g) m
fmapLaw2 f g nothing  = refl
fmapLaw2 f g (just a) = refl

-- untyped de Bruijn terms
data Lam (A : Set) : Set where
    var : A -> Lam A
    app : Lam A -> Lam A -> Lam A
    abs : Lam (Maybe A) -> Lam A

-- functoriality of Lam
lam : {A B : Set} -> (A -> B) -> Lam A -> Lam B
lam f (var a)     = var (f a)
lam f (app t1 t2) = app (lam f t1) (lam f t2)
lam f (abs r)     = abs (lam (fmap f) r)

lamExt : {A B : Set}{f g : A -> B} ->
         (forall a -> f a ≡ g a) -> forall t -> lam f t ≡ lam g t
lamExt f≡g (var a)   = cong var (f≡g a)
lamExt f≡g (abs r)   = cong abs (lamExt (fmapExt f≡g) r)
lamExt f≡g (app r s) = cong₂ app (lamExt f≡g r) (lamExt f≡g s)

lamLaw1 : {A : Set}(t : Lam A) -> lam id t ≡ t
lamLaw1 (var a) = refl
lamLaw1 (app r s) = begin
  lam id (app r s)
     ≡⟨ refl ⟩
  app (lam id r) (lam id s)
     ≡⟨ cong (app (lam id r)) (lamLaw1 s) ⟩
  app (lam id r) s
     ≡⟨ cong (\ x -> app x s) (lamLaw1 r) ⟩
  app r s
     ∎
lamLaw1 (abs t) = begin
  lam id (abs t)
     ≡⟨ refl ⟩
  abs (lam (fmap id) t)
     ≡⟨ cong abs (lamExt {g = id} fmapLaw1 t) ⟩
  abs (lam id t)
     ≡⟨ cong abs (lamLaw1 t) ⟩
  abs t
     ∎

lamLaw2 : {A B C : Set}(f : B -> C)(g : A -> B) ->
          forall t -> lam f (lam g t) ≡ lam (f ∘ g) t
lamLaw2 f g (var a)   = refl
lamLaw2 f g (app r s) = cong₂ app (lamLaw2 f g r) (lamLaw2 f g s)
lamLaw2 f g (abs t)   = begin
  lam f (lam g (abs t))
     ≡⟨ refl ⟩
  lam f (abs (lam (fmap g) t))
     ≡⟨ refl ⟩
  abs (lam (fmap f) (lam (fmap g) t))
     ≡⟨ cong abs (lamLaw2 (fmap f) (fmap g) t) ⟩
  abs (lam (fmap f ∘ fmap g) t)
     ≡⟨ cong abs (lamExt (fmapLaw2 f g) t) ⟩
  abs (lam (fmap (f ∘ g)) t)
     ≡⟨ refl ⟩
  lam (f ∘ g) (abs t)
     ∎

-- lifting a substitution A -> Lam B under a binder
lift : {A B : Set} -> (A -> Lam B) -> Maybe A -> Lam (Maybe B)
lift f nothing  = var nothing
lift f (just a) = lam just (f a)

-- extensionality of lifting
liftExt : {A B : Set}{f g : A -> Lam B} ->
   ((a : A) -> f a ≡ g a) -> (t : Maybe A) -> lift f t ≡ lift g t
liftExt H nothing  = refl
liftExt H (just a) = cong (lam just) $ H a

-- simultaneous substitution
subst : {A B : Set} -> (A -> Lam B) -> Lam A -> Lam B
subst f (var a)     = f a
subst f (app t1 t2) = app (subst f t1) (subst f t2)
subst f (abs r)     = abs (subst (lift f) r)

-- extensionality of subst
substExt : {A B : Set}{f g : A -> Lam B} ->
   ((a : A) -> f a ≡ g a) -> (t : Lam A) -> subst f t ≡ subst g t
substExt H (var a)     = H a
substExt {f = f}{g = g} H (app t1 t2) = begin
  subst f (app t1 t2)
     ≡⟨ refl ⟩
  app (subst f t1) (subst f t2)
     ≡⟨ cong (\ x -> app x (subst f t2)) (substExt H t1) ⟩
  app (subst g t1) (subst f t2)
     ≡⟨ cong (\ x -> app (subst g t1) x) (substExt H t2) ⟩
  app (subst g t1) (subst g t2)
     ∎
substExt {f = f}{g = g} H (abs r) = begin
  subst f (abs r)
     ≡⟨ refl ⟩
  abs (subst (lift f) r)
     ≡⟨ cong abs (substExt (liftExt H) r) ⟩
  abs (subst (lift g) r)
     ≡⟨ refl ⟩
  subst g (abs r)
     ∎

-- Lemma: lift g ∘ fmap f = lift (g ∘ f)
liftLaw1 : {A B C : Set}(f : A -> B)(g : B -> Lam C)(t : Maybe A) ->
  lift g (fmap f t) ≡ lift (g ∘ f) t
liftLaw1 f g nothing = begin
  lift g (fmap f nothing)
     ≡⟨ refl ⟩
  lift g nothing
     ≡⟨ refl ⟩
  var nothing
     ≡⟨ refl ⟩
  lift (g ∘ f) nothing
     ∎
liftLaw1 f g (just a) = begin
  lift g (fmap f (just a))
     ≡⟨ refl ⟩
  lift g (just (f a))
     ≡⟨ refl ⟩
  lam just (g (f a))
     ≡⟨ refl ⟩
  lift (g ∘ f) (just a)
     ∎

-- Lemma: subst g ∘ lam f t = subst (g ∘ f)
substLaw1 : {A B C : Set}(f : A -> B)(g : B -> Lam C)(t : Lam A) ->
  subst g (lam f t) ≡ subst (g ∘ f) t

substLaw1 f g (var a) = refl

substLaw1 f g (app t1 t2) = begin
  subst g (lam f (app t1 t2))
     ≡⟨ refl ⟩
  subst g (app (lam f t1) (lam f t2))
     ≡⟨ refl ⟩
  app (subst g (lam f t1)) (subst g (lam f t2))
     ≡⟨ cong (\ x -> app x (subst g (lam f t2))) (substLaw1 f g t1) ⟩
  app (subst (g ∘ f) t1) (subst g (lam f t2))
     ≡⟨ cong (\ x -> app (subst (g ∘ f) t1) x) (substLaw1 f g t2) ⟩
  app (subst (g ∘ f) t1) (subst (g ∘ f) t2)
     ∎

substLaw1 f g (abs r) =
  begin subst g (lam f (abs r))
     ≡⟨ refl ⟩
  subst g (abs (lam (fmap f) r))
     ≡⟨ refl ⟩
  abs (subst (lift g) (lam (fmap f) r))
     ≡⟨ cong abs (substLaw1 (fmap f) (lift g) r) ⟩
  abs (subst (lift g ∘ fmap f) r)
     ≡⟨ cong abs (substExt {f = lift g ∘ fmap f} {g = lift (g ∘ f)} (liftLaw1 f g) r) ⟩
  abs (subst (lift (g ∘ f)) r)
     ∎

-- Lemma: lift (lam f ∘ g) = lam f ∘ subst g
liftLaw2 : {A B C : Set}(f : B -> C)(g : A -> Lam B)(t : Maybe A) ->
  lift (lam f ∘ g) t ≡ lam (fmap f) (lift g t)
liftLaw2 f g nothing = begin
  lift (lam f ∘ g) nothing
     ≡⟨ refl ⟩
  var nothing
     ≡⟨ refl ⟩
  var (fmap f nothing)
     ≡⟨ refl ⟩
  lam (fmap f) (var nothing)
     ≡⟨ refl ⟩
  lam (fmap f) (lift g nothing)
     ∎
liftLaw2 f g (just a) = begin
  lift (lam f ∘ g) (just a)
     ≡⟨ refl ⟩
  lam just (lam f (g a))
     ≡⟨ lamLaw2 just f (g a) ⟩
  lam (just ∘ f) (g a)
     ≡⟨ lamExt (\ a -> refl) (g a) ⟩
  lam (fmap f ∘ just) (g a)
     ≡⟨ sym (lamLaw2 (fmap f) just (g a)) ⟩
  lam (fmap f) (lam just (g a))
     ≡⟨ refl ⟩
  lam (fmap f) (lift g (just a))
     ∎

-- Lemma: subst (lam f ∘ g) = lam f ∘ subst g
substLaw2 : {A B C : Set}(f : B -> C)(g : A -> Lam B)(t : Lam A) ->
  subst (lam f ∘ g) t ≡ lam f (subst g t)

substLaw2 f g (var a) = refl

substLaw2 f g (app r s) = begin
  subst (lam f ∘ g) (app r s)
     ≡⟨ refl ⟩
  app (subst (lam f ∘ g) r) (subst (lam f ∘ g) s)
     ≡⟨ cong (app (subst (lam f ∘ g) r)) (substLaw2 f g s) ⟩
  app (subst (lam f ∘ g) r) (lam f (subst g s))
     ≡⟨ cong (\ x -> app x (lam f (subst g s))) (substLaw2 f g r) ⟩
  app (lam f (subst g r)) (lam f (subst g s))
     ≡⟨ refl ⟩
  lam f (app (subst g r) (subst g s))
     ≡⟨ refl ⟩
  lam f (subst g (app r s))
     ∎

substLaw2 f g (abs t) = begin
  subst (lam f ∘ g) (abs t)
     ≡⟨ refl ⟩
  abs (subst (lift (lam f ∘ g)) t)
     ≡⟨ cong abs (substExt (liftLaw2 f g) t) ⟩
  abs (subst (lam (fmap f) ∘ (lift g)) t)
     ≡⟨ cong abs (substLaw2 (fmap f) (lift g) t) ⟩
  abs (lam (fmap f) (subst (lift g) t))
     ≡⟨ refl ⟩
  lam f (abs (subst (lift g) t))
     ≡⟨ refl ⟩
  lam f (subst g (abs t))
     ∎


------------------------------------------------------------------------
-- The Agda standard library
--
-- Pointwise lifting of a predicate to a binary tree
------------------------------------------------------------------------

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

module Data.Tree.Binary.Relation.Unary.All where

open import Level
open import Data.Tree.Binary as Tree using (Tree; leaf; node)
open import Relation.Unary

private
  variable
    a b p q : Level
    A : Set a
    B : Set b

data All {A : Set a} (P : A → Set p) : Tree A → Set (a ⊔ p) where
  leaf : All P leaf
  node : ∀ {l m r} → All P l → P m → All P r → All P (node l m r)

module _ {P : A → Set p} {Q : A → Set q} where

  map : ∀[ P ⇒ Q ] → ∀[ All P ⇒ All Q ]
  map f leaf         = leaf
  map f (node l m r) = node (map f l) (f m) (map f r)


------------------------------------------------------------------------------
-- The LTC-PCF base
------------------------------------------------------------------------------

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

{-
LTC-PCF                               The logical framework (Agda)

* Logical constants                   * Curry-Howard isomorphism
* Equality                            * Identity type
* Term language and conversion rules  * Postulates
* Inductively defined predicates      * Inductive families
-}

module LTC-PCF.Base where

-- First-order logic with equality.
open import Common.FOL.FOL-Eq public

-- Common definitions.
open import Common.DefinitionsI public

infixl 7 _·_
infix  0 if_then_else_

------------------------------------------------------------------------------
-- The term language of LTC-PCF correspond to the PCF terms.

--   t ::= x
--      | t · t
--      | λ x.t
--      | fix x.t
--      | true | false | if
--      | zero | succ  | pred | iszero

-- NB. We define the PCF terms as constants. After that, we will
-- define some function symbols based on these constants for
-- convenience in writing.

postulate
  _·_                   : D → D → D    -- LTC-PCF application.
  lam                   : (D → D) → D  -- LTC-PCF λ-abstraction.
  fix                   : (D → D) → D  -- LTC-PCF fixed-point operator.
  true false if         : D            -- LTC-PCF partial Booleans.
  zero succ pred iszero : D            -- LTC-PCF partial natural numbers.

------------------------------------------------------------------------------
-- Definitions

-- We define some function symbols for convenience in writing.
abstract
  if_then_else_ : D → D → D → D
  if b then t else t' = if · b · t · t'

  succ₁ : D → D
  succ₁ n = succ · n

  pred₁ : D → D
  pred₁ n = pred · n

  iszero₁ : D → D
  iszero₁ n = iszero · n

------------------------------------------------------------------------------
-- Conversion rules

-- The conversion relation _conv_ satifies (Aczel 1977. The strength
-- of Martin-Löf's intuitionistic type theory with one universe,
-- p. 8).
--
-- x conv y <=> FOTC ⊢ x ≡ y,
--
-- therefore, we introduce the conversion rules as non-logical axioms.

-- N.B. We write the conversion rules on the defined function symbols
-- instead of on the PCF constants.

-- Conversion rule for the λ-abstraction and the application.
postulate beta : ∀ f a → lam f · a ≡ f a

-- Conversion rule for the fixed-pointed operator.
postulate fix-eq : ∀ f → fix f ≡ f (fix f)

-- Conversion rules for Booleans.
postulate
  -- if-true  : ∀ t {t'} → if · true  · t · t' ≡ t
  -- if-false : ∀ {t} t' → if · false · t · t' ≡ t'
  if-true  : ∀ t {t'} → (if true then t else t')  ≡ t
  if-false : ∀ {t} t' → (if false then t else t') ≡ t'

-- Conversion rules for pred.
postulate
  -- pred-0 : pred · zero ≡ zero
  -- pred-S : ∀ d → pred · (succ · d) ≡ d

 -- N.B. We don't need this equation in FOTC.
  pred-0 : pred₁ zero            ≡ zero
  pred-S : ∀ n → pred₁ (succ₁ n) ≡ n

-- Conversion rules for iszero.
postulate
  -- iszero-0 :       iszero · zero       ≡ true
  -- iszero-S : ∀ d → iszero · (succ · d) ≡ false
  iszero-0 : iszero₁ zero            ≡ true
  iszero-S : ∀ n → iszero₁ (succ₁ n) ≡ false

------------------------------------------------------------------------------
-- Discrimination rules

postulate
  t≢f : true ≢ false
  -- 0≢S : ∀ {d} → zero ≢ succ · d
  0≢S : ∀ {n} → zero ≢ succ₁ n


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

module Number.Prelude.Nat where

open import Cubical.Data.Nat.Order public using () renaming
  ( _<_      to _<ⁿᵗ_
  ; <-trans  to <ⁿ-trans -- TODO: use different version
  ; _≟_      to _≟ⁿ_
  ; lt       to ltⁿ
  ; gt       to gtⁿ
  ; eq       to eqⁿ
  ; ¬-<-zero to ¬-<ⁿ-zero
  )
open import Data.Nat public using () renaming
  ( _⊔_    to maxⁿ
  ; _⊓_    to minⁿ
  ; _+_    to _+ⁿ_
  ; _*_    to _·ⁿ_
  ; pred   to predⁿ
  )
open import Cubical.Data.Nat public using (suc; zero; ℕ; HasFromNat) renaming
  ( +-comm      to +ⁿ-comm
  ; +-assoc     to +ⁿ-assoc
  ; *-comm      to ·ⁿ-comm
  ; *-suc       to ·ⁿ-suc
  ; *-assoc     to ·ⁿ-assoc
  ; +-suc       to +ⁿ-suc
  ; *-distribˡ  to ·ⁿ-distribˡ
  ; *-distribʳ  to ·ⁿ-distribʳ
  ; *-identityʳ to ·ⁿ-identityʳ
  ; *-identityˡ to ·ⁿ-identityˡ
  ; snotz       to snotzⁿ
  ; injSuc      to injSucⁿ
  ; isSetℕ      to is-setⁿ
  ; inj-m+      to +ⁿ-preserves-≡ˡ
  ; inj-+m      to +ⁿ-preserves-≡ʳ
  ; inj-sm*     to ·ⁿ-reflects-≡ˡ'
  ; inj-*sm     to ·ⁿ-reflects-≡ʳ'
  )
open import Number.Instances.Nat as Nat public using () renaming
  ( bundle         to ℕbundle
  ; _<_            to _<ⁿ_
  ; 0<suc          to 0<ⁿsuc
  ; ·-nullifiesˡ   to ·ⁿ-nullifiesˡ
  ; ·-nullifiesʳ   to ·ⁿ-nullifiesʳ
  ; <-irrefl       to <ⁿ-irrefl
  ; suc-creates-<  to sucⁿ-creates-<ⁿ
  ; <-cotrans      to <ⁿ-cotrans
  ; ¬suc<0         to ¬suc<ⁿ0
  ; ·-reflects-<   to ·ⁿ-reflects-<ⁿ
  ; ·-preserves-<  to ·ⁿ-preserves-<ⁿ
  ; +-createsʳ-<   to +ⁿ-createsʳ-<ⁿ
  ; +-createsˡ-<   to +ⁿ-createsˡ-<ⁿ
  ; min-comm       to minⁿ-comm
  ; min-tightˡ     to minⁿ-tightˡ
  ; min-tightʳ     to minⁿ-tightʳ
  ; min-identity   to minⁿ-identity
  ; max-comm       to maxⁿ-comm
  ; max-tightˡ     to maxⁿ-tightˡ
  ; max-tightʳ     to maxⁿ-tightʳ
  ; max-identity   to maxⁿ-identity
  ; MinTrichtotomy to MinTrichtotomyⁿ
  ; MaxTrichtotomy to MaxTrichtotomyⁿ
  ; min-trichotomy to minⁿ-trichotomy
  ; max-trichotomy to maxⁿ-trichotomy
  ; is-min         to is-minⁿ
  ; is-max         to is-maxⁿ
  ; +-<-ext        to +ⁿ-<ⁿ-ext
  ; ·-reflects-≡ʳ  to ·ⁿ-reflects-≡ʳ
  ; ·-reflects-≡ˡ  to ·ⁿ-reflects-≡ˡ
  )

open import MorePropAlgebra.Definitions
open import MorePropAlgebra.Structures
open import Number.Structures2

open IsMonoid            Nat.+-Monoid            public using () renaming (is-identity to +ⁿ-identity)
open IsMonoid            Nat.·-Monoid            public using () renaming (is-identity to ·ⁿ-identity)
open IsSemiring          Nat.is-Semiring         public using () renaming (is-dist     to is-distⁿ)
open IsStrictLinearOrder Nat.<-StrictLinearOrder public using () renaming (is-tricho   to is-trichoⁿ)
-- <-StrictLinearOrder .IsStrictLinearOrder.is-trans  a b c = <-trans {a} {b} {c}


------------------------------------------------------------------------
-- The Agda standard library
--
-- A universe which includes several kinds of "relatedness" for sets,
-- such as equivalences, surjections and bijections
------------------------------------------------------------------------

module Function.Related where

open import Level
open import Function
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence as Eq      using (Equivalence)
open import Function.Injection   as Inj     using (Injection; _↣_)
open import Function.Inverse     as Inv     using (Inverse; _↔_)
open import Function.LeftInverse as LeftInv using (LeftInverse)
open import Function.Surjection  as Surj    using (Surjection)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P using (_≡_)

------------------------------------------------------------------------
-- Wrapper types

-- Synonyms which are used to make _∼[_]_ below "constructor-headed"
-- (which implies that Agda can deduce the universe code from an
-- expression matching any of the right-hand sides).

record _←_ {a b} (A : Set a) (B : Set b) : Set (a ⊔ b) where
  constructor lam
  field app-← : B → A

open _←_ public

record _↢_ {a b} (A : Set a) (B : Set b) : Set (a ⊔ b) where
  constructor lam
  field app-↢ : B ↣ A

open _↢_ public

------------------------------------------------------------------------
-- Relatedness

-- There are several kinds of "relatedness".

-- The idea to include kinds other than equivalence and bijection came
-- from Simon Thompson and Bengt Nordström. /NAD

data Kind : Set where
  implication reverse-implication
    equivalence
    injection reverse-injection
    left-inverse surjection
    bijection
    : Kind

-- Interpretation of the codes above. The code "bijection" is
-- interpreted as Inverse rather than Bijection; the two types are
-- equivalent.

infix 4 _∼[_]_

_∼[_]_ : ∀ {ℓ₁ ℓ₂} → Set ℓ₁ → Kind → Set ℓ₂ → Set _
A ∼[ implication         ] B = A → B
A ∼[ reverse-implication ] B = A ← B
A ∼[ equivalence         ] B = Equivalence (P.setoid A) (P.setoid B)
A ∼[ injection           ] B = Injection   (P.setoid A) (P.setoid B)
A ∼[ reverse-injection   ] B = A ↢ B
A ∼[ left-inverse        ] B = LeftInverse (P.setoid A) (P.setoid B)
A ∼[ surjection          ] B = Surjection  (P.setoid A) (P.setoid B)
A ∼[ bijection           ] B = Inverse     (P.setoid A) (P.setoid B)

-- A non-infix synonym.

Related : Kind → ∀ {ℓ₁ ℓ₂} → Set ℓ₁ → Set ℓ₂ → Set _
Related k A B = A ∼[ k ] B

-- The bijective equality implies any kind of relatedness.

↔⇒ : ∀ {k x y} {X : Set x} {Y : Set y} →
     X ∼[ bijection ] Y → X ∼[ k ] Y
↔⇒ {implication}         = _⟨$⟩_ ∘ Inverse.to
↔⇒ {reverse-implication} = lam ∘′ _⟨$⟩_ ∘ Inverse.from
↔⇒ {equivalence}         = Inverse.equivalence
↔⇒ {injection}           = Inverse.injection
↔⇒ {reverse-injection}   = lam ∘′ Inverse.injection ∘ Inv.sym
↔⇒ {left-inverse}        = Inverse.left-inverse
↔⇒ {surjection}          = Inverse.surjection
↔⇒ {bijection}           = id

-- Actual equality also implies any kind of relatedness.

≡⇒ : ∀ {k ℓ} {X Y : Set ℓ} → X ≡ Y → X ∼[ k ] Y
≡⇒ P.refl = ↔⇒ Inv.id

------------------------------------------------------------------------
-- Special kinds of kinds

-- Kinds whose interpretation is symmetric.

data Symmetric-kind : Set where
  equivalence bijection : Symmetric-kind

-- Forgetful map.

⌊_⌋ : Symmetric-kind → Kind
⌊ equivalence ⌋ = equivalence
⌊ bijection   ⌋ = bijection

-- The proof of symmetry can be found below.

-- Kinds whose interpretation include a function which "goes in the
-- forward direction".

data Forward-kind : Set where
  implication equivalence injection
    left-inverse surjection bijection : Forward-kind

-- Forgetful map.

⌊_⌋→ : Forward-kind → Kind
⌊ implication  ⌋→ = implication
⌊ equivalence  ⌋→ = equivalence
⌊ injection    ⌋→ = injection
⌊ left-inverse ⌋→ = left-inverse
⌊ surjection   ⌋→ = surjection
⌊ bijection    ⌋→ = bijection

-- The function.

⇒→ : ∀ {k x y} {X : Set x} {Y : Set y} → X ∼[ ⌊ k ⌋→ ] Y → X → Y
⇒→ {implication}  = id
⇒→ {equivalence}  = _⟨$⟩_ ∘ Equivalence.to
⇒→ {injection}    = _⟨$⟩_ ∘ Injection.to
⇒→ {left-inverse} = _⟨$⟩_ ∘ LeftInverse.to
⇒→ {surjection}   = _⟨$⟩_ ∘ Surjection.to
⇒→ {bijection}    = _⟨$⟩_ ∘ Inverse.to

-- Kinds whose interpretation include a function which "goes backwards".

data Backward-kind : Set where
  reverse-implication equivalence reverse-injection
    left-inverse surjection bijection : Backward-kind

-- Forgetful map.

⌊_⌋← : Backward-kind → Kind
⌊ reverse-implication ⌋← = reverse-implication
⌊ equivalence         ⌋← = equivalence
⌊ reverse-injection   ⌋← = reverse-injection
⌊ left-inverse        ⌋← = left-inverse
⌊ surjection          ⌋← = surjection
⌊ bijection           ⌋← = bijection

-- The function.

⇒← : ∀ {k x y} {X : Set x} {Y : Set y} → X ∼[ ⌊ k ⌋← ] Y → Y → X
⇒← {reverse-implication} = app-←
⇒← {equivalence}         = _⟨$⟩_ ∘ Equivalence.from
⇒← {reverse-injection}   = _⟨$⟩_ ∘ Injection.to ∘ app-↢
⇒← {left-inverse}        = _⟨$⟩_ ∘ LeftInverse.from
⇒← {surjection}          = _⟨$⟩_ ∘ Surjection.from
⇒← {bijection}           = _⟨$⟩_ ∘ Inverse.from

-- Kinds whose interpretation include functions going in both
-- directions.

data Equivalence-kind : Set where
    equivalence left-inverse surjection bijection : Equivalence-kind

-- Forgetful map.

⌊_⌋⇔ : Equivalence-kind → Kind
⌊ equivalence  ⌋⇔ = equivalence
⌊ left-inverse ⌋⇔ = left-inverse
⌊ surjection   ⌋⇔ = surjection
⌊ bijection    ⌋⇔ = bijection

-- The functions.

⇒⇔ : ∀ {k x y} {X : Set x} {Y : Set y} →
     X ∼[ ⌊ k ⌋⇔ ] Y → X ∼[ equivalence ] Y
⇒⇔ {equivalence}  = id
⇒⇔ {left-inverse} = LeftInverse.equivalence
⇒⇔ {surjection}   = Surjection.equivalence
⇒⇔ {bijection}    = Inverse.equivalence

-- Conversions between special kinds.

⇔⌊_⌋ : Symmetric-kind → Equivalence-kind
⇔⌊ equivalence ⌋ = equivalence
⇔⌊ bijection   ⌋ = bijection

→⌊_⌋ : Equivalence-kind → Forward-kind
→⌊ equivalence  ⌋ = equivalence
→⌊ left-inverse ⌋ = left-inverse
→⌊ surjection   ⌋ = surjection
→⌊ bijection    ⌋ = bijection

←⌊_⌋ : Equivalence-kind → Backward-kind
←⌊ equivalence  ⌋ = equivalence
←⌊ left-inverse ⌋ = left-inverse
←⌊ surjection   ⌋ = surjection
←⌊ bijection    ⌋ = bijection

------------------------------------------------------------------------
-- Opposites

-- For every kind there is an opposite kind.

_op : Kind → Kind
implication         op = reverse-implication
reverse-implication op = implication
equivalence         op = equivalence
injection           op = reverse-injection
reverse-injection   op = injection
left-inverse        op = surjection
surjection          op = left-inverse
bijection           op = bijection

-- For every morphism there is a corresponding reverse morphism of the
-- opposite kind.

reverse : ∀ {k a b} {A : Set a} {B : Set b} →
          A ∼[ k ] B → B ∼[ k op ] A
reverse {implication}         = lam
reverse {reverse-implication} = app-←
reverse {equivalence}         = Eq.sym
reverse {injection}           = lam
reverse {reverse-injection}   = app-↢
reverse {left-inverse}        = Surj.fromRightInverse
reverse {surjection}          = Surjection.right-inverse
reverse {bijection}           = Inv.sym

------------------------------------------------------------------------
-- Equational reasoning

-- Equational reasoning for related things.

module EquationalReasoning where

  private

    refl : ∀ {k ℓ} → Reflexive (Related k {ℓ})
    refl {implication}         = id
    refl {reverse-implication} = lam id
    refl {equivalence}         = Eq.id
    refl {injection}           = Inj.id
    refl {reverse-injection}   = lam Inj.id
    refl {left-inverse}        = LeftInv.id
    refl {surjection}          = Surj.id
    refl {bijection}           = Inv.id

    trans : ∀ {k ℓ₁ ℓ₂ ℓ₃} →
            Trans (Related k {ℓ₁} {ℓ₂})
                  (Related k {ℓ₂} {ℓ₃})
                  (Related k {ℓ₁} {ℓ₃})
    trans {implication}         = flip _∘′_
    trans {reverse-implication} = λ f g → lam (app-← f ∘ app-← g)
    trans {equivalence}         = flip Eq._∘_
    trans {injection}           = flip Inj._∘_
    trans {reverse-injection}   = λ f g → lam (Inj._∘_ (app-↢ f) (app-↢ g))
    trans {left-inverse}        = flip LeftInv._∘_
    trans {surjection}          = flip Surj._∘_
    trans {bijection}           = flip Inv._∘_

  sym : ∀ {k ℓ₁ ℓ₂} →
        Sym (Related ⌊ k ⌋ {ℓ₁} {ℓ₂})
            (Related ⌊ k ⌋ {ℓ₂} {ℓ₁})
  sym {equivalence} = Eq.sym
  sym {bijection}   = Inv.sym

  infix  2 _∎
  infixr 2 _∼⟨_⟩_ _↔⟨_⟩_ _↔⟨⟩_ _≡⟨_⟩_

  _∼⟨_⟩_ : ∀ {k x y z} (X : Set x) {Y : Set y} {Z : Set z} →
           X ∼[ k ] Y → Y ∼[ k ] Z → X ∼[ k ] Z
  _ ∼⟨ X↝Y ⟩ Y↝Z = trans X↝Y Y↝Z

  -- Isomorphisms can be combined with any other kind of relatedness.

  _↔⟨_⟩_ : ∀ {k x y z} (X : Set x) {Y : Set y} {Z : Set z} →
           X ↔ Y → Y ∼[ k ] Z → X ∼[ k ] Z
  X ↔⟨ X↔Y ⟩ Y⇔Z = X ∼⟨ ↔⇒ X↔Y ⟩ Y⇔Z

  _↔⟨⟩_ : ∀ {k x y} (X : Set x) {Y : Set y} →
          X ∼[ k ] Y → X ∼[ k ] Y
  X ↔⟨⟩ X⇔Y = X⇔Y

  _≡⟨_⟩_ : ∀ {k ℓ z} (X : Set ℓ) {Y : Set ℓ} {Z : Set z} →
           X ≡ Y → Y ∼[ k ] Z → X ∼[ k ] Z
  X ≡⟨ X≡Y ⟩ Y⇔Z = X ∼⟨ ≡⇒ X≡Y ⟩ Y⇔Z

  _∎ : ∀ {k x} (X : Set x) → X ∼[ k ] X
  X ∎ = refl

-- For a symmetric kind and a fixed universe level we can construct a
-- setoid.

setoid : Symmetric-kind → (ℓ : Level) → Setoid _ _
setoid k ℓ = record
  { Carrier       = Set ℓ
  ; _≈_           = Related ⌊ k ⌋
  ; isEquivalence =
      record {refl = _ ∎; sym = sym; trans = _∼⟨_⟩_ _}
  } where open EquationalReasoning

-- For an arbitrary kind and a fixed universe level we can construct a
-- preorder.

preorder : Kind → (ℓ : Level) → Preorder _ _ _
preorder k ℓ = record
  { Carrier    = Set ℓ
  ; _≈_        = _↔_
  ; _∼_        = Related k
  ; isPreorder = record
    { isEquivalence = Setoid.isEquivalence (setoid bijection ℓ)
    ; reflexive     = ↔⇒
    ; trans         = _∼⟨_⟩_ _
    }
  } where open EquationalReasoning

------------------------------------------------------------------------
-- Some induced relations

-- Every unary relation induces a preorder and, for symmetric kinds,
-- an equivalence. (No claim is made that these relations are unique.)

InducedRelation₁ : Kind → ∀ {a s} {A : Set a} →
                   (A → Set s) → A → A → Set _
InducedRelation₁ k S = λ x y → S x ∼[ k ] S y

InducedPreorder₁ : Kind → ∀ {a s} {A : Set a} →
                   (A → Set s) → Preorder _ _ _
InducedPreorder₁ k S = record
  { _≈_        = P._≡_
  ; _∼_        = InducedRelation₁ k S
  ; isPreorder = record
    { isEquivalence = P.isEquivalence
    ; reflexive     = reflexive ∘
                      Setoid.reflexive (setoid bijection _) ∘
                      P.cong S
    ; trans         = trans
    }
  } where open Preorder (preorder _ _)

InducedEquivalence₁ : Symmetric-kind → ∀ {a s} {A : Set a} →
                      (A → Set s) → Setoid _ _
InducedEquivalence₁ k S = record
  { _≈_           = InducedRelation₁ ⌊ k ⌋ S
  ; isEquivalence = record {refl = refl; sym = sym; trans = trans}
  } where open Setoid (setoid _ _)

-- Every binary relation induces a preorder and, for symmetric kinds,
-- an equivalence. (No claim is made that these relations are unique.)

InducedRelation₂ : Kind → ∀ {a b s} {A : Set a} {B : Set b} →
                   (A → B → Set s) → B → B → Set _
InducedRelation₂ k _S_ = λ x y → ∀ {z} → (z S x) ∼[ k ] (z S y)

InducedPreorder₂ : Kind → ∀ {a b s} {A : Set a} {B : Set b} →
                   (A → B → Set s) → Preorder _ _ _
InducedPreorder₂ k _S_ = record
  { _≈_        = P._≡_
  ; _∼_        = InducedRelation₂ k _S_
  ; isPreorder = record
    { isEquivalence = P.isEquivalence
    ; reflexive     = λ x≡y {z} →
                        reflexive $
                        Setoid.reflexive (setoid bijection _) $
                        P.cong (_S_ z) x≡y

    ; trans         = λ i↝j j↝k → trans i↝j j↝k
    }
  } where open Preorder (preorder _ _)

InducedEquivalence₂ : Symmetric-kind →
                      ∀ {a b s} {A : Set a} {B : Set b} →
                      (A → B → Set s) → Setoid _ _
InducedEquivalence₂ k _S_ = record
  { _≈_           = InducedRelation₂ ⌊ k ⌋ _S_
  ; isEquivalence = record
    { refl  = refl
    ; sym   = λ i↝j → sym i↝j
    ; trans = λ i↝j j↝k → trans i↝j j↝k
    }
  } where open Setoid (setoid _ _)


----------------------------------------------------------------------------
-- The FOTC lists of natural numbers type
----------------------------------------------------------------------------

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

module FOTC.Data.Nat.List.Type where

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

------------------------------------------------------------------------------
-- The FOTC lists of natural numbers type (inductive predicate for
-- total lists of natural numbers).
data ListN : D → Set where
  lnnil  : ListN []
  lncons : ∀ {n ns} → N n → ListN ns → ListN (n ∷ ns)
{-# ATP axioms lnnil lncons #-}

-- Induction principle.
ListN-ind : (A : D → Set) →
            A [] →
            (∀ {n ns} → N n → A ns → A (n ∷ ns)) →
            ∀ {ns} → ListN ns → A ns
ListN-ind A A[] h lnnil           = A[]
ListN-ind A A[] h (lncons Nn Lns) = h Nn (ListN-ind A A[] h Lns)


even : ℕ → Bool
odd  : ℕ → Bool

even zero    = true
even (suc n) = odd n

odd zero    = false
odd (suc n) = even n


module evenodd where

mutual
  data Even : Set where
    Z  : Even
    S  : Odd -> Even

  data Odd : Set where
    S' : Even -> Odd


module Numeral.Natural.Function.FlooredLogarithm where

open import Data
open import Data.Boolean.Stmt
open import Numeral.Natural
open import Numeral.Natural.Inductions
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Comparisons
open import Numeral.Natural.Oper.FlooredDivision
open import Numeral.Natural.Oper.FlooredDivision.Proofs
open import Numeral.Natural.Oper.Proofs
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals
open import Structure.Relator.Ordering
open        Structure.Relator.Ordering.Strict.Properties

⌊log⌋ : (b : ℕ) → ⦃ _ : IsTrue(b ≥? 2) ⦄ → (n : ℕ) → ⦃ _ : IsTrue(n ≥? 1) ⦄ → ℕ
⌊log⌋ b@(𝐒(𝐒 _)) n = wellfounded-recursion (_<_) f(n) where
  f : (n : ℕ) → ((prev : ℕ) ⦃ _ : (prev < n) ⦄ → ℕ) → ℕ
  f 𝟎          _    = 𝟎
  f (𝐒 𝟎)      _    = 𝟎
  f n@(𝐒(𝐒 _)) prev = 𝐒(prev((n ⌊/⌋ b)) ⦃ [⌊/⌋]-ltₗ {b = b} ⦄)


module Numeral.Integer where

open import Data.Tuple
open import Logic
import      Lvl
open import Numeral.Natural
open import Numeral.Natural.Oper
open import Relator.Equals
open import Type
open import Type.Quotient

-- Equivalence relation of difference equality.
-- Essentially (if one would already work in the integers):
--   (a₁ , a₂) diff-≡_ (b₁ , b₂)
--   ⇔ a₁ + b₂ ≡ a₂ + b₁
--   ⇔ a₁ − a₂ ≡ b₁ − b₂
_diff-≡_ : (ℕ ⨯ ℕ) → (ℕ ⨯ ℕ) → Stmt{Lvl.𝟎}
(a₁ , a₂) diff-≡ (b₁ , b₂) = (a₁ + b₂ ≡ a₂ + b₁)

ℤ : Type{Lvl.𝟎}
ℤ = (ℕ ⨯ ℕ) / (_diff-≡_)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of binary trees
------------------------------------------------------------------------

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

module Data.Tree.Binary.Properties where

open import Level using (Level)
open import Data.Nat.Base using (suc; _+_)
open import Data.Tree.Binary
open import Function.Base
open import Relation.Binary.PropositionalEquality

private
  variable
    a b : Level
    A : Set a
    B : Set b

size-map : ∀ (f : A → B) t → size (map f t) ≡ size t
size-map f leaf         = refl
size-map f (node l m r) =
  cong₂ (λ l r → l + suc r) (size-map f l) (size-map f r)

map-id : ∀ (t : Tree A) → map id t ≡ t
map-id leaf         = refl
map-id (node l v r) = cong₂ (flip node v) (map-id l) (map-id r)


-- Testing termination using subpatterns
module TerminationSubpattern where

-- a list with two different conses
data EOList (A : Set) : Set where
    Nil : EOList A
    ECons : A -> EOList A -> EOList A
    OCons : A -> EOList A -> EOList A

butLastWithDefault : {A : Set} -> A -> EOList A -> A
butLastWithDefault a Nil = a
butLastWithDefault a (ECons b l) = butLastWithDefault b l
butLastWithDefault a (OCons b l) = butLastWithDefault b l

-- a very stupid implementation:
butLastWithDefault' : {A : Set} -> A -> EOList A -> A
butLastWithDefault' a Nil = a
butLastWithDefault' a (ECons b Nil) = b
butLastWithDefault' a (OCons b Nil) = b
butLastWithDefault' a (ECons b (OCons c l)) = butLastWithDefault' b (OCons c l)
butLastWithDefault' a (ECons b (ECons c l)) = butLastWithDefault' b (ECons c l)
butLastWithDefault' a (OCons b (OCons c l)) = butLastWithDefault' b (OCons c l)
butLastWithDefault' a (OCons b (ECons c l)) = butLastWithDefault' b (ECons c l)

-- terminates, because, e.g. in the last line
--
--   ECons c l   is a subpattern of   OCons b (ECons c l)

-- another justification is with structured orders
-- if all constructors are considered equivalent


-- making sure that the fun clauses are kept in declaration order
-- in an interleaved mutual block

open import Agda.Builtin.Nat

interleaved mutual

  plus  : Nat → Nat → Nat
  minus : Nat → Nat → Nat

  -- 0 being neutral
  plus 0 n = n
  minus n 0 = n

  -- other 0 case
  plus n 0 = n
  minus 0 n = 0

  -- suc suc
  plus (suc m) (suc n) = suc (suc (plus m n))
  minus (suc m) (suc n) = minus m n

-- All of these test cases should be true by computation
-- It will not be the case if the definitions have been interleaved
-- the wrong way around (because the resulting definition would be
-- strict in a different argument)

open import Agda.Builtin.Equality

_ : ∀ {n} → plus 0 n ≡ n
_ = refl

_ : ∀ {n} → minus n 0 ≡ n
_ = refl

-- The following should not check with refl; for the same reasons

-- _ : ∀ {n} → plus n 0 ≡ n
-- _ = refl

-- _ : ∀ {n} → minus 0 n ≡ 0
-- _ = refl

-- but they are of course provable by case analysis:

_ : ∀ n → plus n 0 ≡ n
_ = λ where
      zero → refl
      (suc _) → refl

_ : ∀ n → minus 0 n ≡ 0
_ = λ where
      zero → refl
      (suc _) → refl


{-# OPTIONS --safe #-}
module Cubical.Categories.Morphism where

open import Cubical.Foundations.Prelude
open import Cubical.Data.Sigma
open import Cubical.Categories.Category

private
  variable
    ℓ ℓ' : Level

-- C needs to be explicit for these definitions as Agda can't infer it
module _ (C : Category ℓ ℓ') where
  open Category C

  private
    variable
      x y z w : ob

  isMonic : Hom[ x , y ] → Type (ℓ-max ℓ ℓ')
  isMonic {x} {y} f =
    ∀ {z} {a a' : Hom[ z , x ]} → f ∘ a ≡ f ∘ a' → a ≡ a'

  isEpic : (Hom[ x , y ]) → Type (ℓ-max ℓ ℓ')
  isEpic {x} {y} g =
    ∀ {z} {b b' : Hom[ y , z ]} → b ∘ g ≡ b' ∘ g → b ≡ b'

  -- A morphism is split monic if it has a *retraction*
  isSplitMon : (Hom[ x , y ]) → Type ℓ'
  isSplitMon {x} {y} f = ∃[ r ∈ Hom[ y , x ] ] r ∘ f ≡ id

  -- A morphism is split epic if it has a *section*
  isSplitEpi : (Hom[ x , y ]) → Type ℓ'
  isSplitEpi {x} {y} g = ∃[ s ∈ Hom[ y , x ] ] g ∘ s ≡ id

  record areInv (f : Hom[ x , y ]) (g : Hom[ y , x ]) : Type ℓ' where
    field
      sec : g ⋆ f ≡ id
      ret : f ⋆ g ≡ id

  record isIso (f : Hom[ x , y ]) : Type ℓ' where
    field
      inv : Hom[ y , x ]
      sec : inv ⋆ f ≡ id
      ret : f ⋆ inv ≡ id

-- C can be implicit here
module _ {C : Category ℓ ℓ'} where
  open Category C

  private
    variable
      x y z w : ob

  open areInv

  symAreInv : {f : Hom[ x , y ]} {g : Hom[ y , x ]} → areInv C f g → areInv C g f
  sec (symAreInv x) = ret x
  ret (symAreInv x) = sec x

  -- equational reasoning with inverses
  invMoveR : ∀ {f : Hom[ x , y ]} {g : Hom[ y , x ]} {h : Hom[ z , x ]} {k : Hom[ z , y ]}
           → areInv C f g
           → h ⋆ f ≡ k
           → h ≡ k ⋆ g
  invMoveR {f = f} {g} {h} {k} ai p
    = h
    ≡⟨ sym (⋆IdR _) ⟩
      (h ⋆ id)
    ≡⟨ cong (h ⋆_) (sym (ai .ret)) ⟩
      (h ⋆ (f ⋆ g))
    ≡⟨ sym (⋆Assoc _ _ _) ⟩
      ((h ⋆ f) ⋆ g)
    ≡⟨ cong (_⋆ g) p ⟩
      k ⋆ g
    ∎

  invMoveL : ∀ {f : Hom[ x , y ]} {g : Hom[ y , x ]} {h : Hom[ y , z ]} {k : Hom[ x , z ]}
          → areInv C f g
          → f ⋆ h ≡ k
          → h ≡ g ⋆ k
  invMoveL {f = f} {g} {h} {k} ai p
    = h
    ≡⟨ sym (⋆IdL _) ⟩
      id ⋆ h
    ≡⟨ cong (_⋆ h) (sym (ai .sec)) ⟩
      (g ⋆ f) ⋆ h
    ≡⟨ ⋆Assoc _ _ _ ⟩
      g ⋆ (f ⋆ h)
    ≡⟨ cong (g ⋆_) p ⟩
      (g ⋆ k)
    ∎

  open isIso

  isIso→areInv : ∀ {f : Hom[ x , y ]}
               → (isI : isIso C f)
               → areInv C f (isI .inv)
  sec (isIso→areInv isI) = sec isI
  ret (isIso→areInv isI) = ret isI

  open CatIso

  -- isIso agrees with CatIso
  isIso→CatIso : ∀ {f : C [ x , y ]}
               → isIso C f
               → CatIso C x y
  mor (isIso→CatIso {f = f} x) = f
  inv (isIso→CatIso x) = inv x
  sec (isIso→CatIso x) = sec x
  ret (isIso→CatIso x) = ret x

  CatIso→isIso : (cIso : CatIso C x y)
               → isIso C (cIso .mor)
  inv (CatIso→isIso f) = inv f
  sec (CatIso→isIso f) = sec f
  ret (CatIso→isIso f) = ret f

  CatIso→areInv : (cIso : CatIso C x y)
                → areInv C (cIso .mor) (cIso .inv)
  CatIso→areInv cIso = isIso→areInv (CatIso→isIso cIso)

  -- reverse of an iso is also an iso
  symCatIso : ∀ {x y}
             → CatIso C x y
             → CatIso C y x
  symCatIso (catiso mor inv sec ret) = catiso inv mor ret sec


module O where

open import Data.Product
open import Function renaming (_∘_ to _○_)

open import Circle

------------------------------------------------------------------------------
-- Abstract interpretation:
-- natural numbers with paths equating all even numbers in one
-- connected component and all odd numbers in another connected
-- component

-- module with 0,1,2,3,4 ... this is the concrete domain

data N : Set where
  Zero  : N
  One   : N
  Two   : N
  Three : N
  Four  : N

recN : (C : Set) → C → C → C → C → C → N → C
recN C c0 c1 c2 c3 c4 Zero = c0
recN C c0 c1 c2 c3 c4 One = c1
recN C c0 c1 c2 c3 c4 Two = c2
recN C c0 c1 c2 c3 c4 Three = c3
recN C c0 c1 c2 c3 c4 Four = c4

-- module for the abstract domain {even, odd} except that we don't define it
-- this way: we simply add paths between the even elements and paths between
-- the odd elements

module Parity where

  private
    data N* : Set where
      Zero*  : N*
      One*   : N*
      Two*   : N*
      Three* : N*
      Four*  : N*

  NA : Set
  NA = N*

  zero : NA
  zero = Zero*

  one : NA
  one = One*

  two : NA
  two = Two*

  three : NA
  three = Three*

  four : NA
  four = Four*

  postulate
    even02 : Zero* ≡ Two*
    even04 : Zero* ≡ Four*
    odd13  : One* ≡ Three*

  recNA : (C : Set) → (c0 c1 c2 c3 c4 : C) →
    (ceven02 : c0 ≡ c2) → (ceven04 : c0 ≡ c4) → (codd13 : c1 ≡ c3) →
    NA → C
  recNA C c0 c1 c2 c3 c4 _ _ _ Zero* = c0
  recNA C c0 c1 c2 c3 c4 _ _ _ One* = c1
  recNA C c0 c1 c2 c3 c4 _ _ _ Two* = c2
  recNA C c0 c1 c2 c3 c4 _ _ _ Three* = c3
  recNA C c0 c1 c2 c3 c4 _ _ _ Four* = c4

open Parity

-- Now we define functions back and forth

abs : N → NA
abs = recN NA zero one two three four

con : NA → N
con = recNA N Two Three Two Three Two (refl Two) (refl Two) (refl Three)

-- Computations on N and NA can be related
-- Concrete computation

incN : N → N

incN Zero = One
incN One = Two
incN Two = Three
incN Three = Four
incN Four = Zero

-- we can apply an operation in the abstract domain and report the
-- approximate result

absF : (N → N) → (NA → NA)
absF f = abs ○ f ○ con

approx : (N → N) → (N → N)
approx f n = con ((absF f) (abs n))

test0 : approx incN Zero ≡ Three
test0 = refl Three

test1 : approx incN One ≡ Two
test1 = refl Two

test2 : approx incN Two ≡ Three
test2 = refl Three

test3 : approx incN Three ≡ Two
test3 = refl Two

test4 : approx incN Four ≡ Three
test4 = refl Three

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


------------------------------------------------------------------------
-- The Agda standard library
--
-- Fresh lists, a proof relevant variant of Catarina Coquand's contexts in
-- "A Formalised Proof of the Soundness and Completeness of a Simply Typed
-- Lambda-Calculus with Explicit Substitutions"
------------------------------------------------------------------------

-- See README.Data.List.Fresh and README.Data.Trie.NonDependent for
-- examples of how to use fresh lists.

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

module Data.List.Fresh where

open import Level using (Level; _⊔_; Lift)
open import Data.Bool.Base using (true; false)
open import Data.Unit.Base
open import Data.Product using (∃; _×_; _,_; -,_; proj₁; proj₂)
open import Data.List.Relation.Unary.All using (All; []; _∷_)
open import Data.List.Relation.Unary.AllPairs using (AllPairs; []; _∷_)
open import Data.Maybe.Base as Maybe using (Maybe; just; nothing)
open import Data.Nat.Base using (ℕ; zero; suc)
open import Function using (_∘′_; flip; id; _on_)
open import Relation.Nullary      using (does)
open import Relation.Unary   as U using (Pred)
open import Relation.Binary  as B using (Rel)
open import Relation.Nary

private
  variable
    a b p r s : Level
    A : Set a
    B : Set b

------------------------------------------------------------------------
-- Basic type

-- If we pick an R such that (R a b) means that a is different from b
-- then we have a list of distinct values.

module _ {a} (A : Set a) (R : Rel A r) where

  data List# : Set (a ⊔ r)
  fresh : (a : A) (as : List#) → Set r

  data List# where
    []   : List#
    cons : (a : A) (as : List#) → fresh a as → List#

  -- Whenever R can be reconstructed by η-expansion (e.g. because it is
  -- the erasure ⌊_⌋ of a decidable predicate, cf. Relation.Nary) or we
  -- do not care about the proof, it is convenient to get back list syntax.

  -- We use a different symbol to avoid conflict when importing both Data.List
  -- and Data.List.Fresh.
  infixr 5 _∷#_
  pattern _∷#_ x xs = cons x xs _

  fresh a []        = Lift _ ⊤
  fresh a (x ∷# xs) = R a x × fresh a xs

-- Convenient notation for freshness making A and R implicit parameters
infix 5 _#_
_#_ : {R : Rel A r} (a : A) (as : List# A R) → Set r
_#_ = fresh _ _

------------------------------------------------------------------------
-- Operations for modifying fresh lists

module _ {R : Rel A r} {S : Rel B s} (f : A → B) (R⇒S : ∀[ R ⇒ (S on f) ]) where

  map   : List# A R → List# B S
  map-# : ∀ {a} as → a # as → f a # map as

  map []             = []
  map (cons a as ps) = cons (f a) (map as) (map-# as ps)

  map-# []        _        = _
  map-# (a ∷# as) (p , ps) = R⇒S p , map-# as ps

module _ {R : Rel B r} (f : A → B) where

  map₁ : List# A (R on f) → List# B R
  map₁ = map f id

module _ {R : Rel A r} {S : Rel A s} (R⇒S : ∀[ R ⇒ S ]) where

  map₂ : List# A R → List# A S
  map₂ = map id R⇒S

------------------------------------------------------------------------
-- Views

data Empty {A : Set a} {R : Rel A r} : List# A R → Set (a ⊔ r) where
  [] : Empty []

data NonEmpty {A : Set a} {R : Rel A r} : List# A R → Set (a ⊔ r) where
  cons : ∀ x xs pr → NonEmpty (cons x xs pr)

------------------------------------------------------------------------
-- Operations for reducing fresh lists

length : {R : Rel A r} → List# A R → ℕ
length []        = 0
length (_ ∷# xs) = suc (length xs)

------------------------------------------------------------------------
-- Operations for constructing fresh lists

pattern [_] a = a ∷# []

fromMaybe : {R : Rel A r} → Maybe A → List# A R
fromMaybe nothing  = []
fromMaybe (just a) = [ a ]

module _ {R : Rel A r} (R-refl : B.Reflexive R) where

  replicate   : ℕ → A → List# A R
  replicate-# : (n : ℕ) (a : A) → a # replicate n a

  replicate zero    a = []
  replicate (suc n) a = cons a (replicate n a) (replicate-# n a)

  replicate-# zero    a = _
  replicate-# (suc n) a = R-refl , replicate-# n a

------------------------------------------------------------------------
-- Operations for deconstructing fresh lists

uncons : {R : Rel A r} → List# A R → Maybe (A × List# A R)
uncons []        = nothing
uncons (a ∷# as) = just (a , as)

head : {R : Rel A r} → List# A R → Maybe A
head = Maybe.map proj₁ ∘′ uncons

tail : {R : Rel A r} → List# A R → Maybe (List# A R)
tail = Maybe.map proj₂ ∘′ uncons

take   : {R : Rel A r} → ℕ → List# A R → List# A R
take-# : {R : Rel A r} → ∀ n a (as : List# A R) → a # as → a # take n as

take zero    xs             = []
take (suc n) []             = []
take (suc n) (cons a as ps) = cons a (take n as) (take-# n a as ps)

take-# zero    a xs        _        = _
take-# (suc n) a []        ps       = _
take-# (suc n) a (x ∷# xs) (p , ps) = p , take-# n a xs ps

drop : {R : Rel A r} → ℕ → List# A R → List# A R
drop zero    as        = as
drop (suc n) []        = []
drop (suc n) (a ∷# as) = drop n as

module _ {P : Pred A p} (P? : U.Decidable P) where

  takeWhile   : {R : Rel A r} → List# A R → List# A R
  takeWhile-# : ∀ {R : Rel A r} a (as : List# A R) → a # as → a # takeWhile as

  takeWhile []             = []
  takeWhile (cons a as ps) with does (P? a)
  ... | true  = cons a (takeWhile as) (takeWhile-# a as ps)
  ... | false = []

  takeWhile-# a []        _        = _
  takeWhile-# a (x ∷# xs) (p , ps) with does (P? x)
  ... | true  = p , takeWhile-# a xs ps
  ... | false = _

  dropWhile : {R : Rel A r} → List# A R → List# A R
  dropWhile []            = []
  dropWhile aas@(a ∷# as) with does (P? a)
  ... | true  = dropWhile as
  ... | false = aas

  filter   : {R : Rel A r} → List# A R → List# A R
  filter-# : ∀ {R : Rel A r} a (as : List# A R) → a # as → a # filter as

  filter []             = []
  filter (cons a as ps) with does (P? a)
  ... | true  = cons a (filter as) (filter-# a as ps)
  ... | false = filter as

  filter-# a []        _        = _
  filter-# a (x ∷# xs) (p , ps) with does (P? x)
  ... | true  = p , filter-# a xs ps
  ... | false = filter-# a xs ps

------------------------------------------------------------------------
-- Relationship to List and AllPairs

toList : {R : Rel A r} → List# A R → ∃ (AllPairs R)
toAll  : ∀ {R : Rel A r} {a} as → fresh A R a as → All (R a) (proj₁ (toList as))

toList []             = -, []
toList (cons x xs ps) = -, toAll xs ps ∷ proj₂ (toList xs)

toAll []        ps       = []
toAll (a ∷# as) (p , ps) = p ∷ toAll as ps

fromList   : ∀ {R : Rel A r} {xs} → AllPairs R xs → List# A R
fromList-# : ∀ {R : Rel A r} {x xs} (ps : AllPairs R xs) →
             All (R x) xs → x # fromList ps

fromList []       = []
fromList (r ∷ rs) = cons _ (fromList rs) (fromList-# rs r)

fromList-# []       _        = _
fromList-# (p ∷ ps) (r ∷ rs) = r , fromList-# ps rs


module plfa.part1.Naturals where

import Relation.Binary.PropositionalEquality as Eq

-- import Data.Nat using (ℕ; zero; suc; _+_; _*_; _^_; _∸_)

open Eq using (_≡_; refl)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _∎)

-- 'refl' - the name for evidence that two terms are equal

-- Agda uses underbars to indicate where terms appear in
-- infix or mixfix operators:
--
-- * _≡_ and _≡⟨⟩_ -- infix
-- * begin_        -- prefix
-- * _∎            -- postfix

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

-- The following pragma tells Agda that ℕ corresponds to the
-- natural numbers, and hence one is permitted to type 0 as
-- shorthand for 'zero,' 1 as shorthand for 'suc zero'. It also
-- enables a more efficient internal representation of naturals
-- using the Haskell type for arbitrary-precision integers.

{-# BUILTIN NATURAL ℕ #-}

-- Operations on naturals are recursive functions

-- The empty braces are called a hole,
-- and 0 is a number used for referring to the hole

-------------------------------------------------------------
-- Workflow & hotkeys:
-------------------------------------------------------------
-- C-c C-l   - load the current file
-- C-c C-f   - moves to the next hole
-- C-c C-b   - moves to the previous hole
-- C-c C-,   - displays information on the required
--             type of the hole and available free vars
-- C-c C-c   - case split on a variable
-- C-c C-SPC - give to the hole at point an expression in it
-- C-c C-r   - solve the case trivially (refine)
-- gd        - go to definition (custom key binding)
-------------------------------------------------------------

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

-- It works because addition of larger numbers is defined in
-- terms of addition of smaller numbers. Such a definition is
-- called well founded.

-- 0       + n  ≡  n
-- (1 + m) + n  ≡  1 + (m + n)

-- We write '=' for definitions, while we write '≡' for
-- assertions that two already defined things are the same.

_ : 2 + 3 ≡ 5
_ =
  begin
    2 + 3
  ≡⟨⟩
    (suc (suc zero)) + (suc (suc (suc zero)))
  ≡⟨⟩
    suc ((suc zero) + (suc (suc (suc zero))))
  ≡⟨⟩
    suc (suc (zero + (suc (suc (suc zero)))))
  ≡⟨⟩
    suc (suc (suc (suc (suc zero))))
  ≡⟨⟩
    5
  ∎

_ : 2 + 3 ≡ 5
_ =
  begin
    2 + 3
  ≡⟨⟩
    suc (1 + 3)
  ≡⟨⟩
    suc (suc (0 + 3))
  ≡⟨⟩
    suc (suc 3)
  ≡⟨⟩
    5
  ∎

-- In fact, both proofs are longer than need be, and Agda is
-- satisfied with the following:

_ : 2 + 3 ≡ 5
_ = refl

-- Agda knows how to compute the value of 2 + 3, and so can
-- immediately check it is the same as 5. A binary relation is
-- said to be reflexive if every value relates to itself.
-- Evidence that a value is equal to itself is written 'refl'.

-- ^ 'refl' is defined almost the
-- same way as 'eq_relf' in Coq

-- Excercise:

_ : 3 + 4 ≡ 7
_ =
  begin
    3 + 4
  ≡⟨⟩
    suc (2 + 4)
  ≡⟨⟩
    suc (suc (1 + 4))
  ≡⟨⟩
    suc (suc (suc (0 + 4)))
  ≡⟨⟩
    7
  ∎

-- Multiplication

_*_ : ℕ → ℕ → ℕ
zero    * n = zero
(suc m) * n = n + (m * n)

_ =
  begin
    2 * 3
  ≡⟨⟩    -- inductive case
    3 + (1 * 3)
  ≡⟨⟩    -- inductive case
    3 + (3 + (0 * 3))
  ≡⟨⟩    -- base case
    3 + (3 + 0)
  ≡⟨⟩    -- simplify
    6
  ∎

-- Exercise:

_^_ : ℕ → ℕ → ℕ
m ^ zero    = suc zero
m ^ (suc n) = m * (m ^ n)

_ : 3 ^ 4 ≡ 81
_ =
  begin
    3 ^ 4
  ≡⟨⟩
   3 * (3 ^ 3)
  ≡⟨⟩
   3 * (3 * (3 ^ 2))
  ≡⟨⟩
   3 * (3 * (3 * (3 ^ 1)))
  ≡⟨⟩
   81
  ∎

_∸_ : ℕ → ℕ → ℕ
m     ∸ zero   =  m
zero  ∸ suc n  =  zero
suc m ∸ suc n  =  m ∸ n

_ =
  begin
    3 ∸ 2
  ≡⟨⟩
    2 ∸ 1
  ≡⟨⟩
    1 ∸ 0
  ≡⟨⟩
    1
  ∎

_ =
  begin
    2 ∸ 3
  ≡⟨⟩
    1 ∸ 2
  ≡⟨⟩
    0 ∸ 1
  ≡⟨⟩
    0
  ∎

-- Precedence

infixl 6  _+_  _∸_
infixl 7  _*_

-- Application binds more tightly than
-- (or has precedence over) any operator

-- Currying _

-- ℕ → ℕ → ℕ stands for ℕ → (ℕ → ℕ)

-- and

-- _+_ 2 3 stands for (_+_ 2) 3.

-- Writing definitions interactively

_+₁_ : ℕ → ℕ → ℕ
zero +₁ n = n
suc m +₁ n = suc (m +₁ n)

-- Exercise

data Bin : Set where
  ⟨⟩ : Bin
  _O : Bin → Bin
  _I : Bin → Bin

inc : Bin → Bin
inc ⟨⟩    = ⟨⟩ O
inc (x O) = x I
inc (x I) = inc x O

_ : inc (⟨⟩ I O I I) ≡ ⟨⟩ I I O O
_ = {!!}

to : ℕ → Bin
to zero    = ⟨⟩ O
to (suc m) = (to m) I

_ : to 12 ≡ ⟨⟩ I O I I
_ = {!!}

from : Bin → ℕ
from ⟨⟩    = 0
from (x O) = from x
from (x I) = suc (from x)

_ : from (⟨⟩ I O I I) ≡ 12
_ = {!!}


open import Prelude
open import Data.Nat.Properties.Simple
  using (+-comm; +-right-identity; +-assoc)

open import RW.Language.RTerm

open import Relation.Binary.PropositionalEquality
open import RW.Strategy.PropEq

open import RW.RW (≡-strat ∷ [])

module PropEqTransitivityTest where

  open ≡-Reasoning

  -- This is pretty slow...
  test2 : (x y : ℕ) → (x + y) + 0 ≡ y + (x + 0)
  test2 x y
    = begin
      (x + y) + 0
    ≡⟨ (tactic (by*-≡ (quote +-comm ∷ quote +-assoc ∷ []))) ⟩
      y + (x + 0)
    ∎

  {-

  Using a max height of 2 in the goal guesser.

  Finished RWTestingTrans.
  46,981,963,256 bytes allocated in the heap
   7,318,699,728 bytes copied during GC
     387,537,960 bytes maximum residency (20 sample(s))
       8,253,392 bytes maximum slop
            1042 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0     90092 colls,     0 par   17.25s   17.25s     0.0002s    0.0030s
  Gen  1        20 colls,     0 par    5.15s    5.17s     0.2587s    0.6522s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time  241.64s  (241.88s elapsed)
  GC      time   22.40s  ( 22.42s elapsed)
  EXIT    time    0.09s  (  0.09s elapsed)
  Total   time  264.12s  (264.40s elapsed)

  %GC     time       8.5%  (8.5% elapsed)

  Alloc rate    194,432,035 bytes per MUT second

  Productivity  91.5% of total user, 91.4% of total elapsed

  -}
  {-

  Using a height of 1

  Finished RWTestingTrans.
  31,222,657,544 bytes allocated in the heap
   5,109,928,984 bytes copied during GC
     355,162,768 bytes maximum residency (18 sample(s))
       7,579,240 bytes maximum slop
             952 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0     59723 colls,     0 par   12.21s   12.22s     0.0002s    0.0036s
  Gen  1        18 colls,     0 par    3.91s    3.92s     0.2179s    0.6516s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time  154.42s  (154.57s elapsed)
  GC      time   16.12s  ( 16.14s elapsed)
  EXIT    time    0.09s  (  0.09s elapsed)
  Total   time  170.63s  (170.80s elapsed)

  %GC     time       9.5%  (9.5% elapsed)

  Alloc rate    202,197,812 bytes per MUT second

  Productivity  90.5% of total user, 90.5% of total elapsed

  -}


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

-- Definition of the Arrow Category of a Category C
module Categories.Category.Construction.Arrow {o ℓ e} (C : Category o ℓ e) where

open import Level
open import Data.Product using (_,_; _×_; map; zip)
open import Function using (_$_)
open import Relation.Binary using (Rel)

import Categories.Morphism as M
open M C
open import Categories.Morphism.Reasoning C

open Category C hiding (dom; cod)
open HomReasoning

private
  variable
    A B D E : Obj

record Morphism : Set (o ⊔ ℓ) where
  field
    {dom} : Obj
    {cod} : Obj
    arr   : dom ⇒ cod

record Morphism⇒ (f g : Morphism) : Set (ℓ ⊔ e) where
  constructor mor⇒
  private
    module f = Morphism f
    module g = Morphism g

  field
    {dom⇒} : f.dom ⇒ g.dom
    {cod⇒} : f.cod ⇒ g.cod
    square : CommutativeSquare f.arr dom⇒ cod⇒ g.arr

Arrow : Category _ _ _
Arrow = record
  { Obj       = Morphism
  ; _⇒_       = Morphism⇒
  ; _≈_       = λ f g → dom⇒ f ≈ dom⇒ g × cod⇒ f ≈ cod⇒ g
  ; id        = mor⇒ $ identityˡ ○ ⟺ identityʳ
  ; _∘_       = λ m₁ m₂ → mor⇒ $ glue (square m₁) (square m₂)
  ; assoc     = assoc , assoc
  ; sym-assoc = sym-assoc , sym-assoc
  ; identityˡ = identityˡ , identityˡ
  ; identityʳ = identityʳ , identityʳ
  ; identity² = identity² , identity²
  ; equiv     = record
    { refl  = refl , refl
    ; sym   = map sym sym
    ; trans = zip trans trans
    }
  ; ∘-resp-≈  = zip ∘-resp-≈ ∘-resp-≈
  }
  where open Morphism⇒

private
  module MM = M Arrow

module _ where
  open _≅_

  lift-iso : ∀ {f h} →
               (iso₁ : A ≅ D) → (iso₂ : B ≅ E) →
               CommutativeSquare f (from iso₁) (from iso₂) h →
               record { arr = f } MM.≅ record { arr = h }
  lift-iso {f = f} {h = h} iso₁ iso₂ sq = record
    { from = record { square = sq }
    ; to   = record { square = begin
      to iso₂ ∘ h                           ≈⟨ introʳ (isoʳ iso₁) ⟩
      (to iso₂ ∘ h) ∘ from iso₁ ∘ to iso₁   ≈⟨ assoc ⟩
      to iso₂ ∘ h ∘ from iso₁ ∘ to iso₁     ≈˘⟨ refl ⟩∘⟨ pushˡ sq ⟩
      to iso₂ ∘ (from iso₂ ∘ f) ∘ to iso₁   ≈˘⟨ assoc ⟩
      (to iso₂ ∘ (from iso₂ ∘ f)) ∘ to iso₁ ≈⟨ cancelˡ (isoˡ iso₂) ⟩∘⟨ refl ⟩
      f ∘ to iso₁                           ∎ }
    ; iso  = record
      { isoˡ = isoˡ iso₁ , isoˡ iso₂
      ; isoʳ = isoʳ iso₁ , isoʳ iso₂
      }
    }


------------------------------------------------------------------------
-- The Agda standard library
--
-- "Finite" sets indexed on coinductive "natural" numbers
------------------------------------------------------------------------

module Data.Cofin where

open import Coinduction
open import Data.Conat as Conat using (Coℕ; suc; ∞ℕ)
open import Data.Nat using (ℕ; zero; suc)
open import Data.Fin using (Fin; zero; suc)

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

-- Note that Cofin ∞ℕ is /not/ finite. Note also that this is not a
-- coinductive type, but it is indexed on a coinductive type.

data Cofin : Coℕ → Set where
  zero : ∀ {n} → Cofin (suc n)
  suc  : ∀ {n} (i : Cofin (♭ n)) → Cofin (suc n)

------------------------------------------------------------------------
-- Some operations

fromℕ : ℕ → Cofin ∞ℕ
fromℕ zero    = zero
fromℕ (suc n) = suc (fromℕ n)

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

fromFin : ∀ {n} → Fin n → Cofin (Conat.fromℕ n)
fromFin zero    = zero
fromFin (suc i) = suc (fromFin i)

toFin : ∀ n → Cofin (Conat.fromℕ n) → Fin n
toFin zero    ()
toFin (suc n) zero    = zero
toFin (suc n) (suc i) = suc (toFin n i)


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

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

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

module Fields.Orders.Total.Archimedean {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ _*_ : A → A → A} {R : Ring S _+_ _*_} {c : _} {_<_ : A → A → Set c} {pOrder : SetoidPartialOrder S _<_} {F : Field R} (p : PartiallyOrderedField F pOrder) where

open Setoid S
open Equivalence eq
open Ring R
open Group additiveGroup
open import Groups.Lemmas additiveGroup
open import Groups.Cyclic.Definition additiveGroup
open import Groups.Cyclic.DefinitionLemmas additiveGroup
open import Groups.Orders.Archimedean (toGroup R (PartiallyOrderedField.oRing p))
open import Rings.Orders.Partial.Lemmas (PartiallyOrderedField.oRing p)
open import Rings.InitialRing R
open SetoidPartialOrder pOrder
open PartiallyOrderedRing (PartiallyOrderedField.oRing p)
open Field F

ArchimedeanField : Set (a ⊔ c)
ArchimedeanField = (x : A) → (0R < x) → Sg ℕ (λ n → x < (fromN n))

private
  lemma : (r : A) (N : ℕ) → (positiveEltPower 1R N * r) ∼ positiveEltPower r N
  lemma r zero = timesZero'
  lemma r (succ n) = transitive *DistributesOver+' (+WellDefined identIsIdent (lemma r n))

  findBound : (0<1 : 0R < 1R) → (r s : A) (N : ℕ) → (1R < r) → (s < positiveEltPower 1R N) → s < positiveEltPower r N
  findBound _ r s zero 1<r s<N = s<N
  findBound 0<1 r s (succ N) 1<r s<N = <Transitive s<N (<WellDefined (transitive *Commutative identIsIdent) (lemma r (succ N)) (ringCanMultiplyByPositive' (fromNPreservesOrder 0<1 (succIsPositive N)) 1<r))

archFieldToGrp : ((x y : A) → 0R < x → (x * y) ∼ 1R → 0R < y) → ArchimedeanField → Archimedean
archFieldToGrp reciprocalPositive a r s 0<r 0<s with allInvertible r (λ r=0 → irreflexive (<WellDefined reflexive r=0 0<r))
... | inv , prInv with a inv (reciprocalPositive r inv 0<r (transitive *Commutative prInv))
... | N , invBound with a s 0<s
... | Ns , nSBound = (Ns *N N) , <WellDefined reflexive (symmetric (elementPowerMultiplies (nonneg Ns) (nonneg N) r)) (findBound (<WellDefined reflexive (transitive *Commutative prInv) (orderRespectsMultiplication 0<r (reciprocalPositive r inv 0<r (transitive *Commutative prInv)))) (positiveEltPower r N) s Ns m nSBound)
  where
    m : 1R < positiveEltPower r N
    m = <WellDefined prInv (lemma r N) (ringCanMultiplyByPositive 0<r invBound)

archToArchField : 0R < 1R → Archimedean → ArchimedeanField
archToArchField 0<1 arch a 0<a with arch 1R a 0<1 0<a
... | N , pr = N , pr


module BBHeap.Compound {A : Set}(_≤_ : A → A → Set) where

open import BBHeap _≤_
open import Bound.Lower A
open import Bound.Lower.Order _≤_

data Compound {b : Bound} : BBHeap b → Set where
  cl : {x : A}{l r : BBHeap (val x)}(b≤x : LeB b (val x))(l⋘r : l ⋘ r) → Compound (left b≤x l⋘r)
  cr : {x : A}{l r : BBHeap (val x)}(b≤x : LeB b (val x))(l⋙r : l ⋙ r) → Compound (right b≤x l⋙r)


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

open import LogicalFormulae

module ClassicalLogic.ClassicalFive where

em = {A : Set} → (A || (A → False))
dne = {A : Set} → ((A → False) → False) → A
peirce = {A B : Set} → ((A → B) → A) → A
iad = {A B : Set} → (A → B) → ((A → False) || B)
dem = {A B : Set} → (((A → False) && (B → False)) → False) → A || B

emToDne : em → dne
emToDne em {A} pr with em {A}
emToDne em {A} pr | inl x = x
emToDne em {A} pr | inr x = exFalso (pr x)

dneToPeirce : dne → peirce
dneToPeirce dne {A} {B} aba = dne (λ z → z (aba (λ a → dne (λ _ → z a))))

peirceToIad : peirce → iad
peirceToIad peirce {A} {B} aToB = peirce (λ z → inl (λ x → z (inr (aToB x))))

iadToDem : iad → dem
iadToDem iad {A} {B} x with iad {A} {A} (λ i → i)
iadToDem iad {A} {B} x | inl notA with iad {B} {B} (λ i → i)
iadToDem iad {A} {B} x | inl notA | inl notB = exFalso (x (notA ,, notB))
iadToDem iad {A} {B} x | inl notA | inr b = inr b
iadToDem iad {A} {B} x | inr a = inl a

demToEm : dem → em
demToEm dem {A} = dem (λ z → _&&_.snd z (_&&_.fst z))


module BTree.Complete.Base.Properties {A : Set} where

open import BTree {A}
open import BTree.Complete.Base {A}
open import BTree.Equality {A}
open import BTree.Equality.Properties {A}

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

lemma-⋗-≃ : {l r r' : BTree} → l ⋗ r → r ≃ r' → l ⋗ r'
lemma-⋗-≃ (⋗lf x) ≃lf = ⋗lf x
lemma-⋗-≃ (⋗nd {r' = r'} x x' r l' l⋗r') (≃nd {l' = l''} .x' x'' l'≃r' l'≃l'' l''≃r'') = ⋗nd x x'' r l'' (lemma-⋗-≃ l⋗r' (trans≃ (symm≃ l'≃r') (trans≃ l'≃l'' l''≃r'')))


------------------------------------------------------------------------
-- Examples for modalities
------------------------------------------------------------------------

module CTL.ModalityExamples where

open import Library

open import FStream.Containers
open import FStream.Core

open import CTL.Modalities

readDouble : ⟦ ReaderC ℕ ⟧ ℕ
readDouble = fmap (_* 2) ask

readSuc : ⟦ ReaderC ℕ ⟧ ℕ
readSuc = fmap (suc) ask

alwaysPos : (n : ℕ) → runReader readSuc n > 0
alwaysPos n = s≤s z≤n

alwaysPosC : □ (_> 0) readSuc
alwaysPosC = λ p → s≤s z≤n

sometimes3 : ◇ (_≡ 3) readSuc
sometimes3 = suc (suc zero) , refl

sometimes5 : ◇ (_≡ 5) readSuc
sometimes5 = suc (suc (suc (suc zero))) , refl

-- It is always the case that constantly readSuc outputs ℕ > 0,
-- regardless of the environment
always>0 : AG (map (_> 0) (constantly readSuc))
nowA (always>0 p) = alwaysPos p
laterA (always>0 p) = {!!}

{-nowA always>0 = λ p → s≤s z≤n
laterA always>0 = λ p → always>0
-}

{-
nowA always>0 p = s≤s z≤n
laterA always>0 p = always>0
-}

-- Sums all values in the reader-environment
sumFrom : ℕ → FStream (ReaderC ℕ) ℕ
proj₁ (inF (sumFrom n0)) = tt
head (proj₂ (inF (sumFrom n0)) n) = n0 + n
tail (proj₂ (inF (sumFrom n0)) n) = sumFrom (n0 + n)

sum : FStream (ReaderC ℕ) ℕ
sum = sumFrom 0

-- Eventually the sum is greater than 2
eventuallysometimes>2 : EF (map (_> 2) sum)
-- ... having 3 as input, this is of course the case after 1 step
eventuallysometimes>2 = ? --alreadyE (suc (suc (suc zero)) , s≤s (s≤s (s≤s z≤n)))

-- Always somehow the sum is greater than 2
alwaysSomehow>2 : ∀ {i} → EG {i} (map (_> 2) sum)
alwaysSomehow>2 = {!!}

{-proj₁ alwaysSomehow>2 = suc (suc (suc zero))
nowE' (proj₂ alwaysSomehow>2) = s≤s (s≤s (s≤s z≤n))
proj₁ (laterE' (proj₂ alwaysSomehow>2)) = zero
proj₂ (laterE' (proj₂ alwaysSomehow>2)) = {!   !}
-}

{-
nowE alwaysSomehow>2 = (ℕ.suc (ℕ.suc (ℕ.suc ℕ.zero)) , s≤s (s≤s (s≤s z≤n)))
laterE alwaysSomehow>2 = ℕ.zero , alwaysSomehow>2
-}

--


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

open import Sets.EquivalenceRelations
open import Setoids.Setoids
open import Functions.Definition
open import Groups.Definition
open import Groups.Homomorphisms.Definition
open import Groups.Subgroups.Definition
open import Groups.Subgroups.Normal.Definition

module Groups.Cosets {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ : A → A → A} (G : Group S _+_) {c : _} {pred : A → Set c} (subgrp : Subgroup G pred) where

open Equivalence (Setoid.eq S)
open import Groups.Lemmas G
open Group G
open Subgroup subgrp

cosetSetoid : Setoid A
Setoid._∼_ cosetSetoid g h = pred ((Group.inverse G h) + g)
Equivalence.reflexive (Setoid.eq cosetSetoid) = isSubset (symmetric (Group.invLeft G)) containsIdentity
Equivalence.symmetric (Setoid.eq cosetSetoid) yx = isSubset (transitive invContravariant (+WellDefined reflexive invInv)) (closedUnderInverse yx)
Equivalence.transitive (Setoid.eq cosetSetoid) yx zy = isSubset (transitive +Associative (+WellDefined (transitive (symmetric +Associative) (transitive (+WellDefined reflexive invRight) identRight)) reflexive)) (closedUnderPlus zy yx)

cosetGroup : normalSubgroup G subgrp → Group cosetSetoid _+_
Group.+WellDefined (cosetGroup norm) {m} {n} {x} {y} m=x n=y = ans
  where
    t : pred (inverse y + n)
    t = n=y
    u : pred (inverse x + m)
    u = m=x
    v : pred (m + inverse x)
    v = isSubset (+WellDefined reflexive (transitive (symmetric +Associative) (transitive (+WellDefined reflexive invRight) identRight))) (norm u)
    ans' : pred ((inverse y) + ((inverse x + m) + inverse (inverse y)))
    ans' = norm u
    ans'' : pred ((inverse y) + ((inverse x + m) + y))
    ans'' = isSubset (+WellDefined reflexive (+WellDefined reflexive (invTwice y))) ans'
    ans : pred (inverse (x + y) + (m + n))
    ans = isSubset (transitive (transitive +Associative (transitive (+WellDefined (transitive (symmetric +Associative) (transitive (+WellDefined reflexive (transitive (symmetric +Associative) (transitive (+WellDefined reflexive invRight) identRight))) +Associative)) reflexive) (symmetric +Associative))) (symmetric (+WellDefined invContravariant reflexive))) (closedUnderPlus ans'' t)
Group.0G (cosetGroup norm) = 0G
Group.inverse (cosetGroup norm) = inverse
Group.+Associative (cosetGroup norm) {a} {b} {c} = isSubset (symmetric (transitive (+WellDefined (inverseWellDefined (symmetric +Associative)) reflexive) (invLeft {a + (b + c)}))) containsIdentity
Group.identRight (cosetGroup norm) = isSubset (symmetric (transitive +Associative (transitive (+WellDefined invLeft reflexive) identRight))) containsIdentity
Group.identLeft (cosetGroup norm) = isSubset (symmetric (transitive (+WellDefined reflexive identLeft) invLeft)) containsIdentity
Group.invLeft (cosetGroup norm) = isSubset (symmetric (transitive (+WellDefined reflexive invLeft) invLeft)) containsIdentity
Group.invRight (cosetGroup norm) = isSubset (symmetric (transitive (+WellDefined reflexive invRight) invLeft)) containsIdentity

cosetGroupHom : (norm : normalSubgroup G subgrp) → GroupHom G (cosetGroup norm) id
GroupHom.groupHom (cosetGroupHom norm) = isSubset (symmetric (transitive (+WellDefined invContravariant reflexive) (transitive +Associative (transitive (+WellDefined (transitive (symmetric +Associative) (+WellDefined reflexive invLeft)) reflexive) (transitive (+WellDefined identRight reflexive) invLeft))))) (Subgroup.containsIdentity subgrp)
GroupHom.wellDefined (cosetGroupHom norm) {x} {y} x=y = isSubset (symmetric (transitive (+WellDefined reflexive x=y) invLeft)) (Subgroup.containsIdentity subgrp)


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

module Relation.Binary.PropositionalEquality.Subst.Properties where

-- Properties of 'subst' onto binary relations.

open import Level
open import Function using (_$_; flip) renaming (id to idFun; _∘_ to _⊚_)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Binary.Construct.Closure.ReflexiveTransitive

private
  variable
    ℓ ℓ₁ ℓ₂ t t₁ t₂ o : Level

-- Two shorthands:  transport the domain or codomain of a relation along an equality.
module Shorthands {O : Set o} (R : Rel O ℓ) where
  infixr 9 _◂_
  infixl 9 _▸_

  _◂_ : ∀ {A B C} → A ≡ B → R B C → R A C
  p ◂ f = subst (flip R _) (sym p) f

  _▸_ : ∀ {A B C} → R A B → B ≡ C → R A C
  f ▸ p = subst (R _) p f

  -- Some simple properties of transports
module Transport {O : Set o} (R : Rel O ℓ) where
  open Shorthands R public

  ◂-▸-id : ∀ {A} (f : R A A) → refl ◂ f ≡ f ▸ refl
  ◂-▸-id f = refl

  ◂-▸-comm : ∀ {A B C D} (p : A ≡ B) (f : R B C) (q : C ≡ D) →
             (p ◂ (f ▸ q)) ≡ ((p ◂ f) ▸ q)
  ◂-▸-comm refl f refl = refl

  ◂-assocˡ : ∀ {A B C D} (p : A ≡ B) {q : B ≡ C} (f : R C D) →
            p ◂ q ◂ f ≡ (trans p q) ◂ f
  ◂-assocˡ refl {refl} f = refl

  ▸-assocʳ : ∀ {A B C D} (f : R A B) {p : B ≡ C} (q : C ≡ D) →
            f ▸ p ▸ q ≡ f ▸ trans p q
  ▸-assocʳ f {refl} refl = refl

-- If we have a relation Q over a relation R, we can transport over that too
module TransportOverQ {O : Set o} (R : Rel O ℓ) (Q : {X Y : O} → Rel (R X Y) t)  where
  open Transport R

  ◂-resp-≈ : ∀ {A B C} (p : A ≡ B) {f g : R B C} → Q f g → Q (p ◂ f) (p ◂ g)
  ◂-resp-≈ refl f≈g = f≈g

  ▸-resp-≈ : ∀ {A B C} {f g : R A B} → Q f g → (p : B ≡ C) → Q (f ▸ p) (g ▸ p)
  ▸-resp-≈ f≈g refl = f≈g

-- Given two relations and a homomorphism between them,
-- congruence properties over subst
module TransportMor {O₁ O₂ : Set o}
  (R₁ : Rel O₁ ℓ) (R₂ : Rel O₂ t)
  (M₀       : O₁ → O₂)
  (M₁       : ∀ {A B} → R₁ A B → R₂ (M₀ A) (M₀ B)) where

  open Shorthands R₁
  open Shorthands R₂ renaming (_◂_ to _◃_; _▸_ to _▹_)

  M-resp-▸ : ∀ {A B C} (f : R₁ A B) (p : B ≡ C) →
             M₁ (f ▸ p) ≡ M₁ f ▹ cong M₀ p
  M-resp-▸ f refl = refl

  M-resp-◂ : ∀ {A B C} (p : A ≡ B) (f : R₁ B C) →
             M₁ (p ◂ f) ≡ cong M₀ p ◃ M₁ f
  M-resp-◂ refl f = refl

-- Transports on paths
module TransportStar {O : Set o} (R : Rel O ℓ) where
  open Shorthands (Star R) public renaming
    ( _◂_ to _◂*_
    ; _▸_ to _▸*_
    )
  open Shorthands R

  -- Lemmas relating transports to path operations.

  ◂*-▸*-ε : {A B : O} (p : A ≡ B) → ε ▸* p ≡ p ◂* ε
  ◂*-▸*-ε refl = refl

  ◂*-◅ : {A B C D : O} (p : A ≡ B) (f : R B C) (fs : Star R C D) →
         p ◂* (f ◅ fs) ≡ (p ◂ f) ◅ fs
  ◂*-◅ refl f fs = refl

  ◅-▸* : {A B C D : O} (f : R A B) (fs : Star R B C) (p : C ≡ D) →
         (f ◅ fs) ▸* p ≡ f ◅ (fs ▸* p)
  ◅-▸* f fs refl = refl

  ◅-◂*-▸ : {A B C D : O} (f : R A B) (p : B ≡ C) (fs : Star R C D) →
           _≡_ {_} {Star R A D} (f ◅ (p ◂* fs)) ((f ▸ p) ◅ fs)
  ◅-◂*-▸ f refl fs = refl


module BHeap.Heap {A : Set}(_≤_ : A → A → Set) where

open import BHeap _≤_
open import Bound.Lower A
open import Bound.Lower.Order _≤_
open import BTree.Heap _≤_

lemma-bheap-heap : {b : Bound}(h : BHeap b) → Heap (forget h)
lemma-bheap-heap lf = leaf
lemma-bheap-heap (nd {x = x} _ lf lf) = single x
lemma-bheap-heap (nd _ (nd (lexy x≤y) l r) lf) = left x≤y (lemma-bheap-heap (nd (lexy x≤y) l r))
lemma-bheap-heap (nd _ lf (nd (lexy x≤y) l r)) = right x≤y (lemma-bheap-heap (nd (lexy x≤y) l r))
lemma-bheap-heap (nd _ (nd (lexy x≤y) l r) (nd (lexy x≤y') l' r')) = both x≤y x≤y' (lemma-bheap-heap (nd (lexy x≤y) l r)) (lemma-bheap-heap (nd (lexy x≤y') l' r'))


------------------------------------------------------------------------------
-- Exclusive disjunction theorems
------------------------------------------------------------------------------

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

module FOL.ExclusiveDisjunction.TheoremsI where

-- The theorems below are valid on intuitionistic logic and with an
-- empty domain.
open import FOL.Base hiding ( D≢∅ ; pem )
open import FOL.ExclusiveDisjunction.Base

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

p⊻q→p→¬q : {P Q : Set} → P ⊻ Q → P → ¬ Q
p⊻q→p→¬q (inj₁ _ , h) p q = h (p , q)
p⊻q→p→¬q (inj₂ _ , h) p q = h (p , q)

p⊻q→q→¬p : {P Q : Set} → P ⊻ Q → Q → ¬ P
p⊻q→q→¬p (inj₁ _ , h) q p = h (p , q)
p⊻q→q→¬p (inj₂ _ , h) q p = h (p , q)

p⊻q→¬p→q : {P Q : Set} → P ⊻ Q → ¬ P → Q
p⊻q→¬p→q (inj₁ p , _) ¬p = ⊥-elim (¬p p)
p⊻q→¬p→q (inj₂ q , _) _  = q

p⊻q→¬q→p : {P Q : Set} → P ⊻ Q → ¬ Q → P
p⊻q→¬q→p (inj₁ p , _) ¬q = p
p⊻q→¬q→p (inj₂ q , _) ¬q = ⊥-elim (¬q q)


open import Data.List using ( List ; [] ; _∷_ )
open import Data.Nat using ( ℕ ; zero ; suc )
open import Data.Maybe using ( Maybe ; just ; nothing )
open import Relation.Binary.PropositionalEquality using ( _≡_ ; refl ; subst )
open import Relation.Binary.PropositionalEquality.TrustMe using ( trustMe )

module AssocFree.Util where

≡-relevant : ∀ {α} {A : Set α} {a b : A} → .(a ≡ b) → (a ≡ b)
≡-relevant a≡b = trustMe

δsubst₂ : ∀ {a b p} {A : Set a} {B : A → Set b} (P : ∀ a → B a → Set p)
         {x₁ x₂ y₁ y₂} → (x₁≡x₂ : x₁ ≡ x₂) → (subst B x₁≡x₂ y₁ ≡ y₂) → P x₁ y₁ → P x₂ y₂
δsubst₂ P refl refl p = p

subst-natural : ∀ {α β γ} {A : Set α} {B : A → Set β} {C : A → Set γ} {a₁ a₂ : A}
  (p : a₁ ≡ a₂) (f : ∀ {a} → B a → C a) (b : B a₁) →
    subst C p (f b) ≡ f (subst B p b)
subst-natural refl f b = refl

lookup : ∀ {α} {A : Set α} → List A → ℕ → Maybe A
lookup [] n             = nothing
lookup (a ∷ as) zero    = just a
lookup (a ∷ as) (suc n) = lookup as n


-- Concrete definition of contexts over a sort T
module SOAS.Context {T : Set} where

open import SOAS.Common

open import Data.List using (List; []; _∷_; _++_)

-- Context: a list of types
data Ctx : Set where
  ∅   : Ctx
  _∙_ : (α : T) → (Γ : Ctx) → Ctx
infixr 50 _∙_

-- Singleton context
pattern _⌋ τ = τ ∙ ∅
pattern ⌈_⌋ α = α ∙ ∅
pattern ⌊_ α = α
infixr 60 _⌋
infix 70 ⌈_⌋
infix 70 ⌊_

-- Context concatenation
_∔_ : Ctx → Ctx → Ctx
∅       ∔ Δ = Δ
(α ∙ Γ) ∔ Δ = α ∙ (Γ ∔ Δ)
infixl 20 _∔_

-- Context concatenation is associative
∔-assoc : (Γ Δ Θ : Ctx) → ((Γ ∔ Δ) ∔ Θ) ≡ (Γ ∔ (Δ ∔ Θ))
∔-assoc ∅ Δ Θ = refl
∔-assoc (α ∙ Γ) Δ Θ = cong (α ∙_) (∔-assoc Γ Δ Θ)

-- Empty context is right unit of context concatenation
∔-unitʳ : (Γ : Ctx) → Γ ∔ ∅ ≡ Γ
∔-unitʳ ∅ = refl
∔-unitʳ (α ∙ Γ) = cong (α ∙_) (∔-unitʳ Γ)


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

module Categories.Category.Complete where

open import Level

open import Categories.Category
open import Categories.Category.Construction.Cones
open import Categories.Functor
open import Categories.Diagram.Cone.Properties
open import Categories.Diagram.Limit using (Limit)

Complete : (o ℓ e : Level) {o′ ℓ′ e′ : Level} (C : Category o′ ℓ′ e′) → Set _
Complete o ℓ e C = ∀ {J : Category o ℓ e} (F : Functor J C) → Limit F

-- a functor between diagrams corresponds to a morphism between limits
module _ {o ℓ e o′ ℓ′ e′} {C : Category o′ ℓ′ e′} (Com : Complete o ℓ e C)
  {J J′ : Category o ℓ e} (F : Functor J′ J) (G : Functor J C) where

  private
    module C  = Category C
    module J  = Category J
    module J′ = Category J′
    module F  = Functor F
    module G  = Functor G

  F⇒arr : Cones (G ∘F F) [ F-map-Coneʳ F (Limit.limit (Com G)) , Limit.limit (Com (G ∘F F)) ]
  F⇒arr = Limit.rep-cone (Com (G ∘F F)) (F-map-Coneʳ F (Limit.limit (Com G)))


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

module Categories.Category.Finite.Fin.Construction.Discrete where

open import Data.Product using (∃; _,_)
open import Data.Nat using (ℕ)
open import Data.Fin
open import Data.Fin.Patterns
open import Function using (case_of_)

open import Relation.Nullary using (Dec; yes; no)
open import Relation.Binary.PropositionalEquality as ≡ using (_≡_ ; refl; ≡-≟-identity; ≢-≟-identity)

open import Categories.Category.Finite.Fin
open import Categories.Category

private
  card : ∀ {n} (j k : Fin n) → ℕ
  card {ℕ.suc n} 0F 0F           = 1
  card {ℕ.suc n} 0F (suc k)      = 0
  card {ℕ.suc n} (suc j) 0F      = 0
  card {ℕ.suc n} (suc j) (suc k) = card j k

  id : ∀ {n} (a : Fin n) → Fin (card a a)
  id {ℕ.suc n} 0F      = 0F
  id {ℕ.suc n} (suc a) = id a

  comp : ∀ n {a b c : Fin n} → Fin (card b c) → Fin (card a b) → Fin (card a c)
  comp (ℕ.suc n) {0F} {0F} {0F} f g = 0F
  comp (ℕ.suc n) {suc a} {suc b} {suc c} f g = comp n f g

  assoc : ∀ n {a b c d : Fin n}
            {f : Fin (card a b)} {g : Fin (card b c)} {h : Fin (card c d)} →
            (comp n (comp n h g) f) ≡ comp n h (comp n g f)
  assoc (ℕ.suc n) {0F} {0F} {0F} {0F} {f} {g} {h}             = refl
  assoc (ℕ.suc n) {suc a} {suc b} {suc c} {suc d} {f} {g} {h} = assoc n

  identityˡ : ∀ n {a b : Fin n} {f : Fin (card a b)} → comp n (id b) f ≡ f
  identityˡ (ℕ.suc n) {0F} {0F} {0F}      = refl
  identityˡ (ℕ.suc n) {suc a} {suc b} {f} = identityˡ n

  identityʳ : ∀ n {a b : Fin n} {f : Fin (card a b)} → comp n f (id a) ≡ f
  identityʳ (ℕ.suc n) {0F} {0F} {0F}      = refl
  identityʳ (ℕ.suc n) {suc a} {suc b} {f} = identityʳ n

module _ (n : ℕ) where

  DiscreteShape : FinCatShape
  DiscreteShape = record
    { size     = n
    ; ∣_⇒_∣    = card {n}
    ; hasShape = record
      { id        = id {n} _
      ; _∘_       = comp n
      ; assoc     = assoc n
      ; identityˡ = identityˡ n
      ; identityʳ = identityʳ n
      }
    }

Discrete : ∀ n → Category _ _ _
Discrete n = FinCategory (DiscreteShape n)

module Discrete n = Category (Discrete n)


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

open import Categories.Category

module Categories.Functor.Core where

open import Level
open import Function renaming (id to id→; _∘_ to _●_) using ()
open import Relation.Binary hiding (_⇒_)

import Relation.Binary.Reasoning.Setoid as SetoidR

import Categories.Morphism as M

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

record Functor (C : Category o ℓ e) (D : Category o′ ℓ′ e′) : Set (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′) where
  eta-equality
  private module C = Category C
  private module D = Category D

  field
    F₀ : C.Obj → D.Obj
    F₁ : ∀ {A B} (f : C [ A , B ]) → D [ F₀ A , F₀ B ]

    identity     : ∀ {A} → D [ F₁ (C.id {A}) ≈ D.id ]
    homomorphism : ∀ {X Y Z} {f : C [ X , Y ]} {g : C [ Y , Z ]} →
                     D [ F₁ (C [ g ∘ f ]) ≈ D [ F₁ g ∘ F₁ f ] ]
    F-resp-≈     : ∀ {A B} {f g : C [ A , B ]} → C [ f ≈ g ] → D [ F₁ f ≈ F₁ g ]

  op : Functor C.op D.op
  op = record
    { F₀           = F₀
    ; F₁           = F₁
    ; identity     = identity
    ; homomorphism = homomorphism
    ; F-resp-≈     = F-resp-≈
    }

Endofunctor : Category o ℓ e → Set _
Endofunctor C = Functor C C

id : ∀ {C : Category o ℓ e} → Endofunctor C
id {C = C} = record
  { F₀           = id→
  ; F₁           = id→
  ; identity     = refl
  ; homomorphism = refl
  ; F-resp-≈     = id→
  }
  where open Category.Equiv C

infixr 9 _∘F_

-- note that this definition could be shortened a lot by inlining the definitions for
-- identity′ and homomorphism′, but the definitions below are simpler to understand.
_∘F_ : ∀ {C : Category o ℓ e} {D : Category o′ ℓ′ e′} {E : Category o′′ ℓ′′ e′′}
    → Functor D E → Functor C D → Functor C E
_∘F_ {C = C} {D = D} {E = E} F G = record
  { F₀ = F₀ ● G₀
  ; F₁ = F₁ ● G₁
  ; identity = identity′
  ; homomorphism = homomorphism′
  ; F-resp-≈ =  F-resp-≈ ● G-resp-≈
  }
  where
  module C = Category C
  module D = Category D
  module E = Category E
  module F = Functor F
  module G = Functor G
  open F
  open G renaming (F₀ to G₀; F₁ to G₁; F-resp-≈ to G-resp-≈)

  identity′ : ∀ {A} → E [ F₁ (G₁ (C.id {A})) ≈ E.id ]
  identity′ = begin
    F₁ (G₁ C.id) ≈⟨ F-resp-≈ G.identity ⟩
    F₁ D.id      ≈⟨ F.identity ⟩
    E.id         ∎
    where open SetoidR E.hom-setoid

  homomorphism′ : ∀ {X Y Z} {f : C [ X , Y ]} {g : C [ Y , Z ]}
                 → E [ F₁ (G₁ (C [ g ∘ f ])) ≈ E [ F₁ (G₁ g) ∘ F₁ (G₁ f) ] ]
  homomorphism′ {f = f} {g = g} = begin
    F₁ (G₁ (C [ g ∘ f ]))       ≈⟨ F-resp-≈ G.homomorphism ⟩
    F₁ (D [ G₁ g ∘ G₁ f ])      ≈⟨ F.homomorphism ⟩
    E [ F₁ (G₁ g) ∘ F₁ (G₁ f) ] ∎
    where open SetoidR E.hom-setoid


-- Copyright:  (c) 2016 Ertugrul Söylemez
-- License:    BSD3
-- Maintainer: Ertugrul Söylemez <esz@posteo.de>

module Algebra.Category.Semigroupoid where

open import Core

-- A semigroupoid is a set of objects and morphisms between objects
-- together with an associative binary function that combines morphisms.

record Semigroupoid {c h r} : Set (lsuc (c ⊔ h ⊔ r)) where
  field
    Ob  : Set c
    Hom : Ob → Ob → Set h
    Eq  : ∀ {A B} → Equiv {r = r} (Hom A B)
    _∘_ : ∀ {A B C} → Hom B C → Hom A B → Hom A C

  infixl 6 _∘_

  open module MyEquiv {A} {B} = Equiv (Eq {A} {B}) public

  field
    ∘-cong :
      ∀ {A B C}
        {f1 f2 : Hom B C} {g1 g2 : Hom A B}
      → f1 ≈ f2 → g1 ≈ g2 → f1 ∘ g1 ≈ f2 ∘ g2

    assoc :
      ∀ {A B C D}
        (f : Hom C D) (g : Hom B C) (h : Hom A B)
      → (f ∘ g) ∘ h ≈ f ∘ (g ∘ h)

  Epic : ∀ {A B} → (f : Hom A B) → Set _
  Epic f = ∀ {C} {g1 g2 : Hom _ C} → g1 ∘ f ≈ g2 ∘ f → g1 ≈ g2

  Monic : ∀ {B C} → (f : Hom B C) → Set _
  Monic f = ∀ {A} {g1 g2 : Hom A _} → f ∘ g1 ≈ f ∘ g2 → g1 ≈ g2

  Unique : ∀ {A B} → (f : Hom A B) → Set _
  Unique f = ∀ g → f ≈ g

  IsProduct : ∀ A B AB → (fst : Hom AB A) (snd : Hom AB B) → Set _
  IsProduct A B AB fst snd =
    ∀ AB' (fst' : Hom AB' A) (snd' : Hom AB' B) →
    ∃ (λ (u : Hom AB' AB) → Unique u × (fst ∘ u ≈ fst') × (snd ∘ u ≈ snd'))

  record Product A B : Set (c ⊔ h ⊔ r) where
    field
      A×B  : Ob
      cfst : Hom A×B A
      csnd : Hom A×B B
      isProduct : IsProduct A B A×B cfst csnd

  record _bimonic_ A B : Set (c ⊔ h ⊔ r) where
    field
      to   : Hom A B
      from : Hom B A
      to-monic   : Monic to
      from-monic : Monic from

-- A semifunctor is a composition-preserving mapping from a semigroupoid
-- to another.

record Semifunctor
           {cc ch cr dc dh dr}
           (C : Semigroupoid {cc} {ch} {cr})
           (D : Semigroupoid {dc} {dh} {dr})
           : Set (cc ⊔ ch ⊔ cr ⊔ dc ⊔ dh ⊔ dr)
       where

  private
    module C = Semigroupoid C
    module D = Semigroupoid D

  field
    F   : C.Ob → D.Ob
    map : ∀ {A B} → C.Hom A B → D.Hom (F A) (F B)

    map-cong :
      ∀ {A B} {f g : C.Hom A B}
      → f C.≈ g
      → map f D.≈ map g

    ∘-preserving :
      ∀ {A B C}
        (f : C.Hom B C) (g : C.Hom A B)
      → map (f C.∘ g) D.≈ map f D.∘ map g


module prelude.list where
open import Data.Nat renaming (zero to z; suc to s)
open import Data.Fin as Fin using (Fin)
import Data.Fin as Fin renaming (zero to z; suc to s)
open import Agda.Builtin.Sigma
open import Data.Product
open import Relation.Binary.PropositionalEquality.Core using (_≡_; _≢_; refl; cong)
open import Data.Empty
open import Function

Vect : ∀ {ℓ} → ℕ → Set ℓ → Set ℓ
Vect n t = Fin n → t
List : ∀ {ℓ} → Set ℓ → Set ℓ
List t = Σ[ n ∈ ℕ ] Vect n t
len : ∀ {ℓ} {a : Set ℓ} → List a → ℕ
len = fst
head : ∀ {ℓ} {a : Set ℓ} → (as : List a) → (len as ≢ z) → a
head (z , as) n≢0 = ⊥-elim (n≢0 refl)
head (s n , as) _ = as Fin.z
tail : ∀ {ℓ} {a : Set ℓ} → (as : List a) → (len as ≢ z) → List a
tail (z , as) n≢0 = ⊥-elim (n≢0 refl)
tail (s n , as) _ = n , (as ∘ Fin.inject₁)


module Metalogic.Classical.Propositional.Syntax {ℓₚ} (Proposition : Set(ℓₚ)) where

import Lvl

infixl 1011 •_
infixl 1010 ¬_
infixl 1005 _∧_
infixl 1004 _∨_
infixl 1000 _⇐_ _⇔_ _⇒_

data Formula : Set(ℓₚ) where
  •_ : Proposition → Formula

  ⊤ : Formula
  ⊥ : Formula

  ¬_ : Formula → Formula

  _∧_ : Formula → Formula → Formula
  _∨_ : Formula → Formula → Formula
  _⇒_ : Formula → Formula → Formula

_⇐_ : Formula → Formula → Formula
_⇐_ a b = _⇒_ b a

_⇔_ : Formula → Formula → Formula
_⇔_ a b = (_⇐_ a b) ∧ (_⇒_ a b)


open import Relation.Binary.Core

module BBHeap.Subtyping {A : Set}
                  (_≤_ : A → A → Set)
                  (trans≤ : Transitive _≤_) where

open import BBHeap _≤_
open import Bound.Lower A
open import Bound.Lower.Order _≤_
open import Bound.Lower.Order.Properties _≤_ trans≤

subtyping : {b b' : Bound} → LeB b' b → BBHeap b → BBHeap b'
subtyping _ leaf = leaf
subtyping b'≤b (left b≤x l⋘r) = left (transLeB b'≤b b≤x) l⋘r
subtyping b'≤b (right b≤x l⋙r) = right (transLeB b'≤b b≤x) l⋙r


data Bool : Set where
  true : Bool
  false : Bool

record Eq (t : Set) : Set where
   field _==_ : t → t → Bool

open Eq {{...}}

-- Now package this into a record type for "sets with boolean equality":
record EqSet : Set₁ where
  field
    set : Set
    instance eq : Eq set

open EqSet

equality : {{A : EqSet}} (x y : set A) → Bool
equality x y = x == y


module Data.Option.Setoid where

import      Lvl
open import Data
open import Data.Option
open import Functional
open import Structure.Relator.Equivalence
open import Structure.Relator.Properties
open import Structure.Setoid
open import Type

private variable ℓ ℓₑ ℓₑₐ : Lvl.Level
private variable A : Type{ℓ}

instance
  Option-equiv : ⦃ equiv : Equiv{ℓₑ}(A) ⦄ → Equiv{ℓₑ}(Option A)
  Equiv._≡_ Option-equiv None     None     = Unit
  Equiv._≡_ Option-equiv None     (Some _) = Empty
  Equiv._≡_ Option-equiv (Some _) None     = Empty
  Equiv._≡_ Option-equiv (Some x) (Some y) = x ≡ y
  Reflexivity.proof  (Equivalence.reflexivity  (Equiv.equivalence Option-equiv)) {None}   = <>
  Reflexivity.proof  (Equivalence.reflexivity  (Equiv.equivalence Option-equiv)) {Some _} = reflexivity(_≡_)
  Symmetry.proof     (Equivalence.symmetry     (Equiv.equivalence Option-equiv)) {None}   {None}   = const(<>)
  Symmetry.proof     (Equivalence.symmetry     (Equiv.equivalence Option-equiv)) {Some _} {Some _} = symmetry(_≡_)
  Transitivity.proof (Equivalence.transitivity (Equiv.equivalence Option-equiv)) {None}   {None}   {None}   = const(const(<>))
  Transitivity.proof (Equivalence.transitivity (Equiv.equivalence Option-equiv)) {Some _} {Some _} {Some _} = transitivity(_≡_)


{-# OPTIONS --safe #-}
module Cubical.Algebra.Group.Instances.Int where

open import Cubical.Foundations.Prelude
open import Cubical.Data.Int renaming (Int to IntType ; _+_ to _+Int_ ; _-_ to _-Int_; -_ to -Int_ ; _·_ to _·Int_)
open import Cubical.Algebra.Group.Base

open GroupStr

Int : Group₀
fst Int = IntType
1g (snd Int) = 0
_·_ (snd Int) = _+Int_
inv (snd Int) = _-Int_ 0
isGroup (snd Int) = isGroupInt
  where
  abstract
    isGroupInt : IsGroup (pos 0) _+Int_ (_-Int_ (pos 0))
    isGroupInt = makeIsGroup isSetInt +-assoc (λ x → refl) (λ x → +-comm 0 x)
                              (λ x → +-comm x (pos 0 -Int x) ∙ minusPlus x 0) (λ x → minusPlus x 0)


------------------------------------------------------------------------
-- Lemmas
------------------------------------------------------------------------

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

module Math.Combinatorics.ListFunction.Properties.Lemma where

open import Data.List hiding (_∷ʳ_)
import Data.List.Properties as Lₚ
open import Data.List.Relation.Binary.Sublist.Propositional using (_⊆_; []; _∷_; _∷ʳ_)
open import Data.Product as Prod using (proj₁; proj₂; _×_; _,_)
open import Function
open import Relation.Binary.PropositionalEquality

module _ {a} {A : Set a} where
  []⊆xs : ∀ (xs : List A) → [] ⊆ xs
  []⊆xs []       = []
  []⊆xs (x ∷ xs) = x ∷ʳ []⊆xs xs

module _ {a b} {A : Set a} {B : Set b} where
  lemma₁ : ∀ (f : A → B) (x : A) (xss : List (List A)) →
    map (λ ys → f x ∷ ys) (map (map f) xss) ≡ map (map f) (map (λ ys → x ∷ ys) xss)
  lemma₁ f x xss = begin
    map (λ ys → f x ∷ ys) (map (map f) xss) ≡⟨ sym $ Lₚ.map-compose xss ⟩
    map (λ ys → f x ∷ map f ys) xss         ≡⟨ Lₚ.map-compose xss ⟩
    map (map f) (map (λ ys → x ∷ ys) xss)   ∎
    where open ≡-Reasoning

module _ {a b c} {A : Set a} {B : Set b} {C : Set c} where
  proj₁-map₁ : ∀ (f : A → B) (t : A × C) → proj₁ (Prod.map₁ f t) ≡ f (Prod.proj₁ t)
  proj₁-map₁ _ _ = refl

module _ {a b} {A : Set a} {B : Set b} where
  proj₁-map₂ : ∀ (f : B → B) (t : A × B) → proj₁ (Prod.map₂ f t) ≡ proj₁ t
  proj₁-map₂ _ _ = refl

  proj₁′ : A × B → A
  proj₁′ = proj₁


{-

Axiom of Finite Choice
- Yep, it's a theorem actually.

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

module Cubical.Data.FinSet.FiniteChoice where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Equiv renaming (_∙ₑ_ to _⋆_)

open import Cubical.HITs.PropositionalTruncation as Prop

open import Cubical.Data.Nat
open import Cubical.Data.Unit
open import Cubical.Data.Empty
open import Cubical.Data.Sum
open import Cubical.Data.Sigma

open import Cubical.Data.SumFin
open import Cubical.Data.FinSet.Base
open import Cubical.Data.FinSet.Properties

private
  variable
    ℓ ℓ' : Level

choice≃Fin :
  {n : ℕ}(Y : Fin n → Type ℓ) → ((x : Fin n) → ∥ Y x ∥) ≃ ∥ ((x : Fin n) → Y x) ∥
choice≃Fin {n = 0} Y =
    isContr→≃Unit (isContrΠ⊥)
  ⋆ Unit≃Unit*
  ⋆ invEquiv (propTruncIdempotent≃ isPropUnit*)
  ⋆ propTrunc≃ (invEquiv (isContr→≃Unit* (isContrΠ⊥ {A = Y})))
choice≃Fin {n = suc n} Y =
    Π⊎≃
  ⋆ Σ-cong-equiv-fst (ΠUnit (λ x → ∥ Y (inl x) ∥))
  ⋆ Σ-cong-equiv-snd (λ _ → choice≃Fin {n = n} (λ x → Y (inr x)))
  ⋆ Σ-cong-equiv-fst (propTrunc≃ (invEquiv (ΠUnit (λ x → Y (inl x)))))
  ⋆ ∥∥-×-≃
  ⋆ propTrunc≃ (invEquiv (Π⊎≃ {E = Y}))

module _
  (X : Type ℓ)(p : isFinOrd X)
  (Y : X → Type ℓ') where

  private
    e = p .snd

  choice≃' : ((x : X) → ∥ Y x ∥) ≃ ∥ ((x : X) → Y x) ∥
  choice≃' =
      equivΠ {B' = λ x → ∥ Y (invEq e x) ∥} e (transpFamily p)
    ⋆ choice≃Fin _
    ⋆ propTrunc≃ (invEquiv (equivΠ {B' = λ x → Y (invEq e x)} e (transpFamily p)))

module _
  (X : FinSet ℓ)
  (Y : X .fst → Type ℓ') where

  choice≃ : ((x : X .fst) → ∥ Y x ∥) ≃ ∥ ((x : X .fst) → Y x) ∥
  choice≃ =
    Prop.rec
      (isOfHLevel≃ 1 (isPropΠ (λ x → isPropPropTrunc)) isPropPropTrunc)
      (λ p → choice≃' (X .fst) (_ , p) Y) (X .snd .snd)

  choice : ((x : X .fst) → ∥ Y x ∥) → ∥ ((x : X .fst) → Y x) ∥
  choice = choice≃ .fst


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

open import Categories.Category

module Categories.Category.BicartesianClosed {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level

open import Categories.Category.CartesianClosed 𝒞
open import Categories.Category.Cocartesian 𝒞

record BicartesianClosed : Set (levelOfTerm 𝒞) where
  field
    cartesianClosed : CartesianClosed
    cocartesian     : Cocartesian

  module cartesianClosed = CartesianClosed cartesianClosed
  module cocartesian     = Cocartesian cocartesian

  open cartesianClosed public
  open cocartesian public