module Data.RangeMin (
LEq,
Comparator,
RangeMin,
rangeMinBy,
rangeMin,
stableRangeMinBy,
stableRangeMin,
vecRangeMinBy,
vecRangeMin,
stableVecRangeMinBy,
stableVecRangeMin) where
import Data.RangeMin.Common.Types
import qualified Data.Vector.Generic as G
import qualified Data.RangeMin.Quadratic as N2
import qualified Data.RangeMin.Linearithmic as Nlogn
import qualified Data.RangeMin.Linear as N
type Comparator a = a -> a -> Ordering
type RangeMin = Int -> Int -> Int
internalRangeMinBy :: SliceMin -> Int -> RangeMin
internalRangeMinBy sM !n = \ i m -> runRM rM i (i+m)
where !rM | n <= 8 = N2.rangeMin (runSliceMin sM 0) n
| n <= 600 = Nlogn.rangeMin (runSliceMin sM 0) n
| otherwise = N.rangeMin sM n
stable :: (Int -> a) -> Comparator a -> MinIx
stable look cmp = toMinIx $ \ i j -> case cmp (look i) (look j) of
EQ -> i <= j
LT -> True
GT -> False
rangeMinBy :: LEq a -> Int -> (Int -> a) -> RangeMin
rangeMinBy (<=?) n look = internalRangeMinBy sM n
where sM = toSliceMin $ \ !off -> toMinIx $ \ i j -> look (i+off) <=? look (j+off)
rangeMin :: Ord a => Int -> (Int -> a) -> RangeMin
rangeMin = rangeMinBy (<=)
stableRangeMinBy :: Comparator a -> Int -> (Int -> a) -> RangeMin
stableRangeMinBy cmp !n look = \ i m ->
if i < 0 || m <= 0 || i+m > n then error "Error: bad range arguments to stableRangeMinBy"
else rM i m
where !rM = internalRangeMinBy sM n
sM = toSliceMin $ \ !off -> stable (look . (off +)) cmp
stableRangeMin :: Ord a => Int -> (Int -> a) -> RangeMin
stableRangeMin = stableRangeMinBy compare
vecRangeMinBy :: G.Vector v a => LEq a -> v a -> RangeMin
vecRangeMinBy (<=?) !xs = internalRangeMinBy sM n
where !n = G.length xs
sM = toSliceMin $ \ !off ->
let
!slice = G.unsafeDrop off xs
look = G.unsafeIndex slice
in toMinIx $ \ i j -> look i <=? look j
vecRangeMin :: (G.Vector v a, Ord a) => v a -> Int -> Int -> Int
vecRangeMin = vecRangeMinBy (<=)
stableVecRangeMinBy :: (G.Vector v a) => Comparator a -> v a -> RangeMin
stableVecRangeMinBy cmp !xs = internalRangeMinBy sM n
where !n = G.length xs
sM = toSliceMin $ \ !off ->
let
!slice = G.unsafeDrop off xs
look = G.unsafeIndex slice
in stable look cmp
stableVecRangeMin :: (G.Vector v a, Ord a) => v a -> RangeMin
stableVecRangeMin = stableVecRangeMinBy compare