combinat 0.2.5.0 → 0.2.6.0
raw patch · 11 files changed
+534/−50 lines, 11 filesdep ~arraydep ~base
Dependency ranges changed: array, base
Files
- Math/Combinat.hs +14/−5
- Math/Combinat/Compositions.hs +38/−4
- Math/Combinat/FreeGroups.hs +65/−2
- Math/Combinat/Helper.hs +43/−3
- Math/Combinat/LatticePaths.hs +199/−0
- Math/Combinat/Numbers.hs +35/−0
- Math/Combinat/Partitions.hs +44/−10
- Math/Combinat/Permutations.hs +2/−1
- Math/Combinat/Sets.hs +74/−5
- Math/Combinat/Trees/Binary.hs +6/−1
- combinat.cabal +14/−19
Math/Combinat.hs view
@@ -1,17 +1,24 @@ -- | A collection of functions to generate combinatorial -- objects like partitions, compositions, permutations,--- Young tableaux, various trees, etc.+-- Young tableaux, various trees, etc etc. -- -- -- The long-term goals are ----- (1) to be efficient; +-- (1) generate most of the standard structures;+-- +-- (2) while being efficient; ----- (2) to be able to enumerate the structures --- with constant memory usage. +-- (3) to be able to enumerate the structures +-- with constant memory usage; ----- The short-term goal is to generate +-- (4) and to be able to randomly sample from them.+--+-- (5) finally, be a repository of algorithms+--+--+-- The short-term goal is simply to generate -- many interesting structures. -- --@@ -40,6 +47,7 @@ , module Math.Combinat.Permutations , module Math.Combinat.Tableaux , module Math.Combinat.Trees+ , module Math.Combinat.LatticePaths , module Math.Combinat.Graphviz ) where @@ -51,4 +59,5 @@ import Math.Combinat.Permutations import Math.Combinat.Tableaux import Math.Combinat.Trees+import Math.Combinat.LatticePaths import Math.Combinat.Graphviz
Math/Combinat/Compositions.hs view
@@ -6,10 +6,19 @@ module Math.Combinat.Compositions where -import Math.Combinat.Numbers (factorial,binomial)+-------------------------------------------------------------------------------- --------------------------------------------------------+import System.Random +import Math.Combinat.Sets ( randomChoice )+import Math.Combinat.Numbers ( factorial , binomial )+import Math.Combinat.Helper++--------------------------------------------------------------------------------+-- * generating all compositions++-- | A /composition/ of an integer @n@ into @k@ parts is an ordered @k@-tuple of nonnegative (sometimes positive) integers+-- whose sum is @n@. type Composition = [Int] -- | Compositions fitting into a given shape and having a given degree.@@ -41,7 +50,7 @@ allCompositions' :: [Int] -> [[Composition]] allCompositions' shape = map (compositions' shape) [0..d] where d = sum shape --- | Compositions of a given length.+-- | Nonnegative compositions of a given length. compositions :: Integral a => a -- ^ length@@ -72,4 +81,29 @@ countCompositions1 :: Integral a => a -> a -> Integer countCompositions1 len d = countCompositions len (d-len) --------------------------------------------------------+--------------------------------------------------------------------------------+-- * random compositions++-- | @randomComposition k n@ returns a uniformly random composition +-- of the number @n@ as an (ordered) sum of @k@ /nonnegative/ numbers+randomComposition :: RandomGen g => Int -> Int -> g -> ([Int],g)+randomComposition k n g0 = + if k<1 || n<0 + then error "randomComposition: k should be positive, and n should be nonnegative" + else (comp, g1) + where+ (cs,g1) = randomChoice (k-1) (n+k-1) g0+ comp = pairsWith (\x y -> y-x-1) (0 : cs ++ [n+k])+ +-- | @randomComposition1 k n@ returns a uniformly random composition +-- of the number @n@ as an (ordered) sum of @k@ /positive/ numbers+randomComposition1 :: RandomGen g => Int -> Int -> g -> ([Int],g)+randomComposition1 k n g0 = + if k<1 || n<k + then error "randomComposition1: we require 0 < k <= n" + else (comp, g1) + where+ (cs,g1) = randomComposition k (n-k) g0 + comp = map (+1) cs++--------------------------------------------------------------------------------
Math/Combinat/FreeGroups.hs view
@@ -1,16 +1,23 @@ --- | Words in free groups (and free powers of cyclic groups) +-- | Words in free groups (and free powers of cyclic groups).+-- This module is not re-exported by "Math.Combinat" -- {-# LANGUAGE PatternGuards #-} module Math.Combinat.FreeGroups where -------------------------------------------------------------------------------- -import Control.Monad (liftM)+import Data.Char ( chr )+import Data.List ( mapAccumL ) +import Control.Monad ( liftM )+import System.Random+ import Math.Combinat.Numbers+import Math.Combinat.Helper --------------------------------------------------------------------------------+-- * Words -- | A generator of a (free) group data Generator a @@ -18,11 +25,28 @@ | Inv a -- @a^(-1)@ deriving (Eq,Ord,Show,Read) +-- | The index of a generator+unGen :: Generator a -> a+unGen g = case g of+ Gen x -> x+ Inv x -> x+ -- | A /word/, describing (non-uniquely) an element of a group. -- The identity element is represented (among others) by the empty word. type Word a = [Generator a] --------------------------------------------------------------------------------++-- | Generators are shown as small letters: @a@, @b@, @c@, ...+-- and their inverses are shown as capital letters, so @A=a^-1@, @B=b^-1@, etc.+showGen :: Generator Int -> Char+showGen (Gen i) = chr (96+i)+showGen (Inv i) = chr (64+i)++showWord :: Word Int -> String+showWord = map showGen++-------------------------------------------------------------------------------- instance Functor Generator where fmap f g = case g of @@ -64,6 +88,45 @@ go 0 = [[]] go n = [ x:xs | xs <- go (n-1) , x <- elems ] elems = [ Gen a | a<-[1..g] ]++--------------------------------------------------------------------------------+-- * Random words++-- | A random group generator (or its inverse) between @1@ and @g@+randomGenerator+ :: RandomGen g+ => Int -- ^ @g@ = number of generators + -> g -> (Generator Int, g)+randomGenerator d g0 = (gen,g2) where+ (b,g1) = random g0+ (k,g2) = randomR (1,d) g1+ gen = if b then Gen k else Inv k++-- | A random group generator (but never its inverse) between @1@ and @g@+randomGeneratorNoInv+ :: RandomGen g+ => Int -- ^ @g@ = number of generators + -> g -> (Generator Int, g)+randomGeneratorNoInv d g0 = (Gen k,g1) where+ (k,g1) = randomR (1,d) g0++-- | A random word of length @n@ using @g@ generators (or their inverses)+randomWord + :: RandomGen g+ => Int -- ^ @g@ = number of generators + -> Int -- ^ @n@ = length of the word+ -> g -> (Word Int, g)+randomWord d n g0 = (word,g1) where+ (g1,word) = mapAccumL (\g _ -> swap (randomGenerator d g)) g0 [1..n] ++-- | A random word of length @n@ using @g@ generators (but not their inverses)+randomWordNoInv+ :: RandomGen g+ => Int -- ^ @g@ = number of generators + -> Int -- ^ @n@ = length of the word+ -> g -> (Word Int, g)+randomWordNoInv d n g0 = (word,g1) where+ (g1,word) = mapAccumL (\g _ -> swap (randomGeneratorNoInv d g)) g0 [1..n] -------------------------------------------------------------------------------- -- * The free group on @g@ generators
Math/Combinat/Helper.hs view
@@ -1,26 +1,57 @@ +-- | Miscellaneous helper functions+ module Math.Combinat.Helper where +--------------------------------------------------------------------------------+ import Control.Monad import Data.List import Data.Ord-import qualified Data.Set as Set +import Data.Set (Set) ; import qualified Data.Set as Set+import Data.Map (Map) ; import qualified Data.Map as Map+ import Debug.Trace --------------------------------------------------------------------------------+-- * debugging debug :: Show a => a -> b -> b debug x y = trace ("-- " ++ show x ++ "\n") y -{-# SPECIALIZE swap :: (a,a) -> (a,a) #-}+--------------------------------------------------------------------------------+-- * pairs++{-# SPECIALIZE swap :: (a ,a ) -> (a ,a ) #-} {-# SPECIALIZE swap :: (Int,Int) -> (Int,Int) #-} 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+ go _ = []++pairsWith :: (a -> a -> b) -> [a] -> [b]+pairsWith f = go where+ go (x:xs@(y:_)) = f x y : go xs+ go _ = []++--------------------------------------------------------------------------------+-- * equality and ordering + equating :: Eq b => (a -> b) -> a -> a -> Bool equating f x y = (f x == f y) @@ -43,6 +74,7 @@ | otherwise = x : worker (Set.insert x s) xs --------------------------------------------------------------------------------+-- * first \/ last -- | The boolean argument will @True@ only for the last element mapWithLast :: (Bool -> a -> b) -> [a] -> [b]@@ -60,7 +92,7 @@ go b (x : xs) = f b False x : go False xs ----------------------------------------------------------------------------------- helpers for ASCII drawing+-- * helpers for ASCII drawing -- | extend lines with spaces so that they have the same line mkLinesUniformWidth :: [String] -> [String]@@ -85,18 +117,25 @@ vConcatLines = concat --------------------------------------------------------------------------------+-- * counting -- helps testing the random rutines count :: Eq a => a -> [a] -> Int count x xs = length $ filter (==x) xs +histogram :: (Eq a, Ord a) => [a] -> [(a,Int)]+histogram xs = Map.toList table where+ table = Map.fromListWith (+) [ (x,1) | x<-xs ] + --------------------------------------------------------------------------------+-- * maybe fromJust :: Maybe a -> a fromJust (Just x) = x fromJust Nothing = error "fromJust: Nothing" --------------------------------------------------------------------------------+-- * bool intToBool :: Int -> Bool intToBool 0 = False@@ -108,6 +147,7 @@ boolToInt True = 1 --------------------------------------------------------------------------------+-- * iteration -- iterated function application nest :: Int -> (a -> a) -> a -> a
+ Math/Combinat/LatticePaths.hs view
@@ -0,0 +1,199 @@+ +-- | Dyck paths, lattice paths, etc + +{-# LANGUAGE BangPatterns #-} +module Math.Combinat.LatticePaths where + +-------------------------------------------------------------------------------- + +import Math.Combinat.Numbers +import Math.Combinat.Trees.Binary + +-------------------------------------------------------------------------------- +-- * Types + +-- | A step in a lattice path +data Step + = UpStep -- ^ the step @(1,1)@ + | DownStep -- ^ the step @(1,-1)@ + deriving (Eq,Ord,Show) + +-- | A lattice path is a path using only the allowed steps, never going below the zero level line @y=0@. +-- +-- Note that if you rotate such a path by 45 degrees counterclockwise, +-- you get a path which uses only the steps @(1,0)@ and @(0,1)@, and stays +-- above the main diagonal (hence the name, we just use a different convention). +-- +type LatticePath = [Step] + +-------------------------------------------------------------------------------- + +-- | A lattice path is called \"valid\", if it never goes below the @y=0@ line. +isValidPath :: LatticePath -> Bool +isValidPath = 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 + go !h !y [] = h + go !h !y (t:ts) = case t of + UpStep -> go (max h (y+1)) (y+1) ts + DownStep -> go h (y-1) ts + +-- | Endpoint of a lattice path, which starts from @(0,0)@. +pathEndpoint :: LatticePath -> (Int,Int) +pathEndpoint = go 0 0 where + go !x !y [] = (x,y) + go !x !y (t:ts) = case t of + UpStep -> go (x+1) (y+1) ts + DownStep -> go (x+1) (y-1) ts + +-- | Returns the coordinates of the path (excluding the starting point @(0,0)@, but including +-- the endpoint +pathCoordinates :: LatticePath -> [(Int,Int)] +pathCoordinates = go 0 0 where + go _ _ [] = [] + go !x !y (t:ts) = let x' = x + 1 + y' = case t of { UpStep -> y+1 ; DownStep -> y-1 } + in (x',y') : go x' y' ts + +-- | 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 +pathNumberOfZeroTouches = pathNumberOfTouches' 0 + +-- | Number of points on the path which touch the level line at height @h@ +-- (excluding the starting point @(0,0)@, but including the endpoint). +pathNumberOfTouches' + :: Int -- ^ @h@ = the touch level + -> LatticePath -> Int +pathNumberOfTouches' h = go 0 0 0 where + go !cnt _ _ [] = cnt + go !cnt !x !y (t:ts) = let y' = case t of { UpStep -> y+1 ; DownStep -> y-1 } + cnt' = if y'==h then cnt+1 else cnt + in go cnt' (x+1) y' ts + + +-------------------------------------------------------------------------------- +-- * Dyck paths + +-- | @dyckPaths m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@. +-- +-- Remark: Dyck paths are obviously in bijection with nested parentheses, and thus +-- also with binary trees. +-- +dyckPaths :: Int -> [LatticePath] +dyckPaths = map (map f) . nestedParentheses where + f p = case p of { LeftParen -> UpStep ; RightParen -> 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 + +-------------------------------------------------------------------------------- +-- * Bounded Dyck paths + +-- | @boundedDyckPaths h m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@ whose height is at most @h@. +-- Synonym for 'boundedDyckPathsNaive'. +-- +boundedDyckPaths + :: Int -- ^ @h@ = maximum height + -> Int -- ^ @m@ = half-length + -> [LatticePath] +boundedDyckPaths = boundedDyckPathsNaive + +-- | @boundedDyckPathsNaive h m@ lists all Dyck paths from @(0,0)@ to @(2m,0)@ whose height is at most @h@. +-- +-- > sort (boundedDyckPaths h m) == sort [ p | p <- dyckPaths m , pathHeight p <= h ] +-- > sort (boundedDyckPaths m m) == sort (dyckPaths m) +-- +-- Naive recursive algorithm, resulting order is pretty ad-hoc. +-- +boundedDyckPathsNaive + :: Int -- ^ @h@ = maximum height + -> Int -- ^ @m@ = half-length + -> [LatticePath] +boundedDyckPathsNaive = worker where + worker !h !m + | h<0 = [] + | m<0 = [] + | m==0 = [[]] + | h<=0 = [] + | otherwise = as ++ bs + where + bracket p = UpStep : p ++ [DownStep] + as = [ bracket p | p <- boundedDyckPaths (h-1) (m-1) ] + bs = [ bracket p ++ q | k <- [1..m-1] , p <- boundedDyckPaths (h-1) (k-1) , q <- boundedDyckPaths h (m-k) ] + +-------------------------------------------------------------------------------- +-- * More general lattice paths + +-- | All lattice paths from @(0,0)@ to @(x,y)@. Clearly empty unless @x-y@ is even. +-- Synonym for 'latticePathsNaive' +-- +latticePaths :: (Int,Int) -> [LatticePath] +latticePaths = latticePathsNaive + +-- | All lattice paths from @(0,0)@ to @(x,y)@. Clearly empty unless @x-y@ is even. +-- +-- Note that +-- +-- > sort (dyckPaths n) == sort (latticePaths (0,2*n)) +-- +-- Naive recursive algorithm, resulting order is pretty ad-hoc. +-- +latticePathsNaive :: (Int,Int) -> [LatticePath] +latticePathsNaive (x,y) = worker x y where + worker !x !y + | odd (x-y) = [] + | x<0 = [] + | y<0 = [] + | y==0 = dyckPaths (div x 2) + | x==1 && y==1 = [[UpStep]] + | otherwise = as ++ bs + where + bracket p = UpStep : p ++ [DownStep] + as = [ UpStep : p | p <- worker (x-1) (y-1) ] + bs = [ bracket p ++ q | k <- [1..(div x 2)] , p <- dyckPaths (k-1) , q <- worker (x-2*k) y ] + +-------------------------------------------------------------------------------- +-- * Zero-level touches + +-- | @touchingDyckPathsNaive 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 + :: Int -- ^ @k@ = number of touches + -> Int -- ^ @m@ = half-length + -> [LatticePath] +touchingDyckPaths = touchingDyckPathsNaive + + +-- | @touchingDyckPathsNaive 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). +-- +-- > sort (touchingDyckPathsNaive k m) == sort [ p | p <- dyckPaths m , pathNumberOfZeroTouches p == k ] +-- +-- Naive recursive algorithm, resulting order is pretty ad-hoc. +-- +touchingDyckPathsNaive + :: Int -- ^ @k@ = number of touches + -> Int -- ^ @m@ = half-length + -> [LatticePath] +touchingDyckPathsNaive = worker where + worker !k !m + | m == 0 = if k==0 then [[]] else [] + | k <= 0 = [] + | m < 0 = [] + | k == 1 = [ bracket p | p <- dyckPaths (m-1) ] + | otherwise = [ bracket p ++ q | l <- [1..m-1] , p <- dyckPaths (l-1) , q <- worker (k-1) (m-l) ] + where + bracket p = UpStep : p ++ [DownStep] + +-------------------------------------------------------------------------------- +
Math/Combinat/Numbers.hs view
@@ -10,6 +10,8 @@ import Data.Array +import Math.Combinat.Helper ( sum' )+ -------------------------------------------------------------------------------- -- | @(-1)^k@@@ -102,6 +104,9 @@ -- | (Signed) Stirling numbers of the first kind. OEIS:A008275. -- This function uses 'signedStirling1stArray', so it shouldn't be used -- to compute /many/ Stirling numbers.+--+-- Argument order: @signedStirling1st n k@+-- signedStirling1st :: Integral a => a -> a -> Integer signedStirling1st n k | k < 1 = 0@@ -114,6 +119,9 @@ -- | Stirling numbers of the second kind. OEIS:A008277. -- This function uses an explicit formula.+-- +-- Argument order: @stirling2nd n k@+-- stirling2nd :: Integral a => a -> a -> Integer stirling2nd n k | k < 1 = 0@@ -138,5 +146,32 @@ / toRational (k+1) --------------------------------------------------------------------------------+-- * Bell numbers++-- | Bell numbers (Sloane's A000110) from B(0) up to B(n). B(0)=B(1)=1, B(2)=2, etc. +--+-- The Bell numbers count the number of /set partitions/ of a set of size @n@+-- +-- See <http://en.wikipedia.org/wiki/Bell_number>+--+bellNumbersArray :: Integral a => a -> Array Int Integer+bellNumbersArray nn = arr where+ arr = array (0::Int,n) kvs + n = fromIntegral nn :: Int+ kvs = (0,1) : [ (k, f k) | k<-[1..n] ] + f n = sum' [ binomial (n-1) k * arr ! k | k<-[0..n-1] ]++-- | The n-th Bell number B(n), using the Stirling numbers of the second kind.+-- This may be slower than using 'bellNumbersArray'.+bellNumber :: Integral a => a -> Integer+bellNumber nn+ | n < 0 = error "bellNumber: expecting a nonnegative index"+ | n == 0 = 1+ | otherwise = sum' [ stirling2nd n k | k<-[1..n] ] + where+ n = fromIntegral nn :: Int++--------------------------------------------------------------------------------+
Math/Combinat/Partitions.hs view
@@ -1,9 +1,10 @@ --- | Partitions. Partitions are nonincreasing sequences of positive integers.+-- | 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.-+-- module Math.Combinat.Partitions ( -- * Type and basic stuff Partition@@ -33,6 +34,13 @@ , allPartitions , countAllPartitions' , countAllPartitions+ -- * Ferrer diagrams+ , printFerrerDiagram + , ferrerDiagram + , ferrerDiagramEnglishNotation + , ferrerDiagramFrenchNotation + , ferrerDiagramEnglishNotation'+ , ferrerDiagramFrenchNotation' -- * Paritions of multisets, vector partitions , partitionMultiset , IntVector@@ -50,7 +58,7 @@ -------------------------------------------------------------------------------- --- | The additional invariant enforced here is that partitions +-- | A partition of an integer. The additional invariant enforced here is that partitions -- are monotone decreasing sequences of positive integers. newtype Partition = Partition [Int] deriving (Eq,Ord,Show,Read) @@ -62,7 +70,7 @@ toPartitionUnsafe :: [Int] -> Partition toPartitionUnsafe = Partition --- | Checks whether the input is a partition. See the note at 'isPartition'!+-- | Checks whether the input is an integer partition. See the note at 'isPartition'! toPartition :: [Int] -> Partition toPartition xs = if isPartition xs then toPartitionUnsafe xs@@ -119,7 +127,7 @@ _elements :: [Int] -> [(Int,Int)] _elements shape = [ (i,j) | (i,l) <- zip [1..] shape, j<-[1..l] ] --- | Computes the number of \"automorphisms\" of a given partition.+-- | Computes the number of \"automorphisms\" of a given integer partition. countAutomorphisms :: Partition -> Integer countAutomorphisms = _countAutomorphisms . fromPartition @@ -128,7 +136,7 @@ --------------------------------------------------------------------------------- --- | Partitions of d, fitting into a given rectangle, as lists.+-- | Integer partitions of @d@, fitting into a given rectangle, as lists. _partitions' :: (Int,Int) -- ^ (height,width) -> Int -- ^ d@@ -153,24 +161,24 @@ countPartitions' (h,w) d = sum [ countPartitions' (i,w-1) (d-i) | i <- [1..min d h] ] --- | Partitions of d, as lists+-- | Partitions of @d@, as lists _partitions :: Int -> [[Int]] _partitions d = _partitions' (d,d) d --- | Partitions of d.+-- | Partitions of @d@. partitions :: Int -> [Partition] partitions d = partitions' (d,d) d countPartitions :: Int -> Integer countPartitions d = countPartitions' (d,d) d --- | All partitions fitting into a given rectangle.+-- | All integer partitions fitting into a given rectangle. allPartitions' :: (Int,Int) -- ^ (height,width) -> [[Partition]] allPartitions' (h,w) = [ partitions' (h,w) i | i <- [0..d] ] where d = h*w --- | All partitions up to a given degree.+-- | All integer partitions up to a given degree (that is, all integer partitions whose sum is less or equal to @d@) allPartitions :: Int -> [[Partition]] allPartitions d = [ partitions i | i <- [0..d] ] @@ -182,6 +190,32 @@ countAllPartitions :: Int -> Integer countAllPartitions d = sum [ countPartitions i | i <- [0..d] ]++--------------------------------------------------------------------------------+-- * Ferrer diagrams++printFerrerDiagram :: Partition -> IO ()+printFerrerDiagram = putStrLn . ferrerDiagram++-- | Synonym for 'ferrerDiagramEnglishNotation'+ferrerDiagram :: Partition -> String+ferrerDiagram = ferrerDiagramEnglishNotation++ferrerDiagramEnglishNotation :: Partition -> String+ferrerDiagramEnglishNotation = ferrerDiagramEnglishNotation' '@'++ferrerDiagramFrenchNotation :: Partition -> String+ferrerDiagramFrenchNotation = ferrerDiagramFrenchNotation' '@'++ferrerDiagramEnglishNotation' :: Char -> Partition -> String+ferrerDiagramEnglishNotation' ch part = unlines (map f ys) where+ ys = fromPartition part+ f n = replicate n ch ++ferrerDiagramFrenchNotation' :: Char -> Partition -> String+ferrerDiagramFrenchNotation' ch part = unlines (map f ys) where+ ys = reverse $ fromPartition $ dualPartition part+ f n = replicate n ch --------------------------------------------------------------------------------
Math/Combinat/Permutations.hs view
@@ -51,7 +51,7 @@ #ifdef QUICKCHECK -- * QuickCheck , checkAll-#endif QUICKCHECK+#endif ) where @@ -66,6 +66,7 @@ import Data.Array import Data.Array.ST+import Data.Array.Unsafe import Math.Combinat.Helper import Math.Combinat.Numbers (factorial,binomial)
Math/Combinat/Sets.hs view
@@ -3,31 +3,56 @@ module Math.Combinat.Sets ( - choose+ -- * choices+ choose , choose_ , combine , compose+ -- * tensor products , tuplesFromList , listTensor- -- + -- * sublists , kSublists , sublists , countKSublists , countSublists+ -- * random choice+ , randomChoice ) where -import Math.Combinat.Numbers (binomial)+-------------------------------------------------------------------------------- +import Data.List ( sort , mapAccumL )+import System.Random++-- import Data.Map (Map)+-- import qualified Data.Map as Map++import Math.Combinat.Numbers ( binomial )+import Math.Combinat.Helper ( swap )+ --------------------------------------------------------------------------------+-- * choices -- | All possible ways to choose @k@ elements from a list, without--- repetitions. \"Antisymmetric power\" for lists. Synonym for "kSublists".+-- repetitions. \"Antisymmetric power\" for lists. Synonym for 'kSublists'. choose :: Int -> [a] -> [[a]] choose 0 _ = [[]] choose k [] = [] choose k (x:xs) = map (x:) (choose (k-1) xs) ++ choose k xs +-- | @choose_ k n@ returns all possible ways of choosing @k@ disjoint elements from @[1..n]@+--+-- > choose_ k n == choose k [1..n]+--+choose_ :: Int -> Int -> [[Int]]+choose_ k n = if n<0 || k<0+ then error "choose_: n and k should nonnegative"+ else if k>n || k<0 + then []+ else choose k [1..n]+ -- | All possible ways to choose @k@ elements from a list, /with repetitions/. --- \"Symmetric power\" for lists. See also "Math.Combinat.Combinations".+-- \"Symmetric power\" for lists. See also "Math.Combinat.Compositions". -- TODO: better name? combine :: Int -> [a] -> [[a]] combine 0 _ = [[]]@@ -38,6 +63,9 @@ compose :: Int -> [a] -> [[a]] compose = combine +--------------------------------------------------------------------------------+-- * tensor products+ -- | \"Tensor power\" for lists. Special case of 'listTensor': -- -- > tuplesFromList k xs == listTensor (replicate k xs)@@ -58,6 +86,7 @@ --listTensor (xs:xss) = [ y:ys | y <- xs, ys <- listTensor xss ] --------------------------------------------------------------------------------+-- * sublists -- | Sublists of a list having given number of elements. kSublists :: Int -> [a] -> [[a]]@@ -79,3 +108,43 @@ countSublists n = 2 ^ n --------------------------------------------------------------------------------+-- * random choice++-- | @randomChoice k n@ returns a uniformly random choice of @k@ elements from the set @[1..n]@+--+-- Example:+--+-- > do+-- > cs <- replicateM 10000 (getStdRandom (randomChoice 3 7))+-- > mapM_ print $ histogram cs+-- +randomChoice :: RandomGen g => Int -> Int -> g -> ([Int],g)+randomChoice k n g0 = + if k>n || k<0 + then error "randomChoice: k out of range" + else (makeChoiceFromIndices as, g1) + where+ -- choose numbers from [1..n], [1..n-1], [1..n-2] etc+ (g1,as) = mapAccumL (\g m -> swap (randomR (1,m) g)) g0 [n,n-1..n-k+1] + +-- | From a list of $k$ numbers, where the first is in the interval @[1..n]@, +-- the second in @[1..n-1]@, the third in @[1..n-2]@, we create a size @k@ subset of @n@.+makeChoiceFromIndices :: [Int] -> [Int]+makeChoiceFromIndices = sort . go [] where++ go :: [Int] -> [Int] -> [Int]+ go acc (b:bs) = b' : go (insert b' acc) bs where b' = skip b acc+ go _ [] = []++ -- skip over the already occupied positions. Second argument should be a sorted list+ skip :: Int -> [Int] -> Int+ skip x (y:ys) = if x>=y then skip (x+1) ys else x+ skip x [] = x++ -- insert into a sorted list+ insert :: Int -> [Int] -> [Int]+ insert x (y:ys) = if x<=y then x:y:ys else y : insert x ys+ insert x [] = [x]++--------------------------------------------------------------------------------+
Math/Combinat/Trees/Binary.hs view
@@ -50,6 +50,7 @@ import Data.Array import Data.Array.ST+import Data.Array.Unsafe import Data.List import Data.Tree (Tree(..),Forest(..))@@ -207,7 +208,11 @@ -------------------------------------------------------------------------------- -- * Nested parentheses --- | Synonym for 'fasc4A_algorithm_P'.+-- | Generates all sequences of nested parentheses of length @2n@ in+-- lexigraphic order.+-- +-- Synonym for 'fasc4A_algorithm_P'.+-- nestedParentheses :: Int -> [[Paren]] nestedParentheses = fasc4A_algorithm_P
combinat.cabal view
@@ -1,5 +1,5 @@ Name: combinat-Version: 0.2.5.0+Version: 0.2.6.0 Synopsis: Generation of various combinatorial objects. Description: A collection of functions to generate (and if there is a formula, count) combinatorial objects like partitions, @@ -13,7 +13,7 @@ Homepage: http://code.haskell.org/~bkomuves/ Stability: Experimental Category: Math-Tested-With: GHC == 7.4.2+Tested-With: GHC == 7.8.3 Cabal-Version: >= 1.6 Build-Type: Simple @@ -21,27 +21,22 @@ Description: Compile with the QuickCheck tests. default: False -Flag splitBase- Description: Choose the new smaller, split-up base package.- Flag base4 Description: Base v4 Library- if flag(splitBase)- if flag(base4)- Build-Depends: base >= 4 && < 5, array, containers, random, transformers- cpp-options: -DBASE_VERSION=4- else - Build-Depends: base >= 3 && < 4, array, containers, random, transformers- cpp-options: -DBASE_VERSION=3- if flag(withQuickCheck)- Build-Depends: QuickCheck- else- Build-Depends: base < 3- cpp-options: -DBASE_VERSION=2 + if flag(base4)+ Build-Depends: base >= 4 && < 5, array >= 0.4, containers, random, transformers+ cpp-options: -DBASE_VERSION=4+ else + Build-Depends: base >= 3 && < 4, array >= 0.4, containers, random, transformers+ cpp-options: -DBASE_VERSION=3 + if flag(withQuickCheck)+ Build-Depends: QuickCheck++ Exposed-Modules: Math.Combinat Math.Combinat.Numbers Math.Combinat.Numbers.Series@@ -56,10 +51,10 @@ Math.Combinat.Trees Math.Combinat.Trees.Binary Math.Combinat.Trees.Nary+ Math.Combinat.LatticePaths Math.Combinat.FreeGroups Math.Combinat.Graphviz- - Other-Modules: Math.Combinat.Helper+ Math.Combinat.Helper Extensions: CPP, MultiParamTypeClasses, ScopedTypeVariables, GeneralizedNewtypeDeriving