module Combinatorics (
permute,
permuteFast,
permuteShare,
permuteMSL,
runPermuteRep,
permuteRep,
permuteRepM,
choose,
chooseMSL,
variateRep,
variateRepMSL,
variate,
variateMSL,
tuples,
tuplesMSL,
tuplesRec,
partitions,
rectifications,
setPartitions,
chooseFromIndex,
chooseFromIndexList,
chooseFromIndexMaybe,
chooseToIndex,
factorial,
binomial,
binomialSeq,
binomialGen,
binomialSeqGen,
multinomial,
factorials,
binomials,
catalanNumber,
catalanNumbers,
derangementNumber,
derangementNumbers,
derangementNumbersAlt,
derangementNumbersInclExcl,
setPartitionNumbers,
surjectiveMappingNumber,
surjectiveMappingNumbers,
surjectiveMappingNumbersStirling,
fibonacciNumber,
fibonacciNumbers,
) where
import qualified PowerSeries
import Combinatorics.Utility (scalarProduct, )
import Data.Function.HT (nest, )
import Data.Maybe.HT (toMaybe, )
import Data.Maybe (mapMaybe, catMaybes, )
import Data.Tuple.HT (mapFst, )
import qualified Data.List.Match as Match
import Data.List.HT (tails, partition, mapAdjacent, removeEach, splitEverywhere, viewL, )
import Data.List (mapAccumL, intersperse, genericIndex, genericReplicate, genericTake, )
import qualified Control.Monad.Trans.Class as MT
import qualified Control.Monad.Trans.State as MS
import Control.Monad (liftM, liftM2, replicateM, forM, guard, )
permute :: [a] -> [[a]]
permute [] = [[]]
permute x =
concatMap (\(y, ys) -> map (y:) (permute ys))
(removeEach x)
permuteFast :: [a] -> [[a]]
permuteFast x = permuteFastStep [] x []
permuteFastStep :: [a] -> [a] -> [[a]] -> [[a]]
permuteFastStep suffix [] tl = suffix:tl
permuteFastStep suffix x tl =
foldr (\c -> permuteFastStep (head c : suffix) (tail c)) tl (allCycles x)
permuteShare :: [a] -> [[a]]
permuteShare x =
map fst $
nest (length x) (concatMap permuteShareStep) [([], x)]
permuteShareStep :: ([a], [a]) -> [([a], [a])]
permuteShareStep (perm,todo) =
map
(mapFst (:perm))
(removeEach todo)
permuteMSL :: [a] -> [[a]]
permuteMSL xs =
flip MS.evalStateT xs $ replicateM (length xs) $
MS.StateT removeEach
runPermuteRep :: ([(a,Int)] -> [[a]]) -> [(a,Int)] -> [[a]]
runPermuteRep f xs =
let (ps,ns) = partition ((>0) . snd) xs
in if any ((<0) . snd) ns
then []
else f ps
permuteRep :: [(a,Int)] -> [[a]]
permuteRep = runPermuteRep permuteRepAux
permuteRepAux :: [(a,Int)] -> [[a]]
permuteRepAux [] = [[]]
permuteRepAux xs =
concatMap (\(ys,(a,n),zs) ->
let m = pred n
in map (a:) (permuteRepAux (ys ++ (m>0, (a, m)) ?: zs))) $
filter (\(_,(_,n),_) -> n>0) $
splitEverywhere xs
permuteRepM :: [(a,Int)] -> [[a]]
permuteRepM = runPermuteRep permuteRepMAux
permuteRepMAux :: [(a,Int)] -> [[a]]
permuteRepMAux [] = [[]]
permuteRepMAux xs =
do (ys,(a,n),zs) <- splitEverywhere xs
let m = pred n
liftM (a:)
(permuteRepMAux (ys ++ (m>0, (a, m)) ?: zs))
infixr 5 ?:
(?:) :: (Bool, a) -> [a] -> [a]
(True,a) ?: xs = a:xs
(False,_) ?: xs = xs
choose :: Int -> Int -> [[Bool]]
choose n k =
if k<0 || k>n
then []
else
if n==0
then [[]]
else
map (False:) (choose (pred n) k) ++
map (True:) (choose (pred n) (pred k))
chooseMSL :: Int -> Int -> [[Bool]]
chooseMSL n0 k0 =
flip MS.evalStateT k0 $ fmap catMaybes $ sequence $
intersperse (MS.StateT $ \k -> [(Just False, k), (Just True, pred k)]) $
flip map [n0,n01..0] $ \n ->
MS.gets (\k -> 0<=k && k<=n) >>= guard >> return Nothing
_chooseMSL :: Int -> Int -> [[Bool]]
_chooseMSL n0 k0 =
flip MS.evalStateT k0 $ do
count <-
forM [n0,n01..1] $ \n ->
MS.StateT $ \k ->
guard (0<=k && k<=n) >> [(False, k), (True, pred k)]
MS.gets (0==) >>= guard
return count
variateRep :: Int -> [a] -> [[a]]
variateRep n x = nest n (\y -> concatMap (\z -> map (z:) y) x) [[]]
variateRepMSL :: Int -> [a] -> [[a]]
variateRepMSL = replicateM
variate :: Int -> [a] -> [[a]]
variate 0 _ = [[]]
variate n x =
concatMap (\(y, ys) -> map (y:) (variate (n1) ys))
(removeEach x)
variateMSL :: Int -> [a] -> [[a]]
variateMSL n xs =
flip MS.evalStateT xs $ replicateM n $
MS.StateT removeEach
tuples :: Int -> [a] -> [[a]]
tuples 0 _ = [[]]
tuples r xs =
concatMap (\(y:ys) -> map (y:) (tuples (r1) ys))
(init (tails xs))
tuplesMSL :: Int -> [a] -> [[a]]
tuplesMSL n xs =
flip MS.evalStateT xs $ replicateM n $
MS.StateT $ mapMaybe viewL . tails
_tuplesMSL :: Int -> [a] -> [[a]]
_tuplesMSL n xs =
flip MS.evalStateT xs $
replicateM n $ do
yl <- MS.get
(y:ys) <- MT.lift $ tails yl
MS.put ys
return y
tuplesRec :: Int -> [a] -> [[a]]
tuplesRec k xt =
if k<0
then []
else
case xt of
[] -> guard (k==0) >> [[]]
x:xs ->
tuplesRec k xs ++
map (x:) (tuplesRec (pred k) xs)
partitions :: [a] -> [([a],[a])]
partitions =
foldr
(\x -> concatMap (\(lxs,rxs) -> [(x:lxs,rxs), (lxs,x:rxs)]))
[([],[])]
rectifications :: Int -> [a] -> [[a]]
rectifications =
let recourse _ 0 xt =
if null xt
then [[]]
else []
recourse ys n xt =
let n1 = pred n
in liftM2 (:) ys (recourse ys n1 xt) ++
case xt of
[] -> []
(x:xs) -> map (x:) (recourse (ys++[x]) n1 xs)
in recourse []
setPartitions :: Int -> [a] -> [[[a]]]
setPartitions 0 xs =
if null xs
then [[]]
else [ ]
setPartitions _ [] = []
setPartitions 1 xs = [[xs]]
setPartitions k (x:xs) =
do (rest, choosen) <- partitions xs
part <- setPartitions (pred k) rest
return ((x:choosen) : part)
chooseFromIndex :: Integral a => a -> a -> a -> [Bool]
chooseFromIndex n 0 _ = genericReplicate n False
chooseFromIndex n k i =
let n1 = pred n
p = binomial n1 k
b = i>=p
in b :
if b
then chooseFromIndex n1 (pred k) (ip)
else chooseFromIndex n1 k i
chooseFromIndexList :: Integral a => a -> a -> a -> [Bool]
chooseFromIndexList n k0 i0 =
snd $
mapAccumL
(\(k,i) bins ->
let p = genericIndex (bins++[0]) k
b = i>=p
in (if b
then (pred k, ip)
else (k, i),
b))
(k0,i0) $
reverse $
genericTake n binomials
chooseFromIndexMaybe :: Int -> Int -> Int -> Maybe [Bool]
chooseFromIndexMaybe n k i =
toMaybe
(0 <= i && i < binomial n k)
(chooseFromIndex n k i)
chooseToIndex :: Integral a => [Bool] -> (a, a, a)
chooseToIndex =
foldl
(\(n,k0,i0) (bins,b) ->
let (k1,i1) = if b then (succ k0, i0 + genericIndex (bins++[0]) k1) else (k0,i0)
in (succ n, k1, i1))
(0,0,0) .
zip binomials .
reverse
factorial :: Integral a => a -> a
factorial n = product [1..n]
binomial :: Integral a => a -> a -> a
binomial n k =
let bino n' k' =
if k'<0
then 0
else genericIndex (binomialSeq n') k'
in if n<2*k
then bino n (nk)
else bino n k
binomialSeq :: Integral a => a -> [a]
binomialSeq n =
scanl (\acc (num,den) -> div (acc*num) den) 1
(zip [n, pred n ..] [1..n])
binomialGen :: (Integral a, Fractional b) => b -> a -> b
binomialGen n k = genericIndex (binomialSeqGen n) k
binomialSeqGen :: (Fractional b) => b -> [b]
binomialSeqGen n =
scanl (\acc (num,den) -> acc*num / den) 1
(zip (iterate (subtract 1) n) (iterate (1+) 1))
multinomial :: Integral a => [a] -> a
multinomial =
product . mapAdjacent binomial . scanr1 (+)
factorials :: Num a => [a]
factorials = scanl (*) 1 (iterate (+1) 1)
binomials :: Num a => [[a]]
binomials =
let conv11 x = zipWith (+) ([0]++x) (x++[0])
in iterate conv11 [1]
catalanNumber :: Integer -> Integer
catalanNumber n =
let (c,r) = divMod (binomial (2*n) n) (n+1)
in if r==0
then c
else error "catalanNumber: Integer implementation broken"
catalanNumbers :: Num a => [a]
catalanNumbers =
let xs = 1 : PowerSeries.mul xs xs
in xs
derangementNumber :: Integer -> Integer
derangementNumber n =
sum (scanl (*) ((1) ^ mod n 2) [n,1n..(1)])
derangementNumbers :: Num a => [a]
derangementNumbers =
let xs = PowerSeries.add
(cycle [1,1])
(0 : PowerSeries.differentiate (0 : xs))
in xs
derangementNumbersAlt :: Num a => [a]
derangementNumbersAlt =
let xs =
1 : 0 :
PowerSeries.differentiate
(PowerSeries.add xs (0 : xs))
in xs
derangementNumbersInclExcl :: Num a => [a]
derangementNumbersInclExcl =
let xs = zipWith () factorials (map (scalarProduct xs . init) binomials)
in xs
setPartitionNumbers :: Num a => [[a]]
setPartitionNumbers =
iterate (\x -> 0 : PowerSeries.add x (PowerSeries.differentiate x)) [1]
surjectiveMappingNumber :: Integer -> Integer -> Integer
surjectiveMappingNumber n k =
foldl subtract 0 $
zipWith (*)
(map (^n) [0..])
(binomialSeq k)
surjectiveMappingNumbers :: Num a => [[a]]
surjectiveMappingNumbers =
iterate
(\x -> 0 : PowerSeries.differentiate
(PowerSeries.add x (0 : x))) [1]
surjectiveMappingNumbersStirling :: Num a => [[a]]
surjectiveMappingNumbersStirling =
map (zipWith (*) factorials) setPartitionNumbers
fiboMul ::
(Integer,Integer,Integer) ->
(Integer,Integer,Integer) ->
(Integer,Integer,Integer)
fiboMul (f0,f1,f2) (g0,g1,g2) =
let h0 = f0*g0 + f1*g1
h1 = f0*g1 + f1*g2
h2 = f1*g1 + f2*g2
in (h0,h1,h2)
fibonacciNumber :: Integer -> Integer
fibonacciNumber x =
let aux 0 = (1,0,1)
aux (1) = (1,1,0)
aux n =
let (m,r) = divMod n 2
f = aux m
f2 = fiboMul f f
in if r==0
then f2
else fiboMul (0,1,1) f2
(_,y,_) = aux x
in y
fibonacciNumbers :: [Integer]
fibonacciNumbers =
let xs = 0 : ys
ys = 1 : zipWith (+) xs ys
in xs
allCycles :: [a] -> [[a]]
allCycles x =
Match.take x (map (Match.take x) (iterate tail (cycle x)))