{-# LANGUAGE BangPatterns #-}
module Math.Combinat.Partitions.Set where
import Data.List
import Data.Ord
import System.Random
import Math.Combinat.Sets
import Math.Combinat.Numbers
import Math.Combinat.Helper
import Math.Combinat.Classes
import Math.Combinat.Partitions.Integer
newtype SetPartition = SetPartition [[Int]] deriving (Eq,Ord,Show,Read)
_standardizeSetPartition :: [[Int]] -> [[Int]]
_standardizeSetPartition = sortBy (comparing myhead) . map sort where
myhead xs = case xs of
(x:xs) -> x
[] -> error "_standardizeSetPartition: empty subset"
fromSetPartition :: SetPartition -> [[Int]]
fromSetPartition (SetPartition zzs) = zzs
toSetPartitionUnsafe :: [[Int]] -> SetPartition
toSetPartitionUnsafe = SetPartition
toSetPartition :: [[Int]] -> SetPartition
toSetPartition zzs = if _isSetPartition zzs
then SetPartition (_standardizeSetPartition zzs)
else error "toSetPartition: not a set partition"
_isSetPartition :: [[Int]] -> Bool
_isSetPartition zzs = sort (concat zzs) == [1..n] where
n = sum' (map length zzs)
instance HasNumberOfParts SetPartition where
numberOfParts (SetPartition p) = length p
setPartitionShape :: SetPartition -> Partition
setPartitionShape (SetPartition pps) = mkPartition (map length pps)
setPartitions :: Int -> [SetPartition]
setPartitions = setPartitionsNaive
setPartitionsWithKParts
:: Int
-> Int
-> [SetPartition]
setPartitionsWithKParts = setPartitionsWithKPartsNaive
setPartitionsNaive :: Int -> [SetPartition]
setPartitionsNaive n = map (SetPartition . _standardizeSetPartition) $ go [1..n] where
go :: [Int] -> [[[Int]]]
go [] = [[]]
go (z:zs) = [ s : rest | k <- [1..n] , s0 <- choose (k-1) zs , let s = z:s0 , rest <- go (zs \\ s) ]
setPartitionsWithKPartsNaive
:: Int
-> Int
-> [SetPartition]
setPartitionsWithKPartsNaive k n = map (SetPartition . _standardizeSetPartition) $ go k [1..n] where
go :: Int -> [Int] -> [[[Int]]]
go !k [] = if k==0 then [[]] else []
go 1 zs = [[zs]]
go !k (z:zs) = [ s : rest | l <- [1..n] , s0 <- choose (l-1) zs , let s = z:s0 , rest <- go (k-1) (zs \\ s) ]
countSetPartitions :: Int -> Integer
countSetPartitions = bellNumber
countSetPartitionsWithKParts
:: Int
-> Int
-> Integer
countSetPartitionsWithKParts k n = stirling2nd n k