{-# OPTIONS --cubical --safe #-}
module InfinitelyDescendingSequences where
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Data.Nat
open import Cubical.Data.Nat.Order  as ℕ
open import Cubical.Data.Nat.Properties
open import Cubical.Data.Sum
open import Cubical.Data.Sigma
open import Cubical.Data.Empty as ⊥
open import Cubical.Relation.Binary
open import Cubical.Relation.Nullary
open BinaryRelation renaming (isTrans to isTransitive ; isRefl to isReflexive)
open import Cubical.Induction.WellFounded
  renaming (WellFounded to isWellFounded)
open import General-Properties
import Abstract.ZerSucLim as Abstract
module _
  (A : Type)
  (isSet⟨A⟩ : isSet A)
  (_<_ : A → A → Type)
  (_≤_ : A → A → Type)
  (isProp⟨<⟩ : isPropValued _<_)
  (isProp⟨≤⟩ : isPropValued _≤_)
  (<-irrefl : isIrrefl _<_)
  (≤-refl : isReflexive _≤_)
  (≤-trans : isTransitive _≤_)
  (≤-antisym : isAntisym _≤_)
  (<-in-≤ : {a b : A} → a < b → a ≤ b)
  (<∘≤-in-< : {a b c : A} → a < b → b ≤ c → a < c)
  
  (𝟎 : A)
  (𝟎-is-zero : Abstract.is-zero _<_ _≤_ 𝟎)
  where
  open Abstract _<_ _≤_
  open Abstract.Properties _<_ _≤_ isSet⟨A⟩ isProp⟨<⟩ isProp⟨≤⟩ <-irrefl ≤-refl ≤-trans ≤-antisym <-in-≤ <∘≤-in-<
  
  pseudo-descending : (ℕ → A) → Type
  pseudo-descending f =
    ∀ i → (f (suc i) < f i)  ⊎ ((f i ≡ 𝟎) × (f (suc i) ≡ 𝟎))
  eventually-zero : (ℕ → A) → Type₀
  eventually-zero f = Σ[ n ∈  ℕ ] (∀ i → n ℕ.≤ i → f i ≡ 𝟎)
  zeroPoint : ∀ {f} → pseudo-descending f → ∀ {i} → f i ≡ 𝟎 → ∀ j → i  ℕ.≤ j → f j ≡ 𝟎
  zeroPoint {f} df fi=0 zero j≤0 = subst (λ z → f z ≡ 𝟎) (≤0→≡0 j≤0) fi=0
  zeroPoint {f} df fi=0 (suc j) (zero , i=sj) = subst (λ z → f z ≡ 𝟎) i=sj fi=0
  zeroPoint {f} df {i} fi=0 (suc j) (suc n , sn+1=sj) with df i
  ... | inl fsi<fi = ⊥.rec (≮-zero 𝟎-is-zero (f (suc i)) (subst (f (suc i) <_) fi=0 fsi<fi))
  ... | inr (_ , fsi=0) = zeroPoint (df ∘ suc) fsi=0 j ((n , injSuc sn+1=sj))
  nonzeroPoint : ∀ {f} → pseudo-descending f → ∀ {i} → 𝟎 < f i → f (suc i) < f i
  nonzeroPoint df fi>0 with df _
  nonzeroPoint df fi>0 | inl fi+1<fi    = fi+1<fi
  nonzeroPoint df fi>0 | inr (fi=0 , _) = ⊥.elim (<-irrefl 𝟎 (subst (𝟎 <_) fi=0 fi>0))
  eventually-zero-cons : ∀ f → eventually-zero (f ∘ suc) → eventually-zero f
  eventually-zero-cons f (n , p) = suc n , p' where
   p' : (i : ℕ) → suc n ℕ.≤ i  → f i ≡ 𝟎
   p' zero sn≤0 = ⊥.rec (snotz (≤0→≡0 sn≤0))
   p' (suc i) (m , q) = p i ((m , injSuc (sym (+-suc m n) ∙ q)))
  
  PD2EZ : ((b : A) → (b ≡ 𝟎) ⊎ (𝟎 < b)) -> isWellFounded _<_ → ∀ f → pseudo-descending f → eventually-zero f
  PD2EZ dec-≡0 wf f df = WFI.induction wf {P = P} step (f 0) f df refl where
    P : A → Type₀
    P a = ∀ f → pseudo-descending f → f 0 ≡ a → eventually-zero f
    step : ∀ x → (∀ y → y < x → P y) → P x
    step x h f df f0=x with dec-≡0 (f 0)
    ... | inr f0>0 = goal where
      f1<x : f 1 < x
      f1<x = subst (f 1 <_) f0=x (nonzeroPoint df f0>0)
      ezfs : eventually-zero (f ∘ suc)
      ezfs = h (f 1) f1<x (f ∘ suc) (df ∘ suc) refl
      goal : eventually-zero f
      goal = eventually-zero-cons f ezfs
    ... | inl f0=0 = goal where
      fi=0 : ∀ i → f i ≡ 𝟎
      fi=0 i = zeroPoint df f0=0 i zero-≤
      goal : eventually-zero f
      goal = 0 , λ i _ → fi=0 i