module Data.RangeMin.Linearithmic (rangeMin) where
import Data.Bits (bit)
import Data.RangeMin.Common
import qualified Data.Vector.Unboxed as UV
rangeMin :: MinIx -> Int -> RM
rangeMin mIx !n =
toRM $ \ i j -> if i == j 1 then i else let
!k = intLog (j i)
row = lookupTable k
in pickMinIx mIx (row i) (row (j bit k))
where !m = ceilLog n
lookupTable k i = table ! (k * n + i)
!table = buildTable m n mIx
buildTable :: Int -> Int -> MinIx -> UV.Vector Int
buildTable !m !n mIx = buildSliced (m+1) n Nothing (UV.enumFromStepN 0 1 n) $ \ i prev ->
let !k = bit (i1) in UV.zipWith (pickMinIx mIx) prev (UV.unsafeDrop k prev)