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

open import Cubical.Data.Nat using (; zero; suc) renaming (_+_ to _N+_)
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.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Relation.Nullary

open import Iff
open import PropTrunc

open import BrouwerTree.Everything

open import  BrouwerTree.OrdinalDecidability.Basic
open import  BrouwerTree.OrdinalDecidability.GeneralProperties


-- Definition of relational limMin simultaneously with its monotonicity

mutual
 data limMin[_,_]~_ : Brw  Brw  Brw  Type where
  zero-left : (y : Brw)  limMin[ zero , y ]~ zero
  succ-left : (x y z : Brw)  limMin[ x , y ]~ z  limMin[ succ x , y ]~ z
  lim-zero : (f :   Brw) {f↑ : increasing f}  limMin[ limit f {f↑} , zero ]~ zero
  lim-succ : (f :   Brw) {f↑ : increasing f} (y z : Brw)
            limMin[ limit f {f↑} , y ]~ z  limMin[ limit f {f↑} , succ y ]~ z
  lim-lim : (f g :   Brw) {f↑ : increasing f} {g↑ : increasing g}
           (r :   Brw)
           (rspec : (n : )  limMin[ f n , g n ]~ r n)
           let r↑ = λ n  ≤-succ-mono (+x-mono (ι n)
                                                (limMin[,]~-mono (<-in-≤ (f↑ n))
                                                                 (<-in-≤ (g↑ n))
                                                                 (rspec n)
                                                                 (rspec (suc n))))
          in limMin[ limit f {f↑} , limit g {g↑} ]~ limit  n  r n + ι n) {r↑}
  trunc : {x y z : Brw}  (p q : limMin[ x , y ]~ z)  p  q

 limMin[,]~-mono : {x x' y y' z z' : Brw}  x  x'  y  y'
                  limMin[ x , y ]~ z  limMin[ x' , y' ]~ z'  z  z'
 limMin[,]~-mono u v (zero-left y) σ = ≤-zero
 limMin[,]~-mono u v (succ-left x₁ y z ρ) σ =
  limMin[,]~-mono (≤-trans ≤-succ-incr-simple u) v ρ σ
 limMin[,]~-mono u v (lim-zero f) σ = ≤-zero
 limMin[,]~-mono u v (lim-succ f y₁ z ρ) σ =
  limMin[,]~-mono  u (≤-trans ≤-succ-incr-simple v) ρ σ
 limMin[,]~-mono u v (lim-lim f g r rspec) (zero-left y') = ⊥.rec (lim≰zero u)
 limMin[,]~-mono u v (lim-lim f g r rspec) (succ-left x₁ y' z' σ) =
  limMin[,]~-mono  (lim≤sx→lim≤x f x₁ u) v (lim-lim f g r rspec) σ
 limMin[,]~-mono u v (lim-lim f g r rspec) (lim-zero f₁) = ⊥.rec (lim≰zero v)
 limMin[,]~-mono u v (lim-lim f g r rspec) (lim-succ f₁ y₁ z' σ) =
  limMin[,]~-mono u (lim≤sx→lim≤x g y₁ v) (lim-lim f g r rspec) σ
 limMin[,]~-mono u v (lim-lim f f' {f↑} {f'↑} r rspec) (lim-lim g g' {g↑} {g'↑} s sspec) =
  weakly-bisimilar→lim≤lim _ _ h
   where
     h :  k  r k + ι k)   k  s k + ι k)
     h k  =  ∥-∥rec isPropPropTrunc β (lim≤lim→weakly-bisimilar f g u k)
      where
       β :  Σ[ n   ] f k  g n  ∃[ n   ] (r k + ι k  s n + ι n)
       β (n₁ , m₁) = ∥-∥map α (lim≤lim→weakly-bisimilar f' g' v k)
        where
         α : Σ[ n   ] f' k  g' n  Σ[ n   ] r k + ι k  s n + ι n
         α (n₂ , m₂) = (n₀ , u₀)
          where
           n₀ = n₁ N+ (n₂ N+ k)
           u₀ : r k + ι k  s n₀ + ι n₀
           u₀ = +-mono w (ι-mono (N.≤-trans (N.≤SumRight {k}) (N.≤SumRight {k = n₁})))
            where
             w : r k  s n₀
             w = limMin[,]~-mono u₁ u₂ (rspec k) (sspec n₀)
              where
               u₁ : f k  g n₀
               u₁ = ≤-trans m₁ (increasing-monotone g↑ (N.≤SumLeft {n₁}))

               u₂ : f' k  g' n₀
               u₂ = ≤-trans m₂
                            (increasing-monotone g'↑ (N.≤-trans (N.≤SumLeft {n₂})
                                                                (N.≤SumRight {k = n₁})))
 limMin[,]~-mono u v (lim-lim f g r rspec) (trunc σ σ' i) =
  isProp→PathP  i  ≤-trunc) (limMin[,]~-mono  u v (lim-lim f g r rspec) σ)
                               (limMin[,]~-mono u v (lim-lim f g r rspec) σ') i
 limMin[,]~-mono u v (trunc ρ ρ' i) σ =
  isProp→PathP  i  ≤-trunc) (limMin[,]~-mono u v ρ σ)
                               (limMin[,]~-mono u v ρ' σ) i


limMin[,]~-single-valued : {x y z z' : Brw}
                          limMin[ x , y ]~ z  limMin[ x , y ]~ z'  z  z'
limMin[,]~-single-valued ρ σ =
 ≤-antisym (limMin[,]~-mono ≤-refl ≤-refl ρ σ) (limMin[,]~-mono  ≤-refl ≤-refl σ ρ)

limMin[,]-outputs-unique : {x y : Brw}  isProp (Σ[ z  Brw ] limMin[ x , y ]~ z)
limMin[,]-outputs-unique (z , r) (z' , r') =
 Σ≡Prop  w  trunc) (limMin[,]~-single-valued r r')

limMin[,]~-total : (x y : Brw)  Σ[ z  Brw ] limMin[ x , y ]~ z
limMin[,]~-total = Brw-ind P  x  isPropΠ  y  limMin[,]-outputs-unique)) P₀ Pₛ Pₗ
 where
  P : Brw  Type
  P x = (y : Brw)   Σ[ z  Brw ] limMin[ x , y ]~ z
  P₀ : P zero
  P₀ y = zero , zero-left y
  Pₛ : {x : Brw}  P x  P (succ x)
  Pₛ {x} p y = (fst (p y)) , (succ-left x y (fst (p y)) (snd (p y)))
  Pₗ : {f :   Brw} {f↑ : increasing f}
     ((k : )  P (f k))  P (limit f {f↑})
  Pₗ {f} {f↑} p = Brw-ind Q  x  limMin[,]-outputs-unique) (zero , lim-zero f) Qₛ Qₗ
   where
    Q : Brw  Type
    Q y = Σ[ z  Brw ] limMin[ limit f , y ]~ z
    Qₛ : {y : Brw}  Q y  Q (succ y)
    Qₛ {y} q = (fst q) , (lim-succ f y (fst q) (snd q))
    Qₗ : {g :   Brw} {g↑ : increasing g}
        ((k : )  Q (g k))  Q (limit g {g↑})
    Qₗ {g} {g↑} q = (limit  n  r n + ι n)) , (lim-lim f g r rspec)
     where
      r :   Brw
      r n = fst (p n (g n))
      rspec : (n : )  limMin[ f n , g n ]~ r n
      rspec n = snd (p n (g n))
      r↑ : increasing  n  r n + ι n)
      r↑ n = ≤-succ-mono (+x-mono (ι n) (limMin[,]~-mono
                         (<-in-≤ (f↑ n)) (<-in-≤ (g↑ n)) (rspec n) (rspec (suc n))))



-------------------- Definition and monotonicity of limMin as a function: --------------

limMin : Brw  Brw  Brw
limMin x y = fst (limMin[,]~-total x y)

limMin-spec : (x y : Brw)  limMin[ x , y ]~ (limMin x y)
limMin-spec x y = snd (limMin[,]~-total x y)

limMin-mono : {x x' y y' : Brw}  x  x'  y  y'  limMin x y  limMin x' y'
limMin-mono {x} {x'} {y} {y'} u v =
 limMin[,]~-mono u v (limMin-spec x y) (limMin-spec x' y')

private
 limMin-zero-y≡zero : (y : Brw)  limMin zero y  zero
 limMin-zero-y≡zero y = refl

 limMin-succ⟨x⟩-y≡limMin-x-y : (x y : Brw)  limMin (succ x) y  limMin x y
 limMin-succ⟨x⟩-y≡limMin-x-y x y = refl

 limMin-limit⟨f⟩-limit⟨g⟩≡limit⟨limMin-fn-gn+n⟩
  : (f g :   Brw) {f↑ : increasing f} {g↑ : increasing g}
   limMin (limit f {f↑}) (limit g {g↑})
      limit  n  limMin (f n) (g n) + ι n)
              n  ≤-succ-mono (+x-mono (ι n)
                                         (limMin-mono (<-in-≤ (f↑ n)) (<-in-≤ (g↑ n))))}
 limMin-limit⟨f⟩-limit⟨g⟩≡limit⟨limMin-fn-gn+n⟩ f g {f↑} {g↑} = refl

-------------------- Properties of limMin --------------------------

limMin-left : (x y : Brw)  limMin x y  x
limMin-left =
 Brw-ind  x  (y : Brw)  limMin x y  x)  x  isPropΠ  y  ≤-trunc)) P₀ Pₛ Pₗ
  where
   P₀ : (y : Brw)  limMin zero y  zero
   P₀ y = ≤-refl

   Pₛ : {x : Brw}
       ((y : Brw)  limMin x y  x)
       (y : Brw)  limMin (succ x) y  succ x
   Pₛ {x} r y = ≤-trans (r y) ≤-succ-incr-simple

   Pₗ : {f :   Brw} {f↑ : increasing f}
       ((k : ) (y : Brw)  limMin (f k) y  f k)
       (y : Brw)  limMin (limit f {f↑}) y  limit f {f↑}
   Pₗ {f} {f↑} r =
    Brw-ind  y  limMin (limit f) y  limit f)  y  ≤-trunc) ≤-zero  u  u) h
     where
      h : {g :   Brw} {g↑ : increasing g}
         ((k : )  limMin (limit f {f↑}) (g k)  limit f {f↑})
         limMin (limit f {f↑}) (limit g {g↑})  limit f {f↑}
      h {g} {g↑} r' = ≤-limiting  n  limMin (f n) (g n) + ι n) u
       where
        u : (k : )  limMin (f k) (g k) + ι k  limit f {f↑}
        u k = ≤-trans (+x-mono (ι k) u₁) u₂
         where
          u₁ : limMin (f k) (g k)  f k
          u₁ = r k (g k)
          u₂ : f k + ι k  limit f {f↑}
          u₂ = add-finite-part-lemma f k

limMin-right : (x y : Brw)  limMin x y  y
limMin-right = Brw-ind _  x  isPropΠ  y  ≤-trunc))  y  ≤-zero)  r  r) h
 where
  h : {f :   Brw} {f↑ : increasing f}
     ((k : ) (y : Brw)  limMin (f k) y  y)
     (y : Brw)  limMin (limit f {f↑}) y  y
  h {f} {f↑} r = Brw-ind _  y  ≤-trunc) ≤-refl  {x} r  ≤-trans r ≤-succ-incr-simple) u
   where
    u : {g :   Brw} {g↑ : increasing g}
       ((k : )  limMin (limit f {f↑}) (g k)  g k)
       limMin (limit f {f↑}) (limit g {g↑})  limit g {g↑}
    u {g} {g↑} r' =
     ≤-limiting  n  limMin (f n) (g n) + ι n)
                 n  ≤-trans (+x-mono (ι n) (r n (g n))) (add-finite-part-lemma g n))

limMin-succ : (x y : Brw)  limMin x (succ y)  limMin x y
limMin-succ = Brw-ind _  x  isPropΠ  y  Brw-is-set _ _))
                         y  refl)  {x} r y  r y)  {f} {f↑} r y  refl)

limMin-diagonal-is-⇓ : (x : Brw)  limMin x x   x
limMin-diagonal-is-⇓ = Brw-ind _  x  Brw-is-set _ _)
                                 refl
                                  {x} u  limMin-succ x x  u)
                                 h
 where
  h : {f :   Brw} {f↑ : increasing f}
     ((k : )  limMin (f k) (f k)   (f k))
     limMin (limit f {f↑}) (limit f {f↑})  limit f {f↑}
  h {f} {f↑} r = ≤-antisym (limMin-left (limit f) (limit f)) (≤-limiting f u)
   where
    u : (k : )  f k  limMin (limit f) (limit f)
    u k = ≤-cocone  n  limMin (f n) (f n) + ι n) {k = m} v
     where
      k₀ : 
      k₀ = finite-part (f k)
      m : 
      m = k N+ k₀
      v : f k  (limMin (f m) (f m) + ι m)
      v = ≤-trans (≤-refl-≡ (decompose-⇓-fin (f k)))
                  (≤-trans (≤-refl-≡ (cong (_+ ι k₀) (sym (r k)))) w)
       where
        w : limMin (f k) (f k) + ι k₀  limMin (f m) (f m) + ι m
        w = ≤-trans (x+-mono w₁) (+x-mono (ι m) w₂)
         where
          w₁ : ι k₀  ι m
          w₁ = transport (cong (ι k₀ ≤_) (sym (ι-+-commutes k₀ k)))
                         (x+-increasing (ι k))
          w₂ : limMin (f k) (f k)  limMin (f m) (f m)
          w₂ = limMin-mono (increasing-monotone f↑ N.≤SumLeft)
                           (increasing-monotone f↑ N.≤SumLeft)


limMin-diagonal-limit : (f :   Brw) {f↑ : increasing f}
                       limMin (limit f) (limit f)  limit f {f↑}
limMin-diagonal-limit f {f↑} = limMin-diagonal-is-⇓ (limit f)


----- Theorem : Ordinal Decidability is Closed Under Binary Conjunction --------

limMin-key-property-str : (f :   Brw) {f↑ : increasing f} (x y : Brw)
                         limit f {f↑}  x
                         limit f {f↑}  y
                         limit f {f↑}  limMin x y
limMin-key-property-str f x y u v =
 transport (cong (_≤ limMin x y) (limMin-diagonal-limit f)) (limMin-mono u v)

limMin-key-property : (α : Brw)  is-lim α  (x y : Brw)
                     α  x
                     α  y
                     α  limMin x y
limMin-key-property α αIsLim x y = ∥-∥rec (isProp→ (isProp→ ≤-trunc)) H αIsLim
 where
  H : is-Σlim α  α  x  α  y  α  limMin x y
  H ((f , f↑) , (p₀ , p₁)) α≤x α≤y =
   transport (cong (_≤ limMin x y)  limf=α)
             (limMin-key-property-str f x y limf≤x limf≤y)
   where
    limf=α : limit f {f↑}  α
    limf=α = ≤-antisym (≤-limiting f p₀) (p₁ (limit f) λ i  ≤-cocone-simple f)
    limf≤x : limit f  x
    limf≤x = transport (cong (_≤ x) (sym limf=α)) α≤x
    limf≤y : limit f  y
    limf≤y =  transport (cong (_≤ y) (sym limf=α)) α≤y

ordinal-dec-×-aux : { : Level} (P Q : Type ) (α : Brw)  is-lim α
                   ordinal-dec α P
                   ordinal-dec α Q
                   ordinal-dec α (P × Q)
ordinal-dec-×-aux P Q α α-lim = ∥-∥map2 h
 where
  h : ordinal-dec-str α P  ordinal-dec-str α Q  ordinal-dec-str α (P × Q)
  h (x , e₁) (y , e₂) =
   limMin x y ,
    (p , q)  limMin-key-property α α-lim x y (lr e₁ p) (lr e₂ q)) ,
    l  rl e₁ (≤-trans l (limMin-left x y)) ,
          rl e₂ (≤-trans l (limMin-right x y)))

ordinal-dec-× : { : Level} (P Q : Type )  isProp P  isProp Q
               (α : Brw)
               ordinal-dec α P
               ordinal-dec α Q
               ordinal-dec α (P × Q)
ordinal-dec-× P Q PProp QProp α hP hQ with dec-n≡ α 0
... | yes α-zero =
 subst  -  ordinal-dec - (P × Q)) α-zero
       (rl (zero-decidable-iff-true (P × Q) (isProp× PProp QProp))
         (lr (zero-decidable-iff-true P PProp)
             (subst  -  ordinal-dec - P) (sym α-zero) hP) ,
         (lr (zero-decidable-iff-true Q QProp)
             (subst  -  ordinal-dec - Q) (sym α-zero) hQ))))
... | no α-non-zero =
 rl (ordinal-dec-equivalent-lim-benchmark (P × Q) (isProp× PProp QProp) α) [3]
  where
   [1] : ordinal-dec ( α) P
   [1] = lr (ordinal-dec-equivalent-lim-benchmark P PProp α) hP
   [2] : ordinal-dec ( α) Q
   [2] = lr (ordinal-dec-equivalent-lim-benchmark Q QProp α) hQ
   [3] : ordinal-dec ( α) (P × Q)
   [3] = ordinal-dec-×-aux P Q ( α) [4] [1] [2]
    where
     [4] : is-lim ( α)
     [4] with (⇑-is-lim α)
     ... | inl α-lim = α-lim
     ... | inr α-zero = ⊥.elim (α-non-zero (sym α-zero))

-------------------------------------------------------
----------Definition of limMin over Brwᶻˡ---------------

limMin-is-zl : (x y : Brw)  Brw-zero-or-limit (limMin x y)
limMin-is-zl =
 Brw-ind P  z  isPropΠ  x  isPropBrw-zero-or-limit _)) P₀  {s}  Pₛ s) Pₗ
 where
  P : Brw  Type
  P x = (y : Brw)  Brw-zero-or-limit (limMin x y)

  P₀ : P zero
  P₀ y = inr refl

  Pₛ : (x : Brw)  P x  P (succ x)
  Pₛ x p y = p y

  Pₗ : {f :   Brw} {f↑ : increasing f}  ((k : )  P (f k))  P (limit f {f↑})
  Pₗ {f} {f↑} p = Brw-ind Q  y  isPropBrw-zero-or-limit _) Q₀  {s}  Qₛ s) Qₗ
   where
    Q : Brw  Type
    Q y =  Brw-zero-or-limit (limMin (limit f) y)

    Q₀ : Q zero
    Q₀ = inr refl

    Qₛ : (y : Brw)  Q y  Q (succ y)
    Qₛ y q = q

    Qₗ : {g :   Brw} {g↑ : increasing g}  ((k : )  Q (g k))  Q (limit g)
    Qₗ {g} {g↑} q =
     inl  ((λ n  r n + ι n) , r↑) , limit-is-sup  z  r z + ι z) r↑ 
      where
       r :   Brw
       r n = limMin (f n) (g n)
       rspec : (n : )  limMin[ f n , g n ]~ r n
       rspec n = limMin-spec (f n) (g n)
       r↑ : increasing  n  r n + ι n)
       r↑ n = ≤-succ-mono (+x-mono (ι n)
                                   (limMin-mono (<-in-≤ (f↑ n)) (<-in-≤ (g↑ n))))

limMinᶻˡ : Brwᶻˡ   Brwᶻˡ   Brwᶻˡ
limMinᶻˡ (x , hx) (y , hy) = (limMin x y , limMin-is-zl x y)