module Data.RangeMin.Catalan (catalanIndexer) where
import Data.RangeMin.Common
import qualified Data.Vector as V (Vector)
import qualified Data.Vector.Unboxed as UV
import qualified Data.RangeMin.Quadratic as N2
import qualified Data.RangeMin.Linearithmic as Nlogn
maxLog :: Int
maxLog = 17
catalans :: UV.Vector Int
catalans = buildSliced maxLog maxLog (Just 0) (UV.replicate maxLog 1) $
const (UV.postscanl' (+) 0 . UV.unsafeTail)
catalan :: Int -> Int -> Int
catalan !p !q = catalans ! (p * (maxLog 1) + q)
data IL = !Int :< IL | Nil deriving (Show)
data IP = IP !Int !Int
catalanIndex :: MinIx -> Int -> Int -> IP
catalanIndex mIx !bS !n = catalans `seq` scan 0 (bS1) bS 0 0 Nil where
scan !y !p !q !cum !mi !ys
| y == n = IP cum mi
| otherwise = let
scan' !q !cum (x :< xs)
| not (runMinIx mIx x y)
= scan' (q1) (cum + catalan p q) xs
| otherwise
= scan (y+1) (p1) q cum mi (x :< xs)
scan' !q !cum ys
= scan (y+1) (p1) q cum y (y :< ys)
in scan' q cum ys
catalanIndexer :: SliceMin -> Int -> Int -> (V.Vector RM, UV.Vector Int)
catalanIndexer sM !n !bS = catalans `seq` (unsafeBackpermute' ixRMs catIxs, minIxs)
where !m = (n + bS 1) `div'` bS
!mm = m 1
!lastBS = n mm * bS
catIxs :: UV.Vector Int
(!catIxs, !minIxs) = UV.unzip $ UV.generate m (\ b ->
let !z = bS * b in
case catalanIndex (runSliceMin sM z)
bS (if b == mm then lastBS else bS) of
IP i j -> (i, j + z))
!ixRMs = unsafeVec (catalan bS bS) $ streamRI catIxs <$$>
\ (b, ix) -> (ix, let i = bS * b in rmAlgo (runSliceMin sM i) (if b == mm then lastBS else bS))
!rmAlgo = if bS <= 8 then N2.rangeMin else Nlogn.rangeMin