----------------------------------------------------------------------------------------------------
-- Some functions on boolean-value sequences
----------------------------------------------------------------------------------------------------

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

module BooleanSequence where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Sigma
open import Cubical.Data.Bool renaming (true to tt; false to ff) hiding (_≤_)
open import Cubical.Data.Nat
open import Cubical.Data.Nat.Order hiding (_≟_)
open import Cubical.Data.Empty as 
open import Cubical.Relation.Nullary using (¬_; yes; no)
open import Cubical.Relation.Binary


--
-- some-true f n = tt  iff  f i = tt for some i ≤ n
--
some-true : (  Bool)    Bool
some-true f  0      = f 0
some-true f (suc n) = if (some-true f n) then tt else f(suc n)

some-true-spec-tt : (f :   Bool)
   (n : )  f n  tt
   some-true f n  tt
some-true-spec-tt f 0 f0≡tt = f0≡tt
some-true-spec-tt f (suc n) fn+1≡tt with some-true f n  tt
... | yes p = goal
 where
  goal : some-true f (suc n)  tt
  goal = cong (if_then tt else f(suc n)) p
... | no ¬p = goal
 where
  p : some-true f n  ff
  p = ¬true→false _ ¬p
  claim : some-true f (suc n)  f (suc n)
  claim = cong (if_then tt else f(suc n)) p
  goal : some-true f (suc n)  tt
  goal = claim  fn+1≡tt

some-true-case-tt : (f :   Bool)
   (n : )  some-true f n  tt
   Σ[ i   ] (i  n) × (f i  tt)
some-true-case-tt f 0 p = 0 , ≤-refl , p
some-true-case-tt f (suc n) p with some-true f n  tt
... | yes q = fst IH , ≤-suc (fst (snd IH)) , snd (snd IH)
 where
  IH : Σ[ i   ] (i  n) × (f i  tt)
  IH = some-true-case-tt f n q
... | no ¬q = suc n , ≤-refl , fn+1≡tt
 where
  q : some-true f n  ff
  q = ¬true→false _ ¬q
  claim : some-true f (suc n)  f (suc n)
  claim = cong (if_then tt else f(suc n)) q
  fn+1≡tt : f (suc n)  tt
  fn+1≡tt = sym claim  p

some-true-spec-ff : (f :   Bool)
   (n : )  (∀ i  i  n  f i  ff)
   some-true f n  ff
some-true-spec-ff f 0 p = p 0 ≤-refl
some-true-spec-ff f (suc n) p = goal
 where
  q :  i  i  n  f i  ff
  q i i≤n = p i (≤-suc i≤n)
  IH : some-true f n  ff
  IH = some-true-spec-ff f n q
  claim₀ : some-true f (suc n)  f (suc n)
  claim₀ = cong (if_then tt else f(suc n)) IH
  claim₁ : f (suc n)  ff
  claim₁ = p (suc n) ≤-refl
  goal : some-true f (suc n)  ff
  goal = claim₀  claim₁

some-true-case-ff : (f :   Bool)
   (n : )  some-true f n  ff
    i  i  n  f i  ff
some-true-case-ff f 0 p i i≤0 = subst  x  f x  ff) (sym (≤0→≡0 i≤0)) p
some-true-case-ff f (suc n) p with some-true f n  tt
some-true-case-ff f (suc n) p | yes q = ⊥.rec (true≢false tt≡ff)
 where
  tt≡ff : tt  ff
  tt≡ff = sym (cong (if_then tt else f(suc n)) q)  p
some-true-case-ff f (suc n) p | no ¬q = goal
 where
  q : some-true f n  ff
  q = ¬true→false _ ¬q
  IH :  i  i  n  f i  ff
  IH = some-true-case-ff f n q
  fn+1≡ff : f (suc n)  ff
  fn+1≡ff = sym (cong (if_then tt else f(suc n)) q)  p
  goal :  i  i  suc n  f i  ff
  goal i (0 , i≡n+1) = subst  x  f x  ff) (sym i≡n+1) fn+1≡ff
  goal i (suc k , k+i+1≡n+1) = IH i (k , injSuc k+i+1≡n+1)


--
-- least-true f i = tt  iff  i is the least such that f i = tt
--
least-index-true : (  Bool)    Bool
least-index-true f  0      = f 0
least-index-true f (suc n) = if (some-true f n) then ff else f(suc n)

least-index-true-case-tt : (f :   Bool)
   (n : )  least-index-true f n  tt
    i  i < n  f i  ff
least-index-true-case-tt f 0 p i i<0 = ⊥.rec (¬-<-zero i<0)
least-index-true-case-tt f (suc n) p with some-true f n  tt
least-index-true-case-tt f (suc n) p | yes q = ⊥.rec (true≢false (sym p  claim))
 where
  claim : least-index-true f (suc n)  ff
  claim = cong (if_then ff else f(suc n)) q
least-index-true-case-tt f (suc n) p | no ¬q = goal
 where
  q : some-true f n  ff
  q = ¬true→false _ ¬q
  claim :  i  i  n  f i  ff
  claim = some-true-case-ff f n q
  goal :  i  i < suc n  f i  ff
  goal i i<n+1 = claim i (pred-≤-pred i<n+1)

least-index-true-is-true : (f :   Bool)
   (n : )  least-index-true f n  tt
   f n  tt
least-index-true-is-true f zero p = p
least-index-true-is-true f (suc n) p  with some-true f n
... | ff = p
... | tt = ⊥.rec (false≢true p)

least-index-true-spec-tt' : (f :   Bool)
   (n : )  some-true f n  tt
   Σ[ i   ] (i  n) × (least-index-true f i  tt)
least-index-true-spec-tt' f 0 p = 0 , ≤-refl , p
least-index-true-spec-tt' f (suc n) p with some-true f n  tt
... | yes q = fst IH , ≤-suc (fst (snd IH)) , snd (snd IH)
 where
  IH : Σ[ i   ] (i  n) × (least-index-true f i  tt)
  IH = least-index-true-spec-tt' f n q
... | no ¬q = suc n , ≤-refl , claim₃
 where
  q : some-true f n  ff
  q = ¬true→false _ ¬q
  claim₀ : least-index-true f (suc n)  f (suc n)
  claim₀ = cong (if_then ff else f(suc n)) q
  claim₁ : some-true f (suc n)  f(suc n)
  claim₁ = cong (if_then tt else f(suc n)) q
  claim₂ : f (suc n)  tt
  claim₂ = sym claim₁  p
  claim₃ : least-index-true f (suc n)  tt
  claim₃ = claim₀  claim₂

least-index-true-spec-tt : (f :   Bool)
   (n : )  f n  tt
   Σ[ i   ] (i  n) × (least-index-true f i  tt)
least-index-true-spec-tt f n fn≡tt =
  least-index-true-spec-tt' f n (some-true-spec-tt f n fn≡tt)

least-index-true-spec-ff : (f :   Bool)
   (n : )  (∀ i  i  n  f i  ff)
   least-index-true f n  ff
least-index-true-spec-ff f 0 p = p 0 ≤-refl
least-index-true-spec-ff f (suc n) p = goal
 where
  q : some-true f n  ff
  q = some-true-spec-ff f n  i i≤n  p i (≤-suc i≤n))
  claim₀ : least-index-true f (suc n)  f (suc n)
  claim₀ = cong (if_then ff else f(suc n)) q
  claim₁ : f (suc n)  ff
  claim₁ = p (suc n) ≤-refl
  goal : least-index-true f (suc n)  ff
  goal = claim₀  claim₁