{-# OPTIONS --prop --without-K --rewriting #-}

module Data.Nat.Log2 where

open import Data.Nat
open import Data.Nat.Properties

open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl)

open import Agda.Builtin.Equality.Rewrite

private
  aux : (P :   Set)  P zero  P (suc zero)  ((n : )  P  suc (suc n) /2⌉  P (suc (suc n))) 
    (n : )  (m : )  m  n  P m
  aux P bc₀ bc₁ is n zero h = bc₀
  aux P bc₀ bc₁ is n (suc zero) h = bc₁
  aux P bc₀ bc₁ is (suc (suc n)) (suc (suc m)) (s≤s (s≤s h)) =
    is m (aux P bc₀ bc₁ is (suc n)  suc (suc m) /2⌉ (s≤s (≤-trans (⌈n/2⌉≤n m) h)))

strong-induction : (P :   Set)  P zero  P (suc zero)  ((n : )  P  suc (suc n) /2⌉  P (suc (suc n)))  (n : )  P n
strong-induction P bc₀ bc₁ is n = aux P bc₀ bc₁ is n n ≤-refl

strong-induction/is :  {P bc₀ bc₁ is n} 
  aux P bc₀ bc₁ is (suc n)  suc (suc n) /2⌉ (s≤s (≤-trans (⌈n/2⌉≤n n) ≤-refl)) 
  strong-induction P bc₀ bc₁ is  suc (suc n) /2⌉
strong-induction/is {P} {bc₀} {bc₁} {is} {n} = aux/unique
  where
    aux/unique :  {m n₁ n₂ h₁ h₂}  aux P bc₀ bc₁ is n₁ m h₁  aux P bc₀ bc₁ is n₂ m h₂
    aux/unique {zero} = refl
    aux/unique {suc zero} = refl
    aux/unique {suc (suc m)} {h₁ = s≤s (s≤s h₁)} {h₂ = s≤s (s≤s h₂)} = Eq.cong (is m) aux/unique
{-# REWRITE strong-induction/is #-}

⌈log₂_⌉ :   
⌈log₂_⌉ = strong-induction  _  ) zero zero  _  suc)

log₂-mono : ⌈log₂_⌉ Preserves _≤_  _≤_
log₂-mono {n₁} {n₂} =
  strong-induction  n₁   n₂  n₁  n₂  ⌈log₂ n₁   ⌈log₂ n₂ )
     _ _  z≤n)
     _ _  z≤n)
     { n₁ ih (suc (suc n₂)) (s≤s (s≤s h))  s≤s (ih  suc (suc n₂) /2⌉ (⌈n/2⌉-mono (s≤s (s≤s h))))})
    n₁
    n₂

⌈log₂n⌉≤n :  n  ⌈log₂ n   n
⌈log₂n⌉≤n n = strong-induction' n n ≤-refl
  where
    strong-induction' : (n m : )  m  n  ⌈log₂ m   m
    strong-induction' n zero    h = z≤n
    strong-induction' n (suc zero) h = z≤n
    strong-induction' (suc (suc n)) (suc (suc m)) (s≤s (s≤s h)) =
      s≤s (
        let open ≤-Reasoning in
        begin
          ⌈log₂ suc  m /2⌉ 
        ≤⟨ strong-induction' (suc n) (suc  m /2⌉) (s≤s (≤-trans (⌈n/2⌉≤n m) h)) 
          suc  m /2⌉
        ≤⟨ s≤s (⌈n/2⌉≤n m) 
          suc m
        
      )

log₂-suc :  n {k}  ⌈log₂ n   suc k  ⌈log₂  n /2⌉   k
log₂-suc zero h = z≤n
log₂-suc (suc zero) h = z≤n
log₂-suc (suc (suc n)) (s≤s h) = h

⌈log₂n⌉≡0⇒n≤1 : {n : }  ⌈log₂ n   0  n  1
⌈log₂n⌉≡0⇒n≤1 {zero} refl = z≤n
⌈log₂n⌉≡0⇒n≤1 {suc zero} refl = s≤s z≤n