module Data.RangeMin.Int.Linearithmic (rangeMin) where
import Data.RangeMin.Common.Types (RM, toRM)
import Data.RangeMin.Common.Math (bit', intLog)
import Data.RangeMin.Common.Vector
import Data.RangeMin.Int.Linearithmic.Combinators
import qualified Data.RangeMin.Fusion as F
import qualified Data.Vector.Primitive as UV
import Prelude hiding (drop)
rangeMin :: UV.Vector Int -> RM
rangeMin !xs = toRM $ \ i d -> case d of
1 -> i
2 -> table ! i
_ -> let
!k = intLog d
row = getRow nn table (k1)
in minIndex xs (row i) (row (i + d bit' k))
where !n = UV.length xs
!m = intLog n
!nn = n 1
!table = buildTable m n xs
buildTable :: Int -> Int -> UV.Vector Int -> UV.Vector Int
buildTable !m !n !xs = buildRowsUnf m (n1) Nothing row0 sucRow
where !nn = n 1
row0 = F.iunfoldN nn (\ i xi -> let
i' = i + 1
xi' = xs ! i'
in if i < nn then Just (if xi <= xi' then i else i', xi') else Nothing) (xs ! 0)
sucRow !k !prev = let
!prev' = drop (bit' k) prev
in F.imap (\ i -> minIndex xs (prev ! i)) prev'