{-# LANGUAGE BangPatterns #-}
module Math.Combinat.Partitions.Vector where
import Data.Array.Unboxed
import Data.List
type IntVector = UArray Int Int
vectorPartitions :: IntVector -> [[IntVector]]
vectorPartitions = fasc3B_algorithm_M . elems
_vectorPartitions :: [Int] -> [[[Int]]]
_vectorPartitions = map (map elems) . fasc3B_algorithm_M
fasc3B_algorithm_M :: [Int] -> [[IntVector]]
fasc3B_algorithm_M xs = worker [start] where
m = length xs
start = [ (j,x,x) | (j,x) <- zip [1..] xs ]
worker stack@(last:_) =
case decrease stack' of
Nothing -> [visited]
Just stack'' -> visited : worker stack''
where
stack' = subtract_rec stack
visited = map to_vector stack'
decrease (last:rest) =
case span (\(_,_,v) -> v==0) (reverse last) of
( _ , [(_,_,1)] ) -> case rest of
[] -> Nothing
_ -> decrease rest
( second , (c,u,v):first ) -> Just (modified:rest) where
modified =
reverse first ++
(c,u,v-1) :
[ (c,u,u) | (c,u,_) <- reverse second ]
_ -> error "fasc3B_algorithm_M: should not happen"
to_vector cuvs =
accumArray (flip const) 0 (1,m)
[ (c,v) | (c,_,v) <- cuvs ]
subtract_rec all@(last:_) =
case subtract last of
[] -> all
new -> subtract_rec (new:all)
subtract [] = []
subtract full@((c,u,v):rest) =
if w >= v
then (c,w,v) : subtract rest
else subtract_b full
where w = u - v
subtract_b [] = []
subtract_b ((c,u,v):rest) =
if w /= 0
then (c,w,w) : subtract_b rest
else subtract_b rest
where w = u - v