module Cubical.Data.Nat.BinarySearch where
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Data.Empty as ⊥
open import Cubical.Data.Nat
open import Cubical.Data.Nat.Mod renaming (quotient_/_ to _/_ ; remainder_/_ to _%_)
open import Cubical.Data.Nat.Order
open import Cubical.Data.Nat.Order.Inductive
open import Cubical.Data.Sigma
open import Cubical.Data.Sum
open import Cubical.Relation.Nullary
private
variable
ℓ : Level
P : ℕ → Type ℓ
open Minimal hiding (search ; →Least)
module IncreasingDec (dec : ∀ n → Dec (P n)) (P≤ : ∀ {m n} → m ≤ᵗ n → P m → P n) where
mid : ℕ → ℕ → ℕ
mid a Δ = Δ / 2 + suc a
private
¬P> : ∀ {m n} → m <ᵗ n → ¬ P n → ¬ P m
¬P> {m} m<n ¬Pn = ¬Pn ∘_ $ P≤ $ <ᵗ-weaken {m} $ m<n
sum≤gap/2+mid : ∀ {a} Δ → Δ + a ≤ᵗ Δ / 2 + mid a Δ
sum≤gap/2+mid {a} Δ = ≤→≤ᵗ $
subst (Δ + a ≤_) (sym $ +-assoc (Δ / 2) _ (suc a) ∙ +-suc _ a) (≤-+ʳ (≤1+/2+/2 Δ))
≤ᵗf : ∀ Δ' {f} → Δ' ≤ᵗ f → suc Δ' / 2 ≤ᵗ f
≤ᵗf Δ' {f} = <ᵗ≤ᵗ-trans {suc Δ' / 2} {suc Δ'} {suc f} (<→<ᵗ (quotient<id Δ' 0))
helper : ∀ a Δ f → Δ ≤ᵗ f → ¬ (P a) → P (Δ + a) → Σ[ m ∈ ℕ ] Least P m
helper a zero f _ ¬Pa Pa = ⊥.rec (¬Pa Pa)
helper a Δ@(suc Δ') (suc f) Δ'≤f ¬Pa PΔ+a with dec (suc a)
... | yes P1+a = suc a , P1+a , λ _ → (¬Pa ∘_) ∘ P≤
... | no ¬P1+a with dec (mid a Δ)
... | yes Pm =
helper (suc a) (Δ / 2) f (≤ᵗf Δ' Δ'≤f) ¬P1+a Pm
... | no ¬Pm =
helper (mid a Δ) (Δ / 2) f (≤ᵗf Δ' Δ'≤f) ¬Pm (P≤ (sum≤gap/2+mid Δ) PΔ+a)
search[_,_] : ∀ a n → a ≤ n → ¬ P a → (Σ[ m ∈ ℕ ] Least P m) ⊎ (∀ m → m <ᵗ n → ¬ P m)
search[ a , n ] (Δ , Δ+a≡n) ¬Pa with dec (Δ + a)
... | yes Pn = inl (helper a Δ Δ (≤ᵗ-refl Δ) ¬Pa Pn)
... | no ¬Pn = inr (λ _ → flip ¬P> (¬Pn ∘ subst P (sym Δ+a≡n)))
→Least[_,_] : ∀ a n → a ≤ n → ¬ P a → P n → Σ ℕ (Least P)
→Least[ a , n ] (Δ , Δ+a≡n) ¬Pa Pn =
helper a Δ Δ (≤ᵗ-refl Δ) ¬Pa (subst P (sym Δ+a≡n) Pn)
search : ∀ n → (Σ[ m ∈ ℕ ] Least P m) ⊎ (∀ m → m <ᵗ n → ¬ P m)
search n with dec 0
... | yes P0 = inl (0 , P0 , λ _ b _ → b)
... | no ¬P0 = search[ 0 , n ] zero-≤ ¬P0
→Least : Σ _ P → Σ _ (Least P)
→Least (n , Pn) with search n
... | inl least = least
... | inr ¬P<n = n , Pn , ¬P<n
module BiggestImage≤ (f : ℕ → ℕ) (inc : isIncreasing f) (f0=0 : f 0 ≡ 0) (k : ℕ) where
open IncreasingDec
((k <ᵗ?_) ∘ f)
(λ {m} {n} → flip (<ᵗ≤ᵗ-trans {k} {f m} {f n}) ∘ ≤→≤ᵇ ∘ inc ∘ ≤ᵇ→≤)
public hiding (mid)
private
module withLeast where
preimage : Σ ℕ (Least ((k <ᵗ_) ∘ f)) → ℕ
preimage = predℕ ∘ fst
<imageSuc : ∀ ΣLeast → k < f (suc (preimage ΣLeast))
<imageSuc (zero , k<f0 , _) = <≤-trans (<ᵗ→< k<f0) (inc zero-≤)
<imageSuc (suc n , k<fsn , _) = <ᵗ→< k<fsn
image≤ : ∀ ΣLeast → f (preimage ΣLeast) ≤ k
image≤ (zero , k<f0 , r<n→¬k<fsr) = subst (_≤ k) (sym f0=0) zero-≤
image≤ (suc n , k<fsn , r<n→¬k<fsr) = <-asym' $ r<n→¬k<fsr n (<ᵗsuc {n}) ∘ <→<ᵗ
module →Biggest[_,_] (a n : ℕ) (a≤n : a ≤ n) (fa≤k : f a ≤ᵗ k) (k<fn : k <ᵗ f n) where
private
ΣLeast : Σ ℕ (Least ((k <ᵗ_) ∘ f))
ΣLeast = →Least[ a , n ] a≤n (flip (<ᵗ-asym {k} {f a}) (≤ᵗ→≤ fa≤k)) k<fn
preimage : ℕ
preimage = withLeast.preimage ΣLeast
<imageSuc : k < f (suc preimage)
<imageSuc = withLeast.<imageSuc ΣLeast
image≤ : f preimage ≤ k
image≤ = withLeast.image≤ ΣLeast
module →Biggest (ΣP : Σ[ n ∈ ℕ ] k <ᵗ f n) where
preimage : ℕ
preimage = withLeast.preimage (→Least ΣP)
<imageSuc : k < f (suc preimage)
<imageSuc = withLeast.<imageSuc (→Least ΣP)
image≤ : f preimage ≤ k
image≤ = withLeast.image≤ (→Least ΣP)