module Combinatorics (
permute,
permuteFast,
permuteShare,
permuteRep,
choose,
variateRep,
variate,
tuples,
partitions,
rectifications,
setPartitions,
chooseUnrank,
chooseUnrankMaybe,
chooseRank,
factorial,
binomial,
binomialSeq,
binomialGen,
binomialSeqGen,
multinomial,
factorials,
binomials,
catalanNumber,
catalanNumbers,
derangementNumber,
derangementNumbers,
setPartitionNumbers,
surjectiveMappingNumber,
surjectiveMappingNumbers,
fibonacciNumber,
fibonacciNumbers,
) where
import qualified PowerSeries
import qualified Combinatorics.Private as Comb
import Data.Function.HT (nest, )
import Data.Maybe.HT (toMaybe, )
import Data.Tuple.HT (mapFst, )
import qualified Data.List.Match as Match
import Data.List.HT (mapAdjacent, removeEach, )
import Data.List (genericIndex, )
import Control.Monad (liftM2, )
permute :: [a] -> [[a]]
permute = Comb.permuteRec
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)
permuteRep :: [(a,Int)] -> [[a]]
permuteRep = Comb.permuteRep
choose :: Int -> Int -> [[Bool]]
choose = Comb.chooseRec
variateRep :: Int -> [a] -> [[a]]
variateRep = Comb.variateRep
variate :: Int -> [a] -> [[a]]
variate = Comb.variateRec
tuples :: Int -> [a] -> [[a]]
tuples = Comb.tuplesRec
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)
chooseUnrank :: Integral a => a -> a -> a -> [Bool]
chooseUnrank = Comb.chooseUnrankRec
chooseUnrankMaybe :: Int -> Int -> Int -> Maybe [Bool]
chooseUnrankMaybe n k i =
toMaybe
(0 <= i && i < binomial n k)
(chooseUnrank n k i)
chooseRank :: Integral a => [Bool] -> (a, a, a)
chooseRank =
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 = Comb.binomial
binomialSeq :: Integral a => a -> [a]
binomialSeq = Comb.binomialSeq
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 = Comb.factorials
binomials :: Num a => [[a]]
binomials = Comb.binomials
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,1-n..(-1)])
derangementNumbers :: Num a => [a]
derangementNumbers = Comb.derangementNumbersPS0
setPartitionNumbers :: Num a => [[a]]
setPartitionNumbers = Comb.setPartitionNumbers
surjectiveMappingNumber :: Integer -> Integer -> Integer
surjectiveMappingNumber n k =
foldl subtract 0 $
zipWith (*)
(map (^n) [0..])
(binomialSeq k)
surjectiveMappingNumbers :: Num a => [[a]]
surjectiveMappingNumbers = Comb.surjectiveMappingNumbersPS
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)))