module Data.RangeMin.Int.Catalan (CatType, catalanIndexer) where
import Data.RangeMin.Common
import qualified Data.RangeMin.Fusion as F
import qualified Data.RangeMin.Int.Quadratic as N2
import qualified Data.RangeMin.Int.Linearithmic as Nlogn
import Data.RangeMin.Int.Catalan.Combinators
import Data.RangeMin.Int.Catalan.Table
import Prelude hiding (drop, read)
data IL = !Value :< IL | Nil
type CatType = Int
data C = C !CatType !Index !Value
catalanIndexer :: PVector Value -> Length -> (PVector CatType, VVector RM, PVector Index, PVector Value)
catalanIndexer !xs !bS = (catIxs0, typeRMs0, minIxs0, minVals0)
where !n = vlength xs
!m = (n + bS 1) `div'` bS
!mm = m 1
rmAlgo = if forceBlockN2 || bS <= n2Cross then N2.rangeMin else Nlogn.rangeMin
lastBlock = drop (bS * mm) xs
block b = slice (b * bS) bS xs
!(!catIxs0, !minIxs0, !minVals0) = catalans `seq`
let off b (C cum mi vmi) = (cum, mi + bS * b, vmi)
!lastCat = off mm (catalanIndex lastBlock)
catalanIndex !vec = scan 0 (bS1) bS 0 0 maxBound Nil where
!n = vlength vec
scan !y !p !q !cum !mi !vmi !ys
| y < n = let
vy = vec ! y
catp = catalan p
scan' !q !cum xs0@(vx :< xs)
| vx > vy
= scan' (q1) (cum + catp q) xs
| otherwise
= scan (y+1) (p1) q cum mi vmi (vy :< xs0)
scan' !q !cum ys
= scan (y+1) (p1) q cum y vy (vy :< ys)
in scan' q cum ys
| otherwise = C cum mi vmi
in F.unzip3 (F.generate mm (\ b -> off b (catalanIndex (block b))) `F.snoc` lastCat)
!typeRMs0 =
let !lastMin = (catIxs0 ! mm, rmAlgo lastBlock) in
equivClasses (catalan bS bS) (F.generate (m1) (\ b -> (catIxs0 ! b, rmAlgo (block b))) `F.snoc` lastMin)