{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Vector.Algorithms.Search
( binarySearch
, binarySearchBy
, binarySearchByBounds
, binarySearchL
, binarySearchLBy
, binarySearchLByBounds
, binarySearchR
, binarySearchRBy
, binarySearchRByBounds
, binarySearchP
, binarySearchPBounds
, gallopingSearchLeftP
, gallopingSearchLeftPBounds
, gallopingSearchRightP
, gallopingSearchRightPBounds
, Comparison
) where
import Prelude hiding (read, length)
import Control.Monad.Primitive
import Data.Bits
import Data.Vector.Generic.Mutable
import Data.Vector.Algorithms.Common (Comparison, midPoint)
binarySearch :: (PrimMonad m, MVector v e, Ord e)
=> v (PrimState m) e -> e -> m Int
binarySearch = binarySearchBy compare
{-# INLINE binarySearch #-}
binarySearchBy :: (PrimMonad m, MVector v e)
=> Comparison e -> v (PrimState m) e -> e -> m Int
binarySearchBy cmp vec e = binarySearchByBounds cmp vec e 0 (length vec)
{-# INLINE binarySearchBy #-}
binarySearchByBounds :: (PrimMonad m, MVector v e)
=> Comparison e -> v (PrimState m) e -> e -> Int -> Int -> m Int
binarySearchByBounds cmp vec e = loop
where
loop !l !u
| u <= l = return l
| otherwise = do e' <- unsafeRead vec k
case cmp e' e of
LT -> loop (k+1) u
EQ -> return k
GT -> loop l k
where k = midPoint u l
{-# INLINE binarySearchByBounds #-}
binarySearchL :: (PrimMonad m, MVector v e, Ord e) => v (PrimState m) e -> e -> m Int
binarySearchL = binarySearchLBy compare
{-# INLINE binarySearchL #-}
binarySearchLBy :: (PrimMonad m, MVector v e)
=> Comparison e -> v (PrimState m) e -> e -> m Int
binarySearchLBy cmp vec e = binarySearchLByBounds cmp vec e 0 (length vec)
{-# INLINE binarySearchLBy #-}
binarySearchLByBounds :: (PrimMonad m, MVector v e)
=> Comparison e -> v (PrimState m) e -> e -> Int -> Int -> m Int
binarySearchLByBounds cmp vec e = binarySearchPBounds p vec
where p e' = case cmp e' e of LT -> False ; _ -> True
{-# INLINE binarySearchLByBounds #-}
binarySearchR :: (PrimMonad m, MVector v e, Ord e) => v (PrimState m) e -> e -> m Int
binarySearchR = binarySearchRBy compare
{-# INLINE binarySearchR #-}
binarySearchRBy :: (PrimMonad m, MVector v e)
=> Comparison e -> v (PrimState m) e -> e -> m Int
binarySearchRBy cmp vec e = binarySearchRByBounds cmp vec e 0 (length vec)
{-# INLINE binarySearchRBy #-}
binarySearchRByBounds :: (PrimMonad m, MVector v e)
=> Comparison e -> v (PrimState m) e -> e -> Int -> Int -> m Int
binarySearchRByBounds cmp vec e = binarySearchPBounds p vec
where p e' = case cmp e' e of GT -> True ; _ -> False
{-# INLINE binarySearchRByBounds #-}
binarySearchP :: (PrimMonad m, MVector v e) => (e -> Bool) -> v (PrimState m) e -> m Int
binarySearchP p vec = binarySearchPBounds p vec 0 (length vec)
{-# INLINE binarySearchP #-}
binarySearchPBounds :: (PrimMonad m, MVector v e)
=> (e -> Bool) -> v (PrimState m) e -> Int -> Int -> m Int
binarySearchPBounds p vec = loop
where
loop !l !u
| u <= l = return l
| otherwise = unsafeRead vec k >>= \e -> if p e then loop l k else loop (k+1) u
where k = midPoint u l
{-# INLINE binarySearchPBounds #-}
gallopingSearchLeftP
:: (PrimMonad m, MVector v e) => (e -> Bool) -> v (PrimState m) e -> m Int
gallopingSearchLeftP p vec = gallopingSearchLeftPBounds p vec 0 (length vec)
{-# INLINE gallopingSearchLeftP #-}
gallopingSearchRightP
:: (PrimMonad m, MVector v e) => (e -> Bool) -> v (PrimState m) e -> m Int
gallopingSearchRightP p vec = gallopingSearchRightPBounds p vec 0 (length vec)
{-# INLINE gallopingSearchRightP #-}
gallopingSearchLeftPBounds :: (PrimMonad m, MVector v e)
=> (e -> Bool)
-> v (PrimState m) e
-> Int
-> Int
-> m Int
gallopingSearchLeftPBounds p vec l u
| u <= l = return l
| otherwise = do x <- unsafeRead vec l
if p x then return l else iter (l+1) l 2
where
binSearch = binarySearchPBounds p vec
iter !i !j !_stepSize | i >= u - 1 = do
x <- unsafeRead vec (u-1)
if p x then binSearch (j+1) (u-1) else return u
iter !i !j !stepSize = do
x <- unsafeRead vec i
if p x then binSearch (j+1) i else iter (i+stepSize) i (2*stepSize)
{-# INLINE gallopingSearchLeftPBounds #-}
gallopingSearchRightPBounds :: (PrimMonad m, MVector v e)
=> (e -> Bool)
-> v (PrimState m) e
-> Int
-> Int
-> m Int
gallopingSearchRightPBounds p vec l u
| u <= l = return l
| otherwise = iter (u-1) (u-1) (-1)
where
binSearch = binarySearchPBounds p vec
iter !i !j !_stepSize | i <= l = do
x <- unsafeRead vec l
if p x then return l else binSearch (l+1) j
iter !i !j !stepSize = do
x <- unsafeRead vec i
if p x then iter (i+stepSize) i (2*stepSize) else binSearch (i+1) j
{-# INLINE gallopingSearchRightPBounds #-}