combinat (empty) → 0.1
raw patch · 11 files changed
+908/−0 lines, 11 filesdep +arraydep +basedep +containerssetup-changed
Dependencies added: array, base, containers
Files
- LICENSE +29/−0
- Math/Combinat.hs +40/−0
- Math/Combinat/Combinations.hs +59/−0
- Math/Combinat/Helper.hs +63/−0
- Math/Combinat/Partitions.hs +148/−0
- Math/Combinat/Permutations.hs +86/−0
- Math/Combinat/Tableaux.hs +118/−0
- Math/Combinat/Trees.hs +259/−0
- Math/Combinat/Tuples.hs +61/−0
- Setup.lhs +4/−0
- combinat.cabal +41/−0
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2008, Balazs Komuves+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- Neither names of the copyright holders nor the names of the contributors+may be used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Math/Combinat.hs view
@@ -0,0 +1,40 @@++-- | A collection of functions to generate combinatorial+-- objects like partitions, combinations, permutations,+-- Young tableaux, various trees, etc.+--+-- The long-term goals are +--+-- (1) to be efficient; +--+-- (2) to be able to enumerate the structures +-- with constant memory usage. +--+-- The short-term goal is to generate +-- many interesting structures.+--+-- Naming conventions (subject to change): +--+-- * prime suffix: additional constrains, typically more general;+--+-- * underscore prefix: use plain lists instead of other types with +-- enforced invariants;+--+-- * \"count\" prefix: counting functions.++module Math.Combinat + ( module Math.Combinat.Tuples+ , module Math.Combinat.Combinations+ , module Math.Combinat.Partitions+ , module Math.Combinat.Permutations+ , module Math.Combinat.Tableaux+ , module Math.Combinat.Trees+ ) where++import Math.Combinat.Tuples+import Math.Combinat.Combinations+import Math.Combinat.Partitions+import Math.Combinat.Permutations+import Math.Combinat.Tableaux+import Math.Combinat.Trees+
+ Math/Combinat/Combinations.hs view
@@ -0,0 +1,59 @@++-- | Combinations++module Math.Combinat.Combinations where++import Math.Combinat.Helper++-------------------------------------------------------++-- | Combinations fitting into a given shape and having a given degree.+-- The order is lexicographic, that is, +--+-- > sort cs == cs where cs = combinations' shape k+--+combinations' + :: [Int] -- ^ shape+ -> Int -- ^ sum+ -> [[Int]]+combinations' [] 0 = [[]]+combinations' [] _ = []+combinations' shape@(s:ss) n = + [ x:xs | x <- [0..min s n] , xs <- combinations' ss (n-x) ] ++countCombinations' :: [Int] -> Int -> Integer+countCombinations' [] 0 = 1+countCombinations' [] _ = 0+countCombinations' shape@(s:ss) n = sum + [ countCombinations' ss (n-x) | x <- [0..min s n] ] ++-- | All combinations fitting into a given shape.+allCombinations' :: [Int] -> [[[Int]]]+allCombinations' shape = map (combinations' shape) [0..d] where d = sum shape++-- | Combinations of a given length.+combinations + :: Int -- ^ length+ -> Int -- ^ sum+ -> [[Int]]+combinations len d = combinations' (replicate len d) d++-- | # = \\binom { len+d-1 } { len-1 }+countCombinations :: Int -> Int -> Integer+countCombinations len d = binomial (len+d-1) (len-1)++-- | Positive combinations of a given length.+combinations1 + :: Int -- ^ length+ -> Int -- ^ sum+ -> [[Int]]+combinations1 len d + | len > d = []+ | otherwise = map plus1 $ combinations len (d-len)+ where+ plus1 = map (+1)++countCombinations1 :: Int -> Int -> Integer+countCombinations1 len d = countCombinations len (d-len)++-------------------------------------------------------
+ Math/Combinat/Helper.hs view
@@ -0,0 +1,63 @@++module Math.Combinat.Helper where++import Debug.Trace++debug :: Show a => a -> b -> b+debug x y = trace (show x) y++fromJust :: Maybe a -> a+fromJust (Just x) = x+fromJust Nothing = error "fromJust: Nothing"++-- iterated function application+nest :: Int -> (a -> a) -> a -> a+nest 0 _ x = x+nest n f x = nest (n-1) f (f x)++reverseOrdering :: Ordering -> Ordering+reverseOrdering LT = GT+reverseOrdering GT = LT+reverseOrdering EQ = EQ++reverseCompare :: Ord a => a -> a -> Ordering+reverseCompare x y = reverseOrdering $ compare x y++factorial :: Int -> Integer+factorial 0 = 1+factorial n = product [1..fromIntegral n]++binomial :: Int -> Int -> Integer+binomial n k + | k > n = 0+ | k < 0 = 0+ | k > (n `div` 2) = binomial n (n-k)+ | otherwise = (product [n'-k'+1 .. n']) `div` (product [1..k'])+ where + k' = fromIntegral k+ n' = fromIntegral n+ +intToBool :: Int -> Bool+intToBool 0 = False+intToBool 1 = True+intToBool _ = error "intToBool"++boolToInt :: Bool -> Int +boolToInt False = 0+boolToInt True = 1++unfold1 :: (a -> Maybe a) -> a -> [a]+unfold1 f x = case f x of + Nothing -> [x] + Just y -> x : unfold1 f y + +unfold :: (b -> (a,Maybe b)) -> b -> [a]+unfold f y = let (x,m) = f y in case m of + Nothing -> [x]+ Just y' -> x : unfold f y'++unfoldEither :: (b -> Either c (b,a)) -> b -> (c,[a])+unfoldEither f y = case f y of+ Left z -> (z,[])+ Right (y,x) -> let (z,xs) = unfoldEither f y in (z,x:xs)+
+ Math/Combinat/Partitions.hs view
@@ -0,0 +1,148 @@++-- | Partitions. Partitions are nonincreasing sequences of positive integers.++module Math.Combinat.Partitions+ ( -- * Type and basic stuff+ Partition+ , toPartition+ , toPartitionUnsafe+ , mkPartition+ , isPartition+ , fromPartition+ , height+ , width+ , heightWidth+ , weight+ , _dualPartition+ , dualPartition+ -- * Generation+ , _partitions' + , partitions' + , countPartitions'+ , _partitions+ , partitions+ , countPartitions+ , allPartitions' + , allPartitions + , countAllPartitions'+ , countAllPartitions+ ) + where++import Data.List+import Math.Combinat.Helper++-------------------------------------------------------++-- | The additional invariant enforced here is that partitions +-- are monotone decreasing sequences of positive integers.+newtype Partition = Partition [Int] deriving (Eq,Ord,Show,Read)++-- | Sorts the input.+mkPartition :: [Int] -> Partition+mkPartition xs = Partition $ sortBy (reverseCompare) $ filter (>0) xs++-- | Assumes that the input is decreasing.+toPartitionUnsafe :: [Int] -> Partition+toPartitionUnsafe = Partition++-- | Checks whether the input is a partition.+toPartition :: [Int] -> Partition+toPartition xs = if isPartition xs+ then toPartitionUnsafe xs+ else error "toPartition: not a partition"+ +isPartition :: [Int] -> Bool+isPartition [] = True+isPartition [_] = True+isPartition (x:xs@(y:_)) = (x >= y) && isPartition xs++fromPartition :: Partition -> [Int]+fromPartition (Partition part) = part++-- | The first element of the sequence.+height :: Partition -> Int+height (Partition part) = case part of+ (p:_) -> p+ [] -> 0+ +-- | The length of the sequence.+width :: Partition -> Int+width (Partition part) = length part++heightWidth :: Partition -> (Int,Int)+heightWidth part = (height part, width part)++-- | The weight of the partition +-- (that is, the sum of the corresponding sequence).+weight :: Partition -> Int+weight (Partition part) = sum part++-- | The dual (or conjugate) partition.+dualPartition :: Partition -> Partition+dualPartition (Partition part) = Partition (_dualPartition part)++-- (we could be more efficient, but it hardly matters)+_dualPartition :: [Int] -> [Int]+_dualPartition [] = []+_dualPartition xs@(k:_) = [ length $ filter (>=i) xs | i <- [1..k] ]+ +-------------------------------------------------------++-- | 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 = + [ 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.+partitions' + :: (Int,Int) -- ^ (height,width)+ -> Int -- ^ d+ -> [Partition]+partitions' hw d = map toPartitionUnsafe $ _partitions' hw d ++countPartitions' :: (Int,Int) -> Int -> Integer+countPartitions' _ 0 = 1+countPartitions' (0,_) d = if d==0 then 1 else 0+countPartitions' (_,0) d = if d==0 then 1 else 0+countPartitions' (h,w) d = sum+ [ countPartitions' (i,w-1) (d-i) | i <- [1..min d h] ] ++-- | Partitions of d, as lists+_partitions :: Int -> [[Int]]+_partitions d = _partitions' (d,d) 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.+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.+allPartitions :: Int -> [[Partition]]+allPartitions d = [ partitions i | i <- [0..d] ]++-- | # = \\binom { h+w } { h }+countAllPartitions' :: (Int,Int) -> Integer+countAllPartitions' (h,w) = + binomial (h+w) (min h w)+ --sum [ countPartitions' (h,w) i | i <- [0..d] ] where d = h*w++countAllPartitions :: Int -> Integer+countAllPartitions d = sum [ countPartitions i | i <- [0..d] ]++-------------------------------------------------------+
+ Math/Combinat/Permutations.hs view
@@ -0,0 +1,86 @@++-- | Permutations. See:+-- Donald E. Knuth: The Art of Computer Programming, vol 4, pre-fascicle 2B.+--+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+module Math.Combinat.Permutations where++import Data.List+import Data.Array++import Math.Combinat.Helper++-------------------------------------------------------+{-+-- * Types++-- | Standard notation for permutations+newtype Permutation = Permutation (Array Int Int) deriving (Eq,Ord,Show,Read)++-- | Disjoint cycle notation for permutations+newtype DisjCycles = DisjCycles [[Int]] deriving (Eq,Ord,Show,Read)+-}++-------------------------------------------------------+-- * Permutations of distinct elements++-- | Permutations of [1..n] in lexicographic order, naive algorithm.+_permutations :: Int -> [[Int]] +_permutations 0 = [[]]+_permutations 1 = [[1]]+_permutations n = helper [1..n] where+ helper [] = [[]]+ helper xs = [ i : ys | i <- xs , ys <- helper (xs `minus` i) ]+ minus [] _ = []+ minus (x:xs) i = if x < i then x : minus xs i else xs++{-+permutations :: Int -> [Permutation]+permutations n = map toPermutationUnsafe $ _permutations n +-}++-- | # = n!+countPermutations :: Int -> Integer+countPermutations = factorial++-------------------------------------------------------+-- * Permutations of a multiset++-- | Generates all permutations of a multiset. +-- The order is lexicographic. +permute :: (Eq a, Ord a) => [a] -> [[a]] +permute = fasc2B_algorithm_L++-- | # = \\frac { (\sum_i n_i) ! } { \\prod_i (n_i !) } +countPermute :: (Eq a, Ord a) => [a] -> Integer+countPermute xs = factorial n `div` product [ factorial (length z) | z <- group ys ] + where+ ys = sort xs+ n = length xs+ +-- | Generates all permutations of a multiset +-- (based on \"algorithm L\" in Knuth; somewhat less efficient). +-- The order is lexicographic. +fasc2B_algorithm_L :: (Eq a, Ord a) => [a] -> [[a]] +fasc2B_algorithm_L xs = unfold1 next (sort xs) where+ -- next :: [a] -> Maybe [a]+ next xs = case findj (reverse xs,[]) of + Nothing -> Nothing+ Just ( (l:ls) , rs) -> Just $ inc l ls (reverse rs,[]) + Just ( [] , _ ) -> error "permute: should not happen"++ -- we use simple list zippers: (left,right)+ -- findj :: ([a],[a]) -> Maybe ([a],[a]) + findj ( xxs@(x:xs) , yys@(y:_) ) = if x >= y + then findj ( xs , x : yys )+ else Just ( xxs , yys )+ findj ( x:xs , [] ) = findj ( xs , [x] ) + findj ( [] , _ ) = Nothing+ + -- inc :: a -> [a] -> ([a],[a]) -> [a]+ inc u us ( (x:xs) , yys ) = if u >= x+ then inc u us ( xs , x : yys ) + else reverse (x:us) ++ reverse (u:yys) ++ xs+ inc _ _ ( [] , _ ) = error "permute: should not happen"+ +-------------------------------------------------------
+ Math/Combinat/Tableaux.hs view
@@ -0,0 +1,118 @@++-- | Young tableaux and similar gadgets. +-- See e.g. William Fulton: Young Tableaux, with Applications to +-- Representation theory and Geometry (CUP 1997).+-- +-- The convention is that we use +-- the English notation, and we store the tableaux as lists of the rows.+-- +-- That is, the following standard tableau of shape [5,4,1]+-- +-- > 1 3 4 6 7+-- > 2 5 8 10+-- > 9+--+-- is encoded conveniently as+-- +-- > [ [ 1 , 3 , 4 , 6 , 7 ]+-- > , [ 2 , 5 , 8 ,10 ]+-- > , [ 9 ]+-- > ]+--++module Math.Combinat.Tableaux where++import Data.List++import Math.Combinat.Helper+import Math.Combinat.Partitions++-------------------------------------------------------+-- * Basic stuff++type Tableau a = [[a]]++_shape :: Tableau a -> [Int]+_shape t = map length t ++shape :: Tableau a -> Partition+shape t = toPartition (_shape t)++dualTableau :: Tableau a -> Tableau a+dualTableau = transpose++hooks :: Partition -> Tableau Int+hooks part = zipWith f p [1..] where + p = fromPartition part+ q = _dualPartition p+ f l i = zipWith (\x y -> x+y-i) q [l,l-1..1] ++-------------------------------------------------------+-- * Row and column words++rowWord :: Tableau a -> [a]+rowWord = concat . reverse++rowWordToTableau :: Ord a => [a] -> Tableau a+rowWordToTableau xs = reverse rows where+ rows = break xs+ break [] = [[]]+ break [x] = [[x]]+ break (x:xs@(y:_)) = if x>y+ then [x] : break xs+ else let (h:t) = break xs in (x:h):t++columnWord :: Tableau a -> [a]+columnWord = rowWord . transpose++columnWordToTableau :: Ord a => [a] -> Tableau a+columnWordToTableau = transpose . rowWordToTableau+ +-------------------------------------------------------+-- * Standard Young tableaux++-- | Standard Young tableaux of a given shape.+-- Adapted from John Stembridge, +-- <http://www.math.lsa.umich.edu/~jrs/software/SFexamples/tableaux>.+standardYoungTableaux :: Partition -> [Tableau Int]+standardYoungTableaux shape' = map rev $ tableaux shape where+ shape = fromPartition shape'+ rev = reverse . map reverse+ tableaux :: [Int] -> [Tableau Int]+ tableaux p = + case p of+ [] -> [[]]+ [n] -> [[[n,n-1..1]]]+ _ -> worker (n,k) 0 [] p+ where+ n = sum p+ k = length p+ worker :: (Int,Int) -> Int -> [Int] -> [Int] -> [Tableau Int]+ worker _ _ _ [] = []+ worker nk i ls (x:rs) = case rs of+ (y:_) -> if x==y + then worker nk (i+1) (x:ls) rs+ else worker2 nk i ls x rs+ [] -> worker2 nk i ls x rs+ worker2 :: (Int,Int) -> Int -> [Int] -> Int -> [Int] -> [Tableau Int]+ worker2 nk@(n,k) i ls x rs = new ++ worker nk (i+1) (x:ls) rs where+ old = if x>1 + then tableaux $ reverse ls ++ (x-1) : rs+ else map ([]:) $ tableaux $ reverse ls ++ rs + a = k-1-i+ new = {- debug ( i , a , head old , f a (head old) ) $ -}+ map (f a) old+ f :: Int -> Tableau Int -> Tableau Int+ f _ [] = []+ f 0 (t:ts) = (n:t) : f (-1) ts+ f j (t:ts) = t : f (j-1) ts+ +-- | hook-length formula+countStandardYoungTableaux :: Partition -> Integer+countStandardYoungTableaux part = {- debug (hooks part) $ -}+ factorial n `div` h where+ h = product $ map fromIntegral $ concat $ hooks part + n = weight part+ +-------------------------------------------------------+
+ Math/Combinat/Trees.hs view
@@ -0,0 +1,259 @@++-- | Trees, forests, etc. See:+-- Donald E. Knuth: The Art of Computer Programming, vol 4, pre-fascicle 4A.++module Math.Combinat.Trees + ( -- * Types+ BinTree(..)+ , leaf+ , module Data.Tree + , Paren(..)+ , parenthesesToString+ , stringToParentheses+ -- * Bijections+ , forestToNestedParentheses+ , forestToBinaryTree+ , nestedParenthesesToForest+ , nestedParenthesesToForestUnsafe+ , nestedParenthesesToBinaryTree+ , nestedParenthesesToBinaryTreeUnsafe+ , binaryTreeToForest+ , binaryTreeToNestedParentheses+ -- * Nested parentheses+ , nestedParentheses + , fasc4A_algorithm_P+ -- * Binary trees+ , binaryTrees+ , countBinaryTrees+ , binaryTreesNaive+ ) + where++import Data.List+import Data.Tree (Tree(..),Forest(..))++import Math.Combinat.Helper++-------------------------------------------------------+-- * Types++data BinTree a+ = Branch (BinTree a) (BinTree a)+ | Leaf a+ deriving (Eq,Ord,Show,Read)++leaf :: BinTree ()+leaf = Leaf ()++-------------------------------------------------------++data Paren = LeftParen | RightParen deriving (Eq,Ord,Show,Read)++parenToChar :: Paren -> Char+parenToChar LeftParen = '('+parenToChar RightParen = ')'++parenthesesToString :: [Paren] -> String+parenthesesToString = map parenToChar++stringToParentheses :: String -> [Paren]+stringToParentheses [] = []+stringToParentheses (x:xs) = p : stringToParentheses xs where+ p = case x of+ '(' -> LeftParen+ ')' -> RightParen+ _ -> error "stringToParentheses: invalid character"++-------------------------------------------------------+-- * Bijections++forestToNestedParentheses :: Forest a -> [Paren]+forestToNestedParentheses = forest where+ -- forest :: Forest a -> [Paren]+ forest = concatMap tree + -- tree :: Tree a -> [Paren]+ tree (Node _ sf) = LeftParen : forest sf ++ [RightParen]++forestToBinaryTree :: Forest a -> BinTree ()+forestToBinaryTree = forest where+ -- forest :: Forest a -> BinTree ()+ forest = foldr Branch leaf . map tree + -- tree :: Tree a -> BinTree ()+ tree (Node _ sf) = case sf of+ [] -> leaf+ _ -> forest sf + +nestedParenthesesToForest :: [Paren] -> Maybe (Forest ())+nestedParenthesesToForest ps = + case parseForest ps of + (rest,forest) -> case rest of+ [] -> Just forest+ _ -> Nothing+ where + parseForest :: [Paren] -> ( [Paren] , Forest () )+ parseForest ps = unfoldEither parseTree ps+ parseTree :: [Paren] -> Either [Paren] ( [Paren] , Tree () ) + parseTree orig@(LeftParen:ps) = let (rest,ts) = parseForest ps in case rest of+ (RightParen:qs) -> Right (qs, Node () ts)+ _ -> Left orig+ parseTree qs = Left qs++nestedParenthesesToForestUnsafe :: [Paren] -> Forest ()+nestedParenthesesToForestUnsafe = fromJust . nestedParenthesesToForest++nestedParenthesesToBinaryTree :: [Paren] -> Maybe (BinTree ())+nestedParenthesesToBinaryTree ps = + case parseForest ps of + (rest,forest) -> case rest of+ [] -> Just forest+ _ -> Nothing+ where + parseForest :: [Paren] -> ( [Paren] , BinTree () )+ parseForest ps = let (rest,ts) = unfoldEither parseTree ps in (rest , foldr Branch leaf ts)+ parseTree :: [Paren] -> Either [Paren] ( [Paren] , BinTree () ) + parseTree orig@(LeftParen:ps) = let (rest,ts) = parseForest ps in case rest of+ (RightParen:qs) -> Right (qs, ts)+ _ -> Left orig+ parseTree qs = Left qs+ +nestedParenthesesToBinaryTreeUnsafe :: [Paren] -> BinTree ()+nestedParenthesesToBinaryTreeUnsafe = fromJust . nestedParenthesesToBinaryTree++binaryTreeToNestedParentheses :: BinTree a -> [Paren]+binaryTreeToNestedParentheses = worker where+ worker (Branch l r) = LeftParen : worker l ++ RightParen : worker r+ worker (Leaf _) = []++binaryTreeToForest :: BinTree a -> Forest ()+binaryTreeToForest = worker where+ worker (Branch l r) = Node () (worker l) : worker r+ worker (Leaf _) = []++-------------------------------------------------------+-- * Nested parentheses++-- | Synonym for 'fasc4A_algorithm_P'.+nestedParentheses :: Int -> [[Paren]]+nestedParentheses = fasc4A_algorithm_P++-- | Generates all sequences of nested parentheses of length 2n.+-- Order is lexigraphic (when right parentheses are considered +-- smaller then left ones).+-- Based on \"Algorithm P\" in Knuth, but less efficient because of+-- the \"idiomatic\" code.+fasc4A_algorithm_P :: Int -> [[Paren]]+fasc4A_algorithm_P 0 = []+fasc4A_algorithm_P 1 = [[LeftParen,RightParen]]+fasc4A_algorithm_P n = unfold next ( start , [] ) where + start = concat $ replicate n [RightParen,LeftParen] -- already reversed!+ + next :: ([Paren],[Paren]) -> ( [Paren] , Maybe ([Paren],[Paren]) )+ next ( (a:b:ls) , [] ) = next ( ls , b:a:[] )+ next ( lls@(l:ls) , rrs@(r:rs) ) = ( visit , new ) where+ visit = reverse lls ++ rrs+ new = + {- debug (reverse ls,l,r,rs) $ -} + case l of + RightParen -> Just ( ls , LeftParen:RightParen:rs )+ LeftParen -> + {- debug ("---",reverse ls,l,r,rs) $ -}+ findj ( lls , [] ) ( reverse (RightParen:rs) , [] ) ++ findj :: ([Paren],[Paren]) -> ([Paren],[Paren]) -> Maybe ([Paren],[Paren])+ findj ( [] , _ ) _ = Nothing+ findj ( lls@(l:ls) , rs) ( xs , ys ) = + {- debug ((reverse ls,l,rs),(reverse xs,ys)) $ -}+ case l of+ LeftParen -> case xs of+ (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 , [] )+ ++-------------------------------------------------------+-- * Binary trees++-- | Generates all binary trees with n nodes. +binaryTrees :: Int -> [BinTree ()]+binaryTrees = binaryTreesNaive++-- | # = Catalan(n) = \\frac { 1 } { n+1 } \\binom { 2n } { n }.+--+-- This is also the counting function for forests and nested parentheses.+countBinaryTrees :: Int -> Integer+countBinaryTrees n = binomial (2*n) n `div` (1 + fromIntegral n)++-- | Generates all binary trees with n nodes. The naive algorithm.+binaryTreesNaive :: Int -> [BinTree ()]+binaryTreesNaive 0 = [ leaf ]+binaryTreesNaive n = + [ Branch l r + | i <- [0..n-1] + , l <- binaryTreesNaive i + , r <- binaryTreesNaive (n-1-i) + ]++----- binary tree zipper++data Ctx a+ = Top + | L (Ctx a) (BinTree a)+ | R (BinTree a) (Ctx a) ++type Loc a = (BinTree a, Ctx a)++left :: Loc a -> Loc a+left (Branch l r , c) = (l , L c r)+left (Leaf _ , _) = error "left: Leaf"++right :: Loc a -> Loc a+right (Branch l r , c) = (r , R l c)+right (Leaf _ , _) = error "right: Leaf"+ +top :: BinTree a -> Loc a+top t = (t, Top)+ +up :: Loc a -> Loc a+up (t, L c r) = (Branch t r, c)+up (t, R l c) = (Branch l t, c)+up (t, Top ) = error "up: top"++upmost :: Loc a -> Loc a+upmost l@(t, Top) = l+upmost l = upmost (up l)+ +modify :: (BinTree a -> BinTree a) -> Loc a -> Loc a+modify f (t, c) = (f t, c)++-----++{-+-- | Generates all binary trees with n nodes.+-- Based on \"Algorithm B\" in Knuth, uses tree zippers.+fasc4A_algorithm_B :: Int -> [BinTree ()]+fasc4A_algorithm_B 0 = [ leaf ]+fasc4A_algorithm_B n = unfold1 next start where+ start = nest n (\t -> Branch t leaf) leaf++ killLeft (Branch _ r) = Branch leaf r+ killRight (Branch l _) = Branch l leaf+ + next t = case findj (top t) of+ Nothing -> Nothing+ Just locj@(s,c) -> case findk (top s) of+ lock@(u,Top) -> Just $ promote (modify killLeft locj ) lock + lock@(u,_ ) -> Just $ promote locj (modify killRight lock)+ + findj :: Loc () -> Maybe (Loc ())+ findj (Branch (Leaf _) t , c) = case t of+ Branch l r -> findj $ left (Branch t leaf , c) + Leaf _ -> Nothing+ findj loc@(Leaf _ , c) = Just loc++ findk :: Loc () -> Loc ()+ findk loc@( Branch l (Leaf _) , _) = loc+ findk loc@( Branch l r , _) = findk (right loc)+ + promote :: Loc () -> Loc () -> BinTree ()+ promote locj lock = undefined+-}
+ Math/Combinat/Tuples.hs view
@@ -0,0 +1,61 @@++-- | Tuples.++module Math.Combinat.Tuples where++import Math.Combinat.Helper++-------------------------------------------------------+-- Tuples++-- | \"Tuples\" fitting into a give shape. The order is lexicographic, that is,+--+-- > sort ts == ts where ts = tuples' shape+--+-- Example: +--+-- > tuples' [2,3] = +-- > [[0,0],[0,1],[0,2],[0,3],[1,0],[1,1],[1,2],[1,3],[2,0],[2,1],[2,2],[2,3]]+--+tuples' :: [Int] -> [[Int]]+tuples' [] = [[]]+tuples' (s:ss) = [ x:xs | x <- [0..s] , xs <- tuples' ss ] ++-- | positive \"tuples\" fitting into a give shape.+tuples1' :: [Int] -> [[Int]]+tuples1' [] = [[]]+tuples1' (s:ss) = [ x:xs | x <- [1..s] , xs <- tuples1' ss ] ++-- | # = \\prod_i (m_i + 1)+countTuples' :: [Int] -> Integer+countTuples' shape = product $ map f shape where+ f k = 1 + fromIntegral k++-- | # = \\prod_i m_i+countTuples1' :: [Int] -> Integer+countTuples1' shape = product $ map fromIntegral shape++tuples + :: Int -- ^ length (width)+ -> Int -- ^ maximum (height)+ -> [[Int]]+tuples len k = tuples' (replicate len k)++tuples1 + :: Int -- ^ length (width)+ -> Int -- ^ maximum (height)+ -> [[Int]]+tuples1 len k = tuples1' (replicate len k)++-- | # = (m+1) ^ len+countTuples :: Int -> Int -> Integer+countTuples len k = (1 + fromIntegral k) ^ len++-- | # = m ^ len+countTuples1 :: Int -> Int -> Integer+countTuples1 len k = fromIntegral k ^ len++binaryTuples :: Int -> [[Bool]]+binaryTuples len = map (map intToBool) (tuples len 1)++-------------------------------------------------------
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell + +> import Distribution.Simple +> main = defaultMain
+ combinat.cabal view
@@ -0,0 +1,41 @@+Name: combinat+Version: 0.1+Synopsis: Generation of various combinatorial objects.+Description: A collection of functions to generate combinatorial+ objects like partitions, combinations, permutations,+ Young tableaux, various trees, etc.+License: BSD3+License-file: LICENSE+Author: Balazs Komuves+Copyright: (c) 2008 Balazs Komuves+Maintainer: bkomuves (plus) hackage (at) gmail (dot) com+Stability: Unstable+--Portability: Portable+Category: Math+Tested-With: GHC == 6.8.3+Cabal-Version: >= 1.2+Build-Type: Simple++Flag splitBase+ Description: Choose the new smaller, split-up base package.++Library+ if flag(splitBase)+ Build-Depends: base >= 3, array, containers+ else+ Build-Depends: base < 3++ Exposed-Modules: Math.Combinat, + Math.Combinat.Tuples, + Math.Combinat.Combinations,+ Math.Combinat.Partitions,+ Math.Combinat.Permutations,+ Math.Combinat.Tableaux,+ Math.Combinat.Trees+ + Other-Modules: Math.Combinat.Helper++ Hs-Source-Dirs: .++ ghc-options: -Wall -fno-warn-unused-matches+