{-# OPTIONS --cubical --erasure --guardedness #-}
module BrouwerTree.OrdinalDecidability.Basic where

open import Cubical.Data.Nat
  using (; zero; suc; ·-comm ; max ; +-zero ; +-suc ; isSetℕ)
  renaming (_+_ to _N+_; _·_ to _N·_; +-assoc to N+-assoc)
import Cubical.Data.Nat.Order as N
open import Cubical.Data.Sigma hiding (; ∃-syntax)
open import Cubical.Data.Sum
open import Cubical.Data.Empty as 
open import Cubical.Data.Unit
open import Cubical.Relation.Nullary
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Function

open import BrouwerTree.Everything

open import PropTrunc
open import Iff
open import Bool as B
open import BooleanSequence
open import General-Properties


private
 variable
   ℓ' : Level

------------------ General definitions -------------

down-closed : (P :   Type )  Type 
down-closed P = (n : )  P (suc n)  P n

up-closed : (P :   Type )  Type 
up-closed P = (n : )  P n  P (suc n)

------------------ Definition of ordinal decidability -------------

ordinal-dec-str : (z : Brw)  (P : Type )  Type 
ordinal-dec-str z P = Σ[ y  Brw ] (P  (z  y))

ordinal-dec : (z : Brw)  (P : Type )  Type 
ordinal-dec z P =  ordinal-dec-str z P 


------------------ Definition of semidecidable proposition---------

semi-dec-str : (P : Type )  Type 
semi-dec-str  P = Σ[ s  (  Bool) ] (P  (∃[ n   ] s n  true))

semi-dec :  (P : Type )  Type 
semi-dec P  =  semi-dec-str P 

dec→semi-dec : (P : Type )  Dec P  semi-dec-str P
dec→semi-dec P dec =  n  decRec  _  true)  _  false) dec) , f dec , g dec
 where
  f : (dec : Dec P)  P  ∃[ n   ] decRec  _  true)  _  false) dec  true
  f (yes p') p =  17 , refl 
  f (no ¬p) p = ⊥.rec (¬p p)

  g : (dec : Dec P)  ∃[ n   ] decRec  _  true)  _  false) dec  true  P
  g (yes p) _ = p
  g (no ¬p') q = ⊥.rec (∥-∥rec isProp⊥  (_ , e)  false≢true e) q)

⊤-semi-dec-str : semi-dec-str Unit
⊤-semi-dec-str = dec→semi-dec Unit (yes tt)

⊥-semi-dec-str : semi-dec-str 
⊥-semi-dec-str = dec→semi-dec  (no λ x  x)


∨-semi-dec : (P : Type ) (Q : Type ℓ')
            semi-dec P
            semi-dec Q
            semi-dec ( P  Q )
∨-semi-dec P Q  = ∥-∥map2 [1]
 where
  [1] : semi-dec-str P   semi-dec-str Q   semi-dec-str  P  Q 
  [1] (s , s-fwd , s-bwd) (t , t-fwd , t-bwd) =
   s⊕t , ∥-∥rec squash fwd , ∥-∥map bwd
    where
     or-one-of : {x y : Bool}  x or y  true  (x  true)  (y  true)
     or-one-of {false} {y} e = inr e
     or-one-of {true} {y} e = inl refl
     s⊕t :   Bool
     s⊕t n = (s n) or (t n)
     fwd : P  Q  ∃[ n   ] s⊕t n  true
     fwd (inl p) =
      ∥-∥map  (n , e)  n , subst  -  - or (t n)  true) (sym e) refl)
             (s-fwd p)
     fwd (inr q) =
      ∥-∥map
         (n , e)  n , subst  -  s n or -  true) (sym e) (or-zeroʳ (s n)))
        (t-fwd q)
     bwd : Σ   n  s⊕t n  true)  P  Q
     bwd (n , h) with or-one-of h
     ... | inl e = inl (s-bwd  (n , e) )
     ... | inr e = inr (t-bwd  (n , e) )

∧-semi-dec-str : (P : Type ) (Q : Type ℓ')
                semi-dec-str P  semi-dec-str Q  semi-dec-str (P × Q)
∧-semi-dec-str P Q (s , s-fwd , s-bwd) (t , t-fwd , t-bwd) = s⊗t , fwd , bwd
 where
  open import Cubical.Data.Nat.Bijections.Product
  open import Cubical.Foundations.Isomorphism
  ϕ :    × 
  ϕ = Iso.inv ℕ×ℕ≅ℕ
  ψ :  ×   
  ψ = Iso.fun ℕ×ℕ≅ℕ
  s⊗t :   Bool
  s⊗t n = s (fst (ϕ n)) and t (snd (ϕ n))
  fwd : P × Q  ∃[ n   ] s⊗t n  true
  fwd (p , q) = ∥-∥map2 h (s-fwd p) (t-fwd q)
   where
    h : Σ   n  s n  true)
       Σ   n  t n  true)
       Σ   n  s⊗t n  true)
    h (n , e) (m , e') = ψ (n , m) , [2]  [3]
     where
      [2] : s⊗t (ψ (n , m))  s n and t m
      [2] = subst2  x y  (s x and t y)  (s n and t m))
             (cong fst (sym (Iso.ret ℕ×ℕ≅ℕ (n , m))))
             (cong snd (sym (Iso.ret ℕ×ℕ≅ℕ (n , m))))
             refl
      [3] : (s n and t m)  true
      [3] = subst2  x y  x and y  true) (sym e) (sym e') refl
  bwd : ∃[ n   ] s⊗t n  true  P × Q
  bwd =  t  h₁ t , h₂ t)
   where
    and-both : {x y : Bool}  x and y  true  (x  true) × (y  true)
    and-both {false} {y} e =
     ⊥.elim {_}  _  (false  true) × (y  true)} (false≢true e)
    and-both {true} {false} e =
     ⊥.elim {_}  _  (true  true) × (false  true)} (false≢true e)
    and-both {true} {true} _ = refl , refl
    h₁ : ∃[ n   ] s⊗t n  true  P
    h₁ t = s-bwd (∥-∥map  (n , e)  fst (ϕ n) , fst (and-both e)) t)
    h₂ : ∃[ n   ] s⊗t n  true  Q
    h₂ t = t-bwd (∥-∥map  (n , e)  snd (ϕ n) , snd (and-both e)) t)

∧-semi-dec : (P : Type ) (Q : Type ℓ')
            semi-dec P  semi-dec Q  semi-dec (P × Q)
∧-semi-dec P Q = ∥-∥map2 (∧-semi-dec-str P Q)

∃-semi-dec-str : (P :   Type )
                ((n : )  semi-dec-str (P n))
                semi-dec-str (  P)
∃-semi-dec-str P σ = s  ϕ , ↔-trans γ (∥-∥↔ (γ' , γ''))
 where
  open import Cubical.Data.Nat.Bijections.Product
  open import Cubical.Foundations.Isomorphism
  ϕ :    × 
  ϕ = Iso.inv ℕ×ℕ≅ℕ
  ψ :  ×   
  ψ = Iso.fun ℕ×ℕ≅ℕ

  s :  ×   Bool
  s (n , m) = fst (σ n) m
  s-spec : (n : )  P n  ∃[ m   ] s (n , m)  true
  s-spec n = snd (σ n)
  γ :   P  ∃[ n   ] Σ[ m   ] s (n , m)  true
  γ = [1] , [2]
   where
    [1] :   P  ∃[ n   ] Σ[ m   ] s (n , m)  true
    [1] = ∥-∥rec isPropPropTrunc
                  (n , p)  ∥-∥map  (m , e)  n , m , e) (lr (s-spec n) p) )
    [2] : ∃[ n   ] Σ[ m   ] s (n , m)  true    P
    [2] = ∥-∥map λ (n , m , e)  n , rl (s-spec n)  m , e 
  γ' : Σ[ n   ] Σ[ m   ] s (n , m)  true  Σ[ n   ] s (ϕ n)  true
  γ' (n , m , e) = ψ (n , m) , cong s (Iso.ret ℕ×ℕ≅ℕ (n , m))  e

  γ'' : Σ[ n   ] s (ϕ n)  true  Σ[ n   ] Σ[ m   ] s (n , m)  true
  γ'' (n , e) = _ , _ , cong (s  ϕ) (Iso.sec ℕ×ℕ≅ℕ n)  e

semi-dec-str-stable-under-↔ : (P : Type ) (Q : Type ℓ')
                             (P  Q)
                             (semi-dec-str P  semi-dec-str Q)
semi-dec-str-stable-under-↔ P Q (f , g) = [1] P Q f g , [1] Q P g f
 where
  [1] : (P : Type ) (Q : Type ℓ')
       (P  Q)  (Q  P)
       semi-dec-str P  semi-dec-str Q
  [1] P Q f g (β , (d₀ , d₁)) = (β , (d₀  g , f  d₁))

semi-dec-stable-under-↔ : (P : Type ) (Q : Type ℓ')
                         (P  Q)
                         (semi-dec P  semi-dec  Q)
semi-dec-stable-under-↔  P Q e =
 (∥-∥map (lr (semi-dec-str-stable-under-↔ P Q e)) ,
  ∥-∥map (rl (semi-dec-str-stable-under-↔ P Q e)))

semi-dec-sim : (P : Type )
              ((s , q) (s' , q') : semi-dec-str P)
              (k : )  ∃[ m   ] s k B≤ s' m
semi-dec-sim P (s , q) (s' , q') k = aux (s k) refl
 where
  aux : (y : Bool)  y  s k  ∃[ m   ] y B≤ s' m
  aux false e =  17 , tt 
  aux true e = ∥-∥map (map-snd λ p  Bool≡→≤ (sym p))
                      ((lr q' (rl q  k , sym e )))

LPO' : ( : Level)  Type (ℓ-suc )
LPO'  = (P : Type )  isProp P  semi-dec P  Dec P

LPO'→LPO : LPO' ℓ-zero  LPO
LPO'→LPO lpo' s = decRec inr (inl  [2]) [1]
 where
  [1] : Dec (∃[ n   ] s n  true)
  [1] = lpo' (∃[ n   ] s n  true) isPropPropTrunc  (s , ↔-refl) 
  [2] : ¬ (∃[ n   ] s n  true)  (k : )  s k  false
  [2] h k = ¬true→false (s k)  e  h  k , e )

MP' : ( : Level)  Type (ℓ-suc )
MP'  = (P : Type )  isProp P  semi-dec P  ¬ ¬ P  P

MP→MP' : MP  MP' 
MP→MP' mp P P-prop σ ¬¬P = ∥-∥rec P-prop [1] σ
 where
  [1] : semi-dec-str P  P
  [1] (s , ρ) = rl ρ  mp s (¬¬-functor [2] (¬¬-functor (lr ρ) ¬¬P)) 
   where
    [2] : ∃[ n   ] s n  true  Σ[ n   ] s n  true
    [2] = least-witness  n  s n  true)  n  isSetBool _ _)  n  s n  true)

-----------------First Observation Toward Ordinal Decidability:-----------------
--Proposition: P is decidable iff it is ω-decidable iff it is finite-decidable.

dec↔ω-dec : (P : Type )  isProp P  (Dec P  ordinal-dec ω P)
dec↔ω-dec P  P-prop = [1] , [2]
 where
  [1] : Dec P  ordinal-dec ω P
  [1] (yes p) =  ω ,  _  ≤-refl) ,  _  p) 
  [1] (no ¬p) =  zero ,  p  ⊥.elim (¬p p)) ,  l  ⊥.elim (lim≰zero l)) 
  [2] : ordinal-dec ω P   Dec P
  [2] h = ∥-∥rec (isPropDec P-prop) [3] h
   where
    [3] : ordinal-dec-str ω P  Dec P
    [3] (x , f , g) = κ (<ω-or-≥ω x)
     where
      κ : (x < ω)  (ω  x)  Dec P
      κ (inl l) = no  p  <-irreflexive x (<∘≤-in-< l (f p)))
      κ (inr l) = yes (g l)

dec↔1-dec : (P : Type )  isProp P
           Dec P  ordinal-dec one P
dec↔1-dec P i = [1] , [2]
 where
  [1] : Dec P  ordinal-dec one P
  [1] (yes p) =  one ,  _  ≤-refl) ,  _  p) 
  [1] (no ¬p) =  zero ,  p  ⊥.elim (¬p p)) ,  l  ⊥.elim (succ≰zero l)) 
  [2] : ordinal-dec one P  Dec P
  [2] = ∥-∥rec (isPropDec i) [3]
   where
    [3] : ordinal-dec-str one P  Dec P
    [3] (x , f , g) = mapDec g  ν p  ν (f p)) (dec-n≤ x 1)

dec↔fin-dec : (P : Type )  isProp P
             Dec P  (Σ[ n   ] ordinal-dec (ι (suc n)) P)
dec↔fin-dec P P-is-prop = [1] , [2]
 where
  [1] : Dec P  Σ[ n   ] ordinal-dec (ι (suc n)) P
  [1] (yes p) = 1 ,  ι 2 ,  _  ≤-refl) ,  _  p) 
  [1] (no ¬p) = 1 ,  zero ,  p  ⊥.elim (¬p p)) ,  l  ⊥.elim (succ≰zero l)) 
  [2] : Σ   n  ordinal-dec (ι (suc n)) P)  Dec P
  [2] (n , h) = ∥-∥rec (isPropDec P-is-prop) [3] h
   where
    [3] : ordinal-dec-str (ι (suc n)) P  Dec P
    [3] (x , f , g) = mapDec g  ν p  ν (f p)) (dec-n≤ x (suc n))

semidec↔ω+1-dec : (P : Type )  isProp P
                 semi-dec P  ordinal-dec (succ ω) P
semidec↔ω+1-dec P P-is-prop = ∥-∥map semidec→ω+1-dec ,
                              ∥-∥rec isPropPropTrunc ω+1-dec→semidec
 where
  semidec→ω+1-dec : semi-dec-str P  ordinal-dec-str (succ ω) P
  semidec→ω+1-dec (s , ρ) = limit[ s ]↑ , [1] , [2]
   where
    [1] : P  ω < limit[ s ]↑
    [1] p = subst (ω <_) (sym (jumpSeq-translate-forth s (lr ρ p))) ω<ω·2
    [2] : ω < limit[ s ]↑  P
    [2] l = rl ρ  jumpSeq>ω-translate-back s l 

  ω+1-dec→semidec : ordinal-dec-str (succ ω) P  semi-dec P
  ω+1-dec→semidec (x , ρ) = Brw-ind  x  P  ω < x  semi-dec P)
                                     x  isProp→ isPropPropTrunc)
                                    [1]
                                    [2]
                                     {f} {f↑}  [3] {f} {f↑})
                                    x ρ
   where
    [1] : P  (ω < zero)  semi-dec P
    [1] τ =   _  false) , ↔-trans τ ([1]₁ , ∥-∥rec isProp⟨<⟩ [1]₂) 
     where
      [1]₁ : ω < zero  ∃[ n   ] false  true
      [1]₁ l = ⊥.rec (x≮zero l)
      [1]₂ : Σ[ n   ] false  true  ω < zero
      [1]₂ (_ , e) = ⊥.rec (false≢true e)
    [2] : {y : Brw}  (P  (ω < y)  semi-dec P)
         P  (ω < succ y)  semi-dec P
    [2] {y} ih τ = lr (semi-dec-stable-under-↔ (¬ isFinite y) P [2]₁) [2]₂
     where
      [2]₁ : ¬ isFinite y  P
      [2]₁ = ↔-trans (notFinite-correct-↔ y) (↔-sym (↔-trans τ ≤-succ-mono-↔))
      [2]₂ : semi-dec (¬ isFinite y)
      [2]₂ =  (dec→semi-dec (¬ isFinite y) (Dec¬ (decIsFinite y))) 
    [3] : {f :   Brw} {f↑ : increasing f}
         ((k : )  P  (ω < f k)  semi-dec P)
         P  (ω < limit f)  semi-dec P
    [3] {f} {f↑} ih τ =  g , ↔-trans τ [3]₁ 
     where
      d : (n : )  Dec (¬ isFinite (f n))
      d n = Dec¬ (decIsFinite (f n))
      g :   Bool
      g = unjump f (¬_  isFinite) d
      [3]₁ : ω < limit f  ∃[ n    ] g n  true
      [3]₁ = ↔-trans (below-limit-↔ ω f) (∥-∥↔ ([3]₂₋₁ , [3]₂₋₂))
       where
        [3]₂₋₁ : Σ[ n    ] ω < f n  Σ[ n    ] g n  true
        [3]₂₋₁ (n , l) = n , P-to-unjump≡true f (¬_  isFinite) d n
                                              (rl (notFinite-correct-↔ (f n))
                                                  (<-in-≤ l))

        [3]₂₋₂ : Σ[ n    ] g n  true  Σ[ n    ] ω < f n
        [3]₂₋₂ (n , e) = (suc n , ≤∘<-in-< [3]₂-₃ (f↑ n))
         where
          [3]₂₋₃ : ¬ isFinite (f n)
          [3]₂₋₃ = unjump≡true-to-P f (¬_  isFinite) d n e
          [3]₂-₃ : ω  f n
          [3]₂-₃ = lr (notFinite-correct-↔ (f n)) [3]₂₋₃

∃∃dec-is-semidec : (P :     Type )
                  ((n m : )  Dec (P n m))
                  semi-dec (∃[ n   ] Σ[ m   ] P n m)
∃∃dec-is-semidec P Pdec =  s , ∥-∥rec isPropPropTrunc [1] , ∥-∥map [2] 
 where
  open import Cubical.Data.Nat.Bijections.Product
  open import Cubical.Foundations.Isomorphism
  ϕ :    × 
  ϕ = Iso.inv ℕ×ℕ≅ℕ
  ψ :  ×   
  ψ = Iso.fun ℕ×ℕ≅ℕ
  s :   Bool
  s n = Dec→Bool (Pdec (fst (ϕ n)) (snd (ϕ n)))

  [1] : Σ[ n   ] Σ[ m   ] P n m  ∃[ k   ] s k  true
  [1] (n , t) =   [1]' t 
   where
    [1]' : Σ  (P n)  Σ[ k   ] s k  true
    [1]' (m , p) = (ψ (n , m) , e)
     where
      e = s (ψ (n , m))       ≡⟨ cong₂  x y  Dec→Bool (Pdec x y)) e₁ e₂ 
          Dec→Bool (Pdec n m) ≡⟨ Dec→Bool≡true (P n m) p (Pdec n m) 
          true                
       where
        e₁ = cong fst (Iso.ret ℕ×ℕ≅ℕ (n , m))
        e₂ = cong snd (Iso.ret ℕ×ℕ≅ℕ (n , m))

  [2] : Σ[ k   ] s k  true  Σ[ n   ] Σ  (P n)
  [2] (k , e) = n ,  (m , toWitness P-holds)
   where
    n = fst (ϕ k)
    m = snd (ϕ k)
    P-holds : True (Pdec n m)
    P-holds = subst Bool→Type (sym e) tt

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

finite-decidability-all-equivalent
 : (P : Type ) (n m : )
  ordinal-dec (ι (suc n)) P  ordinal-dec (ι (suc m)) P
finite-decidability-all-equivalent P n m = wlog n m , wlog m n
 where
  wlog : (n m : )  ordinal-dec (ι (suc n)) P  ordinal-dec (ι (suc m)) P
  wlog n m = ∥-∥map [1]
   where
    [1] : ordinal-dec-str (ι (suc n)) P   ordinal-dec-str (ι (suc m)) P
    [1] (u , g) = [2] (dec-n≤ u (suc n))
     where
      [2] : Dec (ι (suc n)  u)  ordinal-dec-str (ι (suc m)) P
      [2] (yes u≤n) = ι (suc m) ,  _  ≤-refl) ,  _  rl g u≤n)
      [2] (no ¬u≤n) =
       ι m ,  p  ⊥.rec (¬u≤n (lr g p))) , λ l  ⊥.rec (<-irreflexive (ι m) l)

zero-decidable-str-iff-true : (P : Type )  ordinal-dec-str zero P  P
zero-decidable-str-iff-true P = [1] , [2]
 where
  [1] : ordinal-dec-str zero P  P
  [1] (u , g) = rl g ≤-zero

  [2] : P  ordinal-dec-str zero P
  [2] p = zero ,  _  ≤-refl) ,  _  p)

zero-decidable-iff-true : (P : Type )  isProp P  ordinal-dec zero P  P
zero-decidable-iff-true P P-prop =
 ∥-∥rec P-prop (lr (zero-decidable-str-iff-true P)) ,
 ∣_∣  rl (zero-decidable-str-iff-true P)

---------------------- Second Observation Toward Ordinal Decidability:-------------
-- Proposition: a proposition P is semidecidable if and only if it is ω·2-decidable.

semidec→ω·2dec : (P : Type )  isProp P  semi-dec P  ordinal-dec (ω + ω) P
semidec→ω·2dec P P-prop = ∥-∥map h
 where
  h :  semi-dec-str P   ordinal-dec-str (ω + ω)  P
  h (s , (g₁ , g₂)) = α , (q₁ , q₂)
   where
     f :   Brw
     f zero = zero
     f (suc n) with s n  true
     ... | yes _ = f n + ω
     ... | no _ = f n + ι 1
     f-eq₀ : f 0  zero
     f-eq₀ = refl
     f-eq₁ : (n : )  s n  true  f (suc n)  f n + ω
     f-eq₁ n e with s n  true
     ... | yes _ = refl
     ... | no  ν = ⊥.rec (ν e)
     f-eq₂ : (n : )  s n  false  f (suc n)  succ (f n)
     f-eq₂ n e with s n  true
     ... | yes e' = ⊥.rec (true≢false (sym e'  e))
     ... | no  _ = refl
     f↑ : increasing f
     f↑ k  with s k  true
     ... | yes _ = ≤-cocone  n  f k + ι n) {k = 1} ≤-refl
     ... | no _ = ≤-refl
     α : Brw
     α = limit f {f↑}

     q₁ : P  (ω + ω)  α
     q₁ e = ∥-∥rec ≤-trunc M (g₁ e)
      where
       M :  Σ[ n   ] s n  true  ω + ω  α
       M (n₀ , sn0=t) = simulation→≤ Hsim
        where
          v : ω  f (suc n₀)
          v with s n₀  true
          ... | yes z = ω-smallest  n  f (n₀) + ι n)
          ... | no  z' = ⊥.rec (z' sn0=t)
          Hsim : (k : )  Σ[ n   ] ω + ι k  f n
          Hsim k  = (suc n₀ N+ k , hN₀)
            where
              hN₀ : ω + ι k  f (suc n₀ N+ k)
              hN₀ = ≤-offset-by-ι f {f↑} ω v

     q₂ : ω + ω  α  P
     q₂ a  = ∥-∥rec P-prop M L
      where
       L :  ∃[ n   ] ω  f n
       L = lim≤lim→weakly-bisimilar  u  ω + ι u) f a zero
       M : Σ[ n   ] ω  f n  P
       M (n , b) = g₂ (∥-∥map  (k , _ , e)  k , e) w)
        where
         w :  ∃[ k   ] (k N.≤ n) × (s k  true)
         w = δ n b
          where
           δ : (n : )  ω  f n  ∃[ k    ] (k N.≤ n) × (s k  true)
           δ zero l = ⊥.elim (lim≰zero l)
           δ (suc n) l with dec-true-below n s
           ... | yes (k , l , e) =  k , N.≤-suc l , e 
           ... | no v' = ∥-∥map  (k , l , e)  k , N.≤-suc l , e) (δ n [3])
            where
             [1] : s n  false
             [1] = ¬true→false (s n)  (e : s n  true)  v' (n , N.≤-refl , e))
             [2] : ω  succ (f n)
             [2] = subst (ω ≤_) (f-eq₂ n [1]) l
             [3] : ω  f n
             [3] = lim≤sx→lim≤x ι (f n) [2]

ω·2dec→semidec : (P : Type )  isProp P  ordinal-dec (ω + ω) P  semi-dec P
ω·2dec→semidec {} P P-prop = ∥-∥rec isPropPropTrunc f
 where
  f : ordinal-dec-str (ω + ω) P  semi-dec P
  f (X , (b₁ , b₂)) = F X b₁ b₂
   where
    F : (x : Brw)  (β₁ : P  ω + ω  x)  (β₂ : ω + ω  x  P)  semi-dec P
    F = Brw-ind PF  x  isProp→ (isProp→ isPropPropTrunc))  P₀ Pₛ Pₗ
     where
         PF : Brw  Type 
         PF x = (P  ω + ω  x)  (ω + ω  x  P)  semi-dec P

         P₀ : PF zero
         P₀ β₁ β₂ =   _  false) , [1] , [2] 
          where
           [1] : P  ∃[ n   ] false  true
           [1] p = ⊥.rec (lim≰zero (β₁ p))
           [2] : ∃[ n   ] false  true  P
           [2] = ∥-∥rec P-prop  (n , e)  ⊥.rec (false≢true e))

         Pₛ : {x : Brw}  PF x  PF (succ x)
         Pₛ {x} IH β₁ β₂ = ∥-∥map  σ  σ) (IH ([1]  β₁) (β₂  [2]))
          where
           [1] : ω + ω  succ x  ω + ω  x
           [1] = lim≤sx→lim≤x  n  ω + ι n) x
           [2] : ω + ω  x  ω + ω  succ x
           [2] = ≤-succ-incr

         Pₗ : {g :   Brw} {g↑ : increasing g}
             ((k : )  PF (g k))  PF (limit g {g↑})
         Pₗ {g} {g↑} _ β₁ β₂ =  s , γ₁ , γ₂ 
           where
            s :   Bool
            s zero = false
            s (suc k) with <ω-or-≥ω (g k)
            ... | inl gk<ω = false
            ... | inr ω≤gk = true
            s-eq₁ : (k : )  g k < ω  s (suc k)  false
            s-eq₁ k l with <ω-or-≥ω (g k)
            ... | inl _ = refl
            ... | inr ω≤gk = ⊥.elim (<-irreflexive (g k) (<∘≤-in-< l ω≤gk))
            s-eq₂ : (k : )  ω  g k  s (suc k)  true
            s-eq₂ k l with <ω-or-≥ω (g k)
            ... | inl gk<ω = ⊥.elim (<-irreflexive ω (≤∘<-in-< l gk<ω))
            ... | inr _ = refl
            s-eq₃ : (k : )  s (suc k)  true  ω  g k
            s-eq₃ k e with <ω-or-≥ω (g k)
            ... | inl _ = ⊥.elim {_}  _  ω  g k} (false≢true e)
            ... | inr ω≤gk = ω≤gk
            γ₁ : P  ∃[ n   ] s n  true
            γ₁ p = ∥-∥map [3] ([2] 0)
             where
              [1] : ω + ω  limit g
              [1] = β₁ p
              [2] : (k : )  ∃[ n   ] ω + ι k  g n
              [2] = lim≤lim→weakly-bisimilar  n  ω + ι n) g [1]
              [3] : Σ[ n   ] ω  g n  Σ[ n   ] s n  true
              [3] (n , l) = (suc n , s-eq₂ n l)
            γ₂ : ∃[ n   ] s n  true  P
            γ₂ = ∥-∥rec P-prop (β₂   ϕ)
             where
              ϕ : Σ[ n   ] s n  true  ω + ω  limit g
              ϕ (zero , e) = ⊥.rec (false≢true e)
              ϕ (suc n , e) = [3]
               where
                [1] : ω  g n
                [1] = s-eq₃ n e
                [2] : (k : )  ω + ι k  g (n N+ k)
                [2] k = ≤-offset-by-ι g {g↑} ω [1]
                [3] : ω + ω  limit g {g↑}
                [3] = weakly-bisimilar→lim≤lim _ _  k   n N+ k , [2] k )

---------------Definition of Brwᶻˡ----------------

Brw-zero-or-limit  : (x : Brw)  Type
Brw-zero-or-limit x = is-lim x  (x  zero)

isPropBrw-zero-or-limit : (x : Brw)  isProp (Brw-zero-or-limit x)
isPropBrw-zero-or-limit x =
 isProp⊎ isProp⟨is-lim⟩
         (Brw-is-set _ _)
          l z  unique.not-z-and-l x (≡zero→is-zero z) l)

Brwᶻˡ : Type
Brwᶻˡ = Σ[ x  Brw ] (Brw-zero-or-limit x)