packages feed

combinat 0.2.6.1 → 0.2.6.2

raw patch · 8 files changed

+487/−31 lines, 8 filesPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

API changes (from Hackage documentation)

+ Math.Combinat.Helper: reverseSort :: Ord a => [a] -> [a]
+ Math.Combinat.LatticePaths: countPeakingDyckPaths :: Int -> Int -> Integer
+ Math.Combinat.LatticePaths: dyckPathToNestedParens :: LatticePath -> [Paren]
+ Math.Combinat.LatticePaths: dyckPathsNaive :: Int -> [LatticePath]
+ Math.Combinat.LatticePaths: isDyckPath :: LatticePath -> Bool
+ Math.Combinat.LatticePaths: nestedParensToDyckPath :: [Paren] -> LatticePath
+ Math.Combinat.LatticePaths: pathNumberOfPeaks :: LatticePath -> Int
+ Math.Combinat.LatticePaths: peakingDyckPaths :: Int -> Int -> [LatticePath]
+ Math.Combinat.LatticePaths: peakingDyckPathsNaive :: Int -> Int -> [LatticePath]
+ Math.Combinat.LatticePaths: randomDyckPath :: RandomGen g => Int -> g -> (LatticePath, g)
+ Math.Combinat.Partitions: class HasNumberOfParts p
+ Math.Combinat.Partitions: countPartitionsWithKParts :: Int -> Int -> Integer
+ Math.Combinat.Partitions: instance HasNumberOfParts Partition
+ Math.Combinat.Partitions: numberOfParts :: HasNumberOfParts p => p -> Int
+ Math.Combinat.Partitions: partitionsWithKParts :: Int -> Int -> [Partition]
+ Math.Combinat.Partitions.NonCrossing: NonCrossing :: [[Int]] -> NonCrossing
+ Math.Combinat.Partitions.NonCrossing: _isNonCrossing :: [[Int]] -> Bool
+ Math.Combinat.Partitions.NonCrossing: _isNonCrossingUnsafe :: [[Int]] -> Bool
+ Math.Combinat.Partitions.NonCrossing: _nonCrossingPartitionToDyckPathMaybe :: [[Int]] -> Maybe LatticePath
+ Math.Combinat.Partitions.NonCrossing: _standardizeNonCrossing :: [[Int]] -> [[Int]]
+ Math.Combinat.Partitions.NonCrossing: countNonCrossingPartitions :: Int -> Integer
+ Math.Combinat.Partitions.NonCrossing: countNonCrossingPartitionsWithKParts :: Int -> Int -> Integer
+ Math.Combinat.Partitions.NonCrossing: dyckPathToNonCrossingPartition :: LatticePath -> NonCrossing
+ Math.Combinat.Partitions.NonCrossing: dyckPathToNonCrossingPartitionMaybe :: LatticePath -> Maybe NonCrossing
+ Math.Combinat.Partitions.NonCrossing: fromNonCrossing :: NonCrossing -> [[Int]]
+ Math.Combinat.Partitions.NonCrossing: instance Eq NonCrossing
+ Math.Combinat.Partitions.NonCrossing: instance HasNumberOfParts NonCrossing
+ Math.Combinat.Partitions.NonCrossing: instance Ord NonCrossing
+ Math.Combinat.Partitions.NonCrossing: instance Read NonCrossing
+ Math.Combinat.Partitions.NonCrossing: instance Show NonCrossing
+ Math.Combinat.Partitions.NonCrossing: newtype NonCrossing
+ Math.Combinat.Partitions.NonCrossing: nonCrossingPartitionToDyckPath :: NonCrossing -> LatticePath
+ Math.Combinat.Partitions.NonCrossing: nonCrossingPartitions :: Int -> [NonCrossing]
+ Math.Combinat.Partitions.NonCrossing: nonCrossingPartitionsWithKParts :: Int -> Int -> [NonCrossing]
+ Math.Combinat.Partitions.NonCrossing: randomNonCrossingPartition :: RandomGen g => Int -> g -> (NonCrossing, g)
+ Math.Combinat.Partitions.NonCrossing: setPartitionToNonCrossing :: SetPartition -> Maybe NonCrossing
+ Math.Combinat.Partitions.NonCrossing: toNonCrossing :: [[Int]] -> NonCrossing
+ Math.Combinat.Partitions.NonCrossing: toNonCrossingMaybe :: [[Int]] -> Maybe NonCrossing
+ Math.Combinat.Partitions.NonCrossing: toNonCrossingUnsafe :: [[Int]] -> NonCrossing
+ Math.Combinat.Partitions.Set: SetPartition :: [[Int]] -> SetPartition
+ Math.Combinat.Partitions.Set: _isSetPartition :: [[Int]] -> Bool
+ Math.Combinat.Partitions.Set: _standardizeSetPartition :: [[Int]] -> [[Int]]
+ Math.Combinat.Partitions.Set: countSetPartitions :: Int -> Integer
+ Math.Combinat.Partitions.Set: countSetPartitionsWithKParts :: Int -> Int -> Integer
+ Math.Combinat.Partitions.Set: fromSetPartition :: SetPartition -> [[Int]]
+ Math.Combinat.Partitions.Set: instance Eq SetPartition
+ Math.Combinat.Partitions.Set: instance HasNumberOfParts SetPartition
+ Math.Combinat.Partitions.Set: instance Ord SetPartition
+ Math.Combinat.Partitions.Set: instance Read SetPartition
+ Math.Combinat.Partitions.Set: instance Show SetPartition
+ Math.Combinat.Partitions.Set: newtype SetPartition
+ Math.Combinat.Partitions.Set: setPartitions :: Int -> [SetPartition]
+ Math.Combinat.Partitions.Set: setPartitionsNaive :: Int -> [SetPartition]
+ Math.Combinat.Partitions.Set: setPartitionsWithKParts :: Int -> Int -> [SetPartition]
+ Math.Combinat.Partitions.Set: setPartitionsWithKPartsNaive :: Int -> Int -> [SetPartition]
+ Math.Combinat.Partitions.Set: toSetPartition :: [[Int]] -> SetPartition
+ Math.Combinat.Partitions.Set: toSetPartitionUnsafe :: [[Int]] -> SetPartition

Files

Math/Combinat/Helper.hs view
@@ -29,16 +29,6 @@ swap :: (a,b) -> (b,a) swap (x,y) = (y,x) ------------------------------------------------------------------------------------ * lists--{-# SPECIALIZE sum' :: [Int]     -> Int     #-}-{-# SPECIALIZE sum' :: [Integer] -> Integer #-}-sum' :: Num a => [a] -> a-sum' = foldl' (+) 0----------------------------------------------------------------------------------- pairs :: [a] -> [(a,a)] pairs = go where   go (x:xs@(y:_)) = (x,y) : go xs@@ -50,6 +40,14 @@   go _            = []  --------------------------------------------------------------------------------+-- * lists++{-# SPECIALIZE sum' :: [Int]     -> Int     #-}+{-# SPECIALIZE sum' :: [Integer] -> Integer #-}+sum' :: Num a => [a] -> a+sum' = foldl' (+) 0++-------------------------------------------------------------------------------- -- * equality and ordering   equating :: Eq b => (a -> b) -> a -> a -> Bool@@ -62,6 +60,9 @@  reverseCompare :: Ord a => a -> a -> Ordering reverseCompare x y = reverseOrdering $ compare x y++reverseSort :: Ord a => [a] -> [a]+reverseSort = sortBy reverseCompare  groupSortBy :: (Eq b, Ord b) => (a -> b) -> [a] -> [[a]] groupSortBy f = groupBy (equating f) . sortBy (comparing f) 
Math/Combinat/LatticePaths.hs view
@@ -6,6 +6,8 @@ 
 --------------------------------------------------------------------------------
 
+import System.Random
+
 import Math.Combinat.Numbers
 import Math.Combinat.Trees.Binary
 
@@ -36,6 +38,14 @@                  in  if y'<0 then False 
                              else go y' ts
 
+-- | A Dyck path is a lattice path whose last point lies on the @y=0@ line
+isDyckPath :: LatticePath -> Bool
+isDyckPath = go 0 where
+  go !y []     = y==0
+  go !y (t:ts) = let y' = case t of { UpStep -> y+1 ; DownStep -> y-1 }
+                 in  if y'<0 then False 
+                             else go y' ts
+
 -- | Maximal height of a lattice path
 pathHeight :: LatticePath -> Int
 pathHeight = go 0 0 where
@@ -53,7 +63,7 @@     DownStep -> go (x+1) (y-1) ts
 
 -- | Returns the coordinates of the path (excluding the starting point @(0,0)@, but including
--- the endpoint
+-- the endpoint)
 pathCoordinates :: LatticePath -> [(Int,Int)]
 pathCoordinates = go 0 0 where
   go _  _  []     = []
@@ -61,6 +71,13 @@                         y' = case t of { UpStep -> y+1 ; DownStep -> y-1 }
                     in  (x',y') : go x' y' ts
 
+-- | Number of peaks of a path (excluding the endpoint)
+pathNumberOfPeaks :: LatticePath -> Int
+pathNumberOfPeaks = go 0 where
+  go !k (x:xs@(y:_)) = go (if x==UpStep && y==DownStep then k+1 else k) xs
+  go !k [x] = k
+  go !k [ ] = k
+
 -- | Number of points on the path which touch the @y=0@ zero level line
 -- (excluding the starting point @(0,0)@, but including the endpoint; that is, for Dyck paths it this is always positive!).
 pathNumberOfZeroTouches :: LatticePath -> Int
@@ -86,14 +103,41 @@ -- Remark: Dyck paths are obviously in bijection with nested parentheses, and thus
 -- also with binary trees.
 --
+-- Order is reverse lexicographical:
+--
+-- > sort (dyckPaths m) == reverse (dyckPaths m)
+-- 
 dyckPaths :: Int -> [LatticePath]
-dyckPaths = map (map f) . nestedParentheses where
-  f p = case p of { LeftParen -> UpStep ; RightParen -> DownStep }
+dyckPaths = map nestedParensToDyckPath . nestedParentheses 
 
+-- | @dyckPaths m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@. 
+--
+-- > sort (dyckPathsNaive m) == sort (dyckPaths m) 
+--  
+-- Naive recursive algorithm, order is ad-hoc
+--
+dyckPathsNaive :: Int -> [LatticePath]
+dyckPathsNaive = worker where
+  worker  0 = [[]]
+  worker  m = as ++ bs where
+    as = [ bracket p      | p <- worker (m-1) ] 
+    bs = [ bracket p ++ q | k <- [1..m-1] , p <- worker (k-1) , q <- worker (m-k) ]
+  bracket p = UpStep : p ++ [DownStep]
+
 -- | The number of Dyck paths from @(0,0)@ to @(2m,0)@ is simply the m\'th Catalan number.
 countDyckPaths :: Int -> Integer
 countDyckPaths m = catalan m
 
+-- | The trivial bijection
+nestedParensToDyckPath :: [Paren] -> LatticePath
+nestedParensToDyckPath = map f where
+  f p = case p of { LeftParen -> UpStep ; RightParen -> DownStep }
+
+-- | The trivial bijection in the other direction
+dyckPathToNestedParens :: LatticePath -> [Paren]
+dyckPathToNestedParens = map g where
+  g s = case s of { UpStep -> LeftParen ; DownStep -> RightParen }
+
 --------------------------------------------------------------------------------
 -- * Bounded Dyck paths
 
@@ -163,7 +207,7 @@ --------------------------------------------------------------------------------
 -- * Zero-level touches
 
--- | @touchingDyckPathsNaive k m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@ which touch the 
+-- | @touchingDyckPaths k m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@ which touch the 
 -- zero level line @y=0@ exactly @k@ times (excluding the starting point, but including the endpoint;
 -- thus, @k@ should be positive). Synonym for 'touchingDyckPathsNaive'.
 touchingDyckPaths
@@ -194,6 +238,64 @@     | otherwise = [ bracket p ++ q | l <- [1..m-1] , p <- dyckPaths (l-1) , q <- worker (k-1) (m-l) ]
     where
       bracket p = UpStep : p ++ [DownStep] 
+
+--------------------------------------------------------------------------------
+-- * Dyck paths with given number of peaks
+
+-- | @peakingDyckPaths k m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@ with exactly @k@ peaks.
+--
+-- Synonym for 'peakingDyckPathsNaive'
+--
+peakingDyckPaths
+  :: Int      -- ^ @k@ = number of peaks
+  -> Int      -- ^ @m@ = half-length
+  -> [LatticePath]
+peakingDyckPaths = peakingDyckPathsNaive 
+
+-- | @peakingDyckPathsNaive k m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@ with exactly @k@ peaks.
+--
+-- > sort (peakingDyckPathsNaive k m) = sort [ p | p <- dyckPaths m , pathNumberOfPeaks p == k ]
+--  
+-- Naive recursive algorithm, resulting order is pretty ad-hoc.
+--
+peakingDyckPathsNaive 
+  :: Int      -- ^ @k@ = number of peaks
+  -> Int      -- ^ @m@ = half-length
+  -> [LatticePath]
+peakingDyckPathsNaive = worker where
+  worker !k !m
+    | m == 0    = if k==0 then [[]] else []       
+    | k <= 0    = []
+    | m <  0    = []
+    | k == 1    = [ singlePeak m ] 
+    | otherwise = as ++ bs ++ cs
+    where
+      as = [ bracket p      |                                 p <- worker k (m-1)                           ]
+      bs = [ smallHill ++ q |                                                       q <- worker (k-1) (m-1) ]
+      cs = [ bracket p ++ q | l <- [2..m-1] , a <- [1..k-1] , p <- worker a (l-1) , q <- worker (k-a) (m-l) ]
+      smallHill     = [ UpStep , DownStep ]
+      singlePeak !m = replicate m UpStep ++ replicate m DownStep 
+      bracket p = UpStep : p ++ [DownStep] 
+
+-- | Dyck paths of length @2m@ with @k@ peaks are counted by the Narayana numbers @N(m,k) = \binom{m}{k} \binom{m}{k-1} / m@
+countPeakingDyckPaths
+  :: Int      -- ^ @k@ = number of peaks
+  -> Int      -- ^ @m@ = half-length
+  -> Integer
+countPeakingDyckPaths k m 
+  | m == 0    = if k==0 then 1 else 0
+  | k <= 0    = 0
+  | m <  0    = 0
+  | k == 1    = 1
+  | otherwise = div (binomial m k * binomial m (k-1)) (fromIntegral m)
+
+--------------------------------------------------------------------------------
+-- * Random lattice paths
+
+-- | A uniformly random Dyck path of length @2m@
+randomDyckPath :: RandomGen g => Int -> g -> (LatticePath,g)
+randomDyckPath m g0 = (nestedParensToDyckPath parens, g1) where
+  (parens,g1) = randomNestedParentheses m g0
 
 --------------------------------------------------------------------------------
 
Math/Combinat/Numbers.hs view
@@ -109,9 +109,10 @@ -- signedStirling1st :: Integral a => a -> a -> Integer signedStirling1st n k -  | k < 1     = 0-  | k > n     = 0-  | otherwise = signedStirling1stArray n ! (fromIntegral k)+  | k==0 && n==0 = 1+  | k < 1        = 0+  | k > n        = 0+  | otherwise    = signedStirling1stArray n ! (fromIntegral k)  -- | (Unsigned) Stirling numbers of the first kind. See 'signedStirling1st'. unsignedStirling1st :: Integral a => a -> a -> Integer@@ -124,8 +125,9 @@ -- stirling2nd :: Integral a => a -> a -> Integer stirling2nd n k -  | k < 1     = 0-  | k > n     = 0+  | k==0 && n==0 = 1+  | k < 1        = 0+  | k > n        = 0   | otherwise = sum xs `div` factorial k where       xs = [ paritySign (k-i) * binomial k i * (fromIntegral i)^n | i<-[0..k] ] 
Math/Combinat/Partitions.hs view
@@ -2,9 +2,14 @@ -- | Partitions of integers and multisets.  -- Integer partitions are nonincreasing sequences of positive integers. ----- See also ---   Donald E. Knuth: The Art of Computer Programming, vol 4, pre-fascicle 3B.+-- See: --+--  * Donald E. Knuth: The Art of Computer Programming, vol 4, pre-fascicle 3B.+--+--  * <http://en.wikipedia.org/wiki/Partition_(number_theory)>+--++{-# LANGUAGE BangPatterns #-} module Math.Combinat.Partitions   ( -- * Type and basic stuff     Partition@@ -23,6 +28,7 @@   , _elements   , countAutomorphisms   , _countAutomorphisms+  , HasNumberOfParts(..)     -- * Generation   , partitions'     , _partitions' @@ -30,10 +36,12 @@   , partitions   , _partitions   , countPartitions+  , partitionsWithKParts   , allPartitions'     , allPartitions    , countAllPartitions'   , countAllPartitions+  , countPartitionsWithKParts     -- * Ferrer diagrams   , printFerrerDiagram    , ferrerDiagram @@ -103,7 +111,7 @@ -- | The weight of the partition  --   (that is, the sum of the corresponding sequence). weight :: Partition -> Int-weight (Partition part) = sum part+weight (Partition part) = sum' part  -- | The dual (or conjugate) partition. dualPartition :: Partition -> Partition@@ -133,18 +141,26 @@  _countAutomorphisms :: [Int] -> Integer _countAutomorphisms = multinomial . map length . group- + --------------------------------------------------------------------------------- +class HasNumberOfParts p where+  numberOfParts :: p -> Int++instance HasNumberOfParts Partition where+  numberOfParts (Partition p) = length p+  +---------------------------------------------------------------------------------+ -- | Integer partitions of @d@, fitting into a given rectangle, as lists. _partitions'    :: (Int,Int)     -- ^ (height,width)   -> Int           -- ^ d   -> [[Int]]         _partitions' _ 0 = [[]] -_partitions' (0,_) d = if d==0 then [[]] else []-_partitions' (_,0) d = if d==0 then [[]] else []-_partitions' (h,w) d = +_partitions' ( 0 , _) d = if d==0 then [[]] else []+_partitions' ( _ , 0) d = if d==0 then [[]] else []+_partitions' (!h ,!w) d =    [ i:xs | i <- [1..min d h] , xs <- _partitions' (i,w-1) (d-i) ]  -- | Partitions of d, fitting into a given rectangle. The order is again lexicographic.@@ -189,9 +205,46 @@   --sum [ countPartitions' (h,w) i | i <- [0..d] ] where d = h*w  countAllPartitions :: Int -> Integer-countAllPartitions d = sum [ countPartitions i | i <- [0..d] ]+countAllPartitions d = sum' [ countPartitions i | i <- [0..d] ]  --------------------------------------------------------------------------------+-- partitions with given number of parts++-- | Lists partitions of @n@ into @k@ parts.+--+-- > sort (partitionsWithKParts k n) == sort [ p | p <- partitions n , numberOfParts p == k ]+--+-- Naive recursive algorithm.+--+partitionsWithKParts +  :: Int    -- ^ @k@ = number of parts+  -> Int    -- ^ @n@ = the integer we partition+  -> [Partition]+partitionsWithKParts k n = map Partition $ go n k n where+{-+  h = max height+  k = number of parts+  n = integer+-}+  go !h !k !n +    | k <  0     = []+    | k == 0     = if h>=0 && n==0 then [[] ] else []+    | k == 1     = if h>=n && n>=1 then [[n]] else []+    | otherwise  = [ a:p | a <- [1..(min h (n-k+1))] , p <- go a (k-1) (n-a) ]++countPartitionsWithKParts +  :: Int    -- ^ @k@ = number of parts+  -> Int    -- ^ @n@ = the integer we partition+  -> Integer+countPartitionsWithKParts k n = go n k n where+  go !h !k !n +    | k <  0     = 0+    | k == 0     = if h>=0 && n==0 then 1 else 0+    | k == 1     = if h>=n && n>=1 then 1 else 0+    | otherwise  = sum' [ go a (k-1) (n-a) | a<-[1..(min h (n-k+1))] ]+++-------------------------------------------------------------------------------- -- * Ferrer diagrams  printFerrerDiagram :: Partition -> IO ()@@ -269,7 +322,7 @@           reverse first ++            (c,u,v-1) :             [ (c,u,u) | (c,u,_) <- reverse second ] -      _ -> error "should not happen"+      _ -> error "fasc3B_algorithm_M: should not happen"            to_vector cuvs =      accumArray (flip const) 0 (1,m)
+ Math/Combinat/Partitions/NonCrossing.hs view
@@ -0,0 +1,195 @@+
+-- | Non-crossing partitions.
+--
+-- See eg. <http://en.wikipedia.org/wiki/Noncrossing_partition>
+--
+
+{-# LANGUAGE BangPatterns #-}
+module Math.Combinat.Partitions.NonCrossing where
+
+--------------------------------------------------------------------------------
+
+import Control.Applicative
+
+import Data.List
+import Data.Ord
+
+import System.Random
+
+import Math.Combinat.Numbers
+import Math.Combinat.LatticePaths
+import Math.Combinat.Helper
+import Math.Combinat.Partitions.Set
+import Math.Combinat.Partitions ( HasNumberOfParts(..) )
+
+--------------------------------------------------------------------------------
+-- * The type of non-crossing partitions
+
+-- | A non-crossing partition of the set @[1..n]@ in standard form: 
+-- entries decreasing in each block  and blocks listed in increasing order of their first entries.
+newtype NonCrossing = NonCrossing [[Int]] deriving (Eq,Ord,Show,Read)
+
+-- | Checks whether a set partition is noncrossing.
+--
+-- Implementation method: we convert to a Dyck path and then back again, and finally compare. 
+-- Probably not very efficient, but should be better than a naive check for crosses...)
+--
+_isNonCrossing :: [[Int]] -> Bool
+_isNonCrossing zzs0 = _isNonCrossingUnsafe (_standardizeNonCrossing zzs0)
+
+-- | Warning: This function assumes the standard ordering!
+_isNonCrossingUnsafe :: [[Int]] -> Bool
+_isNonCrossingUnsafe zzs = 
+  case _nonCrossingPartitionToDyckPathMaybe zzs of
+    Nothing   -> False
+    Just dyck -> case dyckPathToNonCrossingPartitionMaybe dyck of
+      Nothing                -> False
+      Just (NonCrossing yys) -> yys == zzs
+
+-- | Convert to standard form: entries decreasing in each block 
+-- and blocks listed in increasing order of their first entries.
+_standardizeNonCrossing :: [[Int]] -> [[Int]]
+_standardizeNonCrossing = sortBy (comparing myhead) . map reverseSort where
+  myhead xs = case xs of
+    (x:xs) -> x
+    []     -> error "_standardizeNonCrossing: empty subset"
+
+fromNonCrossing :: NonCrossing -> [[Int]]
+fromNonCrossing (NonCrossing xs) = xs
+
+toNonCrossingUnsafe :: [[Int]] -> NonCrossing
+toNonCrossingUnsafe = NonCrossing
+
+-- | Throws an error if the input is not a non-crossing partition
+toNonCrossing :: [[Int]] -> NonCrossing
+toNonCrossing xxs = case toNonCrossingMaybe xxs of
+  Just nc -> nc
+  Nothing -> error "toNonCrossing: not a non-crossing partition"
+
+toNonCrossingMaybe :: [[Int]] -> Maybe NonCrossing
+toNonCrossingMaybe xxs0 = 
+  if _isNonCrossingUnsafe xxs
+    then Just $ NonCrossing xxs
+    else Nothing
+  where 
+    xxs = _standardizeNonCrossing xxs0
+
+-- | If a set partition is actually non-crossing, then we can convert it
+setPartitionToNonCrossing :: SetPartition -> Maybe NonCrossing
+setPartitionToNonCrossing (SetPartition zzs0) =
+  if _isNonCrossingUnsafe zzs
+    then Just $ NonCrossing zzs
+    else Nothing
+  where
+    zzs = _standardizeNonCrossing zzs0
+
+instance HasNumberOfParts NonCrossing where
+  numberOfParts (NonCrossing p) = length p
+
+--------------------------------------------------------------------------------
+-- * Bijection to Dyck paths
+
+-- | Bijection between Dyck paths and noncrossing partitions
+--
+-- Based on: David Callan: /Sets, Lists and Noncrossing Partitions/
+--
+-- Fails if the input is not a Dyck path.
+dyckPathToNonCrossingPartition :: LatticePath -> NonCrossing
+dyckPathToNonCrossingPartition = NonCrossing . go 0 [] [] [] where
+  go :: Int -> [Int] -> [Int] -> [[Int]] -> LatticePath -> [[Int]] 
+  go !cnt stack small big path =
+    case path of
+      (x:xs) -> case x of 
+        UpStep   -> let cnt' = cnt + 1 in case xs of
+          (y:ys)   -> case y of
+            UpStep   -> go cnt' (cnt':stack) small                  big  xs  
+            DownStep -> go cnt' (cnt':stack) []    (reverse small : big) xs
+          []       -> error "dyckPathToNonCrossingPartition: last step is an UpStep (thus input was not a Dyck path)"
+        DownStep -> case stack of
+          (k:ks)   -> go cnt ks (k:small) big xs
+          []       -> error "dyckPathToNonCrossingPartition: empty stack, shouldn't happen (thus input was not a Dyck path)"
+      [] -> tail $ reverse (reverse small : big)
+
+-- | Safe version of 'dyckPathToNonCrossingPartition'
+dyckPathToNonCrossingPartitionMaybe :: LatticePath -> Maybe NonCrossing
+dyckPathToNonCrossingPartitionMaybe = fmap NonCrossing . go 0 [] [] [] where
+  go :: Int -> [Int] -> [Int] -> [[Int]] -> LatticePath -> Maybe [[Int]] 
+  go !cnt stack small big path =
+    case path of
+      (x:xs) -> case x of 
+        UpStep   -> let cnt' = cnt + 1 in case xs of
+          (y:ys)   -> case y of
+            UpStep   -> go cnt' (cnt':stack) small                  big  xs  
+            DownStep -> go cnt' (cnt':stack) []    (reverse small : big) xs
+          []       -> Nothing
+        DownStep -> case stack of
+          (k:ks)   -> go cnt ks (k:small) big xs
+          []       -> Nothing
+      [] -> Just $ tail $ reverse (reverse small : big)
+
+-- | The inverse bijection (should never fail proper 'NonCrossing'-s)
+nonCrossingPartitionToDyckPath :: NonCrossing -> LatticePath
+nonCrossingPartitionToDyckPath (NonCrossing zzs) = go 0 zzs where
+  go !k (ys@(y:_):yys) = replicate (y-k) UpStep ++ replicate (length ys) DownStep ++ go y yys
+  go !k []             = []
+  go _  _              = error "nonCrossingPartitionToDyckPath: shouldnt't happen"
+
+-- | Safe version 'nonCrossingPartitionToDyckPath'
+_nonCrossingPartitionToDyckPathMaybe :: [[Int]] -> Maybe LatticePath
+_nonCrossingPartitionToDyckPathMaybe = go 0 where
+  go !k (ys@(y:_):yys) = fmap (\zs -> replicate (y-k) UpStep ++ replicate (length ys) DownStep ++ zs) (go y yys)
+  go !k []             = Just []
+  go _  _              = Nothing
+
+--------------------------------------------------------------------------------
+
+{- 
+-- this should be mapped to NonCrossing [[3],[5,4,2],[7,6,1],[9,8]]
+testpath = [u,u,u,d,u,u,d,d,d,u,u,d,d,d,u,u,d,d] where
+  u = UpStep
+  d = DownStep
+
+testnc = NonCrossing [[3],[5,4,2],[7,6,1],[9,8]]
+-}
+
+--------------------------------------------------------------------------------
+-- * Generating non-crossing partitions
+
+-- | Lists all non-crossing partitions of @[1..n]@
+--
+-- Equivalent to (but orders of magnitude faster than) filtering out the non-crossing ones:
+--
+-- > (sort $ catMaybes $ map setPartitionToNonCrossing $ setPartitions n) == sort (nonCrossingPartitions n)
+--
+nonCrossingPartitions :: Int -> [NonCrossing]
+nonCrossingPartitions = map dyckPathToNonCrossingPartition . dyckPaths
+
+-- | Lists all non-crossing partitions of @[1..n]@ into @k@ parts.
+--
+-- > sort (nonCrossingPartitionsWithKParts k n) == sort [ p | p <- nonCrossingPartitions n , numberOfParts p == k ]
+--
+nonCrossingPartitionsWithKParts 
+  :: Int   -- ^ @k@ = number of parts 
+  -> Int   -- ^ @n@ = size of the set
+  -> [NonCrossing]
+nonCrossingPartitionsWithKParts k n = map dyckPathToNonCrossingPartition $ peakingDyckPaths k n
+
+-- | Non-crossing partitions are counted by the Catalan numbers
+countNonCrossingPartitions :: Int -> Integer
+countNonCrossingPartitions = countDyckPaths
+
+-- | Non-crossing partitions with @k@ parts are counted by the Naranaya numbers
+countNonCrossingPartitionsWithKParts 
+  :: Int   -- ^ @k@ = number of parts 
+  -> Int   -- ^ @n@ = size of the set
+  -> Integer
+countNonCrossingPartitionsWithKParts = countPeakingDyckPaths
+
+--------------------------------------------------------------------------------
+
+-- | Uniformly random non-crossing partition
+randomNonCrossingPartition :: RandomGen g => Int -> g -> (NonCrossing,g)
+randomNonCrossingPartition n g0 = (dyckPathToNonCrossingPartition dyck, g1) where
+  (dyck,g1) = randomDyckPath n g0
+
+--------------------------------------------------------------------------------
+ Math/Combinat/Partitions/Set.hs view
@@ -0,0 +1,99 @@+
+-- | Set partitions.
+--
+-- See eg. <http://en.wikipedia.org/wiki/Partition_of_a_set>
+-- 
+
+{-# 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.Partitions ( HasNumberOfParts(..) )
+
+--------------------------------------------------------------------------------
+-- * The type of set partitions
+
+-- | A partition of the set @[1..n]@ (in standard order)
+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
+
+--------------------------------------------------------------------------------
+-- * Generating set partitions
+
+-- | Synonym for 'setPartitionsNaive'
+setPartitions :: Int -> [SetPartition]
+setPartitions = setPartitionsNaive
+
+-- | Synonym for 'setPartitionsWithKPartsNaive'
+--
+-- > sort (setPartitionsWithKParts k n) == sort [ p | p <- setPartitions n , numberOfParts p == k ]
+-- 
+setPartitionsWithKParts   
+  :: Int    -- ^ @k@ = number of parts
+  -> Int    -- ^ @n@ = size of the set
+  -> [SetPartition]
+setPartitionsWithKParts = setPartitionsWithKPartsNaive
+
+-- | List all set partitions of @[1..n]@, naive algorithm
+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) ]
+
+-- | Set partitions of the set @[1..n]@ into @k@ parts
+setPartitionsWithKPartsNaive 
+  :: Int    -- ^ @k@ = number of parts
+  -> Int    -- ^ @n@ = size of the set
+  -> [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) ]
+
+
+-- | Set partitions are counted by the Bell numbers
+countSetPartitions :: Int -> Integer
+countSetPartitions = bellNumber 
+
+-- | Set partitions of size @k@ are counted by the Stirling numbers of second kind
+countSetPartitionsWithKParts 
+  :: Int    -- ^ @k@ = number of parts
+  -> Int    -- ^ @n@ = size of the set
+  -> Integer
+countSetPartitionsWithKParts k n = stirling2nd n k
+
+--------------------------------------------------------------------------------
Math/Combinat/Trees/Binary.hs view
@@ -228,7 +228,7 @@ countNestedParentheses = countBinaryTrees  -- | Generates all sequences of nested parentheses of length 2n.--- Order is lexigraphic (when right parentheses are considered +-- Order is lexicographical (when right parentheses are considered  -- smaller then left ones). -- Based on \"Algorithm P\" in Knuth, but less efficient because of -- the \"idiomatic\" code.@@ -249,6 +249,7 @@ 	      LeftParen  ->  	        {- debug ("---",reverse ls,l,r,rs) $ -} 	        findj ( lls , [] ) ( reverse (RightParen:rs) , [] ) +  next _ = error "fasc4A_algorithm_P: fatal error shouldn't happen"    findj :: ([Paren],[Paren]) -> ([Paren],[Paren]) -> Maybe ([Paren],[Paren])   findj ( [] , _ ) _ = Nothing@@ -259,6 +260,7 @@ 	      (a:_:as) -> findj ( ls, RightParen:rs ) ( as , LeftParen:a:ys ) 	      _ -> findj ( lls, [] ) ( reverse rs ++ xs , ys)  	    RightParen -> Just ( reverse ys ++ xs ++ reverse (LeftParen:rs) ++ ls , [] )+  findj _ _ = error "fasc4A_algorithm_P: fatal error shouldn't happen"      -- | Generates a uniformly random sequence of nested parentheses of length 2n.     -- Based on \"Algorithm W\" in Knuth.
combinat.cabal view
@@ -1,5 +1,5 @@ Name:                combinat-Version:             0.2.6.1+Version:             0.2.6.2 Synopsis:            Generation of various combinatorial objects. Description:         A collection of functions to generate (and if there is                       a formula, count) combinatorial objects like partitions, @@ -45,6 +45,8 @@                        Math.Combinat.Tuples                         Math.Combinat.Compositions                        Math.Combinat.Partitions+                       Math.Combinat.Partitions.Set+                       Math.Combinat.Partitions.NonCrossing                        Math.Combinat.Permutations                        Math.Combinat.Tableaux                        Math.Combinat.Tableaux.Kostka@@ -57,7 +59,7 @@                        Math.Combinat.Helper    Extensions:          CPP, MultiParamTypeClasses, ScopedTypeVariables, -                       GeneralizedNewtypeDeriving +                       GeneralizedNewtypeDeriving, BangPatterns     Hs-Source-Dirs:      .