module plfa.working.Induction where

  import Relation.Binary.PropositionalEquality as Eq
  open Eq using (_≡_; refl; cong; sym)
  open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; step-≡; _∎)
  open import Data.Nat using (ℕ; zero; suc; _+_; _*_; _∸_)

  +-assoc : ∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
  +-assoc zero n p =
    begin
      (zero + n) + p
    ≡⟨⟩
      n + p
    ≡⟨⟩
      zero + (n + p)
    ∎
  +-assoc (suc m) n p =
    begin
      (suc m + n) + p
    ≡⟨⟩
      suc (m + n) + p
    ≡⟨⟩
      suc ((m + n) + p)
    ≡⟨ cong suc (+-assoc m n p) ⟩
      suc (m + (n + p))
    ≡⟨⟩
      suc m + (n + p)
    ∎

  +-identity : ∀ (m : ℕ) → m + zero ≡ m
  +-identity zero =
    begin
      zero + zero
    ≡⟨⟩
      zero
    ∎
  +-identity (suc m) =
    begin
      (suc m) + zero
    ≡⟨⟩
      suc (m + zero)
    ≡⟨ cong suc (+-identity m) ⟩
      suc m
    ∎

  +-suc : ∀ (m n : ℕ) → m + suc n ≡ suc (m + n)
  +-suc zero n =
    begin
      zero + suc n
    ≡⟨⟩
      suc n
    ≡⟨⟩
      suc (zero + n)
    ∎
  +-suc (suc m) n =
    begin
      suc m + suc n
    ≡⟨⟩
      (suc m) + suc n
    ≡⟨ cong suc (+-suc m n) ⟩
      suc (suc m + n)
    ∎

  +-comm : ∀ (m n : ℕ) → m + n ≡ n + m
  +-comm m zero =
    begin
      m + zero
    ≡⟨ +-identity m ⟩
      m
    ≡⟨⟩
      zero + m
    ∎
  +-comm m (suc n) =
    begin
      m + suc n
    ≡⟨ +-suc m n ⟩
      suc (m + n)
    ≡⟨ cong suc (+-comm m n) ⟩
      suc (n + m)
    ≡⟨⟩
      suc n + m
    ∎


module examplesPaperJFP.Colists where

-- open import Function

-- Case expressions (to be used with pattern-matching lambdas, see
-- README.Case).

infix 0 case_return_of_ case_of_

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

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

data ListF A S : Set where
  nil   :  ListF A S
  cons  :  (a : A) (s : S) → ListF A S

record Colist A : Set where
  coinductive
  field force : ListF A (Colist A)

open Colist using (force)

mapF : ∀{A S S′} (f : S → S′) → (ListF A S → ListF A S′)
mapF f nil         =  nil
mapF f (cons a s)  =  cons a (f s)

-- As an example, we define mapping over potentially infinite lists using
-- copattern matching:

map : ∀{A B} (f : A → B) (l : Colist A) → Colist B
force (map f l) with force l
... | nil        =  nil
... | cons x xs  =  cons (f x) (map f xs)

unfold              :  ∀{A S} (t : S → ListF A S) → (S → Colist A)
force (unfold t s)  with t s
... | nil           =  nil
... | cons a s′     =  cons a (unfold t s′)

fmap : ∀{A B} (f : A → B) (l : Colist A) → Colist B
fmap f = unfold λ l → case force l of λ
  { nil → nil
  ; (cons a s) → cons (f a) s
  }


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

open import Prelude
open import Relation.Binary

module Relation.Binary.Construct.LowerBound {e} {E : Type e} {r} (totalOrder : TotalOrder E r) where

open TotalOrder totalOrder renaming (refl to ≤-refl)
import Data.Unit.UniversePolymorphic as Poly
import Data.Empty.UniversePolymorphic as Poly

data ⌊∙⌋ : Type e where
  ⌊⊥⌋ : ⌊∙⌋
  ⌊_⌋ : E → ⌊∙⌋

_≤⌊_⌋ : ⌊∙⌋ → E → Type r
⌊⊥⌋   ≤⌊ y ⌋ = Poly.⊤
⌊ x ⌋ ≤⌊ y ⌋ = x ≤ y

_⌊≤⌋_ : ⌊∙⌋ → ⌊∙⌋ → Type r
x     ⌊≤⌋ ⌊ y ⌋ = x ≤⌊ y ⌋
⌊⊥⌋   ⌊≤⌋ ⌊⊥⌋   = Poly.⊤
⌊ x ⌋ ⌊≤⌋ ⌊⊥⌋   = Poly.⊥

lb-ord : TotalOrder ⌊∙⌋ r
PartialOrder._≤_ (TotalOrder.partialOrder lb-ord) = _⌊≤⌋_
PartialOrder.refl (partialOrder lb-ord) {⌊⊥⌋} = Poly.tt
PartialOrder.refl (partialOrder lb-ord) {⌊ x ⌋} = ≤-refl
PartialOrder.antisym (TotalOrder.partialOrder lb-ord) {⌊⊥⌋} {⌊⊥⌋} x≤y y≤x _ = ⌊⊥⌋
PartialOrder.antisym (TotalOrder.partialOrder lb-ord) {⌊ x ⌋} {⌊ x₁ ⌋} x≤y y≤x i = ⌊ antisym x≤y y≤x i ⌋
PartialOrder.trans (TotalOrder.partialOrder lb-ord) {⌊⊥⌋} {⌊⊥⌋} {⌊⊥⌋} x≤y y≤z = Poly.tt
PartialOrder.trans (TotalOrder.partialOrder lb-ord) {⌊⊥⌋} {⌊⊥⌋} {⌊ x ⌋} x≤y y≤z = Poly.tt
PartialOrder.trans (TotalOrder.partialOrder lb-ord) {⌊⊥⌋} {⌊ x ⌋} {⌊ x₁ ⌋} x≤y y≤z = Poly.tt
PartialOrder.trans (TotalOrder.partialOrder lb-ord) {⌊ x ⌋} {⌊ x₁ ⌋} {⌊ x₂ ⌋} x≤y y≤z = trans x≤y y≤z
TotalOrder._≤?_ lb-ord ⌊⊥⌋ ⌊⊥⌋ = inl Poly.tt
TotalOrder._≤?_ lb-ord ⌊ x ⌋ ⌊⊥⌋ = inr Poly.tt
TotalOrder._≤?_ lb-ord ⌊⊥⌋ ⌊ x₁ ⌋ = inl Poly.tt
TotalOrder._≤?_ lb-ord ⌊ x ⌋ ⌊ y ⌋ = x ≤? y


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

syntax Inception | IA

type
  L : 0-ary
  P : 0-ary
  A : 0-ary

term
  rec : L  P  ->  A
  inc : L.A  P.A  ->  A

theory
  (S) p : P   a : P.A |> inc (l. rec (l, p[]), x. a[x]) = a[p[]]
  (E) a : L.A  |> k : L |- inc (l. a[l], x. rec(k, x)) = a[k]
  (W) m : A  a : P.A  |> inc (l. m[], x. a[x]) = m[]
  (A) p : (L,L).A  a : (L,P).A  b : P.A |>         inc (l. inc (k. p[l, k], x. a[l,x]), y. b[y])       = inc (k. inc(l. p[l,k], y.b[y]), x. inc(l. a[l,x], y.b[y]))
-}

module Inception.Signature where

open import SOAS.Context

-- Type declaration
data IAT : Set where
  L : IAT
  P : IAT
  A : IAT

open import SOAS.Syntax.Signature IAT public
open import SOAS.Syntax.Build IAT public

-- Operator symbols
data IAₒ : Set where
  recₒ incₒ : IAₒ

-- Term signature
IA:Sig : Signature IAₒ
IA:Sig = sig λ
  {  recₒ  → (⊢₀ L) , (⊢₀ P) ⟼₂ A
  ;  incₒ  → (L ⊢₁ A) , (P ⊢₁ A) ⟼₂ A
  }

open Signature IA:Sig public


module List.Permutation.Pair (A : Set) where

open import Data.List
open import Data.Product

data _≈_ : List A → List A × List A → Set where
  ≈[]r : (xs : List A)
                   → xs ≈ (xs , [])
  ≈[]l : (xs : List A)
                   → xs ≈ ([] , xs)
  ≈xr : {x : A}{xs ys zs : List A}
                   → xs ≈ (ys , zs)
                   → (x ∷ xs) ≈ (ys , x ∷ zs)
  ≈xl : {x : A}{xs ys zs : List A}
                   → xs ≈ (ys , zs)
                   → (x ∷ xs) ≈ (x ∷ ys , zs)


module Base where

data True : Set where
  T : True

data False : Set where

infix 20 _*_

data _*_ (A : Set)(B : A -> Set) : Set where
 <_,_> : (x : A) -> B x -> A * B

rel : Set -> Set1
rel A = A -> A -> Set

pred : Set -> Set1
pred A = A -> Set

Refl : {A : Set} -> rel A -> Set
Refl {A} R = {x : A} -> R x x

Sym : {A : Set} -> rel A -> Set
Sym {A} R = {x y : A} -> R x y -> R y x

Trans : {A : Set} -> rel A -> Set
Trans {A} R = {x y z : A} -> R x y -> R y z -> R x z

Map : {A : Set} -> rel A -> {B : Set} -> rel B -> pred (A -> B)
Map {A} _R_ _S_ f = {x y : A} -> x R y -> f x S f y


{-# OPTIONS --cubical --safe #-}
module Cubical.HITs.Ints.QuoInt.Properties where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.GroupoidLaws

open import Cubical.HITs.Ints.QuoInt.Base
  renaming (_+ℤ_ to _+_)
open import Cubical.Data.Nat
  hiding (+-comm; +-zero; _+_)

+-pos-0 : ∀ a → pos 0 + a ≡ a
+-pos-0 (pos zero) = refl
+-pos-0 (pos (suc n)) = cong sucℤ (+-pos-0 (pos n))
+-pos-0 (neg zero) = posneg
+-pos-0 (neg (suc n)) = cong predℤ (+-pos-0 (neg n))
+-pos-0 (posneg i) j = posneg (i ∧ j)

+-neg-0 : ∀ a → neg 0 + a ≡ a
+-neg-0 (neg zero) = refl
+-neg-0 (neg (suc n)) = cong predℤ (+-neg-0 (neg n))
+-neg-0 (pos zero) = sym posneg
+-neg-0 (pos (suc n)) = cong sucℤ (+-neg-0 (pos n))
+-neg-0 (posneg i) j = posneg (i ∨ ~ j)

+-pos-suc : ∀ a b → sucℤ (pos b + a) ≡ (pos (suc b) + a)
+-pos-suc (pos zero) b = refl
+-pos-suc (pos (suc n)) b = cong sucℤ (+-pos-suc (pos n) b)
+-pos-suc (neg zero) b = refl
+-pos-suc (posneg i) b = refl
+-pos-suc (neg (suc n)) b =
  sucPredℤ (pos b + neg n) ∙∙
  sym (predSucℤ (pos b + neg n)) ∙∙
  cong predℤ (+-pos-suc (neg n) b)
  -- the following hcomp does not termination-check:
  -- hcomp (λ j → λ
  --  { (i = i0) → sucPredℤ (pos b + neg n) (~ j)
  --  ; (i = i1) → {!predℤ ((+-pos-suc (neg n) b) j)!}
  --  }) (predSucℤ (pos b + neg n) (~ i))

+-neg-pred : ∀ a b → predℤ (neg b + a) ≡ (neg (suc b) + a)
+-neg-pred (pos zero) b = refl
+-neg-pred (neg zero) b = refl
+-neg-pred (neg (suc n)) b = cong predℤ (+-neg-pred (neg n) b)
+-neg-pred (posneg i) b = refl
+-neg-pred (pos (suc n)) b =
  predSucℤ (neg b + pos n) ∙∙
  sym (sucPredℤ (neg b + pos n)) ∙∙
  cong sucℤ (+-neg-pred (pos n) b)

+-comm : ∀ a b → a + b ≡ b + a
+-comm a (pos zero) = sym (+-pos-0 a)
+-comm a (neg zero) = sym (+-neg-0 a)
+-comm a (pos (suc b)) = cong sucℤ (+-comm a (pos b)) ∙ +-pos-suc a b
+-comm a (neg (suc b)) = cong predℤ (+-comm a (neg b)) ∙ +-neg-pred a b
+-comm a (posneg i) = lemma a i
  where
  -- get some help from:
  -- https://www.codewars.com/kata/reviews/5c878e3ef1abb10001e32eb1/groups/5cca3f9e840f4b0001d8ac98
  lemma : ∀ a → (λ i → (a + posneg i) ≡ (posneg i + a))
          [ sym (+-pos-0 a) ≡ sym (+-neg-0 a) ]
  lemma (pos zero) i j = posneg (i ∧ j)
  lemma (pos (suc n)) i = cong sucℤ (lemma (pos n) i)
  lemma (neg zero) i j = posneg (i ∨ ~ j)
  lemma (neg (suc n)) i = cong predℤ (lemma (neg n) i)
  lemma (posneg i) j k = posneg ((i ∧ ~ k) ∨ (i ∧ j) ∨ (j ∧ k))


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

open import Categories.Category

--  obtain free properties from duality
module Categories.Diagram.Pushout.Properties {o ℓ e} (C : Category o ℓ e) where

open Category C

open import Data.Product using (∃; _,_)

open import Categories.Category.Cocartesian C
open import Categories.Morphism C
open import Categories.Morphism.Properties C
open import Categories.Morphism.Duality C
open import Categories.Object.Initial C
open import Categories.Object.Terminal op
open import Categories.Object.Coproduct C
open import Categories.Object.Duality C
open import Categories.Diagram.Coequalizer C
open import Categories.Diagram.Pushout C
open import Categories.Diagram.Duality C
open import Categories.Diagram.Pullback op as P′ using (Pullback)
open import Categories.Diagram.Pullback.Properties op

private
  variable
    A B X Y : Obj
    f g h i : A ⇒ B

module _ (p : Pushout f g) where
  open Pushout p

  private
    pullback : Pullback f g
    pullback = Pushout⇒coPullback p

  open Pullback pullback
    using (unique′; id-unique; unique-diagram)
    public

  swap : Pushout g f
  swap = coPullback⇒Pushout (P′.swap pullback)

  glue : Pushout h i₁ → Pushout (h ∘ f) g
  glue p = coPullback⇒Pushout (P′.glue pullback (Pushout⇒coPullback p))

  unglue : Pushout (h ∘ f) g → Pushout h i₁
  unglue p = coPullback⇒Pushout (P′.unglue pullback (Pushout⇒coPullback p))

  Pushout-resp-Epi : Epi g → Epi i₁
  Pushout-resp-Epi epi = P′.Pullback-resp-Mono pullback epi

  Pushout-resp-Iso : Iso g h → ∃ λ j → Iso i₁ j
  Pushout-resp-Iso iso with P′.Pullback-resp-Iso pullback (Iso⇒op-Iso (Iso-swap iso))
  ... | j , record { isoˡ = isoˡ ; isoʳ = isoʳ } = j , record { isoˡ = isoʳ ; isoʳ = isoˡ }

Coproduct×Coequalizer⇒Pushout : (cp : Coproduct A B) →
                                Coequalizer (Coproduct.i₁ cp ∘ f) (Coproduct.i₂ cp ∘ g) →
                                Pushout f g
Coproduct×Coequalizer⇒Pushout cp coe =
  coPullback⇒Pushout (P′.Product×Equalizer⇒Pullback (coproduct→product cp)
                                                    (Coequalizer⇒coEqualizer coe))

Coproduct×Pushout⇒Coequalizer : (cp : Coproduct A B) →
                                Pushout f g →
                                Coequalizer (Coproduct.i₁ cp ∘ f) (Coproduct.i₂ cp ∘ g)
Coproduct×Pushout⇒Coequalizer cp p =
  coEqualizer⇒Coequalizer (P′.Product×Pullback⇒Equalizer (coproduct→product cp)
                                                         (Pushout⇒coPullback p))

module _ (i : Initial) where
  open Initial i
  private
    t : Terminal
    t = ⊥⇒op⊤ i

  pushout-⊥⇒coproduct : Pushout (! {X}) (! {Y}) → Coproduct X Y
  pushout-⊥⇒coproduct p = product→coproduct (pullback-⊤⇒product t (Pushout⇒coPullback p))

  coproduct⇒pushout-⊥ : Coproduct X Y → Pushout (! {X}) (! {Y})
  coproduct⇒pushout-⊥ c = coPullback⇒Pushout (product⇒pullback-⊤ t (coproduct→product c))

pushout-resp-≈ : Pushout f g → f ≈ h → g ≈ i → Pushout h i
pushout-resp-≈ p eq eq′ = coPullback⇒Pushout (pullback-resp-≈ (Pushout⇒coPullback p) eq eq′)

module _ (pushouts : ∀ {X Y Z} (f : X ⇒ Y) (g : X ⇒ Z) → Pushout f g)
         (cocartesian : Cocartesian) where
  open Cocartesian cocartesian
  open Dual

  pushout×cocartesian⇒coequalizer : Coequalizer f g
  pushout×cocartesian⇒coequalizer = coEqualizer⇒Coequalizer
    (pullback×cartesian⇒equalizer (λ f g → Pushout⇒coPullback (pushouts f g)) op-cartesian)


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

open import LogicalFormulae
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Setoids.Setoids
open import Setoids.Subset
open import Setoids.Functions.Definition
open import Sets.EquivalenceRelations

module Setoids.Functions.Lemmas {a b c d : _} {A : Set a} {B : Set b} {S : Setoid {a} {c} A} {T : Setoid {b} {d} B} {f : A → B} (w : WellDefined S T f) where

inverseImagePred : {e : _} → {pred : B → Set e} → (sub : subset T pred) → A → Set (b ⊔ d ⊔ e)
inverseImagePred {pred = pred} subset a = Sg B (λ b → (pred b) && (Setoid._∼_ T (f a) b))

inverseImageWellDefined : {e : _} {pred : B → Set e} → (sub : subset T pred) → subset S (inverseImagePred sub)
inverseImageWellDefined sub {x} {y} x=y (b , (predB ,, fx=b)) = f x , (sub (symmetric fx=b) predB ,, symmetric (w x=y))
  where
    open Setoid T
    open Equivalence eq


module Data.Vec.Any.Membership.Propositional.Properties where

open import Algebra
open import Data.Vec as Vec
open import Data.Vec.Any
open import Data.Vec.Any.Membership.Propositional
open import Data.Vec.Any.Properties
import Data.Vec.Any.Membership.Properties as Membershipᵖ
open import Function
open import Function.Inverse as Inv using (_↔_)
import Function.Related as Related
open import Function.Related.TypeIsomorphisms
open import Relation.Binary.PropositionalEquality as P
import Relation.Binary.Sigma.Pointwise as Σ
open import Relation.Unary using (_⟨×⟩_)
open import Data.Product

private
  module ×⊎ {k ℓ} = CommutativeSemiring (×⊎-CommutativeSemiring k ℓ)

-- map

module _ {a b} {A : Set a} {B : Set b} {f : A → B} where
  ∈′-map⁺ : ∀ {n x}{xs : Vec A n} → x ∈′ xs → f x ∈′ Vec.map f xs
  ∈′-map⁺ = Membershipᵖ.∈′-map⁺ (P.setoid _) (P.setoid _) (P.cong f)

  ∈′-map⁻ : ∀ {n y}{xs : Vec A n} → y ∈′ Vec.map f xs → ∃ λ x → x ∈′ xs × y ≡ f x
  ∈′-map⁻ = Membershipᵖ.∈′-map⁻ (P.setoid _) (P.setoid _)

  map-∈′↔ : ∀ {n y}{xs : Vec A n} →
    (∃ λ x → x ∈′ xs × y ≡ f x) ↔ y ∈′ Vec.map f xs
  map-∈′↔ {n}{y}{xs} =
    (∃ λ x → x ∈′ xs × y ≡ f x) ↔⟨ Any↔ ⟩
    Any (λ x → y ≡ f x)   xs    ↔⟨ map↔ ⟩
    y ∈′ Vec.map f xs       ∎
    where open Related.EquationalReasoning


{-# OPTIONS --copatterns #-}
-- {-# OPTIONS -v tc.pos:20 -v tc.meta.eta:100 #-}
-- {-# OPTIONS -v tc.lhs:100 #-}

module LinearTemporalLogic where

import Common.Level

record Stream (A : Set) : Set where
  coinductive
  field head : A
        tail : Stream A

-- Stream properties
Proposition : Set → Set₁
Proposition A = Stream A → Set

Now : {A : Set} → (A → Set) → Proposition A
Now P s = P (Stream.head s)

-- Next time
◌ : {A : Set} → Proposition A → Proposition A
◌ P s = P (Stream.tail s)

-- Forever
record ▢ {A : Set} (P : Proposition A) (s : Stream A) : Set where
  coinductive
  field head : P s
        tail : ◌ (▢ P) s

-- Sometimes
data ◇ {A : Set} (P : Proposition A) (s : Stream A) : Set where
  now   : P s → ◇ P s
  later : ◌ (◇ P) s → ◇ P s

-- Infinitely often
▢◇ : {A : Set} → Proposition A → Proposition A
▢◇ P = ▢ (◇ P)

-- Next inf. often  implies inf. often
◌▢◇⇒▢◇ : {A : Set}{P : Proposition A}{s : Stream A} →
    ◌ (▢◇ P) s → ▢◇ P s
▢.head (◌▢◇⇒▢◇ f) = later (▢.head f)
▢.tail (◌▢◇⇒▢◇ f) = ◌▢◇⇒▢◇ (▢.tail f)

-- Forever implies inf. oft.
▢⇒▢◇ : {A : Set}{P : Proposition A}{s : Stream A} →
    ▢ P s → ▢◇ P s
▢.head (▢⇒▢◇ f) = now (▢.head f)
▢.tail (▢⇒▢◇ f) = ▢⇒▢◇ (▢.tail f)

-- Eventually
◇▢ : {A : Set} → Proposition A → Proposition A
◇▢ P = ◇ (▢ P)

-- Eventually implies inf. oft.
◇▢⇒▢◇ : {A : Set}{P : Proposition A}{s : Stream A} →
  ◇▢ P s → ▢◇ P s
◇▢⇒▢◇ (now forever) = ▢⇒▢◇ forever
◇▢⇒▢◇ (later event) = ◌▢◇⇒▢◇ (◇▢⇒▢◇ event)

-- We now prove that inf. oft. does not imply eventually
-- by exhibiting a counter example

data ⊥ : Set where
record ⊤ : Set where
  constructor tt

data Bool : Set where
  true false : Bool

True : Bool → Set
True true = ⊤
True false = ⊥

open Stream

alternate : Stream Bool
(     (head alternate)) = true
(head (tail alternate)) = false
(tail (tail alternate)) = alternate

-- alternate contains infinitely many 'true's
thm1 : ▢◇ (Now True) alternate
(        (▢.head thm1)) = now tt
(▢.head (▢.tail thm1)) = later (now tt)
(▢.tail (▢.tail thm1)) = thm1

-- alternate does not eventually contain only 'true's
mutual

  thm2 : ◇▢ (Now True) alternate → ⊥
  thm2 (now forever⊤) = ▢.head (▢.tail forever⊤)
  thm2 (later event)  = thm2′ event

  thm2′ : ◇▢ (Now True) (tail alternate) → ⊥
  thm2′ (now forever⊤) = ▢.head forever⊤
  thm2′ (later event)  = thm2 event


------------------------------------------------------------------------------
-- The gcd program is correct
------------------------------------------------------------------------------

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

-- This module proves the correctness of the gcd program using
-- the Euclid's algorithm.

module FOTC.Program.GCD.Total.CorrectnessProofI where

open import FOTC.Base
open import FOTC.Data.Nat.Type
open import FOTC.Program.GCD.Total.CommonDivisorI using ( gcdCD )
open import FOTC.Program.GCD.Total.Definitions using ( gcdSpec )
open import FOTC.Program.GCD.Total.DivisibleI using ( gcdDivisible )
open import FOTC.Program.GCD.Total.GCD using ( gcd )

------------------------------------------------------------------------------
-- The gcd is correct.
gcdCorrect : ∀ {m n} → N m → N n → gcdSpec m n (gcd m n)
gcdCorrect Nm Nn = gcdCD Nm Nn , gcdDivisible Nm Nn


module Data.Tuple.List{ℓ} where

import      Lvl
open import Data using (Unit ; <>)
open import Data.Tuple using (_⨯_ ; _,_)
import      Data.List
open        Data.List using (List)
open import Type{ℓ}

-- Constructs a tuple from a list
Tuple : List(Type) → Type
Tuple(List.∅)          = Unit
Tuple(T List.⊰ List.∅) = T
Tuple(T List.⊰ L)      = (T ⨯ Tuple(L))

pattern ∅        = <>
pattern _⊰∅ a    = a
pattern _⊰+_ a l = (a , l)

import Data.List.Functions as List

_⊰_ : ∀{T}{L} → T → Tuple(L) → Tuple(T List.⊰ L)
_⊰_ {_}{List.∅}     a _ = a
_⊰_ {_}{_ List.⊰ _} a l = (a , l)

head : ∀{T}{L} → Tuple(T List.⊰ L) → T
head{_}{List.∅}    (a ⊰∅)   = a
head{_}{_ List.⊰ _}(a ⊰+ _) = a

tail : ∀{T}{L} → Tuple(T List.⊰ L) → Tuple(L)
tail{_}{List.∅}    (_ ⊰∅)   = ∅
tail{_}{_ List.⊰ _}(_ ⊰+ l) = l

module _ where
  open import Data.List.Equiv.Id
  open import Data.List.Proofs
  open import Relator.Equals
  open import Relator.Equals.Proofs
  open import Structure.Relator
  open import Structure.Operator.Properties

  _++_ : ∀{L₁ L₂} → Tuple(L₁) → Tuple(L₂) → Tuple(L₁ List.++ L₂)
  _++_{L}                   {List.∅} (l)(_)         = substitute₁ₗ(Tuple) {y = L} (identityᵣ(List._++_)(List.∅)) l
  _++_{List.∅}              {_}      (_)(l)         = l
  _++_{A List.⊰ List.∅}     {L₂}     (a ⊰∅)   (l₂) = _⊰_ {A}{L₂} (a) (l₂)
  _++_{A List.⊰ B List.⊰ L₁}{L₂}     (a ⊰+ l₁)(l₂) = _⊰_ {A}{(B Data.List.⊰ L₁) List.++ L₂} (a) (_++_ {B Data.List.⊰ L₁}{L₂} l₁ l₂)

module _ where
  open import Numeral.Natural

  length : ∀{L} → Tuple(L) → ℕ
  length{L} (_) = List.length(L)

-- TODO: TupleRaise : Tuple(repeat(n)(T)) ≡ T ^ n


module TypeTheory.Nat.AnotherMono.Structure where

open import Level renaming (zero to lzero; suc to lsuc)
open import Data.Empty using (⊥)
open import Data.Product using (Σ; _×_; _,_)
open import Relation.Binary using (Rel)
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary using (¬_)

record Nat : Set₁ where
  field
    N        : Set
    zero     : N
    suc      : N → N
    ind      : (P : N → Set) → P zero → (∀ k → P k → P (suc k)) → ∀ n → P n
    ind-zero : ∀ P P-zero P-suc → ind P P-zero P-suc zero ≡ P-zero
    ind-suc  : ∀ P P-zero P-suc n → ind P P-zero P-suc (suc n) ≡
                                    P-suc n (ind P P-zero P-suc n)
    s≢z      : ∀ {n} → suc n ≢ zero

  0N : N
  0N = zero

  1N : N
  1N = suc zero

  z≢s : ∀ {n} → zero ≢ suc n
  z≢s = ≢-sym s≢z

  rec : {A : Set} → A → (A → A) → N → A
  rec {A} z s = ind (λ _ → A) z (λ _ → s)

  rec-zero : ∀ {A} (z : A) s → rec z s zero ≡ z
  rec-zero z s = ind-zero _ _ _

  rec-suc : ∀ {A} (z : A) s n → rec z s (suc n) ≡ s (rec z s n)
  rec-suc z s n = ind-suc _ _ _ _

  infixl 6 _+_
  infixl 7 _*_
  infix 4 _≤_ _<_ _≥_ _>_ _≰_

  -- Arithematic
  -- Addition
  _+_ : N → N → N
  m + n = rec n suc m

  -- Multiplication
  _*_ : N → N → N
  m * n = rec zero (n +_) m

  -- Order
  _≤_ : Rel N lzero
  m ≤ n = Σ N λ o → o + m ≡ n

  _<_ : Rel N lzero
  m < n = suc m ≤ n

  _≥_ : Rel N lzero
  m ≥ n = n ≤ m

  _>_ : Rel N lzero
  m > n = n < m

  _≰_ : Rel N lzero
  m ≰ n = ¬ m ≤ n

  _≮_ : Rel N lzero
  m ≮ n = ¬ m < n

  _≱_ : Rel N lzero
  m ≱ n = ¬ m ≥ n

  _≯_ : Rel N lzero
  m ≯ n = ¬ m > n


module PLRTree.Order.Properties {A : Set} where

open import Data.Nat
open import Data.Nat.Properties
open import Data.Sum
open import Function
open import Induction.Nat
open import Induction.WellFounded
open import PLRTree {A}
open import PLRTree.Order {A}
open import Relation.Binary
open import Relation.Binary.PropositionalEquality

open DecTotalOrder decTotalOrder hiding (refl)
open Inverse-image {_<_ = _<′_} height

≺-wf : Well-founded (_<′_ on height)
≺-wf = well-founded <-well-founded

lemma-≺-left : (t : Tag)(x : A)(l r : PLRTree) → l ≺ node t x l r
lemma-≺-left t x l r
    with total (height l) (height r)
... | inj₁ hl≤hr =  s≤′s (≤⇒≤′ hl≤hr)
... | inj₂ hr≤hl = ≤′-refl

lemma-≺-right : (t : Tag)(x : A)(l r : PLRTree) → r ≺ node t x l r
lemma-≺-right t x l r
    with total (height l) (height r)
... | inj₁ hl≤hr = ≤′-refl
... | inj₂ hr≤hl = s≤′s (≤⇒≤′ hr≤hl)

lemma-≡-height : (t : Tag)(x y : A)(l r : PLRTree) → height (node t x l r) ≡ height (node t y l r)
lemma-≡-height t x y l r
    with total (height l) (height r)
... | inj₁ hl≤hr = refl
... | inj₂ hr≤hl = refl


module Lec8 where

open import CS410-Prelude
open import CS410-Functor
open import CS410-Monoid
open import CS410-Nat

data Maybe (X : Set) : Set where
  yes  : X -> Maybe X
  no   : Maybe X

maybeFunctor : Functor Maybe
maybeFunctor = record
 { map      = \ { f (yes x) -> yes (f x)
                ; f no      -> no
                }
 ; mapid    = \ { (yes x) -> refl ; no -> refl }
 ; mapcomp  = \ { f g (yes x) -> refl ; f g no -> refl } }

open Functor maybeFunctor

data List (X : Set) : Set where  -- X scopes over the whole declaration...
  []    : List X                 -- ...so you can use it here...
  _::_  : X -> List X -> List X  -- ...and here.
infixr 3 _::_

data Hutton : Set where
  val : Nat -> Hutton
  _+H_ : Hutton -> Hutton -> Hutton
  hif_then_else_ : Hutton -> Hutton -> Hutton -> Hutton
  fail : Hutton

maybeApplicative : Applicative Maybe
maybeApplicative = record
                     { pure = yes
                     ; _<*>_ = \ { no mx -> no
                                 ; (yes f) no -> no
                                 ; (yes f) (yes x) -> yes (f x)
                                 }
                     ; identity = \ {(yes x) -> refl ; no -> refl}
                     ; composition = \
                        { (yes f) (yes g) (yes x) -> refl
                        ; (yes f) (yes g) no -> refl
                        ; (yes x) no mx -> refl
                        ; no mg mx -> refl
                        }
                     ; homomorphism = \ f x -> refl
                     ; interchange = \ { (yes f) y -> refl ; no y → refl }
                     }

open Applicative maybeApplicative public

cond : Nat -> Nat -> Nat -> Nat
cond zero t e = e
cond (suc c) t e = t

_>>=_ : forall {X Y} -> Maybe X -> (X -> Maybe Y) -> Maybe Y
yes x >>= x2my = x2my x
no >>= x2my = no

eval : Hutton -> Maybe Nat
eval (val x) = pure x
eval (h +H h') = pure _+N_ <*> eval h <*> eval h'
eval (hif c then t else e)
  -- = pure cond <*> eval c <*> eval t <*> eval e  -- oops
  = eval c >>= \ { zero -> eval e
                 ; (suc _) -> eval t}
eval fail = no

foo : Hutton
foo = hif val 1 then (val 2 +H val 3) else (hif val 0 then val 4 else val 6)

goo : Hutton
goo = hif val 1 then (val 2 +H val 3) else (hif val 0 then fail else val 6)

ap : forall {X Y} -> Maybe (X -> Y) -> Maybe X -> Maybe Y
ap mf mx = mf >>= \ f -> mx >>= \ x -> yes (f x)


module Data.Bin.NatHelpers where

    open import Relation.Binary.PropositionalEquality
    open import Data.Empty
    open import Data.Fin using (Fin; zero; suc) renaming (toℕ to finToℕ)
    open import Data.Nat using(ℕ; zero; suc; _≤_; _+_; _*_; s≤s; z≤n; ≤′-step; ≤′-refl; _<_; _∸_)
    open import Data.Nat.Properties using(_*-mono_; ≤′⇒≤; ≤⇒≤′)
    open import Function using (_∘_)
    open import Relation.Nullary

    ≤-step : ∀ {a b} → a ≤ b → a ≤ suc b
    ≤-step = ≤′⇒≤ ∘ ≤′-step ∘ ≤⇒≤′

    *2-mono : ∀ x → x ≤ x * 2
    *2-mono zero = z≤n
    *2-mono (suc x) = s≤s (≤-step (*2-mono x))

    kojojo : ∀ (b : Fin 2) x → x ≢ 0 → suc x ≤ finToℕ b + x * 2
    kojojo b zero nz = ⊥-elim (nz refl)
    kojojo zero (suc y) nz = s≤s (s≤s (*2-mono y))
    kojojo (suc zero) (suc y) nz = s≤s (s≤s (≤-step (*2-mono y)))
    kojojo (suc (suc ())) (suc y) nz

    *2-gives-space : ∀ {x y z} → (x < y) → z < 2 → x * 2 + z < y * 2
    *2-gives-space {suc x} {suc (suc y)} (s≤s (s≤s less)) zz = s≤s (s≤s (*2-gives-space {x} {suc y} (s≤s less) zz))
    *2-gives-space (s≤s z≤n) (s≤s (s≤s z≤n)) = s≤s (s≤s z≤n)
    *2-gives-space (s≤s z≤n) (s≤s z≤n) = s≤s z≤n

    open import Data.Product

    x≮z→x≡z+y : ∀ {x z} → ¬ x < z → ∃ λ y → x ≡ z + y
    x≮z→x≡z+y {zero} {zero} x≮z = zero , refl
    x≮z→x≡z+y {suc x} {zero} x≮z = suc x , refl
    x≮z→x≡z+y {zero} {suc z} x≮z = ⊥-elim (x≮z (s≤s z≤n))
    x≮z→x≡z+y {suc x} {suc z} x≮z with x≮z→x≡z+y {x} {z} (λ z' → x≮z (s≤s z'))
    x≮z→x≡z+y {suc .(z + y)} {suc z} x≮z | y , refl = y , refl

    +-elim₁ : ∀ {x y z} → z + x < z + y → x < y
    +-elim₁ {x} {y} {zero} lt = lt
    +-elim₁ {x} {y} {suc z} (s≤s lt) = +-elim₁ {x} {y} {z} lt

    import Data.Nat.Properties
    open import Algebra.Structures
    open IsCommutativeSemiring (Data.Nat.Properties.isCommutativeSemiring)

    +-elim₂ : ∀ {x y z} → x + z < y + z → x < y
    +-elim₂ {x} {y} {z} lt rewrite +-comm x z | +-comm y z = +-elim₁ {x} {y} {z} lt


module Numeral.Natural.Oper.Proofs.Structure where

open import Logic.Predicate
open import Numeral.Natural
open import Numeral.Natural.Oper.Proofs
open import Numeral.Natural.Oper
open import Relator.Equals
open import Relator.Equals.Proofs
open import Structure.Operator.Monoid

instance
  [+]-monoid : Monoid(_+_)
  Monoid.identity-existence [+]-monoid = [∃]-intro(𝟎)

instance
  [⋅]-monoid : Monoid(_⋅_)
  Monoid.identity-existence [⋅]-monoid = [∃]-intro(𝐒(𝟎))


module Monad where

module Prelude where

  infixl 40 _∘_

  id : {A : Set} -> A -> A
  id x = x

  _∘_ : {A B C : Set} -> (B -> C) -> (A -> B) -> A -> C
  f ∘ g = \x -> f (g x)

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

module Base where

  data Monad (M : Set -> Set) : Set1 where
    monad : (return : {A : Set} -> A -> M A)                 ->
            (bind   : {A B : Set} -> M A -> (A -> M B) -> M B) ->
            Monad M

  monadReturn : {M : Set -> Set} -> Monad M -> {A : Set} -> A -> M A
  monadReturn (monad ret bind) = ret

  monadBind : {M : Set -> Set} -> Monad M -> {A B : Set} -> M A -> (A -> M B) -> M B
  monadBind (monad ret bind) = bind

module Monad {M : Set -> Set}(monadM : Base.Monad M) where

  open Prelude

  infixl 15 _>>=_

  -- Return and bind --------------------------------------------------------

  return : {A : Set} -> A -> M A
  return = Base.monadReturn monadM

  _>>=_ : {A B : Set} -> M A -> (A -> M B) -> M B
  _>>=_ = Base.monadBind monadM

  -- Other operations -------------------------------------------------------

  liftM : {A B : Set} -> (A -> B) -> M A -> M B
  liftM f m = m >>= return ∘ f

module List where

  infixr 20 _++_ _::_

  -- The list datatype ------------------------------------------------------

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

  -- Some list operations ---------------------------------------------------

  foldr : {A B : Set} -> (A -> B -> B) -> B -> List A -> B
  foldr f e nil     = e
  foldr f e (x :: xs) = f x (foldr f e xs)

  map : {A B : Set} -> (A -> B) -> List A -> List B
  map f nil     = nil
  map f (x :: xs) = f x :: map f xs

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

  concat : {A : Set} -> List (List A) -> List A
  concat = foldr _++_ nil

  -- List is a monad --------------------------------------------------------

  open Base

  monadList : Monad List
  monadList = monad ret bind
    where
      ret : {A : Set} -> A -> List A
      ret x = x :: nil

      bind : {A B : Set} -> List A -> (A -> List B) -> List B
      bind xs f = concat (map f xs)

open Prelude
open List
module MonadList = Monad monadList
open MonadList


{-# OPTIONS --without-K #-}
open import Data.Bits.Search
open import Data.Nat.NP

open import Function.NP

import Relation.Binary.PropositionalEquality.NP as ≡
open ≡

module Data.Bits.Sum where
    open SimpleSearch _+_ using (module Comm; module SearchInterchange; module SearchUnit; module Bij)
    open SimpleSearch _+_ public using () renaming (search to sum; search-≗ to sum-≗; searchBit to sumBit;
                                                    search-≗₂ to sum-≗₂;
                                                    search-+ to sum-+)
    open Comm ℕ°.+-comm public renaming (search-comm to sum-comm)
    open SearchUnit 0 refl public renaming
       (search-constε≡ε to sum-const0≡0)
    open SearchInterchange +-interchange public renaming (
        search-dist to sum-dist;
        search-searchBit to sum-sumBit;
        search-search to sum-sum;
        search-swap to sum-swap)
    open Bij ℕ°.+-comm +-interchange public renaming (search-bij to sum-bij)

    sum-const : ∀ n x → sum {n} (const x) ≡ ⟨2^ n * x ⟩
    sum-const zero    _ = refl
    sum-const (suc n) x = cong₂ _+_ (sum-const n x) (sum-const n x)


module Logic.Leibniz where

-- Leibniz equality
_≡_ : {A : Set} -> A -> A -> Set1
x ≡ y = (P : _ -> Set) -> P x -> P y

≡-refl : {A : Set}(x : A) -> x ≡ x
≡-refl x P px = px

≡-sym : {A : Set}(x y : A) -> x ≡ y -> y ≡ x
≡-sym x y xy P py = xy (\z -> P z -> P x) (\px -> px) py

≡-trans : {A : Set}(x y z : A) -> x ≡ y -> y ≡ z -> x ≡ z
≡-trans x y z xy yz P px = yz P (xy P px)

≡-subst : {A : Set}(P : A -> Set)(x y : A) -> x ≡ y -> P x -> P y
≡-subst P _ _ xy = xy P


{-# OPTIONS --without-K #-}
module hw2 where

open import Level using (_⊔_)
open import Function using (id)
open import Data.Nat using (ℕ; suc; _+_; _*_)
open import Data.Empty using (⊥)
open import Data.Sum using (_⊎_; inj₁; inj₂)

import Level

infix 4 _≡_

recℕ : ∀ {ℓ} → (C : Set ℓ) → C → (ℕ → C → C) → ℕ → C
recℕ C z f 0 = z
recℕ C z f (suc n) = f n (recℕ C z f n)

indℕ : ∀ {ℓ}
         → (C : ℕ → Set ℓ)
         → C 0
         → ((n : ℕ) → C n → C (suc n))
         → (n : ℕ)
         → C n
indℕ C z f 0 = z
indℕ C z f (suc n) = f n (indℕ C z f n)

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

rec≡ : {A : Set} →
       (R : A → A → Set) {reflexiveR : {a : A} → R a a} →
       ({x y : A} (p : x ≡ y) → R x y)
rec≡ R {reflR} (refl y) = reflR {y}

------------------------------------------------------------------------------
-- subst
subst : ∀ {ℓ} {A : Set ℓ} {C : A → Set ℓ} →
        ({x y : A} (p : x ≡ y) → C x → C y)
subst (refl x) = id

------------------------------------------------------------------------------
-- ∘
_∘_ : {A B C : Set} → (f : B → C) → (g : A → B) → A → C
f ∘ g = (λ a → f (g a))

module Circle1 where
  private
    data S¹* : Set where
      base* : S¹*

  S¹ : Set
  S¹ = S¹*

  base : S¹
  base = base*

  postulate
    loop : base ≡ base

  recS¹ : {C : Set} → (cbase : C) → (cloop : cbase ≡ cbase) → S¹ → C
  recS¹ cbase cloop base* = cbase

--  postulate
--    βrecS¹ : {C : Set} → (cbase : C) → (cloop : cbase ≡ cbase)
--      → ap (recS¹ cbase cloop) loop ≡ cloop

-- indS¹ : {C : S¹ → Set}
--  → (cbase : C base) → (cloop : transport C look cbase ≡ cbase)
--  → apd (indS¹ {C} cbase cloop) loop ≡ cloop


module FSM where
open import Sec4
open import Relation.Binary.PropositionalEquality
open import Data.Nat
open import Data.Bool
-- open import Data.Rational
-- open import Data.Integer
-- open import Relation.Nullary.Decidable

data Loc : Set where
  A : Loc
  DONE : Loc

record Values : Set where
  field
    x : ℕ
    δ : ℕ
    k : ℕ

data _Π_ (A B : Set) : Set where
  <_,_> : (a : Loc) → (b : Values) →  A Π B

-- The computation of x in the state
-- The state machine step function
step : (Loc Π Values) → (Loc Π Values)
step < A , b > =
  if (X >= 10)
  then
    < DONE , record { x = X; δ = Values.δ b ; k = Values.k b Data.Nat.+ 1 } >
  else
    < A , record { x = X; δ = Values.δ b ; k = Values.k b Data.Nat.+ 1 } >
 where
 funₓ : ℕ → ℕ → ℕ → ℕ           -- slope = 1 here!
 funₓ x k δ = x Data.Nat.+ δ Data.Nat.* k

 _>=_ : ℕ → ℕ → Bool
 zero >= zero = true
 zero >= suc y = false
 suc x >= zero = false
 suc x >= suc y = x >= y

 _==_ : ℕ → ℕ → Bool
 zero == zero = true
 zero == suc y = false
 suc x == zero = false
 suc x == suc y = x == y

 X : ℕ
 X = funₓ (Values.x b) (Values.k b) (Values.δ b)

step < DONE , b > = < DONE , b > -- Just remain in this state forever

runFSM : (n : ℕ) → (st : (Loc Π Values)) → (Loc Π Values)
runFSM zero st = st
runFSM (suc n) st = runFSM n (step st)

theorem : runFSM 10 (< A , (record { x = zero ; δ = 1 ; k = zero }) >) ≡ < DONE ,
                           record { x = 10 ; δ = 1 ; k = 5 } >
theorem  = refl

-- invariant when in DONE state, X ≥ 10
invariant : (Loc Π Values) → Prop
invariant < A , record { x = x ; δ = δ ; k = k } > = ⊥
invariant < DONE , record { x = x ; δ = δ ; k = k } > =  x ≥ 10

thm : invariant (runFSM 5 (< A , (record { x = zero ; δ = 1 ; k = zero }) >))
thm = s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))))))

-- Example of state machine as a relation
data State : Set where
  A : ∀ (n : ℕ) → State
  D : ∀ (n : ℕ) → State

private funₓ : ℕ → ℕ → ℕ → ℕ
        funₓ x δ slope = x Data.Nat.+ δ Data.Nat.* slope

data _↓_ : State → State → Prop where
  S1 : ∀ (n : ℕ) → (n < 10) → (A n) ↓ (A (funₓ n 1 1))
  S2 : ∀ (n : ℕ) → (n ≥ 10) → (A n) ↓ (D n)

data fState : State → Prop where
  F : ∀ (n : ℕ) →  (n ≥ 10) →  fState (D n)

data oState : State → Prop where
  O : oState (A 0)

y : ∀ (n : ℕ) → (p : n < 10) → (A n) ↓ (A (ℕ.suc n))
y .0 (s≤s z≤n) = S1 zero (s≤s z≤n)
y .1 (s≤s (s≤s z≤n)) = S1 (suc zero) (s≤s (s≤s z≤n))
y .2 (s≤s (s≤s (s≤s z≤n))) = S1 (suc (suc zero)) (s≤s (s≤s (s≤s z≤n)))
y .3 (s≤s (s≤s (s≤s (s≤s z≤n)))) = S1 (suc (suc (suc zero))) (s≤s (s≤s (s≤s (s≤s z≤n))))
y .4 (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))) = S1 (suc (suc (suc (suc zero)))) (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))
y .5 (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))) = S1 (suc (suc (suc (suc (suc zero)))))
                                                 (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))))
y .6 (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))))) = S1 (suc (suc (suc (suc (suc (suc zero))))))
                                                       (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))))
y .7 (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))))) = S1 (suc (suc (suc (suc (suc (suc (suc zero)))))))
                                                             (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))))))
y .8 (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))))))) = S1 (suc (suc (suc (suc (suc (suc (suc (suc zero))))))))
                                                                   (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))))))
y .9 (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n)))))))))) = S1 (suc (suc (suc (suc (suc (suc (suc (suc (suc zero)))))))))
                                                                         (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s (s≤s z≤n))))))))))

y1 : ∀ (n : ℕ) → (p : n ≥ 10) → (A n) ↓ (D n)
y1 n p = S2 n p

-- Example of arithexpr as a relation
data aexp : Set where
  ANum : ∀ (n : ℕ) → aexp
  APlus : aexp → aexp → aexp
  AMult : aexp → aexp → aexp

aeval : aexp → ℕ
aeval (ANum n) = n
aeval (APlus a₁ a₂) = (aeval a₁) + (aeval a₂)
aeval (AMult n₁ n₂) = (aeval n₁) * (aeval n₂)

_==_ : ℕ → ℕ → Bool
zero == zero = true
zero == suc y = false
suc x == zero = false
suc x == suc y = x == y

-- compiler optimization
aexp-opt1 : aexp → aexp
aexp-opt1 (ANum n) = ANum n
aexp-opt1 (APlus (ANum n) (ANum n₁)) with (n == 0) Data.Bool.∧ (n₁ == n)
aexp-opt1 (APlus (ANum n) (ANum n₁)) | false = (APlus (ANum n) (ANum n₁))
aexp-opt1 (APlus (ANum n) (ANum n₁)) | true = (ANum 0)
aexp-opt1 (APlus x x₁) = APlus x x₁
aexp-opt1 (AMult (ANum n) (ANum n₁)) with (n == 0) Data.Bool.∨ (n₁ == 0)
aexp-opt1 (AMult (ANum n) (ANum n₁)) | true = ANum 0
aexp-opt1 (AMult (ANum n) (ANum n₁)) | false = (AMult (ANum n) (ANum n₁))
aexp-opt1 (AMult x x₁) = (AMult x x₁)

-- Theorem that the optimization is correct!
thm-opt1 : ∀ (a : aexp) → ∀ (n : ℕ)
           → (aeval a ≡ n)
           → aeval (aexp-opt1 a) ≡ n
thm-opt1 (ANum n) .n refl = refl
thm-opt1 (APlus (ANum zero) (ANum zero)) .0 refl = refl
thm-opt1 (APlus (ANum zero) (ANum (suc n))) .(suc n) refl = refl
thm-opt1 (APlus (ANum (suc n)) (ANum n₁)) .(suc (n + n₁)) refl = refl
thm-opt1 (APlus (ANum n) (APlus b b₁)) .(n + (aeval b + aeval b₁)) refl = refl
thm-opt1 (APlus (ANum n) (AMult b b₁)) .(n + aeval b * aeval b₁) refl = refl
thm-opt1 (APlus (APlus a a₁) b) .(aeval a + aeval a₁ + aeval b) refl = refl
thm-opt1 (APlus (AMult a a₁) b) .(aeval a * aeval a₁ + aeval b) refl = refl
thm-opt1 (AMult (ANum zero) (ANum n₁)) .0 refl = refl
thm-opt1 (AMult (ANum (suc n)) (ANum zero)) .(n * 0) refl = cc n
  where
  cc : ∀ (n : ℕ) → (0 ≡ n * 0)
  cc zero = refl
  cc (suc n) = cc n
thm-opt1 (AMult (ANum (suc n)) (ANum (suc p))) .(suc (p + n * suc p)) refl = refl
thm-opt1 (AMult (ANum n) (APlus b b₁)) .(n * (aeval b + aeval b₁)) refl = refl
thm-opt1 (AMult (ANum n) (AMult b b₁)) .(n * (aeval b * aeval b₁)) refl = refl
thm-opt1 (AMult (APlus a a₁) b) .((aeval a + aeval a₁) * aeval b) refl = refl
thm-opt1 (AMult (AMult a a₁) b) .(aeval a * aeval a₁ * aeval b) refl = refl

-- Now as a relation
data _⇓_ : aexp → ℕ → Set where
  ANumR : ∀ (n : ℕ) → ANum n ⇓ n
  APlusR : ∀ (n₁ n₂ : ℕ) → ∀ (a₁ a₂ : aexp)
           → (a₁ ⇓ n₁) → (a₂ ⇓ n₂)
           → (APlus a₁ a₂) ⇓ (n₁ + n₂)
  AMultR : ∀ (n₁ n₂ : ℕ) → ∀ (a₁ a₂ : aexp)
           → (a₁ ⇓ n₁) → (a₂ ⇓ n₂)
           → (AMult a₁ a₂) ⇓ (n₁ * n₂)

∧-Zero : ∀ (x y : ℕ) → ((x ≡ 0) Sec4.∧ (y ≡ 0)) Sec4.∨ ⊤
∧-Zero zero zero = ora (and refl refl)
∧-Zero zero (suc y) = orb ⋆
∧-Zero (suc x) y = orb ⋆

∨-Zero : ∀ (x y : ℕ) → ((x ≡ 0) Sec4.∨ (y ≡ 0)) Sec4.∨ ⊤
∨-Zero zero _ = ora (ora refl)
∨-Zero (suc x) zero = ora (orb refl)
∨-Zero (suc x) (suc y) = orb ⋆

-- compiler optimization
aexp-opt2 : aexp → aexp
aexp-opt2 (ANum n) = ANum n
aexp-opt2 (APlus (ANum n) (ANum n₁)) with ∧-Zero n n₁
aexp-opt2 (APlus (ANum .0) (ANum .0)) | ora (and refl refl) = ANum zero
aexp-opt2 (APlus (ANum n) (ANum n₁)) | orb _ = (APlus (ANum n) (ANum n₁))
aexp-opt2 (APlus x x₁) = APlus x x₁
aexp-opt2 (AMult (ANum n) (ANum n₁)) with ∨-Zero n n₁
aexp-opt2 (AMult (ANum .0) (ANum n₁)) | ora (ora refl) = ANum 0
aexp-opt2 (AMult (ANum n) (ANum .0)) | ora (orb refl) = ANum 0
aexp-opt2 (AMult (ANum n) (ANum n₁)) | orb x = (AMult (ANum n) (ANum n₁))
aexp-opt2 (AMult x x₁) = (AMult x x₁)

yy : ∀ (n : ℕ) → (n * 0) ≡ 0
yy zero = refl
yy (suc n) = yy n

-- Theorem that the optimization is correct in relations
thm-rel-opt2 : ∀ (a : aexp) → ∀ (p : ℕ) → (a ⇓ p) → ((aexp-opt2 a) ⇓ p)
thm-rel-opt2 (ANum n) p e = e
thm-rel-opt2 (APlus (ANum n) (ANum n₁)) p e with ∧-Zero n n₁
thm-rel-opt2 (APlus (ANum .0) (ANum .0)) .0 (APlusR .0 .0 .(ANum 0) .(ANum 0) (ANumR .0) (ANumR .0)) | ora (and refl refl) = ANumR zero
thm-rel-opt2 (APlus (ANum n) (ANum n₁)) p e | orb x = e
thm-rel-opt2 (APlus (ANum n) (APlus a a₁)) p e = e
thm-rel-opt2 (APlus (ANum n) (AMult a a₁)) p e = e
thm-rel-opt2 (APlus (APlus a a₁) a₂) p e = e
thm-rel-opt2 (APlus (AMult a a₁) a₂) p e = e
thm-rel-opt2 (AMult (ANum n) (ANum n₁)) p e with ∨-Zero n n₁
thm-rel-opt2 (AMult (ANum .0) (ANum n₃)) .0 (AMultR .0 .n₃ .(ANum 0) .(ANum n₃) (ANumR .0) (ANumR .n₃)) | ora (ora refl) = ANumR zero
-- The below is rewrite
thm-rel-opt2 (AMult (ANum n₁) (ANum .0)) .(n₁ * 0) (AMultR .n₁ .0 .(ANum n₁) .(ANum 0) (ANumR .n₁) (ANumR .0)) | ora (orb refl) with (yy n₁)
thm-rel-opt2 (AMult (ANum n₁) (ANum .0)) .(n₁ * 0) (AMultR .n₁ .0 .(ANum n₁) .(ANum 0) (ANumR .n₁) (ANumR .0)) | ora (orb refl) | j with n₁ * 0
thm-rel-opt2 (AMult (ANum n₁) (ANum _)) .(n₁ * _) (AMultR .n₁ _ .(ANum n₁) .(ANum _) (ANumR .n₁) (ANumR _)) | ora (orb refl) | refl | .0 = ANumR zero
thm-rel-opt2 (AMult (ANum n) (ANum n₁)) p e | orb x = e
thm-rel-opt2 (AMult (ANum n) (APlus b b₁)) p e = e
thm-rel-opt2 (AMult (ANum n) (AMult b b₁)) p e = e
thm-rel-opt2 (AMult (APlus a a₁) b) p e = e
thm-rel-opt2 (AMult (AMult a a₁) b) p e = e

th : (APlus (ANum 10) (ANum 10)) ⇓ 20
th = APlusR
       (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc zero))))))))))
       (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc zero))))))))))
       (ANum
        (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc zero)))))))))))
       (ANum
        (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc zero)))))))))))
       (ANumR
        (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc zero)))))))))))
       (ANumR
        (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc zero)))))))))))

t : ∀ (a : aexp) (p : ℕ) → (aeval a ≡ p) → (a ⇓ p)
t (ANum n) .n refl = ANumR n
t (APlus a a₁) .(aeval a + aeval a₁) refl = APlusR (aeval a) (aeval a₁) a a₁ (t a (aeval a) refl)
                                            (t a₁ (aeval a₁) refl)
t (AMult a a₁) .(aeval a * aeval a₁) refl = AMultR (aeval a) (aeval a₁) a a₁ (t a (aeval a) refl)
                                            (t a₁ (aeval a₁) refl)

tt : ∀ (a : aexp) (n : ℕ) → (a ⇓ n) → (aeval a ≡ n)
tt (ANum n₁) .n₁ (ANumR .n₁) = refl
tt (APlus a a₁) .(n₁ + n₂) (APlusR n₁ n₂ .a .a₁ p p₁) with tt a n₁ p | tt a₁ n₂ p₁
tt (APlus a a₁) .(aeval a + aeval a₁) (APlusR .(aeval a) .(aeval a₁) .a .a₁ p p₁) | refl | refl = refl
tt (AMult a a₁) .(n₁ * n₂) (AMultR n₁ n₂ .a .a₁ p p₁) with tt a n₁ p | tt a₁ n₂ p₁
tt (AMult a a₁) .(aeval a * aeval a₁) (AMultR .(aeval a) .(aeval a₁) .a .a₁ p p₁) | refl | refl = refl


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

module LogicalFramework.Equality where

module LF where
  postulate
    D     : Set
    _≡_   : D → D → Set
    refl  : ∀ {x} → x ≡ x
    subst : (A : D → Set) → ∀ {x y} → x ≡ y → A x → A y

  sym : ∀ {x y} → x ≡ y → y ≡ x
  sym {x} h = subst (λ t → t ≡ x) h refl

  trans : ∀ {x y z} → x ≡ y → y ≡ z → x ≡ z
  trans {x} h₁ h₂ = subst (_≡_ x) h₂ h₁

module Inductive where

  open import Common.FOL.FOL-Eq
  open import Common.FOL.Relation.Binary.EqReasoning

  sym-er : ∀ {x y} → x ≡ y → y ≡ x
  sym-er {x} h = subst (λ t → t ≡ x) h refl

  trans-er : ∀ {x y z} → x ≡ y → y ≡ z → x ≡ z
  trans-er {x} h₁ h₂ = subst (_≡_ x) h₂ h₁

  -- NB. The proofs of sym and trans by pattern matching are in the
  -- module Common.FOL.Relation.Binary.PropositionalEquality.


-- A discussion from -- https://twitter.com/YuumuKonpaku/status/1052959340468953088

module MdJustHighlightAgdaAsHtml where

open import Agda.Builtin.Nat
open import Agda.Builtin.Equality
open import Agda.Primitive public using (lzero)
  renaming (Level to ULevel; lsuc to lsucc; _⊔_ to lmax)

Type : (i : ULevel) -> Set (lsucc i)
Type i = Set i

data ⊥ : Type lzero where
pattern O = zero
pattern S n = (suc n)
variable i : ULevel

¬ : (A : Type i) → Type i
¬ A = A → ⊥
_≠_ : {A : Type i} → (A → A → Type i)
x ≠ y = ¬ (x ≡ y)

infix 10 _∨_
data _∨_ {a b} (A : Type a) (B : Type b) : Set (lmax a b) where
  a-intro : A -> A ∨ B
  b-intro : B -> A ∨ B

test : (x y : Nat) -> (x ≡ y) ∨ (x ≠ y)
test O O = a-intro refl
test O (S y) = b-intro (λ ())
test (S x) O = b-intro (λ ())
test (S x) (S y) with test x y
... | a-intro refl = a-intro refl
... | b-intro k = b-intro (lemma k)
  where
    lemma : {a b : Nat} -> a ≠ b -> S a ≠ S b
    lemma p refl = p refl


{-# OPTIONS --without-K #-}
module sets.nat.ordering.leq.decide where

open import decidable
open import sets.core
open import sets.nat.core
open import sets.nat.ordering.leq.core
open import sets.nat.ordering.lt.core

_≤?_ : (n m : ℕ) → Dec (n ≤ m)
0 ≤? m = yes z≤n
suc n ≤? 0 = no λ ()
suc n ≤? suc m with n ≤? m
suc n ≤? suc m | yes p = yes (s≤s p)
suc n ≤? suc m | no u = no λ p → u (ap-pred-≤ p)


open import Structure.Operator.Field
open import Structure.Setoid
open import Type

-- Operators for matrices over a field.
module Numeral.Matrix.OverField {ℓ ℓₑ}{T : Type{ℓ}} ⦃ equiv : Equiv{ℓₑ}(T) ⦄ {_+ₛ_ _⋅ₛ_ : T → T → T} ⦃ field-structure : Field(_+ₛ_)(_⋅ₛ_) ⦄ where
open Field(field-structure) renaming (_−_ to _−ₛ_ ; −_ to −ₛ_ ; 𝟎 to 𝟎ₛ ; 𝟏 to 𝟏ₛ)

open import Data.Tuple as Tuple using (_,_)
open import Logic.Predicate
open import Numeral.Matrix
open import Numeral.Matrix.Proofs
open import Structure.Operator.Properties

𝟎 : ∀{s} → Matrix(s)(T)
𝟎 = fill(𝟎ₛ)

𝟏 : ∀{n} → Matrix(n , n)(T)
𝟏 = SquareMatrix.scalarMat(𝟎ₛ)(𝟏ₛ)

_+_ : ∀{s} → Matrix(s)(T) → Matrix(s)(T) → Matrix(s)(T)
_+_ = map₂(_+ₛ_)
infixr 1000 _+_

_−_ : ∀{s} → Matrix(s)(T) → Matrix(s)(T) → Matrix(s)(T)
_−_ = map₂(_−ₛ_)
infixr 1000 _−_

−_ : ∀{s} → Matrix(s)(T) → Matrix(s)(T)
−_ = map(−ₛ_)
infixr 1000 −_

_⨯_ : ∀{x y z} → Matrix(y , z)(T) → Matrix(x , y)(T) → Matrix(x , z)(T)
_⨯_ = multPattern(_+ₛ_)(_⋅ₛ_)(𝟎ₛ)
infixr 1000 _⨯_

_⁻¹ : ∀{n} → (M : Matrix(n , n)(T)) ⦃ inver : InvertibleElement(_⨯_) ⦃ [∃]-intro 𝟏 ⦃ {!matrix-multPattern-identity!} ⦄ ⦄ (M) ⦄ → Matrix(n , n)(T)
_⁻¹ _ ⦃ inver ⦄ = [∃]-witness inver


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

open import Numbers.Naturals.Definition
open import Numbers.Integers.Definition
open import Numbers.Integers.Addition
open import Numbers.Integers.Multiplication
open import Numbers.Integers.Order
open import Groups.Definition

module Numbers.Integers.Integers where

open Numbers.Integers.Definition using (ℤ ; nonneg ; negSucc) public
open Numbers.Integers.Addition using (_+Z_ ; ℤGroup ; ℤAbGrp) public
open Numbers.Integers.Multiplication using (_*Z_) public
open import Numbers.Integers.RingStructure.IntegralDomain public using (ℤIntDom) public
open import Numbers.Integers.RingStructure.Ring public using (ℤRing) public
open Numbers.Integers.Order using (_<Z_ ; ℤOrderedRing) public

_-Z_ : ℤ → ℤ → ℤ
a -Z b = a +Z (Group.inverse ℤGroup b)

_^Z_ : ℤ → ℕ → ℤ
a ^Z zero = nonneg 1
a ^Z succ b = a *Z (a ^Z b)


module Data.Fin.Properties.Extra where

open import Data.Fin hiding (_≤_)
open import Data.Nat
open import Data.Nat.Properties

open import Relation.Binary.PropositionalEquality

inject≤-trans : ∀ {l m n} i (p : l ≤ m)(q : m ≤ n) → inject≤ (inject≤ i p) q ≡ inject≤ i (≤-trans p q)
inject≤-trans () z≤n q
inject≤-trans zero (s≤s p) (s≤s q) = refl
inject≤-trans (suc i) (s≤s p) (s≤s q) = cong suc (inject≤-trans i p q)


module EvenOdd where

open import Data.Nat

data Even : ℕ → Set where
  evenZero : Even 0
  evenSuc : {n : ℕ} → Even n → Even (suc (suc n))

data Odd : ℕ → Set where
  oddOne : Odd 1
  oddSuc : {n : ℕ} → Odd n → Odd (suc (suc n))

_e+e_ : {n m : ℕ} → Even n → Even m → Even (n + m)
evenZero e+e b = b
evenSuc a e+e b = evenSuc (a e+e b)

_o+o_ : {n m : ℕ} → Odd n → Odd m → Even (n + m)
oddOne o+o oddOne = evenSuc evenZero
oddOne o+o oddSuc b = evenSuc (oddOne o+o b)
oddSuc a o+o b = evenSuc (a o+o b)

_o+e_ : {n m : ℕ} → Odd n → Even m → Odd (n + m)
oddOne o+e evenZero = oddOne
oddOne o+e evenSuc b = oddSuc (oddOne o+e b)
oddSuc a o+e b = oddSuc (a o+e b)

_e+o_ : {n m : ℕ} → Even n → Odd m → Odd (n + m)
evenZero e+o b = b
evenSuc a e+o b = oddSuc (a e+o b)


module Impure.STLCRef.Welltyped where

open import Prelude
open import Data.Nat
open import Data.Vec
open import Data.List
open import Data.Fin hiding (_<_)
open import Extensions.List as L using ()

open import Impure.STLCRef.Syntax

-- store typings
World : Set
World = List Type

_⊢loc_∶_ : World → ℕ → Type → Set
Σ ⊢loc i ∶ A = Σ L.[ i ]= A

Ctx : (n : ℕ) → Set
Ctx n = Vec Type n

data _,_⊢_∶_ : ∀ {n} → Ctx n → World → Exp n → Type → Set where
  unit : ∀ {n} {Γ : Ctx n} {Σ} →
         ---------------------------------------
         Γ , Σ ⊢ unit ∶ Unit

  var  : ∀ {n i A} {Γ : Ctx n} {Σ} →
         Γ [ i ]= A →
         ---------------------------------------
         Γ , Σ ⊢ var i ∶ A

  loc : ∀ {n i A} {Γ : Ctx n} {Σ} →
         Σ ⊢loc i ∶ A →
         ---------------------------------------
         Γ , Σ ⊢ loc i ∶ Ref A

  ƛ   : ∀ {n e A B} {Γ : Ctx n} {Σ} →
         (A ∷ Γ) , Σ ⊢ e ∶ B →
         ---------------------------------------
         Γ , Σ ⊢ (ƛ A e) ∶ (A ⇒ B)

  _·_ : ∀ {n f x A B} {Γ : Ctx n} {Σ} →
         Γ , Σ ⊢ f ∶ (A ⇒ B) →
         Γ , Σ ⊢ x ∶ A →
         ---------------------------------------
         Γ , Σ ⊢ (f · x) ∶ B

  ref : ∀ {n x A} {Γ : Ctx n} {Σ} →
        Γ , Σ ⊢ x ∶ A →
        ---------------------------------------
        Γ , Σ ⊢ ref x ∶ Ref A

  !_  : ∀ {n x A} {Γ : Ctx n} {Σ} →
        Γ , Σ ⊢ x ∶ Ref A →
        ---------------------------------------
        Γ , Σ ⊢ (! x) ∶ A

  _≔_ : ∀ {n i x A} {Γ : Ctx n} {Σ} →
        Γ , Σ ⊢ i ∶ Ref A →
        Γ , Σ ⊢ x ∶ A →
        ---------------------------------------
        Γ , Σ ⊢ (i ≔ x) ∶ Unit

open import Relation.Binary.List.Pointwise

-- store welltypedness relation
-- as a pointwise lifting of the welltyped relation on closed expressions between a world and a store
_,_⊢_ : ∀ {n} → Ctx n → World → Store n → Set
Γ , Σ ⊢ μ = Rel (λ A x → Γ , Σ ⊢ proj₁ x ∶ A) Σ μ


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties related to multiplication of integers
------------------------------------------------------------------------

module Data.Integer.Multiplication.Properties where

open import Algebra
  using (module CommutativeSemiring; CommutativeMonoid)
import Algebra.FunctionProperties
open import Algebra.Structures using (IsSemigroup; IsCommutativeMonoid)
open import Data.Integer
   using (ℤ; -[1+_]; +_; ∣_∣; sign; _◃_) renaming (_*_ to ℤ*)
open import Data.Nat
  using (suc; zero) renaming (_+_ to _ℕ+_; _*_ to _ℕ*_)
open import Data.Product using (proj₂)
import Data.Nat.Properties as ℕ
open import Data.Sign using () renaming (_*_ to _S*_)
open import Function using (_∘_)
open import Relation.Binary.PropositionalEquality
   using (_≡_; refl; cong; cong₂; isEquivalence)

open Algebra.FunctionProperties (_≡_ {A = ℤ})
open CommutativeSemiring ℕ.commutativeSemiring
  using (+-identity; *-comm) renaming (zero to *-zero)

------------------------------------------------------------------------
-- Multiplication and one form a commutative monoid

private

  identityˡ : LeftIdentity (+ 1) ℤ*
  identityˡ (+ zero ) = refl
  identityˡ -[1+  n ] rewrite proj₂ +-identity n = refl
  identityˡ (+ suc n) rewrite proj₂ +-identity n = refl

  comm : Commutative ℤ*
  comm -[1+ a ] -[1+ b ] rewrite *-comm (suc a) (suc b) = refl
  comm -[1+ a ] (+   b ) rewrite *-comm (suc a) b       = refl
  comm (+   a ) -[1+ b ] rewrite *-comm a       (suc b) = refl
  comm (+   a ) (+   b ) rewrite *-comm a       b       = refl

  lemma : ∀ a b c → c ℕ+ (b ℕ+ a ℕ* suc b) ℕ* suc c
                  ≡ c ℕ+ b ℕ* suc c ℕ+ a ℕ* suc (c ℕ+ b ℕ* suc c)
  lemma =
    solve 3 (λ a b c → c :+ (b :+ a :* (con 1 :+ b)) :* (con 1 :+ c)
                    := c :+ b :* (con 1 :+ c) :+
                       a :* (con 1 :+ (c :+ b :* (con 1 :+ c))))
            refl
    where open ℕ.SemiringSolver

  assoc : Associative ℤ*
  assoc (+ zero) _ _ = refl
  assoc x (+ zero) _ rewrite proj₂ *-zero ∣ x ∣ = refl
  assoc x y (+ zero) rewrite
      proj₂ *-zero ∣ y ∣
    | proj₂ *-zero ∣ x ∣
    | proj₂ *-zero ∣ sign x S* sign y ◃ ∣ x ∣ ℕ* ∣ y ∣ ∣
    = refl
  assoc -[1+ a  ] -[1+ b  ] (+ suc c) = cong (+_ ∘ suc) (lemma a b c)
  assoc -[1+ a  ] (+ suc b) -[1+ c  ] = cong (+_ ∘ suc) (lemma a b c)
  assoc (+ suc a) (+ suc b) (+ suc c) = cong (+_ ∘ suc) (lemma a b c)
  assoc (+ suc a) -[1+ b  ] -[1+ c  ] = cong (+_ ∘ suc) (lemma a b c)
  assoc -[1+ a  ] -[1+ b  ] -[1+ c  ] = cong -[1+_]     (lemma a b c)
  assoc -[1+ a  ] (+ suc b) (+ suc c) = cong -[1+_]     (lemma a b c)
  assoc (+ suc a) -[1+ b  ] (+ suc c) = cong -[1+_]     (lemma a b c)
  assoc (+ suc a) (+ suc b) -[1+ c  ] = cong -[1+_]     (lemma a b c)

  isSemigroup : IsSemigroup _ _
  isSemigroup = record
    { isEquivalence = isEquivalence
    ; assoc         = assoc
    ; ∙-cong        = cong₂ ℤ*
    }

  isCommutativeMonoid : IsCommutativeMonoid _≡_ ℤ* (+ 1)
  isCommutativeMonoid = record
    { isSemigroup = isSemigroup
    ; identityˡ   = identityˡ
    ; comm        = comm
    }

commutativeMonoid : CommutativeMonoid _ _
commutativeMonoid = record
  { Carrier             = ℤ
  ; _≈_                 = _≡_
  ; _∙_                 = ℤ*
  ; ε                   = + 1
  ; isCommutativeMonoid = isCommutativeMonoid
  }


--------------------------------------------------------------------------------
-- This is part of Agda Inference Systems

{-# OPTIONS --sized-types --guardedness #-}

open import Data.Product
open import Data.Vec
open import Data.Unit
open import Codata.Colist
open import Agda.Builtin.Equality
open import Size
open import Data.Nat
open import Data.Fin
open import Codata.Thunk
open import Relation.Unary using (_⊆_)
open import Examples.Colists.Auxiliary.Colist_member

open import is-lib.InfSys

module Examples.Colists.allPos where

  U = Colist ℕ ∞

  data allPosRN : Set where
    allp-Λ allp-t : allPosRN

  allP-Λ-r : FinMetaRule U
  allP-Λ-r .Ctx = ⊤
  allP-Λ-r .comp c =
    [] ,
    -----------------
    []

  allP-t-r : FinMetaRule U
  allP-t-r .Ctx = Σ[ (x , _) ∈ ℕ × Thunk (Colist ℕ) ∞ ] x Data.Nat.> 0
  allP-t-r .comp ((x , xs) , _) =
    xs .force ∷ [] ,
    -----------------
    x ∷ xs

  allPosIS : IS U
  allPosIS .Names = allPosRN
  allPosIS .rules allp-Λ = from allP-Λ-r
  allPosIS .rules allp-t = from allP-t-r

  allPos : U → Set
  allPos = CoInd⟦ allPosIS ⟧

  allPosSpec : U → Set
  allPosSpec xs = ∀{x} → x ∈ xs → x Data.Nat.> 0

  allPosSound : allPos ⊆ allPosSpec
  allPosSound {x ∷ xs} ap mem with ap .CoInd⟦_⟧.unfold
  allPosSound {x ∷ xs} ap here | allp-t , ((.x , .xs) , x>0) , refl , prem = x>0
  allPosSound {x ∷ xs} ap (there mem) | allp-t , ((.x , .xs) , _) , refl , prem = allPosSound (prem zero) mem

  allPosSpecCons : ∀{xs} → allPosSpec xs → ISF[ allPosIS ] allPosSpec xs
  allPosSpecCons {[]} _ = allp-Λ , (tt , (refl , λ ()))
  allPosSpecCons {(x ∷ xs)} Sxs = allp-t , (((x , xs) , Sxs here) , (refl , λ {Fin.zero → λ mem → Sxs (there mem)}))

  allPosComplete : allPosSpec ⊆ allPos
  allPosComplete = coind[ allPosIS ] allPosSpec allPosSpecCons

  {- allPos as Container -}

  open import Data.Empty using (⊥)
  open import Data.Container.Indexed
  open import is-lib.InfSys.Container U
  open ISCont

  allPosCont : ISCont
  allPosCont .Command [] = ⊤
  allPosCont .Command (x ∷ xs) = x Data.Nat.> 0
  allPosCont .Response {[]} tt = ⊥
  allPosCont .Response {_ ∷ _} _ = Fin 1
  allPosCont .next {_ ∷ xs} _ zero = xs .force

  allPosC : U → Set
  allPosC = ISCont.CoInd⟦ allPosCont ⟧