packages feed

combinat 0.2.8.2 → 0.2.9.0

raw patch · 30 files changed

+3556/−766 lines, 30 filesdep +tastydep +tasty-hunitdep +tasty-quickcheckdep ~basedep ~containersPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: tasty, tasty-hunit, tasty-quickcheck

Dependency ranges changed: base, containers

API changes (from Hackage documentation)

- Math.Combinat.Groups.Braid: instance GHC.TypeLits.KnownNat n => Math.Combinat.ASCII.DrawASCII (Math.Combinat.Groups.Braid.Braid n)
- Math.Combinat.Numbers: bellNumber :: Integral a => a -> Integer
- Math.Combinat.Numbers: bellNumbersArray :: Integral a => a -> Array Int Integer
- Math.Combinat.Numbers: bernoulli :: Integral a => a -> Rational
- Math.Combinat.Numbers: binomial :: Integral a => a -> a -> Integer
- Math.Combinat.Numbers: catalan :: Integral a => a -> Integer
- Math.Combinat.Numbers: catalanTriangle :: Integral a => a -> a -> Integer
- Math.Combinat.Numbers: doubleFactorial :: Integral a => a -> Integer
- Math.Combinat.Numbers: factorial :: Integral a => a -> Integer
- Math.Combinat.Numbers: multinomial :: Integral a => [a] -> Integer
- Math.Combinat.Numbers: pascalRow :: Integral a => a -> [Integer]
- Math.Combinat.Numbers: signedBinomial :: Int -> Int -> Integer
- Math.Combinat.Numbers: signedStirling1st :: Integral a => a -> a -> Integer
- Math.Combinat.Numbers: signedStirling1stArray :: Integral a => a -> Array Int Integer
- Math.Combinat.Numbers: stirling2nd :: Integral a => a -> a -> Integer
- Math.Combinat.Numbers: unsignedStirling1st :: Integral a => a -> a -> Integer
- Math.Combinat.Numbers.Primes: ceilingLog2 :: Integer -> Integer
- Math.Combinat.Numbers.Primes: ceilingSquareRoot :: Integer -> Integer
- Math.Combinat.Numbers.Primes: integerLog2 :: Integer -> Integer
- Math.Combinat.Numbers.Primes: integerSquareRoot :: Integer -> Integer
- Math.Combinat.Numbers.Primes: integerSquareRoot' :: Integer -> (Integer, Integer)
- Math.Combinat.Numbers.Primes: integerSquareRootNewton' :: Integer -> (Integer, Integer)
- Math.Combinat.Numbers.Primes: isSquare :: Integer -> Bool
- Math.Combinat.Numbers.Series: integralLagrangeInversion :: (Eq a, Num a) => [a] -> [a]
- Math.Combinat.Partitions.Integer: Pair :: !Int -> !Int -> Pair
- Math.Combinat.Partitions.Integer: Partition :: [Int] -> Partition
- Math.Combinat.Partitions.Integer: _allSubPartitions :: [Int] -> [[Int]]
- Math.Combinat.Partitions.Integer: _countAutomorphisms :: [Int] -> Integer
- Math.Combinat.Partitions.Integer: _dominatedPartitions :: [Int] -> [[Int]]
- Math.Combinat.Partitions.Integer: _dominatingPartitions :: [Int] -> [[Int]]
- Math.Combinat.Partitions.Integer: _dualPartition :: [Int] -> [Int]
- Math.Combinat.Partitions.Integer: _dualPartitionNaive :: [Int] -> [Int]
- Math.Combinat.Partitions.Integer: _elements :: [Int] -> [(Int, Int)]
- Math.Combinat.Partitions.Integer: _partitions :: Int -> [[Int]]
- Math.Combinat.Partitions.Integer: _partitions' :: (Int, Int) -> Int -> [[Int]]
- Math.Combinat.Partitions.Integer: _subPartitions :: Int -> [Int] -> [[Int]]
- Math.Combinat.Partitions.Integer: _superPartitions :: Int -> [Int] -> [[Int]]
- Math.Combinat.Partitions.Integer: _toExponentialForm :: [Int] -> [(Int, Int)]
- Math.Combinat.Partitions.Integer: countAutomorphisms :: Partition -> Integer
- Math.Combinat.Partitions.Integer: countPartitionsNaive :: Int -> Integer
- Math.Combinat.Partitions.Integer: data Pair
- Math.Combinat.Partitions.Integer: diffSequence :: [Int] -> [Int]
- Math.Combinat.Partitions.Integer: dominates :: Partition -> Partition -> Bool
- Math.Combinat.Partitions.Integer: dualPartition :: Partition -> Partition
- Math.Combinat.Partitions.Integer: dualPieriRule :: Partition -> Int -> [Partition]
- Math.Combinat.Partitions.Integer: elements :: Partition -> [(Int, Int)]
- Math.Combinat.Partitions.Integer: emptyPartition :: Partition
- Math.Combinat.Partitions.Integer: fromExponentialFrom :: [(Int, Int)] -> Partition
- Math.Combinat.Partitions.Integer: heightWidth :: Partition -> (Int, Int)
- Math.Combinat.Partitions.Integer: instance GHC.Classes.Eq Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance GHC.Classes.Ord Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance GHC.Read.Read Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance GHC.Show.Show Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance Math.Combinat.ASCII.DrawASCII Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance Math.Combinat.Classes.CanBeEmpty Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance Math.Combinat.Classes.HasDuality Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance Math.Combinat.Classes.HasHeight Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance Math.Combinat.Classes.HasNumberOfParts Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance Math.Combinat.Classes.HasWeight Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: instance Math.Combinat.Classes.HasWidth Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Partitions.Integer: isEmptyPartition :: Partition -> Bool
- Math.Combinat.Partitions.Integer: isSubPartitionOf :: Partition -> Partition -> Bool
- Math.Combinat.Partitions.Integer: isSuperPartitionOf :: Partition -> Partition -> Bool
- Math.Combinat.Partitions.Integer: newtype Partition
- Math.Combinat.Partitions.Integer: partitionCountList :: [Integer]
- Math.Combinat.Partitions.Integer: partitionCountListNaive :: [Integer]
- Math.Combinat.Partitions.Integer: partitionHeight :: Partition -> Int
- Math.Combinat.Partitions.Integer: partitionWeight :: Partition -> Int
- Math.Combinat.Partitions.Integer: partitionWidth :: Partition -> Int
- Math.Combinat.Partitions.Integer: pieriRule :: Partition -> Int -> [Partition]
- Math.Combinat.Partitions.Integer: toExponentialForm :: Partition -> [(Int, Int)]
- Math.Combinat.Tableaux: instance Math.Combinat.Classes.HasShape (Math.Combinat.Tableaux.Tableau a) Math.Combinat.Partitions.Integer.Partition
- Math.Combinat.Trees.Binary: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Math.Combinat.Trees.Binary.BinTree' a b)
- Math.Combinat.Trees.Binary: instance (GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (Math.Combinat.Trees.Binary.BinTree' a b)
- Math.Combinat.Trees.Binary: instance (GHC.Read.Read a, GHC.Read.Read b) => GHC.Read.Read (Math.Combinat.Trees.Binary.BinTree' a b)
- Math.Combinat.Trees.Binary: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Math.Combinat.Trees.Binary.BinTree' a b)
- Math.Combinat.TypeLevel: data Proxy k (t :: k) :: forall k. k -> *
+ Math.Combinat.Groups.Braid: instance GHC.TypeNats.KnownNat n => Math.Combinat.ASCII.DrawASCII (Math.Combinat.Groups.Braid.Braid n)
+ Math.Combinat.Helper: interleave :: [a] -> [a] -> [a]
+ Math.Combinat.Helper: reverseComparing :: Ord b => (a -> b) -> a -> a -> Ordering
+ Math.Combinat.Numbers.Integers: ceilingLog2 :: Integer -> Integer
+ Math.Combinat.Numbers.Integers: ceilingSquareRoot :: Integer -> Integer
+ Math.Combinat.Numbers.Integers: integerLog2 :: Integer -> Integer
+ Math.Combinat.Numbers.Integers: integerSquareRoot :: Integer -> Integer
+ Math.Combinat.Numbers.Integers: integerSquareRoot' :: Integer -> (Integer, Integer)
+ Math.Combinat.Numbers.Integers: integerSquareRootNewton' :: Integer -> (Integer, Integer)
+ Math.Combinat.Numbers.Integers: isSquare :: Integer -> Bool
+ Math.Combinat.Numbers.Sequences: bellNumber :: Integral a => a -> Integer
+ Math.Combinat.Numbers.Sequences: bellNumbersArray :: Integral a => a -> Array Int Integer
+ Math.Combinat.Numbers.Sequences: bernoulli :: Integral a => a -> Rational
+ Math.Combinat.Numbers.Sequences: binomial :: Integral a => a -> a -> Integer
+ Math.Combinat.Numbers.Sequences: catalan :: Integral a => a -> Integer
+ Math.Combinat.Numbers.Sequences: catalanTriangle :: Integral a => a -> a -> Integer
+ Math.Combinat.Numbers.Sequences: doubleFactorial :: Integral a => a -> Integer
+ Math.Combinat.Numbers.Sequences: factorial :: Integral a => a -> Integer
+ Math.Combinat.Numbers.Sequences: multinomial :: Integral a => [a] -> Integer
+ Math.Combinat.Numbers.Sequences: pascalRow :: Integral a => a -> [Integer]
+ Math.Combinat.Numbers.Sequences: signedBinomial :: Int -> Int -> Integer
+ Math.Combinat.Numbers.Sequences: signedStirling1st :: Integral a => a -> a -> Integer
+ Math.Combinat.Numbers.Sequences: signedStirling1stArray :: Integral a => a -> Array Int Integer
+ Math.Combinat.Numbers.Sequences: stirling2nd :: Integral a => a -> a -> Integer
+ Math.Combinat.Numbers.Sequences: unsignedStirling1st :: Integral a => a -> a -> Integer
+ Math.Combinat.Numbers.Series: composeSeriesNaive :: (Eq a, Num a) => [a] -> [a] -> [a]
+ Math.Combinat.Numbers.Series: cosSeries2 :: Fractional a => [a]
+ Math.Combinat.Numbers.Series: differentiateSeries :: Num a => [a] -> [a]
+ Math.Combinat.Numbers.Series: divSeries :: (Eq a, Fractional a) => [a] -> [a] -> [a]
+ Math.Combinat.Numbers.Series: integralLagrangeInversionNaive :: (Eq a, Num a) => [a] -> [a]
+ Math.Combinat.Numbers.Series: integrateSeries :: Fractional a => [a] -> [a]
+ Math.Combinat.Numbers.Series: lagrangeInversionNaive :: (Eq a, Fractional a) => [a] -> [a]
+ Math.Combinat.Numbers.Series: mulSeriesNaive :: Num a => [a] -> [a] -> [a]
+ Math.Combinat.Numbers.Series: sinSeries2 :: Fractional a => [a]
+ Math.Combinat.Numbers.Series: substituteNaive :: (Eq a, Num a) => [a] -> [a] -> [a]
+ Math.Combinat.Partitions.Integer: data Partition
+ Math.Combinat.Partitions.Integer: instance Math.Combinat.ASCII.DrawASCII Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer: sumOfPartitions :: Partition -> Partition -> Partition
+ Math.Combinat.Partitions.Integer: unionOfPartitions :: Partition -> Partition -> Partition
+ Math.Combinat.Partitions.Integer.Compact: Medium1 :: {-# UNPACK #-} !Word64 -> Partition
+ Math.Combinat.Partitions.Integer.Compact: Medium2 :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> Partition
+ Math.Combinat.Partitions.Integer.Compact: Medium3 :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> Partition
+ Math.Combinat.Partitions.Integer.Compact: Medium4 :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> Partition
+ Math.Combinat.Partitions.Integer.Compact: Nibble :: {-# UNPACK #-} !Word64 -> Partition
+ Math.Combinat.Partitions.Integer.Compact: WordList :: {-# UNPACK #-} !Int -> ![Word64] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: c_dual_nibble :: Word64 -> Word64
+ Math.Combinat.Partitions.Integer.Compact: cmp :: Partition -> Partition -> Ordering
+ Math.Combinat.Partitions.Integer.Compact: cons :: Int -> Partition -> Partition
+ Math.Combinat.Partitions.Integer.Compact: data Partition
+ Math.Combinat.Partitions.Integer.Compact: diffSequence :: Partition -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: dominates :: Partition -> Partition -> Bool
+ Math.Combinat.Partitions.Integer.Compact: dualPartition :: Partition -> Partition
+ Math.Combinat.Partitions.Integer.Compact: empty :: Partition
+ Math.Combinat.Partitions.Integer.Compact: fromDescList :: [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: fromDescList' :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: fromExponentialForm :: [(Int, Int)] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: height :: Partition -> Int
+ Math.Combinat.Partitions.Integer.Compact: i2w :: Int -> Word64
+ Math.Combinat.Partitions.Integer.Compact: instance GHC.Classes.Eq Math.Combinat.Partitions.Integer.Compact.Partition
+ Math.Combinat.Partitions.Integer.Compact: instance GHC.Classes.Ord Math.Combinat.Partitions.Integer.Compact.Partition
+ Math.Combinat.Partitions.Integer.Compact: instance GHC.Show.Show Math.Combinat.Partitions.Integer.Compact.Partition
+ Math.Combinat.Partitions.Integer.Compact: isEmpty :: Partition -> Bool
+ Math.Combinat.Partitions.Integer.Compact: isSubPartitionOf :: Partition -> Partition -> Bool
+ Math.Combinat.Partitions.Integer.Compact: makeMedium :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: makeMedium1 :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: makeMedium2 :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: makeMedium3 :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: makeMedium4 :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: makeNibble :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: makeWordList :: Int -> [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Compact: partitionPrefixChar :: Partition -> Char
+ Math.Combinat.Partitions.Integer.Compact: partitionTail :: Partition -> Partition
+ Math.Combinat.Partitions.Integer.Compact: pieriRule :: Partition -> Int -> [Partition]
+ Math.Combinat.Partitions.Integer.Compact: pieriRuleSingleBox :: Partition -> [Partition]
+ Math.Combinat.Partitions.Integer.Compact: reverseDiffSequence :: Partition -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: safeTail :: [Int] -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: singleton :: Int -> Partition
+ Math.Combinat.Partitions.Integer.Compact: snoc :: Partition -> Int -> Partition
+ Math.Combinat.Partitions.Integer.Compact: sum' :: [Word64] -> Word64
+ Math.Combinat.Partitions.Integer.Compact: toAscList :: Partition -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: toDescList :: Partition -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: toExponentialForm :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Integer.Compact: toList :: Partition -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: toOne :: Int -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: toZero :: Int -> [Int]
+ Math.Combinat.Partitions.Integer.Compact: uncons :: Partition -> Maybe (Int, Partition)
+ Math.Combinat.Partitions.Integer.Compact: w2i :: Word64 -> Int
+ Math.Combinat.Partitions.Integer.Compact: width :: Partition -> Int
+ Math.Combinat.Partitions.Integer.Compact: widthHeight :: Partition -> (Int, Int)
+ Math.Combinat.Partitions.Integer.Count: TableOfIntegers :: [Array Int Integer] -> TableOfIntegers
+ Math.Combinat.Partitions.Integer.Count: countAllPartitions :: Int -> Integer
+ Math.Combinat.Partitions.Integer.Count: countAllPartitions' :: (Int, Int) -> Integer
+ Math.Combinat.Partitions.Integer.Count: countPartitions :: Int -> Integer
+ Math.Combinat.Partitions.Integer.Count: countPartitions' :: (Int, Int) -> Int -> Integer
+ Math.Combinat.Partitions.Integer.Count: countPartitionsInfiniteProduct :: Int -> Integer
+ Math.Combinat.Partitions.Integer.Count: countPartitionsNaive :: Int -> Integer
+ Math.Combinat.Partitions.Integer.Count: countPartitionsWithKParts :: Int -> Int -> Integer
+ Math.Combinat.Partitions.Integer.Count: lookupInteger :: TableOfIntegers -> Int -> Integer
+ Math.Combinat.Partitions.Integer.Count: makeTableOfIntegers :: ((Int -> Integer) -> (Int -> Integer)) -> TableOfIntegers
+ Math.Combinat.Partitions.Integer.Count: newtype TableOfIntegers
+ Math.Combinat.Partitions.Integer.Count: partitionCountList :: [Integer]
+ Math.Combinat.Partitions.Integer.Count: partitionCountListInfiniteProduct :: [Integer]
+ Math.Combinat.Partitions.Integer.Count: partitionCountListNaive :: [Integer]
+ Math.Combinat.Partitions.Integer.Count: partitionCountTable :: TableOfIntegers
+ Math.Combinat.Partitions.Integer.IntList: _allPartitions :: Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _allPartitionsGrouped :: Int -> [[[Int]]]
+ Math.Combinat.Partitions.Integer.IntList: _allSubPartitions :: [Int] -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _diffSequence :: [Int] -> [Int]
+ Math.Combinat.Partitions.Integer.IntList: _dominatedPartitions :: [Int] -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _dominates :: [Int] -> [Int] -> Bool
+ Math.Combinat.Partitions.Integer.IntList: _dominatingPartitions :: [Int] -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _dualPartition :: [Int] -> [Int]
+ Math.Combinat.Partitions.Integer.IntList: _dualPartitionNaive :: [Int] -> [Int]
+ Math.Combinat.Partitions.Integer.IntList: _dualPieriRule :: [Int] -> Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _elements :: [Int] -> [(Int, Int)]
+ Math.Combinat.Partitions.Integer.IntList: _fromExponentialForm :: [(Int, Int)] -> [Int]
+ Math.Combinat.Partitions.Integer.IntList: _isPartition :: [Int] -> Bool
+ Math.Combinat.Partitions.Integer.IntList: _isSubPartitionOf :: [Int] -> [Int] -> Bool
+ Math.Combinat.Partitions.Integer.IntList: _isSuperPartitionOf :: [Int] -> [Int] -> Bool
+ Math.Combinat.Partitions.Integer.IntList: _mkPartition :: [Int] -> [Int]
+ Math.Combinat.Partitions.Integer.IntList: _partitions :: Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _partitions' :: (Int, Int) -> Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _partitionsWithDistinctParts :: Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _partitionsWithKParts :: Int -> Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _partitionsWithOddParts :: Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _pieriRule :: [Int] -> Int -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _randomPartition :: RandomGen g => Int -> g -> ([Int], g)
+ Math.Combinat.Partitions.Integer.IntList: _randomPartitions :: forall g. RandomGen g => Int -> Int -> g -> ([[Int]], g)
+ Math.Combinat.Partitions.Integer.IntList: _subPartitions :: Int -> [Int] -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _superPartitions :: Int -> [Int] -> [[Int]]
+ Math.Combinat.Partitions.Integer.IntList: _toExponentialForm :: [Int] -> [(Int, Int)]
+ Math.Combinat.Partitions.Integer.Naive: Partition :: [Int] -> Partition
+ Math.Combinat.Partitions.Integer.Naive: diffSequence :: Partition -> [Int]
+ Math.Combinat.Partitions.Integer.Naive: dominates :: Partition -> Partition -> Bool
+ Math.Combinat.Partitions.Integer.Naive: dualPartition :: Partition -> Partition
+ Math.Combinat.Partitions.Integer.Naive: dualPieriRule :: Partition -> Int -> [Partition]
+ Math.Combinat.Partitions.Integer.Naive: elements :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Integer.Naive: emptyPartition :: Partition
+ Math.Combinat.Partitions.Integer.Naive: fromExponentialForm :: [(Int, Int)] -> Partition
+ Math.Combinat.Partitions.Integer.Naive: heightWidth :: Partition -> (Int, Int)
+ Math.Combinat.Partitions.Integer.Naive: instance GHC.Classes.Eq Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance GHC.Classes.Ord Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance GHC.Read.Read Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance GHC.Show.Show Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance Math.Combinat.Classes.CanBeEmpty Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance Math.Combinat.Classes.HasDuality Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance Math.Combinat.Classes.HasHeight Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance Math.Combinat.Classes.HasNumberOfParts Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance Math.Combinat.Classes.HasWeight Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: instance Math.Combinat.Classes.HasWidth Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Partitions.Integer.Naive: isEmptyPartition :: Partition -> Bool
+ Math.Combinat.Partitions.Integer.Naive: isSubPartitionOf :: Partition -> Partition -> Bool
+ Math.Combinat.Partitions.Integer.Naive: isSuperPartitionOf :: Partition -> Partition -> Bool
+ Math.Combinat.Partitions.Integer.Naive: newtype Partition
+ Math.Combinat.Partitions.Integer.Naive: partitionHeight :: Partition -> Int
+ Math.Combinat.Partitions.Integer.Naive: partitionWeight :: Partition -> Int
+ Math.Combinat.Partitions.Integer.Naive: partitionWidth :: Partition -> Int
+ Math.Combinat.Partitions.Integer.Naive: pieriRule :: Partition -> Int -> [Partition]
+ Math.Combinat.Partitions.Integer.Naive: toDescList :: Partition -> [Int]
+ Math.Combinat.Partitions.Integer.Naive: toExponentialForm :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Integer.Naive: unconsPartition :: Partition -> Maybe (Int, Partition)
+ Math.Combinat.Partitions.Skew: skewPartitionElements :: SkewPartition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: BorderBox :: !Bool -> !Bool -> !Int -> !Int -> BorderBox
+ Math.Combinat.Partitions.Skew.Ribbon: Ribbon :: SkewPartition -> Int -> Int -> Int -> Ribbon
+ Math.Combinat.Partitions.Skew.Ribbon: [_canEndStrip] :: BorderBox -> !Bool
+ Math.Combinat.Partitions.Skew.Ribbon: [_canStartStrip] :: BorderBox -> !Bool
+ Math.Combinat.Partitions.Skew.Ribbon: [_xCoord] :: BorderBox -> !Int
+ Math.Combinat.Partitions.Skew.Ribbon: [_yCoord] :: BorderBox -> !Int
+ Math.Combinat.Partitions.Skew.Ribbon: [rbHeight] :: Ribbon -> Int
+ Math.Combinat.Partitions.Skew.Ribbon: [rbLength] :: Ribbon -> Int
+ Math.Combinat.Partitions.Skew.Ribbon: [rbShape] :: Ribbon -> SkewPartition
+ Math.Combinat.Partitions.Skew.Ribbon: [rbWidth] :: Ribbon -> Int
+ Math.Combinat.Partitions.Skew.Ribbon: annotatedInnerBorderStrip :: Partition -> [BorderBox]
+ Math.Combinat.Partitions.Skew.Ribbon: annotatedOuterBorderStrip :: Partition -> [BorderBox]
+ Math.Combinat.Partitions.Skew.Ribbon: cornerBoxSequence :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: data BorderBox
+ Math.Combinat.Partitions.Skew.Ribbon: data Ribbon
+ Math.Combinat.Partitions.Skew.Ribbon: extendedCornerSequence :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: extendedInnerCorners :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: innerCornerBoxes :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: innerCornerBoxesNaive :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: innerRibbons :: Partition -> [Ribbon]
+ Math.Combinat.Partitions.Skew.Ribbon: innerRibbonsNaive :: Partition -> [Ribbon]
+ Math.Combinat.Partitions.Skew.Ribbon: innerRibbonsOfLength :: Partition -> Int -> [Ribbon]
+ Math.Combinat.Partitions.Skew.Ribbon: innerRibbonsOfLengthNaive :: Partition -> Int -> [Ribbon]
+ Math.Combinat.Partitions.Skew.Ribbon: instance GHC.Classes.Eq Math.Combinat.Partitions.Skew.Ribbon.Ribbon
+ Math.Combinat.Partitions.Skew.Ribbon: instance GHC.Classes.Ord Math.Combinat.Partitions.Skew.Ribbon.Ribbon
+ Math.Combinat.Partitions.Skew.Ribbon: instance GHC.Show.Show Math.Combinat.Partitions.Skew.Ribbon.BorderBox
+ Math.Combinat.Partitions.Skew.Ribbon: instance GHC.Show.Show Math.Combinat.Partitions.Skew.Ribbon.Ribbon
+ Math.Combinat.Partitions.Skew.Ribbon: isRibbon :: SkewPartition -> Bool
+ Math.Combinat.Partitions.Skew.Ribbon: listHooks :: Int -> [Partition]
+ Math.Combinat.Partitions.Skew.Ribbon: outerCornerBoxes :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: outerCornerBoxesNaive :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: outerCorners :: Partition -> [(Int, Int)]
+ Math.Combinat.Partitions.Skew.Ribbon: outerRibbonsOfLength :: Partition -> Int -> [Ribbon]
+ Math.Combinat.Partitions.Skew.Ribbon: outerRibbonsOfLengthNaive :: Partition -> Int -> [Ribbon]
+ Math.Combinat.Partitions.Skew.Ribbon: toRibbon :: SkewPartition -> Maybe Ribbon
+ Math.Combinat.Permutations: concatPermutations :: Permutation -> Permutation -> Permutation
+ Math.Combinat.Permutations: sortingPermutationAsc :: Ord a => [a] -> Permutation
+ Math.Combinat.Permutations: sortingPermutationDesc :: Ord a => [a] -> Permutation
+ Math.Combinat.Sets.VennDiagrams: VennDiagram :: Map [Bool] a -> VennDiagram a
+ Math.Combinat.Sets.VennDiagrams: [vennTable] :: VennDiagram a -> Map [Bool] a
+ Math.Combinat.Sets.VennDiagrams: asciiVennDiagram :: Show a => VennDiagram a -> ASCII
+ Math.Combinat.Sets.VennDiagrams: enumerateVennDiagrams :: [Int] -> [VennDiagram Int]
+ Math.Combinat.Sets.VennDiagrams: instance GHC.Classes.Eq a => GHC.Classes.Eq (Math.Combinat.Sets.VennDiagrams.VennDiagram a)
+ Math.Combinat.Sets.VennDiagrams: instance GHC.Classes.Ord a => GHC.Classes.Ord (Math.Combinat.Sets.VennDiagrams.VennDiagram a)
+ Math.Combinat.Sets.VennDiagrams: instance GHC.Show.Show a => GHC.Show.Show (Math.Combinat.Sets.VennDiagrams.VennDiagram a)
+ Math.Combinat.Sets.VennDiagrams: instance GHC.Show.Show a => Math.Combinat.ASCII.DrawASCII (Math.Combinat.Sets.VennDiagrams.VennDiagram a)
+ Math.Combinat.Sets.VennDiagrams: isTrivialVennDiagram :: VennDiagram Int -> Bool
+ Math.Combinat.Sets.VennDiagrams: newtype VennDiagram a
+ Math.Combinat.Sets.VennDiagrams: prettyVennDiagram :: Show a => VennDiagram a -> String
+ Math.Combinat.Sets.VennDiagrams: printVennDiagram :: Show a => VennDiagram a -> IO ()
+ Math.Combinat.Sets.VennDiagrams: unsafeMakeVennDiagram :: [([Bool], a)] -> VennDiagram a
+ Math.Combinat.Sets.VennDiagrams: vennDiagramNumberOfNonemptyZones :: VennDiagram Int -> Int
+ Math.Combinat.Sets.VennDiagrams: vennDiagramNumberOfSets :: VennDiagram a -> Int
+ Math.Combinat.Sets.VennDiagrams: vennDiagramNumberOfZones :: VennDiagram a -> Int
+ Math.Combinat.Sets.VennDiagrams: vennDiagramSetCardinalities :: VennDiagram Int -> [Int]
+ Math.Combinat.Sign: instance GHC.Base.Semigroup Math.Combinat.Sign.Sign
+ Math.Combinat.Tableaux: instance Math.Combinat.Classes.HasShape (Math.Combinat.Tableaux.Tableau a) Math.Combinat.Partitions.Integer.Naive.Partition
+ Math.Combinat.Trees.Binary: Node :: a -> Forest a -> Tree a
+ Math.Combinat.Trees.Binary: [rootLabel] :: Tree a -> a
+ Math.Combinat.Trees.Binary: [subForest] :: Tree a -> Forest a
+ Math.Combinat.Trees.Binary: data Tree a
+ Math.Combinat.Trees.Binary: instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Math.Combinat.Trees.Binary.BinTree' a b)
+ Math.Combinat.Trees.Binary: instance (GHC.Classes.Ord b, GHC.Classes.Ord a) => GHC.Classes.Ord (Math.Combinat.Trees.Binary.BinTree' a b)
+ Math.Combinat.Trees.Binary: instance (GHC.Read.Read b, GHC.Read.Read a) => GHC.Read.Read (Math.Combinat.Trees.Binary.BinTree' a b)
+ Math.Combinat.Trees.Binary: instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Math.Combinat.Trees.Binary.BinTree' a b)
+ Math.Combinat.Trees.Binary: type Forest a = [Tree a]
+ Math.Combinat.TypeLevel: data Proxy (t :: k) :: forall k. () => k -> *
- Math.Combinat.Trees.Nary: data Tree a :: * -> *
+ Math.Combinat.Trees.Nary: data Tree a
- Math.Combinat.TypeLevel: Proxy :: Proxy k
+ Math.Combinat.TypeLevel: Proxy :: Proxy
- Math.Combinat.TypeLevel: asProxyTypeOf :: a -> Proxy * a -> a
+ Math.Combinat.TypeLevel: asProxyTypeOf :: () => a -> proxy a -> a

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2008-2016, Balazs Komuves+Copyright (c) 2008-2018, Balazs Komuves All rights reserved.  Redistribution and use in source and binary forms, with or without
Math/Combinat/Helper.hs view
@@ -52,6 +52,12 @@ sum' :: Num a => [a] -> a sum' = foldl' (+) 0 +interleave :: [a] -> [a] -> [a]+interleave (x:xs) (y:ys) = x : y : interleave xs ys+interleave [x]    []     = x : []+interleave []     []     = []+interleave _      _      = error "interleave: shouldn't happen"+ -------------------------------------------------------------------------------- -- * equality and ordering  @@ -63,8 +69,11 @@ reverseOrdering GT = LT reverseOrdering EQ = EQ +reverseComparing :: Ord b => (a -> b) -> a -> a -> Ordering+reverseComparing f x y = compare (f y) (f x)+ reverseCompare :: Ord a => a -> a -> Ordering-reverseCompare x y = reverseOrdering $ compare x y+reverseCompare x y = compare y x   -- reverseOrdering $ compare x y  reverseSort :: Ord a => [a] -> [a] reverseSort = sortBy reverseCompare
Math/Combinat/Numbers.hs view
@@ -1,194 +1,9 @@ --- | A few important number sequences. ---  --- See the \"On-Line Encyclopedia of Integer Sequences\",--- <https://oeis.org> .--module Math.Combinat.Numbers where------------------------------------------------------------------------------------import Data.Array--import Math.Combinat.Helper ( sum' )-import Math.Combinat.Sign-------------------------------------------------------------------------------------- | A000142.-factorial :: Integral a => a -> Integer-factorial n-  | n <  0    = error "factorial: input should be nonnegative"-  | n == 0    = 1-  | otherwise = product [1..fromIntegral n]---- | A006882.-doubleFactorial :: Integral a => a -> Integer-doubleFactorial n-  | n <  0    = error "doubleFactorial: input should be nonnegative"-  | n == 0    = 1-  | odd n     = product [1,3..fromIntegral n]-  | otherwise = product [2,4..fromIntegral n]---- | A007318. Note: This is zero for @n<0@ or @k<0@; see also 'signedBinomial' below.-binomial :: Integral a => a -> a -> 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---- | The extension of the binomial function to negative inputs. This should satisfy the following properties:------ > for n,k >=0 : signedBinomial n k == binomial n k--- > for any n,k : signedBinomial n k == signedBinomial n (n-k) --- > for k >= 0  : signedBinomial (-n) k == (-1)^k * signedBinomial (n+k-1) k------ Note: This is compatible with Mathematica's @Binomial@ function.----signedBinomial :: Int -> Int -> Integer-signedBinomial n k-  | n >= 0     = binomial n k-  | k >= 0     = negateIfOdd    k  $ binomial (k-n-1)   k  -  | otherwise  = negateIfOdd (n+k) $ binomial (-k-1) (-n-1)--{--test_signed_0 = [ signedBinomial ( n) k == signedBinomial ( n) ( n-k)                | n<-[-30..40] , k<-[-30..40] ]-test_signed_1 = [ signedBinomial (-n) k == signedBinomial (-n) (-n-k)                | n<-[-30..40] , k<-[-30..40] ]-test_signed_2 = [ signedBinomial (-n) k == negateIfOdd k $ signedBinomial (n+k-1) k  | n<-[-30..40] , k<-[0..30] ]--}---- | A given row of the Pascal triangle; equivalent to a sequence of binomial --- numbers, but much more efficient. You can also left-fold over it.------ > pascalRow n == [ binomial n k | k<-[0..n] ]-pascalRow :: Integral a => a -> [Integer]-pascalRow n' = worker 0 1 where-  n = fromIntegral n'-  worker j x-    | j>n   = [] -    | True  = let j'=j+1 in x : worker j' (div (x*(n-j)) j') --multinomial :: Integral a => [a] -> Integer-multinomial xs = div-  (factorial (sum xs))-  (product [ factorial x | x<-xs ])  -  ------------------------------------------------------------------------------------ * Catalan numbers---- | Catalan numbers. OEIS:A000108.-catalan :: Integral a => a -> Integer-catalan n -  | n < 0     = 0-  | otherwise = binomial (n+n) n `div` fromIntegral (n+1)---- | Catalan's triangle. OEIS:A009766.--- Note:------ > catalanTriangle n n == catalan n--- > catalanTriangle n k == countStandardYoungTableaux (toPartition [n,k])----catalanTriangle :: Integral a => a -> a -> Integer-catalanTriangle n k-  | k > n     = 0-  | k < 0     = 0-  | otherwise = (binomial (n+k) n * fromIntegral (n-k+1)) `div` fromIntegral (n+1)------------------------------------------------------------------------------------- * Stirling numbers---- | Rows of (signed) Stirling numbers of the first kind. OEIS:A008275.--- Coefficients of the polinomial @(x-1)*(x-2)*...*(x-n+1)@.--- This function uses the recursion formula.-signedStirling1stArray :: Integral a => a -> Array Int Integer-signedStirling1stArray n-  | n <  1    = error "stirling1stArray: n should be at least 1"-  | n == 1    = listArray (1,1 ) [1]-  | otherwise = listArray (1,n') [ lkp (k-1) - fromIntegral (n-1) * lkp k | k<-[1..n'] ] +module Math.Combinat.Numbers +  ( module Math.Combinat.Numbers.Sequences+  , module Math.Combinat.Numbers.Integers+  )    where-    prev = signedStirling1stArray (n-1)-    n' = fromIntegral n :: Int-    lkp j | j <  1    = 0-          | j >= n'   = 0-          | otherwise = prev ! j -        --- | (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==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-unsignedStirling1st n k = abs (signedStirling1st n k)---- | 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==0 && n==0 = 1-  | k < 1        = 0-  | k > n        = 0-  | otherwise = sum xs `div` factorial k where-      xs = [ negateIfOdd (k-i) $ binomial k i * (fromIntegral i)^n | i<-[0..k] ]------------------------------------------------------------------------------------- * Bernoulli numbers---- | Bernoulli numbers. @bernoulli 1 == -1%2@ and @bernoulli k == 0@ for--- k>2 and /odd/. This function uses the formula involving Stirling numbers--- of the second kind. Numerators: A027641, denominators: A027642.-bernoulli :: Integral a => a -> Rational-bernoulli n -  | n <  0    = error "bernoulli: n should be nonnegative"-  | n == 0    = 1-  | n == 1    = -1/2-  | otherwise = sum [ f k | k<-[1..n] ] -  where-    f k = toRational (negateIfOdd (n+k) $ factorial k * stirling2nd n k) -        / 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------------------------------------------------------------------------------------- +import Math.Combinat.Numbers.Sequences+import Math.Combinat.Numbers.Integers
+ Math/Combinat/Numbers/Integers.hs view
@@ -0,0 +1,113 @@++-- | Operations on integers++module Math.Combinat.Numbers.Integers +  ( -- * Integer logarithm+    integerLog2+  , ceilingLog2+    -- * Integer square root+  , isSquare+  , integerSquareRoot+  , ceilingSquareRoot+  , integerSquareRoot' +  , integerSquareRootNewton'+  )+  where++--------------------------------------------------------------------------------++-- import Math.Combinat.Numbers++import Data.List ( group , sort )+import Data.Bits++import System.Random++--------------------------------------------------------------------------------+-- Integer logarithm++-- | Largest integer @k@ such that @2^k@ is smaller or equal to @n@+integerLog2 :: Integer -> Integer+integerLog2 n = go n where+  go 0 = -1+  go k = 1 + go (shiftR k 1)++-- | Smallest integer @k@ such that @2^k@ is larger or equal to @n@+ceilingLog2 :: Integer -> Integer+ceilingLog2 0 = 0+ceilingLog2 n = 1 + go (n-1) where+  go 0 = -1+  go k = 1 + go (shiftR k 1)+  +--------------------------------------------------------------------------------+-- Integer square root++isSquare :: Integer -> Bool+isSquare n = +  if (fromIntegral $ mod n 32) `elem` rs +    then snd (integerSquareRoot' n) == 0+    else False+  where+    rs = [0,1,4,9,16,17,25] :: [Int]+    +-- | Integer square root (largest integer whose square is smaller or equal to the input)+-- using Newton's method, with a faster (for large numbers) inital guess based on bit shifts.+integerSquareRoot :: Integer -> Integer+integerSquareRoot = fst . integerSquareRoot'++-- | Smallest integer whose square is larger or equal to the input+ceilingSquareRoot :: Integer -> Integer+ceilingSquareRoot n = (if r>0 then u+1 else u) where (u,r) = integerSquareRoot' n ++-- | We also return the excess residue; that is+--+-- > (a,r) = integerSquareRoot' n+-- +-- means that+--+-- > a*a + r = n+-- > a*a <= n < (a+1)*(a+1)+integerSquareRoot' :: Integer -> (Integer,Integer)+integerSquareRoot' n+  | n<0 = error "integerSquareRoot: negative input"+  | n<2 = (n,0)+  | otherwise = go firstGuess +  where+    k = integerLog2 n+    firstGuess = 2^(div (k+2) 2) -- !! note that (div (k+1) 2) is NOT enough !!+    go a = +      if m < a+        then go a' +        else (a, r + a*(m-a))+      where+        (m,r) = divMod n a+        a' = div (m + a) 2++-- | Newton's method without an initial guess. For very small numbers (<10^10) it+-- is somewhat faster than the above version.+integerSquareRootNewton' :: Integer -> (Integer,Integer)+integerSquareRootNewton' n+  | n<0 = error "integerSquareRootNewton: negative input"+  | n<2 = (n,0)+  | otherwise = go (div n 2) +  where+    go a = +      if m < a+        then go a' +        else (a, r + a*(m-a))+      where+        (m,r) = divMod n a+        a' = div (m + a) 2++{-+-- brute force test of integer square root+isqrt_test n1 n2 = +  [ k +  | k<-[n1..n2] +  , let (a,r) = integerSquareRoot' k+  , (a*a+r/=k) || (a*a>k) || (a+1)*(a+1)<=k +  ]+-}++--------------------------------------------------------------------------------+
Math/Combinat/Numbers/Primes.hs view
@@ -9,15 +9,6 @@     -- * Prime factorization   , groupIntegerFactors   , integerFactorsTrialDivision-    -- * Integer logarithm-  , integerLog2-  , ceilingLog2-    -- * Integer square root-  , isSquare-  , integerSquareRoot-  , ceilingSquareRoot-  , integerSquareRoot' -  , integerSquareRootNewton'     -- * Modulo @m@ arithmetic   , powerMod     -- * Prime testing@@ -29,7 +20,7 @@  -------------------------------------------------------------------------------- --- import Math.Combinat.Numbers+import Math.Combinat.Numbers.Integers  import Data.List ( group , sort ) import Data.Bits@@ -119,92 +110,6 @@ -- brute force testing of factors ifactorsTest :: (Integer -> [Integer]) -> Integer -> Bool ifactorsTest alg n = and [ product (alg k) == k | k<-[1..n] ]   --}------------------------------------------------------------------------------------- Integer logarithm---- | Largest integer @k@ such that @2^k@ is smaller or equal to @n@-integerLog2 :: Integer -> Integer-integerLog2 n = go n where-  go 0 = -1-  go k = 1 + go (shiftR k 1)---- | Smallest integer @k@ such that @2^k@ is larger or equal to @n@-ceilingLog2 :: Integer -> Integer-ceilingLog2 0 = 0-ceilingLog2 n = 1 + go (n-1) where-  go 0 = -1-  go k = 1 + go (shiftR k 1)-  ------------------------------------------------------------------------------------ Integer square root--isSquare :: Integer -> Bool-isSquare n = -  if (fromIntegral $ mod n 32) `elem` rs -    then snd (integerSquareRoot' n) == 0-    else False-  where-    rs = [0,1,4,9,16,17,25] :: [Int]-    --- | Integer square root (largest integer whose square is smaller or equal to the input)--- using Newton's method, with a faster (for large numbers) inital guess based on bit shifts.-integerSquareRoot :: Integer -> Integer-integerSquareRoot = fst . integerSquareRoot'---- | Smallest integer whose square is larger or equal to the input-ceilingSquareRoot :: Integer -> Integer-ceilingSquareRoot n = (if r>0 then u+1 else u) where (u,r) = integerSquareRoot' n ---- | We also return the excess residue; that is------ > (a,r) = integerSquareRoot' n--- --- means that------ > a*a + r = n--- > a*a <= n < (a+1)*(a+1)-integerSquareRoot' :: Integer -> (Integer,Integer)-integerSquareRoot' n-  | n<0 = error "integerSquareRoot: negative input"-  | n<2 = (n,0)-  | otherwise = go firstGuess -  where-    k = integerLog2 n-    firstGuess = 2^(div (k+2) 2) -- !! note that (div (k+1) 2) is NOT enough !!-    go a = -      if m < a-        then go a' -        else (a, r + a*(m-a))-      where-        (m,r) = divMod n a-        a' = div (m + a) 2---- | Newton's method without an initial guess. For very small numbers (<10^10) it--- is somewhat faster than the above version.-integerSquareRootNewton' :: Integer -> (Integer,Integer)-integerSquareRootNewton' n-  | n<0 = error "integerSquareRootNewton: negative input"-  | n<2 = (n,0)-  | otherwise = go (div n 2) -  where-    go a = -      if m < a-        then go a' -        else (a, r + a*(m-a))-      where-        (m,r) = divMod n a-        a' = div (m + a) 2--{---- brute force test of integer square root-isqrt_test n1 n2 = -  [ k -  | k<-[n1..n2] -  , let (a,r) = integerSquareRoot' k-  , (a*a+r/=k) || (a*a>k) || (a+1)*(a+1)<=k -  ] -}  --------------------------------------------------------------------------------
+ Math/Combinat/Numbers/Sequences.hs view
@@ -0,0 +1,198 @@++-- | Some important number sequences. +--  +-- See the \"On-Line Encyclopedia of Integer Sequences\",+-- <https://oeis.org> .++module Math.Combinat.Numbers.Sequences where++--------------------------------------------------------------------------------++import Data.Array++import Math.Combinat.Helper ( sum' )+import Math.Combinat.Sign++--------------------------------------------------------------------------------+-- * Factorial++-- | A000142.+factorial :: Integral a => a -> Integer+factorial n+  | n <  0    = error "factorial: input should be nonnegative"+  | n == 0    = 1+  | otherwise = product [1..fromIntegral n]++-- | A006882.+doubleFactorial :: Integral a => a -> Integer+doubleFactorial n+  | n <  0    = error "doubleFactorial: input should be nonnegative"+  | n == 0    = 1+  | odd n     = product [1,3..fromIntegral n]+  | otherwise = product [2,4..fromIntegral n]++--------------------------------------------------------------------------------+-- * Binomial and multinomial++-- | A007318. Note: This is zero for @n<0@ or @k<0@; see also 'signedBinomial' below.+binomial :: Integral a => a -> a -> 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++-- | The extension of the binomial function to negative inputs. This should satisfy the following properties:+--+-- > for n,k >=0 : signedBinomial n k == binomial n k+-- > for any n,k : signedBinomial n k == signedBinomial n (n-k) +-- > for k >= 0  : signedBinomial (-n) k == (-1)^k * signedBinomial (n+k-1) k+--+-- Note: This is compatible with Mathematica's @Binomial@ function.+--+signedBinomial :: Int -> Int -> Integer+signedBinomial n k+  | n >= 0     = binomial n k+  | k >= 0     = negateIfOdd    k  $ binomial (k-n-1)   k  +  | otherwise  = negateIfOdd (n+k) $ binomial (-k-1) (-n-1)++{-+test_signed_0 = [ signedBinomial ( n) k == signedBinomial ( n) ( n-k)                | n<-[-30..40] , k<-[-30..40] ]+test_signed_1 = [ signedBinomial (-n) k == signedBinomial (-n) (-n-k)                | n<-[-30..40] , k<-[-30..40] ]+test_signed_2 = [ signedBinomial (-n) k == negateIfOdd k $ signedBinomial (n+k-1) k  | n<-[-30..40] , k<-[0..30] ]+-}++-- | A given row of the Pascal triangle; equivalent to a sequence of binomial +-- numbers, but much more efficient. You can also left-fold over it.+--+-- > pascalRow n == [ binomial n k | k<-[0..n] ]+pascalRow :: Integral a => a -> [Integer]+pascalRow n' = worker 0 1 where+  n = fromIntegral n'+  worker j x+    | j>n   = [] +    | True  = let j'=j+1 in x : worker j' (div (x*(n-j)) j') ++multinomial :: Integral a => [a] -> Integer+multinomial xs = div+  (factorial (sum xs))+  (product [ factorial x | x<-xs ])  +  +--------------------------------------------------------------------------------+-- * Catalan numbers++-- | Catalan numbers. OEIS:A000108.+catalan :: Integral a => a -> Integer+catalan n +  | n < 0     = 0+  | otherwise = binomial (n+n) n `div` fromIntegral (n+1)++-- | Catalan's triangle. OEIS:A009766.+-- Note:+--+-- > catalanTriangle n n == catalan n+-- > catalanTriangle n k == countStandardYoungTableaux (toPartition [n,k])+--+catalanTriangle :: Integral a => a -> a -> Integer+catalanTriangle n k+  | k > n     = 0+  | k < 0     = 0+  | otherwise = (binomial (n+k) n * fromIntegral (n-k+1)) `div` fromIntegral (n+1)++--------------------------------------------------------------------------------+-- * Stirling numbers++-- | Rows of (signed) Stirling numbers of the first kind. OEIS:A008275.+-- Coefficients of the polinomial @(x-1)*(x-2)*...*(x-n+1)@.+-- This function uses the recursion formula.+signedStirling1stArray :: Integral a => a -> Array Int Integer+signedStirling1stArray n+  | n <  1    = error "stirling1stArray: n should be at least 1"+  | n == 1    = listArray (1,1 ) [1]+  | otherwise = listArray (1,n') [ lkp (k-1) - fromIntegral (n-1) * lkp k | k<-[1..n'] ] +  where+    prev = signedStirling1stArray (n-1)+    n' = fromIntegral n :: Int+    lkp j | j <  1    = 0+          | j >= n'   = 0+          | otherwise = prev ! j +        +-- | (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==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+unsignedStirling1st n k = abs (signedStirling1st n k)++-- | 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==0 && n==0 = 1+  | k < 1        = 0+  | k > n        = 0+  | otherwise = sum xs `div` factorial k where+      xs = [ negateIfOdd (k-i) $ binomial k i * (fromIntegral i)^n | i<-[0..k] ]++--------------------------------------------------------------------------------+-- * Bernoulli numbers++-- | Bernoulli numbers. @bernoulli 1 == -1%2@ and @bernoulli k == 0@ for+-- k>2 and /odd/. This function uses the formula involving Stirling numbers+-- of the second kind. Numerators: A027641, denominators: A027642.+bernoulli :: Integral a => a -> Rational+bernoulli n +  | n <  0    = error "bernoulli: n should be nonnegative"+  | n == 0    = 1+  | n == 1    = -1/2+  | otherwise = sum [ f k | k<-[1..n] ] +  where+    f k = toRational (negateIfOdd (n+k) $ factorial k * stirling2nd n k) +        / 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/Numbers/Series.hs view
@@ -8,7 +8,7 @@ -- TODO: better names for these functions. -- -{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP, BangPatterns, GeneralizedNewtypeDeriving #-} module Math.Combinat.Numbers.Series where  --------------------------------------------------------------------------------@@ -63,9 +63,17 @@ scaleSeries :: Num a => a -> [a] -> [a] scaleSeries s = map (*s) +-- | A different implementation, taken from:+--+-- M. Douglas McIlroy: Power Series, Power Serious  mulSeries :: Num a => [a] -> [a] -> [a]-mulSeries = convolve+mulSeries xs ys = go (xs ++ repeat 0) (ys ++ repeat 0) where+  go (f:fs) ggs@(g:gs) = f*g : (scaleSeries f gs) `addSeries` go fs ggs +-- | Multiplication of power series. This implementation is a synonym for 'convolve'+mulSeriesNaive :: Num a => [a] -> [a] -> [a]+mulSeriesNaive = convolve+ productOfSeries :: Num a => [[a]] -> [a] productOfSeries = convolveMany @@ -90,6 +98,14 @@ -------------------------------------------------------------------------------- -- * Reciprocals of general power series +-- | Division of series.+--+-- Taken from: M. Douglas McIlroy: Power Series, Power Serious +divSeries :: (Eq a, Fractional a) => [a] -> [a] -> [a]+divSeries xs ys = go (xs ++ repeat 0) (ys ++ repeat 0) where+  go (0:fs)     (0:gs) = go fs gs+  go (f:fs) ggs@(g:gs) = let q = f/g in q : go (fs `subSeries` scaleSeries q gs) ggs+ -- | Given a power series, we iteratively compute its multiplicative inverse reciprocalSeries :: (Eq a, Fractional a) => [a] -> [a] reciprocalSeries series = case series of@@ -119,9 +135,13 @@ -- | @g \`composeSeries\` f@ is the power series expansion of @g(f(x))@. -- This is a synonym for @flip substitute@. ----- We require that the constant term of @f@ is zero.+-- This implementation is taken from+--+-- M. Douglas McIlroy: Power Series, Power Serious  composeSeries :: (Eq a, Num a) => [a] -> [a] -> [a]-composeSeries g f = substitute f g+composeSeries xs ys = go (xs ++ repeat 0) (ys ++ repeat 0) where+  go (f:fs) (0:gs) = f : mulSeries gs (go fs (0:gs))+  go (f:fs) (_:gs) = error "PowerSeries/composeSeries: we expect the the constant term of the inner series to be zero"  -- | @substitute f g@ is the power series corresponding to @g(f(x))@.  -- Equivalently, this is the composition of univariate functions (in the \"wrong\" order).@@ -129,10 +149,18 @@ -- Note: for this to be meaningful in general (not depending on convergence properties), -- we need that the constant term of @f@ is zero. substitute :: (Eq a, Num a) => [a] -> [a] -> [a]-substitute as_ bs_ = +substitute f g = composeSeries g f++-- | Naive implementation of 'composeSeries' (via 'substituteNaive')+composeSeriesNaive :: (Eq a, Num a) => [a] -> [a] -> [a]+composeSeriesNaive g f = substituteNaive f g++-- | Naive implementation of 'substitute'+substituteNaive :: (Eq a, Num a) => [a] -> [a] -> [a]+substituteNaive as_ bs_ =    case head as of     0 -> [ f n | n<-[0..] ]-    _ -> error "PowerSeries/substitute: we expect the the constant term of the inner series to be zero"+    _ -> error "PowerSeries/substituteNaive: we expect the the constant term of the inner series to be zero"   where     as = as_ ++ repeat 0     bs = bs_ ++ repeat 0@@ -148,6 +176,19 @@ -------------------------------------------------------------------------------- -- * Lagrange inversions +-- | We expect the input series to match @(0:a1:_)@. with a1 nonzero The following is true for the result (at least with exact arithmetic):+--+-- > substitute f (lagrangeInversion f) == (0 : 1 : repeat 0)+-- > substitute (lagrangeInversion f) f == (0 : 1 : repeat 0)+--+-- This implementation is taken from:+--+-- M. Douglas McIlroy: Power Series, Power Serious +lagrangeInversion :: (Eq a, Fractional a) => [a] -> [a]+lagrangeInversion xs = go (xs ++ repeat 0) where+  go (0:fs) = rs where rs = 0 : divSeries unitSeries (composeSeries fs rs)+  go (_:fs) = error "lagrangeInversion: the series should start with (0 + a1*x + a2*x^2 + ...) where a1 is non-zero"+ -- | Coefficients of the Lagrange inversion lagrangeCoeff :: Partition -> Integer lagrangeCoeff p = div numer denom where@@ -162,11 +203,11 @@ -- > substitute f (integralLagrangeInversion f) == (0 : 1 : repeat 0) -- > substitute (integralLagrangeInversion f) f == (0 : 1 : repeat 0) ---integralLagrangeInversion :: (Eq a, Num a) => [a] -> [a]-integralLagrangeInversion series_ = +integralLagrangeInversionNaive :: (Eq a, Num a) => [a] -> [a]+integralLagrangeInversionNaive series_ =    case series of     (0:1:rest) -> 0 : 1 : [ f n | n<-[1..] ]-    _ -> error "integralLagrangeInversion: the series should start with (0 + x + a2*x^2 + ...)"+    _ -> error "integralLagrangeInversionNaive: the series should start with (0 + x + a2*x^2 + ...)"   where     series = series_ ++ repeat 0     as  = tail series @@ -175,20 +216,16 @@               | p <- partitions n               ]  --- | We expect the input series to match @(0:a1:_)@. with a1 nonzero The following is true for the result (at least with exact arithmetic):------ > substitute f (lagrangeInversion f) == (0 : 1 : repeat 0)--- > substitute (lagrangeInversion f) f == (0 : 1 : repeat 0)----lagrangeInversion :: (Eq a, Fractional a) => [a] -> [a]-lagrangeInversion series_ = +-- | Naive implementation of 'lagrangeInversion'+lagrangeInversionNaive :: (Eq a, Fractional a) => [a] -> [a]+lagrangeInversionNaive series_ =    case series of     (0:a1:rest) -> if a1 ==0        then err        else 0 : (1/a1) : [ f n / a1^(n+1) | n<-[1..] ]     _ -> err   where-    err    = error "lagrangeInversion: the series should start with (0 + a1*x + a2*x^2 + ...) where a1 is non-zero"+    err    = error "lagrangeInversionNaive: the series should start with (0 + a1*x + a2*x^2 + ...) where a1 is non-zero"     series = series_ ++ repeat 0     a1  = series !! 1     as  = map (/a1) (tail series)@@ -196,8 +233,22 @@     f n = sum [ fromInteger (lagrangeCoeff p) * product [ (a i)^j | (i,j) <- toExponentialForm p ]               | p <- partitions n               ] -  ++ --------------------------------------------------------------------------------+-- * Differentiation and integration++differentiateSeries :: Num a => [a] -> [a]+differentiateSeries (y:ys) = go (1::Int) ys where+  go !n (x:xs) = fromIntegral n * x : go (n+1) xs+  go _  []     = []++integrateSeries :: Fractional a => [a] -> [a]+integrateSeries ys = 0 : go (1::Int) ys where+  go !n (x:xs) = x / (fromIntegral n) : go (n+1) xs+  go _  []     = []++-------------------------------------------------------------------------------- -- * Power series expansions of elementary functions  -- | Power series expansion of @exp(x)@@@ -214,6 +265,13 @@ sinSeries :: Fractional a => [a] sinSeries = go 1 1 where   go i e = 0 : e : go (i+2) (-e / ((i+1)*(i+2)))++-- | Alternative implementation using differential equations.+--+-- Taken from: M. Douglas McIlroy: Power Series, Power Serious+cosSeries2, sinSeries2 :: Fractional a => [a]+cosSeries2 = unitSeries `subSeries` integrateSeries sinSeries2+sinSeries2 =                        integrateSeries cosSeries2  -- | Power series expansion of @cosh(x)@ coshSeries :: Fractional a => [a]
Math/Combinat/Partitions/Integer.hs view
@@ -18,7 +18,54 @@ --   {-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables #-}-module Math.Combinat.Partitions.Integer where+module Math.Combinat.Partitions.Integer +  ( -- module Math.Combinat.Partitions.Integer.Count+    module Math.Combinat.Partitions.Integer.Naive+    -- * Types and basic stuff+  , Partition+    -- * Conversion to\/from lists+  , fromPartition +  , mkPartition +  , toPartition +  , toPartitionUnsafe +  , isPartition +    -- * Union and sum+  , unionOfPartitions+  , sumOfPartitions+    -- * Generating partitions+  , partitions +  , partitions'+  , allPartitions +  , allPartitionsGrouped +  , allPartitions'  +  , allPartitionsGrouped'  +    -- * Counting partitions+  , countPartitions+  , countPartitions'+  , countAllPartitions+  , countAllPartitions'+  , countPartitionsWithKParts +    -- * Random partitions+  , randomPartition+  , randomPartitions+    -- * Dominating \/ dominated partitions+  , dominatedPartitions +  , dominatingPartitions +    -- * Partitions with given number of parts+  , partitionsWithKParts+    -- * Partitions with only odd\/distinct parts+  , partitionsWithOddParts +  , partitionsWithDistinctParts+    -- * Sub- and super-partitions of a given partition+  , subPartitions +  , allSubPartitions +  , superPartitions +    -- * ASCII Ferrers diagrams+  , PartitionConvention(..)+  , asciiFerrersDiagram +  , asciiFerrersDiagram'+  )+  where  -------------------------------------------------------------------------------- @@ -36,31 +83,29 @@ import Data.Array import System.Random ------------------------------------------------------------------------------------ * Type and basic stuff---- | A partition of an integer. The additional invariant enforced here is that partitions --- are monotone decreasing sequences of /positive/ integers. The @Ord@ instance is lexicographical.-newtype Partition = Partition [Int] deriving (Eq,Ord,Show,Read)--instance HasNumberOfParts Partition where-  numberOfParts (Partition p) = length p+import Math.Combinat.Partitions.Integer.Naive+import Math.Combinat.Partitions.Integer.IntList+import Math.Combinat.Partitions.Integer.Count  ---------------------------------------------------------------------------------+-- * Conversion to\/from lists++fromPartition :: Partition -> [Int]+fromPartition (Partition_ part) = part    -- | Sorts the input, and cuts the nonpositive elements. mkPartition :: [Int] -> Partition-mkPartition xs = Partition $ sortBy (reverseCompare) $ filter (>0) xs---- | Assumes that the input is decreasing.-toPartitionUnsafe :: [Int] -> Partition-toPartitionUnsafe = Partition+mkPartition xs = toPartitionUnsafe $ sortBy (reverseCompare) $ filter (>0) xs  -- | Checks whether the input is an integer partition. See the note at 'isPartition'! toPartition :: [Int] -> Partition toPartition xs = if isPartition xs   then toPartitionUnsafe xs   else error "toPartition: not a partition"++-- | Assumes that the input is decreasing.+toPartitionUnsafe :: [Int] -> Partition+toPartitionUnsafe = Partition_    -- | This returns @True@ if the input is non-increasing sequence of  -- /positive/ integers (possibly empty); @False@ otherwise.@@ -70,211 +115,43 @@ isPartition [x] = x > 0 isPartition (x:xs@(y:_)) = (x >= y) && isPartition xs -isEmptyPartition :: Partition -> Bool-isEmptyPartition (Partition p) = null p--emptyPartition :: Partition-emptyPartition = Partition []--instance CanBeEmpty Partition where-  empty   = emptyPartition-  isEmpty = isEmptyPartition--fromPartition :: Partition -> [Int]-fromPartition (Partition part) = part---- | The first element of the sequence.-partitionHeight :: Partition -> Int-partitionHeight (Partition part) = case part of-  (p:_) -> p-  []    -> 0-  --- | The length of the sequence (that is, the number of parts).-partitionWidth :: Partition -> Int-partitionWidth (Partition part) = length part--instance HasHeight Partition where-  height = partitionHeight- -instance HasWidth Partition where-  width = partitionWidth--heightWidth :: Partition -> (Int,Int)-heightWidth part = (height part, width part)---- | The weight of the partition ---   (that is, the sum of the corresponding sequence).-partitionWeight :: Partition -> Int-partitionWeight (Partition part) = sum' part--instance HasWeight Partition where -  weight = partitionWeight---- | The dual (or conjugate) partition.-dualPartition :: Partition -> Partition-dualPartition (Partition part) = Partition (_dualPartition part)--instance HasDuality Partition where -  dual = dualPartition--data Pair = Pair !Int !Int--_dualPartition :: [Int] -> [Int]-_dualPartition [] = []-_dualPartition xs = go 0 (diffSequence xs) [] where-  go !i (d:ds) acc = go (i+1) ds (d:acc)-  go n  []     acc = finish n acc -  finish !j (k:ks) = replicate k j ++ finish (j-1) ks-  finish _  []     = []--{---- more variations:--_dualPartition_b :: [Int] -> [Int]-_dualPartition_b [] = []-_dualPartition_b xs = go 1 (diffSequence xs) [] where-  go !i (d:ds) acc = go (i+1) ds ((d,i):acc)-  go _  []     acc = concatMap (\(d,i) -> replicate d i) acc--_dualPartition_c :: [Int] -> [Int]-_dualPartition_c [] = []-_dualPartition_c xs = reverse $ concat $ zipWith f [1..] (diffSequence xs) where-  f _ 0 = []-  f k d = replicate d k--}---- | A simpler, but bit slower (about twice?) implementation of dual partition-_dualPartitionNaive :: [Int] -> [Int]-_dualPartitionNaive [] = []-_dualPartitionNaive xs@(k:_) = [ length $ filter (>=i) xs | i <- [1..k] ]---- | From a sequence @[a1,a2,..,an]@ computes the sequence of differences--- @[a1-a2,a2-a3,...,an-0]@-diffSequence :: [Int] -> [Int]-diffSequence = go where-  go (x:ys@(y:_)) = (x-y) : go ys -  go [x] = [x]-  go []  = []+--------------------------------------------------------------------------------+-- * Union and sum --- | Example:+-- | This is simply the union of parts. For example  ----- > elements (toPartition [5,4,1]) ==--- >   [ (1,1), (1,2), (1,3), (1,4), (1,5)--- >   , (2,1), (2,2), (2,3), (2,4)--- >   , (3,1)--- >   ]+-- > Partition [4,2,1] `unionOfPartitions` Partition [4,3,1] == Partition [4,4,3,2,1,1] ---elements :: Partition -> [(Int,Int)]-elements (Partition part) = _elements part--_elements :: [Int] -> [(Int,Int)]-_elements shape = [ (i,j) | (i,l) <- zip [1..] shape, j<-[1..l] ] -------------------------------------------------------------------------------------- * Exponential form+-- Note: This is the dual of pointwise sum, 'sumOfPartitions'+--+unionOfPartitions :: Partition -> Partition -> Partition +unionOfPartitions (Partition_ xs) (Partition_ ys) = mkPartition (xs ++ ys) --- | We convert a partition to exponential form.--- @(i,e)@ mean @(i^e)@; for example @[(1,4),(2,3)]@ corresponds to @(1^4)(2^3) = [2,2,2,1,1,1,1]@. Another example:+-- | Pointwise sum of the parts. For example: ----- > toExponentialForm (Partition [5,5,3,2,2,2,2,1,1]) == [(1,2),(2,4),(3,1),(5,2)]+-- > Partition [3,2,1,1] `sumOfPartitions` Partition [4,3,1] == Partition [7,5,2,1] ---toExponentialForm :: Partition -> [(Int,Int)]-toExponentialForm = _toExponentialForm . fromPartition--_toExponentialForm :: [Int] -> [(Int,Int)]-_toExponentialForm = reverse . map (\xs -> (head xs,length xs)) . group--fromExponentialFrom :: [(Int,Int)] -> Partition-fromExponentialFrom = Partition . sortBy reverseCompare . go where-  go ((j,e):rest) = replicate e j ++ go rest-  go []           = []   -------------------------------------------------------------------------------------- * Automorphisms ---- | Computes the number of \"automorphisms\" of a given integer partition.-countAutomorphisms :: Partition -> Integer  -countAutomorphisms = _countAutomorphisms . fromPartition--_countAutomorphisms :: [Int] -> Integer-_countAutomorphisms = multinomial . map length . group+-- Note: This is the dual of 'unionOfPartitions'+--+sumOfPartitions :: Partition -> Partition -> Partition +sumOfPartitions (Partition_ xs) (Partition_ ys) = Partition_ (longZipWith 0 0 (+) xs ys) ----------------------------------------------------------------------------------+-------------------------------------------------------------------------------- -- * Generating partitions  -- | Partitions of @d@. partitions :: Int -> [Partition]-partitions = map Partition . _partitions---- | Partitions of @d@, as lists-_partitions :: Int -> [[Int]]-_partitions d = go d d where-  go _  0  = [[]]-  go !h !n = [ a:as | a<-[1..min n h], as <- go a (n-a) ]---- | Number of partitions of @n@-countPartitions :: Int -> Integer-countPartitions n = partitionCountList !! n---- | This uses 'countPartitions'', and thus is slow-countPartitionsNaive :: Int -> Integer-countPartitionsNaive d = countPartitions' (d,d) d-------------------------------------------------------------------------------------- | Infinite list of number of partitions of @0,1,2,...@------ This uses the infinite product formula the generating function of partitions, recursively--- expanding it; it is quite fast.------ > partitionCountList == map countPartitions [0..]----partitionCountList :: [Integer]-partitionCountList = final where--  final = go 1 (1:repeat 0) --  go !k (x:xs) = x : go (k+1) ys where-    ys = zipWith (+) xs (take k final ++ ys)-    -- explanation:-    --   xs == drop k $ f (k-1)-    --   ys == drop k $ f (k  )  --{---Full explanation of 'partitionCountList':-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--let f k = productPSeries $ map (:[]) [1..k]--f 0 = [1,0,0,0,0,0,0,0...]-f 1 = [1,1,1,1,1,1,1,1...]-f 2 = [1,1,2,2,3,3,4,4...]-f 3 = [1,1,2,3,4,5,7,8...]--observe: --* take (k+1) (f k) == take (k+1) partitionCountList-* f (k+1) == zipWith (+) (f k) (replicate (k+1) 0 ++ f (k+1))--now apply (drop (k+1)) to the second one : --* drop (k+1) (f (k+1)) == zipWith (+) (drop (k+1) $ f k) (f (k+1))-* f (k+1) = take (k+1) final ++ drop (k+1) (f (k+1))+partitions = map toPartitionUnsafe . _partitions --}+-- | 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          -------------------------------------------------------------------------------- --- | Naive infinite list of number of partitions of @0,1,2,...@------ > partitionCountListNaive == map countPartitionsNaive [0..]------ This is much slower than the power series expansion above.----partitionCountListNaive :: [Integer]-partitionCountListNaive = map countPartitionsNaive [0..]- -- | 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 = concat [ partitions i | i <- [0..d] ]@@ -296,48 +173,14 @@   -> [[Partition]] allPartitionsGrouped' (h,w) = [ partitions' (h,w) i | i <- [0..d] ] where d = h*w --- | # = \\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] ]---- | 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 = -  [ 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] ] -- --------------------------------------------------------------------------------- -- * Random partitions  -- | Uniformly random partition of the given weight.  -- -- NOTE: This algorithm is effective for small @n@-s (say @n@ up to a few hundred \/ one thousand it should work nicely),--- and the first time it is executed may be slower (as it needs to build the table 'partitionCountList' first)+-- and the first time it is executed may be slower (as it needs to build the table of partitions counts first) -- -- Algorithm of Nijenhuis and Wilf (1975); see --@@ -359,8 +202,7 @@   -> g -> ([Partition], g) randomPartitions howmany n = runRand $ replicateM howmany (worker n []) where -  table = listArray (0,n) $ take (n+1) partitionCountList :: Array Int Integer-  cnt k = table ! k+  cnt = countPartitions     finish :: [(Int,Int)] -> Partition   finish = mkPartition . concatMap f where f (j,d) = replicate j d@@ -387,21 +229,8 @@     let jd@(!j,!d) = find_jd m capm     worker (m - j*d) (jd:acc) -------------------------------------------------------------------------------------- * Dominance order ---- | @q \`dominates\` p@ returns @True@ if @q >= p@ in the dominance order of partitions--- (this is partial ordering on the set of partitions of @n@).------ See <http://en.wikipedia.org/wiki/Dominance_order>----dominates :: Partition -> Partition -> Bool-dominates (Partition qs) (Partition ps) -  = and $ zipWith (>=) (sums (qs ++ repeat 0)) (sums ps)-  where-    sums = scanl (+) 0-+--------------------------------------------------------------------------------+-- * Dominating \/ dominated partitions  -- | Lists all partitions of the same weight as @lambda@ and also dominated by @lambda@ -- (that is, all partial sums are less or equal):@@ -409,21 +238,7 @@ -- > dominatedPartitions lam == [ mu | mu <- partitions (weight lam), lam `dominates` mu ] --  dominatedPartitions :: Partition -> [Partition]    -dominatedPartitions (Partition lambda) = map Partition (_dominatedPartitions lambda)--_dominatedPartitions :: [Int] -> [[Int]]-_dominatedPartitions []     = [[]]-_dominatedPartitions lambda = go (head lambda) w dsums 0 where--  n = length lambda-  w = sum    lambda-  dsums = scanl1 (+) (lambda ++ repeat 0)--  go _   0 _       _  = [[]]-  go !h !w (!d:ds) !e  -    | w >  0  = [ (a:as) | a <- [1..min h (d-e)] , as <- go a (w-a) ds (e+a) ] -    | w == 0  = [[]]-    | w <  0  = error "_dominatedPartitions: fatal error; shouldn't happen"+dominatedPartitions (Partition_ lambda) = map Partition_ (_dominatedPartitions lambda)  -- | Lists all partitions of the sime weight as @mu@ and also dominating @mu@ -- (that is, all partial sums are greater or equal):@@ -431,21 +246,7 @@ -- > dominatingPartitions mu == [ lam | lam <- partitions (weight mu), lam `dominates` mu ] --  dominatingPartitions :: Partition -> [Partition]    -dominatingPartitions (Partition mu) = map Partition (_dominatingPartitions mu)--_dominatingPartitions :: [Int] -> [[Int]]-_dominatingPartitions []     = [[]]-_dominatingPartitions mu     = go w w dsums 0 where--  n = length mu-  w = sum    mu-  dsums = scanl1 (+) (mu ++ repeat 0)--  go _   0 _       _  = [[]]-  go !h !w (!d:ds) !e  -    | w >  0  = [ (a:as) | a <- [max 0 (d-e)..min h w] , as <- go a (w-a) ds (e+a) ] -    | w == 0  = [[]]-    | w <  0  = error "_dominatingPartitions: fatal error; shouldn't happen"+dominatingPartitions (Partition_ mu) = map Partition_ (_dominatingPartitions mu)  -------------------------------------------------------------------------------- -- * Partitions with given number of parts@@ -460,7 +261,7 @@   :: Int    -- ^ @k@ = number of parts   -> Int    -- ^ @n@ = the integer we partition   -> [Partition]-partitionsWithKParts k n = map Partition $ go n k n where+partitionsWithKParts k n = map Partition_ $ go n k n where {-   h = max height   k = number of parts@@ -472,23 +273,12 @@     | 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))] ]- -------------------------------------------------------------------------------- -- * Partitions with only odd\/distinct parts  -- | Partitions of @n@ with only odd parts partitionsWithOddParts :: Int -> [Partition]-partitionsWithOddParts d = map Partition (go d d) where+partitionsWithOddParts d = map Partition_ (go d d) where   go _  0  = [[]]   go !h !n = [ a:as | a<-[1,3..min n h], as <- go a (n-a) ] @@ -510,143 +300,31 @@ -- > length (partitionsWithDistinctParts d) == length (partitionsWithOddParts d) -- partitionsWithDistinctParts :: Int -> [Partition]-partitionsWithDistinctParts d = map Partition (go d d) where+partitionsWithDistinctParts d = map Partition_ (go d d) where   go _  0  = [[]]   go !h !n = [ a:as | a<-[1..min n h], as <- go (a-1) (n-a) ]  -------------------------------------------------------------------------------- -- * Sub- and super-partitions of a given partition --- | Returns @True@ of the first partition is a subpartition (that is, fit inside) of the second.--- This includes equality-isSubPartitionOf :: Partition -> Partition -> Bool-isSubPartitionOf (Partition ps) (Partition qs) = and $ zipWith (<=) ps (qs ++ repeat 0)---- | This is provided for convenience\/completeness only, as:------ > isSuperPartitionOf q p == isSubPartitionOf p q----isSuperPartitionOf :: Partition -> Partition -> Bool-isSuperPartitionOf (Partition qs) (Partition ps) = and $ zipWith (<=) ps (qs ++ repeat 0)-- -- | Sub-partitions of a given partition with the given weight: -- -- > sort (subPartitions d q) == sort [ p | p <- partitions d, isSubPartitionOf p q ] -- subPartitions :: Int -> Partition -> [Partition]-subPartitions d (Partition ps) = map Partition (_subPartitions d ps)--_subPartitions :: Int -> [Int] -> [[Int]]-_subPartitions d big-  | null big       = if d==0 then [[]] else []-  | d > sum' big   = []-  | d < 0          = []-  | otherwise      = go d (head big) big-  where-    go :: Int -> Int -> [Int] -> [[Int]]-    go !k !h []      = if k==0 then [[]] else []-    go !k !h (b:bs) -      | k<0 || h<0   = []-      | k==0         = [[]]-      | h==0         = []-      | otherwise    = [ this:rest | this <- [1..min h b] , rest <- go (k-this) this bs ]------------------------------------------+subPartitions d (Partition_ ps) = map Partition_ (_subPartitions d ps)  -- | All sub-partitions of a given partition allSubPartitions :: Partition -> [Partition]-allSubPartitions (Partition ps) = map Partition (_allSubPartitions ps)--_allSubPartitions :: [Int] -> [[Int]]-_allSubPartitions big -  | null big   = [[]]-  | otherwise  = go (head big) big-  where-    go _  [] = [[]]-    go !h (b:bs) -      | h==0         = []-      | otherwise    = [] : [ this:rest | this <- [1..min h b] , rest <- go this bs ]------------------------------------------+allSubPartitions (Partition_ ps) = map Partition_ (_allSubPartitions ps)  -- | Super-partitions of a given partition with the given weight: -- -- > sort (superPartitions d p) == sort [ q | q <- partitions d, isSubPartitionOf p q ] -- superPartitions :: Int -> Partition -> [Partition]-superPartitions d (Partition ps) = map Partition (_superPartitions d ps)--_superPartitions :: Int -> [Int] -> [[Int]]-_superPartitions dd small-  | dd < w0     = []-  | null small  = _partitions dd-  | otherwise   = go dd w1 dd (small ++ repeat 0)-  where-    w0 = sum' small-    w1 = w0 - head small-    -- d = remaining weight of the outer partition we are constructing-    -- w = remaining weight of the inner partition (we need to reserve at least this amount)-    -- h = max height (decreasing)-    go !d !w !h (!a:as@(b:_)) -      | d < 0     = []-      | d == 0    = if a == 0 then [[]] else []-      | otherwise = [ this:rest | this <- [max 1 a .. min h (d-w)] , rest <- go (d-this) (w-b) this as ]+superPartitions d (Partition_ ps) = map toPartitionUnsafe (_superPartitions d ps)     ------------------------------------------------------------------------------------ * The Pieri rule---- | The Pieri rule computes @s[lambda]*h[n]@ as a sum of @s[mu]@-s (each with coefficient 1).------ See for example <http://en.wikipedia.org/wiki/Pieri's_formula>----pieriRule :: Partition -> Int -> [Partition] -pieriRule (Partition lambda) n = map Partition (_pieriRule lambda n) where--  -- | We assume here that @lambda@ is a partition (non-increasing sequence of /positive/ integers)! -  _pieriRule :: [Int] -> Int -> [[Int]] -  _pieriRule lambda n-    | n == 0     = [lambda]-    | n <  0     = [] -    | otherwise  = go n diffs dsums (lambda++[0]) -    where-      diffs = n : diffSequence lambda                 -- maximum we can add to a given row-      dsums = reverse $ scanl1 (+) (reverse diffs)    -- partial sums of remaining total we can add-      go !k (d:ds) (p:ps@(q:_)) (l:ls) -        | k > p     = []-        | otherwise = [ h:tl | a <- [ max 0 (k-q) .. min d k ] , let h = l+a , tl <- go (k-a) ds ps ls ]-      go !k [d]    _      [l]    = if k <= d -                                     then if l+k>0 then [[l+k]] else [[]]-                                     else []-      go !k []     _      _      = if k==0 then [[]] else []---- | The dual Pieri rule computes @s[lambda]*e[n]@ as a sum of @s[mu]@-s (each with coefficient 1)-dualPieriRule :: Partition -> Int -> [Partition] -dualPieriRule lam n = map dualPartition $ pieriRule (dualPartition lam) n---{- --- moved to "Math.Combinat.Tableaux.GelfandTsetlin"---- | Computes the Schur expansion of @h[n1]*h[n2]*h[n3]*...*h[nk]@ via iterating the Pieri rule-iteratedPieriRule :: Num coeff => [Int] -> Map Partition coeff-iteratedPieriRule = iteratedPieriRule' (Partition [])---- | Iterating the Pieri rule, we can compute the Schur expansion of--- @h[lambda]*h[n1]*h[n2]*h[n3]*...*h[nk]@-iteratedPieriRule' :: Num coeff => Partition -> [Int] -> Map Partition coeff-iteratedPieriRule' plambda ns = iteratedPieriRule'' (plambda,1) ns--{-# SPECIALIZE iteratedPieriRule'' :: (Partition,Int    ) -> [Int] -> Map Partition Int     #-}-{-# SPECIALIZE iteratedPieriRule'' :: (Partition,Integer) -> [Int] -> Map Partition Integer #-}-iteratedPieriRule'' :: Num coeff => (Partition,coeff) -> [Int] -> Map Partition coeff-iteratedPieriRule'' (plambda,coeff0) ns = worker (Map.singleton plambda coeff0) ns where-  worker old []     = old-  worker old (n:ns) = worker new ns where-    stuff = [ (coeff, pieriRule lam n) | (lam,coeff) <- Map.toList old ] -    new   = foldl' f Map.empty stuff -    f t0 (c,ps) = foldl' (\t p -> Map.insertWith (+) p c t) t0 ps  --}  -------------------------------------------------------------------------------- -- * ASCII Ferrers diagrams
+ Math/Combinat/Partitions/Integer/Compact.hs view
@@ -0,0 +1,819 @@++{- | Compact representation of integer partitions.++Partitions are conceptually nonincreasing sequences of /positive/ integers.++When the partition fits into a 15x15 rectangle, we encode the parts as nibbles in a single 64-bit word.+The most significant nibble is the first element, and the least significant nibble is used to encode+the length. This way equality and comparison of 64-bit words is the same as the corresponding operations+for partitions (lexicographic ordering).++This will make working with small partitions much more memory efficient (very helpful when+building tables indexed by partitions, for example!) and hopefully quite a bit faster, too.++When they do not fit into a 15x15 rectangle, but fit into 255x7, 255x15, 255x23 or 255x31, respectively,+then we extend the above to use the bytes of 1, 2, 3 or 4 64-bit words.++In the general case, we encode the partition as a list of 64-bit words, each encoding 4 16-bit parts.++Partitions with elements bigger than 65535 are not supported.++Note: This is an internal module, you are not supposed to import it directly.+-}++{-# LANGUAGE BangPatterns, PatternSynonyms, ViewPatterns, ForeignFunctionInterface #-}+module Math.Combinat.Partitions.Integer.Compact where++--------------------------------------------------------------------------------++import Data.Bits+import Data.Word+import Data.Ord+import Data.List ( intercalate , group , sort , sortBy , foldl' , scanl' ) ++import Math.Combinat.Compositions ( compositions' )+++--------------------------------------------------------------------------------+-- * The compact partition data type++data Partition+  = Nibble   {-# UNPACK #-} !Word64+  | Medium1  {-# UNPACK #-} !Word64+  | Medium2  {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64+  | Medium3  {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64+  | Medium4  {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64+  | WordList {-# UNPACK #-} !Int ![Word64]+  deriving (Eq,Show)++--------------------------------------------------------------------------------+  +-- | for debugging+partitionPrefixChar :: Partition -> Char+partitionPrefixChar p = case p of+  Nibble   {} -> 'N'+  Medium1  {} -> '1'+  Medium2  {} -> '2' +  Medium3  {} -> '3' +  Medium4  {} -> '4' +  WordList {} -> 'L'++{- +instance Show Partition where+  show compact = partitionPrefixChar compact +               : '<' : intercalate "," (map show $ toList compact) ++ ">"+-}++instance Ord Partition where+  compare = cmp+               +--------------------------------------------------------------------------------+-- * Pattern synonyms ++-- | Pattern sysnonyms allows us to use existing code with minimal modifications+pattern Nil :: Partition+pattern Nil <- (isEmpty -> True) where+        Nil =  empty++pattern Cons :: Int -> Partition -> Partition+pattern Cons x xs <- (uncons -> Just (x,xs)) where+        Cons x xs = cons x xs++-- | Simulated newtype constructor +pattern Partition_ :: [Int] -> Partition+pattern Partition_ xs <- (toList -> xs) where+        Partition_ xs = fromDescList xs++pattern Head :: Int -> Partition +pattern Head h <- (height -> h)++pattern Tail :: Partition -> Partition+pattern Tail xs <- (partitionTail -> xs)++pattern Length :: Int -> Partition +pattern Length n <- (width -> n)        ++--------------------------------------------------------------------------------+-- * Lexicographic comparison++-- | The lexicographic ordering+cmp :: Partition -> Partition -> Ordering+cmp (Nibble  a)           (Nibble  b)           = compare  a             b+cmp (Medium1 a1)          (Medium1 b1)          = compare  a1            b1+cmp (Medium2 a1 a2)       (Medium2 b1 b2)       = compare (a1,a2)       (b1,b2)+cmp (Medium3 a1 a2 a3)    (Medium3 b1 b2 b3)    = compare (a1,a2,a3)    (b1,b2,b3)+cmp (Medium4 a1 a2 a3 a4) (Medium4 b1 b2 b3 b4) = compare (a1,a2,a3,a4) (b1,b2,b3,b4)+cmp (WordList _ as)       (WordList _ bs)       = compare  as            bs+cmp p                     q                     = compare (toList p)    (toList q)+  +--------------------------------------------------------------------------------+-- * Basic (de)constructrion++empty :: Partition+empty = Nibble 0++isEmpty :: Partition -> Bool+isEmpty compact = case compact of+  Nibble x -> (x == 0)+  _        -> False++--------------------------------------------------------------------------------++singleton :: Int -> Partition+singleton x+  | x == 0      = Nibble 0+  | x <= 15     = Nibble     $ shiftL (i2w x) 60 + 1+  | x <= 255    = Medium1    $ shiftL (i2w x) 56 + 1+  | x <= 65535  = WordList 1 [ shiftL (i2w x) 48 ]+  | otherwise   = error "singleton: partitions with elements bigger than 65535 are not supported"++--------------------------------------------------------------------------------++uncons :: Partition -> Maybe (Int,Partition)+uncons compact = case compact of+  Nibble  0           -> Nothing+  Nibble  w           -> Just ( w2i (shiftR w  60) , Nibble $ shiftL (w .&. 0x0ffffffffffffff0) 4 + ((w .&. 15) - 1) )+  Medium1 w1          -> Just ( w2i (shiftR w1 56) , partitionTail compact )+  Medium2 w1 w2       -> Just ( w2i (shiftR w1 56) , partitionTail compact )+  Medium3 w1 w2 w3    -> Just ( w2i (shiftR w1 56) , partitionTail compact )+  Medium4 w1 w2 w3 w4 -> Just ( w2i (shiftR w1 56) , partitionTail compact )+  WordList n (w:rest) -> Just ( w2i (shiftR w  48) , partitionTail compact )++--------------------------------------------------------------------------------++-- | @partitionTail p == snd (uncons p)@+partitionTail :: Partition -> Partition+partitionTail compact = case compact of++  Nibble  0 -> Nibble 0+  Nibble  w -> Nibble $ shiftL (w .&. 0x0ffffffffffffff0) 4 + ((w .&. 15) - 1) ++  Medium1 w1 ->+    let !y = (shiftR w1 48) .&. 255     -- next element+        !n = w1 .&. 15+    in  if y <= 15 +          then makeNibble (w2i $ n-1) $ safeTail $ toList compact+          else Medium1    $ shiftL (w1 .&. 0x00ffffffffffff00) 8 + (n-1) ++  Medium2 w1 w2 ->      +    let !y = (shiftR w1 48) .&. 255+        !n = w2 .&. 255+    in  if y <= 15 +          then makeNibble (w2i $ n-1) $ safeTail $ toList compact+          else if n <= 8+            then Medium1 $ shiftL (w1 .&. 0x00ffffffffffffff) 8 + shiftL (shiftR w2 56) 8 + (n-1) ++            else Medium2 ( shiftL  w1 8 + shiftR w2 56 ) +                         ( shiftL (w2 .&. 0x00ffffffffffff00) 8 + (n-1) )++  Medium3 w1 w2 w3 ->   +    let !y = (shiftR w1 48) .&. 255+        !n = w3 .&. 255+    in  if y <= 15 && n <= 16+          then makeNibble (w2i $ n-1) $ safeTail $ toList compact+          else if n <= 16+            then Medium2 ( shiftL  w1 8 + shiftR w2 56 ) +                         ( shiftL  w2 8 + shiftR w3 56 + shiftL (shiftR w3 56) 8 + (n-1) )+ +            else Medium3 ( shiftL  w1 8 + shiftR w2 56 ) +                         ( shiftL  w2 8 + shiftR w3 56 ) +                         ( shiftL (w3 .&. 0x00ffffffffffff00) 8 + (n-1) )+ +  _ -> +    let n = width compact+    in  fromDescList' (n-1) $ safeTail $ toList compact ++--------------------------------------------------------------------------------++-- | We assume that @x >= partitionHeight p@!+cons :: Int -> Partition -> Partition+cons !x !compact = case compact of++  Nibble 0                -> singleton x+  +  Nibble word+    | x <= 15  && n < 15  -> Nibble $ shiftR word 4 + shiftL xw 60 + (n+1)+    | x <= 255            -> makeMedium   (w2i $ n+1) (x : toList compact)+    | otherwise           -> makeWordList (w2i $ n+1) (x : toList compact)+    where  +      n  = word .&. 15+      xw = i2w x+      +  Medium1 w1+    | x <= 255 && n < 7   -> Medium1 (shiftR w1 8 + shiftL xw 56 + (n+1))+    | x <= 255            -> Medium2 (shiftR w1 8 + shiftL xw 56        ) 8+    | otherwise           -> makeWordList (w2i $ n+1) (x : toList compact)+    where  +      n  = w1 .&. 255+      xw = i2w x++  Medium2 w1 w2+    | x <= 255 && n < 15  -> Medium2 (shiftR w1 8 + shiftL xw 56) (shiftR w2 8 + shiftL (w1 .&. 255) 56 + (n+1))+    | x <= 255            -> Medium3 (shiftR w1 8 + shiftL xw 56) (shiftR w2 8 + shiftL (w1 .&. 255) 56        ) 16+    | otherwise           -> makeWordList (w2i $ n+1) (x : toList compact)+    where  +      n  = w2 .&. 255+      xw = i2w x++  Medium3 w1 w2 w3+    | x <= 255 && n < 23  -> Medium3 (shiftR w1 8 + shiftL xw 56) (shiftR w2 8 + shiftL (w1 .&. 255) 56) (shiftR w3 8 + shiftL (w2 .&. 255) 56 + (n+1))+    | x <= 255            -> Medium4 (shiftR w1 8 + shiftL xw 56) (shiftR w2 8 + shiftL (w1 .&. 255) 56) (shiftR w3 8 + shiftL (w2 .&. 255) 56        ) 24+    | otherwise           -> makeWordList (w2i $ n+1) (x : toList compact)+    where  +      n  = w3 .&. 255+      xw = i2w x++  Medium4 w1 w2 w3 w4+    | x <= 255 && n < 31  -> Medium4 (shiftR w1 8 + shiftL  xw          56) +                                     (shiftR w2 8 + shiftL (w1 .&. 255) 56) +                                     (shiftR w3 8 + shiftL (w2 .&. 255) 56) +                                     (shiftR w4 8 + shiftL (w3 .&. 255) 56 + (n+1))+    | otherwise           -> makeWordList (w2i $ n+1) (x : toList compact)+    where  +      n = w4 .&. 255+      xw = i2w x+      +  _ -> +    let n = width compact+    in  fromDescList' (n+1) (x : toList compact)++--------------------------------------------------------------------------------++-- | We assume that the element is not bigger than the last element!+snoc :: Partition -> Int -> Partition+snoc !compact  0 = compact+snoc !compact !x = case compact of++  Nibble 0 -> singleton x++  Nibble word+    | n < 15    -> Nibble $ (word + 1) .|. shiftL (i2w x) ((15-n)*4)+    | otherwise -> makeMedium (n+1) (toList compact ++ [x])+    where  +      n = w2i (word .&. 15)+      +  Medium1 w1+    | n < 7     -> Medium1 $ (w1 + 1) .|. shiftL (i2w x) ((7-n)*8)+    | otherwise -> Medium2 ((w1 .&. 0xffffffffffffff00) + i2w x) 8+    where  +      n = w2i (w1 .&. 255)++  Medium2 w1 w2+    | n < 15    -> Medium2 w1 $ (w2 + 1) .|. shiftL (i2w x) ((15-n)*8)+    | otherwise -> Medium3 w1 ((w2 .&. 0xffffffffffffff00) + i2w x) 16+    where  +      n = w2i (w2 .&. 255)++  Medium3 w1 w2 w3+    | n < 23    -> Medium3 w1 w2 $ (w3 + 1) .|. shiftL (i2w x) ((23-n)*8)+    | otherwise -> Medium4 w1 w2 ((w3 .&. 0xffffffffffffff00) + i2w x) 24+    where  +      n = w2i (w3 .&. 255)++  Medium4 w1 w2 w3 w4+    | n < 31    -> Medium4 w1 w2 w3 $ (w4 + 1) .|. shiftL (i2w x) ((31-n)*8)+    | otherwise -> makeWordList (n + 1) (toList compact ++ [x])+    where  +      n = w2i (w4 .&. 255)+  +  WordList n list -> WordList (n+1) (go list) where+    go :: [Word64] -> [Word64]+    go (w:[]) = case mod n 4 of+                  0 -> w : shiftL (i2w x) 48 : []+                  1 -> w + shiftL (i2w x) 32 : []+                  2 -> w + shiftL (i2w x) 16 : []+                  3 -> w +        (i2w x)    : []+    go (w:ws) = w : go ws+    go []     = shiftL (i2w x) 48 : []+ +{-   +  _ -> +    let n = width compact+    in  makeWordList (n+1) (toList compact ++ [x])+-}++--------------------------------------------------------------------------------+-- * exponential form++toExponentialForm :: Partition -> [(Int,Int)]+toExponentialForm = map (\xs -> (head xs,length xs)) . group . toAscList++fromExponentialForm :: [(Int,Int)] -> Partition+fromExponentialForm = fromDescList . concatMap f . sortBy g where+  f (!i,!e) = replicate e i+  g (!i, _) (!j,_) = compare j i++--------------------------------------------------------------------------------+-- * Width and height of the bounding rectangle++-- | Width, or the number of parts+width :: Partition -> Int+width compact = case compact of+  Nibble        word -> w2i (word .&.  15)+  Medium1       word -> w2i (word .&. 255)+  Medium2 _     word -> w2i (word .&. 255)+  Medium3 _ _   word -> w2i (word .&. 255)+  Medium4 _ _ _ word -> w2i (word .&. 255)+  WordList n    _    -> n++-- | Height, or the first (that is, the largest) element+height :: Partition -> Int+height compact = case compact of+  Nibble  word        -> w2i (shiftR word 60)+  Medium1 word        -> w2i (shiftR word 56)+  Medium2 word _      -> w2i (shiftR word 56)+  Medium3 word _ _    -> w2i (shiftR word 56)+  Medium4 word _ _ _  -> w2i (shiftR word 56)+  WordList _ (word:_) -> w2i (shiftR word 48)++-- | Width and height +widthHeight :: Partition -> (Int,Int)+widthHeight compact = case compact of +  Nibble  word            -> ( w2i (word  .&.  15) , w2i (shiftR word  60) )+  Medium1 word            -> ( w2i (word  .&. 255) , w2i (shiftR word  56) )+  Medium2 word1     word2 -> ( w2i (word2 .&. 255) , w2i (shiftR word1 56) )+  Medium3 word1 _   word3 -> ( w2i (word3 .&. 255) , w2i (shiftR word1 56) )+  Medium4 word1 _ _ word4 -> ( w2i (word4 .&. 255) , w2i (shiftR word1 56) )+  WordList n (word:_)     -> ( n                   , w2i (shiftR word  48) )++--------------------------------------------------------------------------------+-- * Differential sequence++-- | From a non-increasing sequence @[a1,a2,..,an]@ this computes the sequence of differences+-- @[a1-a2,a2-a3,...,an-0]@+diffSequence :: Partition -> [Int]+diffSequence compact = case compact of++  Nibble 0 -> []++  Nibble w -> +    let !nw = (w .&. 15) +        !w' = w - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w (60 - i*4) - shiftR w' (56 - i*4)) .&. 15 | i<-[0..n-1] ]++  Medium1 w -> +    let !nw = (w .&. 255) +        !w' = w - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w (56 - i*8) - shiftR w' (48 - i*8)) .&. 255 | i<-[0..n-1] ]++  Medium2 w1 w2 -> +    let !nw = (w2 .&. 255) +        !w2' = w2 - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w1 (56 - i*8) - shiftR w1  (48 - i*8)) .&. 255 | i<-[0..6]   ] ++ +        ( w2i $ (       w1            - shiftR w2   56       ) .&. 255               ) : +        [ w2i $ (shiftR w2 (56 - i*8) - shiftR w2' (48 - i*8)) .&. 255 | i<-[0..n-9] ] ++  Medium3 w1 w2 w3 -> +    let !nw = (w3 .&. 255) +        !w3' = w3 - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w1 (56 - i*8) - shiftR w1  (48 - i*8)) .&. 255 | i<-[0..6]    ] ++ +        ( w2i $ (       w1            - shiftR w2   56       ) .&. 255                ) : +        [ w2i $ (shiftR w2 (56 - i*8) - shiftR w2  (48 - i*8)) .&. 255 | i<-[0..6]    ] +++        ( w2i $ (       w2            - shiftR w3   56       ) .&. 255                ) : +        [ w2i $ (shiftR w3 (56 - i*8) - shiftR w3' (48 - i*8)) .&. 255 | i<-[0..n-17] ] ++  Medium4 w1 w2 w3 w4 -> +    let !nw = (w4 .&. 255) +        !w4' = w4 - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w1 (56 - i*8) - shiftR w1  (48 - i*8)) .&. 255 | i<-[0..6]    ] ++ +        ( w2i $ (       w1            - shiftR w2   56       ) .&. 255                ) : +        [ w2i $ (shiftR w2 (56 - i*8) - shiftR w2  (48 - i*8)) .&. 255 | i<-[0..6]    ] +++        ( w2i $ (       w2            - shiftR w3   56       ) .&. 255                ) : +        [ w2i $ (shiftR w3 (56 - i*8) - shiftR w3  (48 - i*8)) .&. 255 | i<-[0..6]    ] +++        ( w2i $ (       w3            - shiftR w4   56       ) .&. 255                ) : +        [ w2i $ (shiftR w4 (56 - i*8) - shiftR w4' (48 - i*8)) .&. 255 | i<-[0..n-25] ] ++  WordList {} -> go (toList compact) where+    go (x:ys@(y:_)) = (x-y) : go ys +    go [x] = [x]+    go []  = []++----------------------------------------++-- | From a non-increasing sequence @[a1,a2,..,an]@ this computes the reversed sequence of differences+-- @[ a[n]-0 , a[n-1]-a[n] , ... , a[2]-a[3] , a[1]-a[2] ] @+reverseDiffSequence :: Partition -> [Int]+reverseDiffSequence compact = case compact of++  Nibble 0 -> []++  Nibble w -> +    let !nw = (w .&. 15) +        !w' = w - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w (60 - i*4) - shiftR w' (56 - i*4)) .&. 15 | i<-toZero (n-1) ]++  Medium1 w -> +    let !nw = (w .&. 255) +        !w' = w - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w (56 - i*8) - shiftR w' (48 - i*8)) .&. 255 | i<-toZero (n-1) ]++  Medium2 w1 w2 -> +    let !nw = (w2 .&. 255) +        !w2' = w2 - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w2 (56 - i*8) - shiftR w2' (48 - i*8)) .&. 255 | i<-toZero (n-9) ] +++        ( w2i $ (       w1            - shiftR w2   56       ) .&. 255                   ) : +        [ w2i $ (shiftR w1 (56 - i*8) - shiftR w1  (48 - i*8)) .&. 255 | i<-toZero 6     ]  +        +  Medium3 w1 w2 w3 -> +    let !nw = (w3 .&. 255) +        !w3' = w3 - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w3 (56 - i*8) - shiftR w3' (48 - i*8)) .&. 255 | i<-toZero (n-17) ] +++        ( w2i $ (       w2            - shiftR w3   56       ) .&. 255                    ) : +        [ w2i $ (shiftR w2 (56 - i*8) - shiftR w2  (48 - i*8)) .&. 255 | i<-toZero 6      ] +++        ( w2i $ (       w1            - shiftR w2   56       ) .&. 255                    ) : +        [ w2i $ (shiftR w1 (56 - i*8) - shiftR w1  (48 - i*8)) .&. 255 | i<-toZero 6      ] ++  Medium4 w1 w2 w3 w4 -> +    let !nw = (w4 .&. 255) +        !w4' = w4 - nw+        !n  = w2i nw+    in  [ w2i $ (shiftR w4 (56 - i*8) - shiftR w4' (48 - i*8)) .&. 255 | i<-toZero (n-25) ] +++        ( w2i $ (       w3            - shiftR w4   56       ) .&. 255                    ) : +        [ w2i $ (shiftR w3 (56 - i*8) - shiftR w3  (48 - i*8)) .&. 255 | i<-toZero 6      ] +++        ( w2i $ (       w2            - shiftR w3   56       ) .&. 255                    ) : +        [ w2i $ (shiftR w2 (56 - i*8) - shiftR w2  (48 - i*8)) .&. 255 | i<-toZero 6      ] +++        ( w2i $ (       w1            - shiftR w2   56       ) .&. 255                    ) : +        [ w2i $ (shiftR w1 (56 - i*8) - shiftR w1  (48 - i*8)) .&. 255 | i<-toZero 6      ] ++  WordList {} -> (h : go asclist) where+    asclist@(h:_) = toAscList compact+    go (x:ys@(y:_)) = (y-x) : go ys +    go [_] = []+    go []  = []++--------------------------------------------------------------------------------+-- *  Dual partition++foreign import ccall unsafe "c_dual_nibble" c_dual_nibble :: Word64 -> Word64++dualPartition :: Partition -> Partition+dualPartition compact = case compact of++  Nibble 0 -> Nibble 0+  Nibble w -> Nibble (c_dual_nibble w)  +  _        -> if (w <= 255 && h <= 31)+                then makeMedium   h dualList+                else makeWordList h dualList+  where+    (w,h) = widthHeight compact+    dualList = concat+      [ replicate d j+      | (j,d) <- zip (toOne w) (reverseDiffSequence compact)+      ]++--------------------------------------------------------------------------------+-- * Conversion to list++toList :: Partition -> [Int]+toList = toDescList++-- | returns a descending (non-increasing) list+toDescList :: Partition -> [Int]+toDescList compact = case compact of++  Nibble 0 -> []++  Nibble word -> +    let !n = w2i (word .&. 15) +    in  [ w2i (shiftR word  (60 - i*4) .&. 15 ) | i<-[0..n-1] ]++  Medium1 word1 -> +    let !n = w2i (word1 .&. 255)+    in  [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-[0..n-1] ]++  Medium2 word1 word2 -> +    let !n = w2i (word2 .&. 255) +    in  [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-[0..7]   ] +++        [ w2i (shiftR word2 (56 - i*8) .&. 255) | i<-[0..n-9] ] ++  Medium3 word1 word2 word3 -> +    let !n = w2i (word3 .&. 255) +    in  [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-[0..7]    ] +++        [ w2i (shiftR word2 (56 - i*8) .&. 255) | i<-[0..7]    ] +++        [ w2i (shiftR word3 (56 - i*8) .&. 255) | i<-[0..n-17] ] ++  Medium4 word1 word2 word3 word4 -> +    let !n = w2i (word4 .&. 255) +    in  [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-[0..7]    ] +++        [ w2i (shiftR word2 (56 - i*8) .&. 255) | i<-[0..7]    ] +++        [ w2i (shiftR word3 (56 - i*8) .&. 255) | i<-[0..7]    ] +++        [ w2i (shiftR word4 (56 - i*8) .&. 255) | i<-[0..n-25] ] ++  WordList _ list -> go list where+    go :: [Word64] -> [Int]+    go !wlist = case wlist of+      (!w):(!ws) -> case ws of +        (_:_)      -> w2i (shiftR w 48          ) :+                      w2i (shiftR w 32 .&. 65535) :+                      w2i (shiftR w 16 .&. 65535) :+                      w2i (       w    .&. 65535) : go ws+        []         -> takeWhile (/=0) (fromWord w)+      []         -> []++    fromWord :: Word64 -> [Int]+    fromWord !word = +      [ w2i (shiftR word 48          )+      , w2i (shiftR word 32 .&. 65535)+      , w2i (shiftR word 16 .&. 65535)+      , w2i (       word    .&. 65535)+      ]++----------------------------------------++-- | Returns a reversed (ascending; non-decreasing) list+toAscList :: Partition -> [Int]+toAscList compact = case compact of++  Nibble 0 -> []++  Nibble word -> +    let !n = w2i (word .&. 15) +    in  [ w2i (shiftR word  (60 - i*4) .&. 15 ) | i<-toZero (n-1) ]++  Medium1 word1 -> +    let !n = w2i (word1 .&. 255)+    in  [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-toZero (n-1) ]++  Medium2 word1 word2 -> +    let !n = w2i (word2 .&. 255) +    in  [ w2i (shiftR word2 (56 - i*8) .&. 255) | i<-toZero (n-9) ] +++        [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-toZero 7     ] ++  Medium3 word1 word2 word3 -> +    let !n = w2i (word3 .&. 255) +    in  [ w2i (shiftR word3 (56 - i*8) .&. 255) | i<-toZero (n-17) ] +++        [ w2i (shiftR word2 (56 - i*8) .&. 255) | i<-toZero 7      ] +++        [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-toZero 7      ]+        +  Medium4 word1 word2 word3 word4 -> +    let !n = w2i (word4 .&. 255) +    in  [ w2i (shiftR word4 (56 - i*8) .&. 255) | i<-toZero (n-25) ] +++        [ w2i (shiftR word3 (56 - i*8) .&. 255) | i<-toZero 7      ] +++        [ w2i (shiftR word2 (56 - i*8) .&. 255) | i<-toZero 7      ] +++        [ w2i (shiftR word1 (56 - i*8) .&. 255) | i<-toZero 7      ]++  WordList _ list -> dropWhile (==0) $ go (reverse list) where+    go :: [Word64] -> [Int]+    go !wlist = case wlist of+      (!w):ws -> w2i (       w    .&. 65535) : +                 w2i (shiftR w 16 .&. 65535) :+                 w2i (shiftR w 32 .&. 65535) :+                 w2i (shiftR w 48          ) : go ws+      [] -> []++{-+    go :: [Word64] -> [Int]+    go (w:[]) = fromWord w+    go (w:ws) = fromWord w ++ go ws+    go []     = []+    fromWord :: Word64 -> [Int]+    fromWord word = [ w2i (shiftR word (48 - i*16) .&. 65535) | i<-toZero 3 ] +-}++--------------------------------------------------------------------------------+-- * Conversion from list++fromDescList :: [Int] -> Partition+fromDescList list = fromDescList' (length list) list++-- | We assume that the input is a non-increasing list of /positive/ integers!+fromDescList' +  :: Int          -- ^ length+  -> [Int]        -- ^ the list+  -> Partition+fromDescList' !n !list =+  case list of+    []                           -> empty+    (h:_) | h <= 0               -> empty+          | h <= 15 && n <= 15   -> makeNibble   n list+          | h >  65535           -> error "partitions with elements bigger than 65535 are not supported"+          | h >  255 || n > 31   -> makeWordList n list+          | otherwise            -> makeMedium   n list++makeNibble :: Int -> [Int] -> Partition+makeNibble !n list = Nibble $ go (i2w n) 60 list where+  go !acc !k (x:xs) = go (acc + shiftL (i2w x) k) (k-4) xs+  go !acc _  []     = acc+{-   +makeNibble :: Int -> [Int] -> Partition+makeNibble !n list = Nibble +  $ sum' [ shiftL (i2w x) (60 - 4*i) | (i,x) <- zip [0..] list ] +  + i2w n+-}++makeMedium :: Int -> [Int] -> Partition+makeMedium !n list +  | n <= 7   = makeMedium1 n list+  | n <= 15  = makeMedium2 n list+  | n <= 23  = makeMedium3 n list+  | n <= 31  = makeMedium4 n list+  | otherwise = error "makeMedium: input list too big (should be smaller than 32)"++makeMedium1 :: Int -> [Int] -> Partition+makeMedium1 !n list = Medium1 +  $ sum' [ shiftL (fromIntegral x) (56 - 8*i) | (i,x) <- zip [0..] list ] +  + fromIntegral n++makeMedium2 :: Int -> [Int] -> Partition+makeMedium2 !n list = Medium2 word1 word2 where+  (list1,list2) = splitAt 8 list+  word1 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list1 ] +  word2 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list2 ] +        + fromIntegral n++makeMedium3 :: Int -> [Int] -> Partition+makeMedium3 !n list = Medium3 word1 word2 word3 where+  (list1,tmp  ) = splitAt 8 list+  (list2,list3) = splitAt 8 tmp+  word1 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list1 ] +  word2 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list2 ] +  word3 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list3 ] +        + i2w n++makeMedium4 :: Int -> [Int] -> Partition+makeMedium4 !n list = Medium4 word1 word2 word3 word4 where+  (list1,tmp1 ) = splitAt 8 list+  (list2,tmp2 ) = splitAt 8 tmp1+  (list3,list4) = splitAt 8 tmp2+  word1 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list1 ] +  word2 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list2 ] +  word3 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list3 ] +  word4 = sum' [ shiftL (i2w x) (56 - 8*i) | (i,x) <- zip [0..] list4 ] +        + i2w n+    +makeWordList :: Int -> [Int] -> Partition+makeWordList !n list = WordList n (go list) where   +  go :: [Int] -> [Word64]+  go !xs = case xs of+    (x:y:z:w:rest) -> makeWord x y z w : go rest+    (x:y:z:  []  ) -> makeWord x y z 0 : []+    (x:y:    []  ) -> makeWord x y 0 0 : []+    (x:      []  ) -> makeWord x 0 0 0 : []+    []             -> []+  makeWord !x !y !z !w = shiftL (i2w x) 48  +                       + shiftL (i2w y) 32  +                       + shiftL (i2w z) 16 +                       +        (i2w w)+{-+  go [] = []+  go xs = case splitAt 4 xs of+    (this,rest) -> case rest of+      [] -> makeWord (take 4 $ this ++ repeat 0) : []+      _  -> makeWord this : go rest+  makeWord [x,y,z,w] = shiftL (i2w x) 48  +                     + shiftL (i2w y) 32  +                     + shiftL (i2w z) 16 +                     +        (i2w w)+-}++--------------------------------------------------------------------------------+-- * Partial orderings++isSubPartitionOf :: Partition -> Partition -> Bool+isSubPartitionOf p q = case (p,q) of++  (Nibble 0 , _       ) -> True+  +  (Nibble u , Nibble v) -> let !n = w2i (u .&. 15) +                           in  and [    (shiftR u (60 - i*4) .&. 15)+                                     <= (shiftR v (60 - i*4) .&. 15) +                                   | i<-[0..n-1] +                                   ]++  _                     -> and $ zipWith (<=) (toList p) (toList q ++ repeat 0)++dominates :: Partition -> Partition -> Bool+dominates q p = case (q,p) of++  (_        , Nibble 0 ) -> True++  (Nibble v , Nibble u ) -> go 60 0 0 where+                              n = u .&. 15                              +                              klimit = w2i (4*(15-n))+                              go !k !b !a = if k <= klimit +                                then True+                                else let !b' = b + (shiftR v k .&. 15)+                                         !a' = a + (shiftR u k .&. 15)+                                     in  if b' < a' +                                           then False +                                           else go (k-4) b' a'++  _                      -> and $ zipWith (>=) (sums $ toList q ++ repeat 0) (sums $ toList p) where+                              sums = tail . scanl' (+) 0++--------------------------------------------------------------------------------+-- * Pieri rule++-- | Expands to product @s[lambda]*h[1] = s[lambda]*e[1]@ as a sum of @s[mu]@-s. See <https://en.wikipedia.org/wiki/Pieri's_formula>+pieriRuleSingleBox :: Partition -> [Partition]+pieriRuleSingleBox !compact = case compact of++  Nibble 0 -> [ singleton 1 ]++  Nibble w | h < 15 -> +    [ Nibble  (w + shiftL 1 (60-4*i)) | (i,d)<-zip [0..n-1] diffs1 , d>0 ] ++ [ snoc compact 1 ]++  Medium1 w | h < 255 -> +    [ Medium1 (w + shiftL 1 (56-8*i)) | (i,d)<-zip [0..n-1] diffs1 , d>0 ] ++ [ snoc compact 1 ]++  Medium2 w1 w2 | h < 255 -> +    let (diffs1a,diffs1b) = splitAt 8 diffs1 +    in  [ Medium2    (w1 + shiftL 1 (56-8*i)) w2 | (i,d)<-zip [0..7  ] diffs1a , d>0 ] +++        [ Medium2 w1 (w2 + shiftL 1 (56-8*i))    | (i,d)<-zip [0..n-9] diffs1b , d>0 ] +++        [ snoc compact 1 ]++  Medium3 w1 w2 w3 | h < 255 -> +    let (diffs1a,tmp    ) = splitAt 8 diffs1 +        (diffs1b,diffs1c) = splitAt 8 tmp+    in  [ Medium3       (w1 + shiftL 1 (56-8*i)) w2 w3 | (i,d)<-zip [0..7   ] diffs1a , d>0 ] +++        [ Medium3    w1 (w2 + shiftL 1 (56-8*i)) w3    | (i,d)<-zip [0..7   ] diffs1b , d>0 ] +++        [ Medium3 w1 w2 (w3 + shiftL 1 (56-8*i))       | (i,d)<-zip [0..n-17] diffs1c , d>0 ] +++        [ snoc compact 1 ]+    +  _ -> genericSingleBox++  where+    (n,h)  =     widthHeight  compact+    list   =     toDescList   compact+    diffs1 = 1 : diffSequence compact++    genericSingleBox :: [Partition]+    genericSingleBox = map (fromDescList' n) (go list diffs1) ++ [ fromDescList' (n+1) (list ++ [1]) ] where+      go :: [Int] -> [Int] -> [[Int]]+      go (a:as) (d:ds) = if d > 0 then ((a+1):as) : map (a:) (go as ds) +                                  else              map (a:) (go as ds)+      go []     _      = []++-- | Expands to product @s[lambda]*h[k]@ as a sum of @s[mu]@-s. See <https://en.wikipedia.org/wiki/Pieri's_formula>+pieriRule :: Partition -> Int -> [Partition]+pieriRule !compact !k +  | k <  0                  = []+  | k == 0                  = [ compact ]+  | k == 1                  = pieriRuleSingleBox compact+  | h == 0                  = [ singleton k ]+  | h + k <= 15  && n < 15  = case compact of { Nibble w -> +                              [ Nibble (w + encode c)  | c <- comps ] }+  | otherwise               = [ fromDescList' (n+b) xs | c <- comps , let (b,xs) = add c ] ++  where+    (n,h)  = widthHeight compact+    list   = toDescList compact+    bounds = k : {- map (min k) -} (diffSequence compact) +    comps = compositions' bounds k++    add clist = go list clist where+      go (!p:ps) (!c:cs) = let (b,rest) = go ps cs in (b, (p+c):rest)+      go []      [c]     = if c>0 then (1,[c]) else (0,[])+      go _       _       = error "Compact/pieriRule/add: shouldn't happen"++    encode :: [Int] -> Word64+    encode = go 60 where+      go !k [c]    = if c==0 then 0 else shiftL (i2w c) k + 1+      go !k (c:cs) = shiftL (i2w c) k + go (k-4) cs+      go !k []     = error "Compact/pieriRule/encode: shouldn't happen"++--------------------------------------------------------------------------------+-- * local (internally used) utility functions++{-# INLINE i2w #-}+i2w :: Int -> Word64+i2w = fromIntegral++{-# INLINE w2i #-}+w2i :: Word64 -> Int+w2i = fromIntegral++{-# INLINE sum' #-}+sum' :: [Word64] -> Word64+sum' = foldl' (+) 0++{-# INLINE safeTail #-}+safeTail :: [Int] -> [Int]+safeTail xs = case xs of { [] -> [] ; _ -> tail xs }++{-# INLINE toZero #-}+toZero :: Int -> [Int]+toZero !n+  | n >  0  = n : toZero (n-1) +  | n == 0  = [0]+  | n <  0  = []++{-# INLINE toOne #-}+toOne :: Int -> [Int]+toOne !n+  | n >  1  = n : toOne (n-1) +  | n == 1  = [1]+  | n <  1  = []++--------------------------------------------------------------------------------++
+ Math/Combinat/Partitions/Integer/Count.hs view
@@ -0,0 +1,215 @@++-- | Counting partitions of integers.++{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables #-}+module Math.Combinat.Partitions.Integer.Count where++--------------------------------------------------------------------------------++import Data.List+import Control.Monad ( liftM , replicateM )++-- import Data.Map (Map)+-- import qualified Data.Map as Map++import Math.Combinat.Numbers ( factorial , binomial , multinomial )+import Math.Combinat.Numbers.Integers -- Primes+import Math.Combinat.Helper++import Data.Array+import System.Random++--------------------------------------------------------------------------------+-- * Infinite tables of integers++-- | A data structure which is essentially an infinite list of @Integer@-s,+-- but fast lookup (for reasonable small inputs)+newtype TableOfIntegers = TableOfIntegers [Array Int Integer]++lookupInteger :: TableOfIntegers -> Int -> Integer+lookupInteger (TableOfIntegers table) !n +  | n >= 0  = (table !! k) ! r+  | n <  0  = 0+  where+    (k,r) = divMod n 1024++makeTableOfIntegers+  :: ((Int -> Integer) -> (Int -> Integer))+  -> TableOfIntegers+makeTableOfIntegers user = table where+  calc  = user lkp+  lkp   = lookupInteger table+  table = TableOfIntegers+    [ listArray (0,1023) (map calc [a..b]) +    | k<-[0..] +    , let a = 1024*k +    , let b = 1024*(k+1) - 1 +    ]++--------------------------------------------------------------------------------+-- * Counting partitions++-- | Number of partitions of @n@ (looking up a table built using Euler's algorithm)+countPartitions :: Int -> Integer+countPartitions = lookupInteger partitionCountTable ++-- | This uses the power series expansion of the infinite product. It is slower than the above.+countPartitionsInfiniteProduct :: Int -> Integer+countPartitionsInfiniteProduct k = partitionCountListInfiniteProduct !! k++-- | This uses 'countPartitions'', and is (very) slow+countPartitionsNaive :: Int -> Integer+countPartitionsNaive d = countPartitions' (d,d) d++--------------------------------------------------------------------------------++-- | This uses Euler's algorithm to compute p(n)+--+-- See eg.:+-- NEIL CALKIN, JIMENA DAVIS, KEVIN JAMES, ELIZABETH PEREZ, AND CHARLES SWANNACK+-- COMPUTING THE INTEGER PARTITION FUNCTION+-- <http://www.math.clemson.edu/~kevja/PAPERS/ComputingPartitions-MathComp.pdf>+--+partitionCountTable :: TableOfIntegers+partitionCountTable = table where++  table = makeTableOfIntegers fun++  fun lkp !n +    | n >  1 = foldl' (+) 0 +             [ (if even k then negate else id) +                 ( lkp (n - div (k*(3*k+1)) 2)+                 + lkp (n - div (k*(3*k-1)) 2)+                 )+             | k <- [1..limit n]+             ]+    | n <  0 = 0+    | n == 0 = 1+    | n == 1 = 1++  limit :: Int -> Int+  limit !n = fromInteger $ ceilingSquareRoot (1 + div (nn+nn+1) 3) where+    nn = fromIntegral n :: Integer++-- | An infinite list containing all @p(n)@, starting from @p(0)@.+partitionCountList :: [Integer]+partitionCountList = map countPartitions [0..]++--------------------------------------------------------------------------------++-- | Infinite list of number of partitions of @0,1,2,...@+--+-- This uses the infinite product formula the generating function of partitions, +-- recursively expanding it; it is reasonably fast for small numbers.+--+-- > partitionCountListInfiniteProduct == map countPartitions [0..]+--+partitionCountListInfiniteProduct :: [Integer]+partitionCountListInfiniteProduct = final where++  final = go 1 (1:repeat 0) ++  go !k (x:xs) = x : go (k+1) ys where+    ys = zipWith (+) xs (take k final ++ ys)+    -- explanation:+    --   xs == drop k $ f (k-1)+    --   ys == drop k $ f (k  )  ++{-++Full explanation of 'partitionCountList':+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++let f k = productPSeries $ map (:[]) [1..k]++f 0 = [1,0,0,0,0,0,0,0...]+f 1 = [1,1,1,1,1,1,1,1...]+f 2 = [1,1,2,2,3,3,4,4...]+f 3 = [1,1,2,3,4,5,7,8...]++observe: ++* take (k+1) (f k) == take (k+1) partitionCountList+* f (k+1) == zipWith (+) (f k) (replicate (k+1) 0 ++ f (k+1))++now apply (drop (k+1)) to the second one : ++* drop (k+1) (f (k+1)) == zipWith (+) (drop (k+1) $ f k) (f (k+1))+* f (k+1) = take (k+1) final ++ drop (k+1) (f (k+1))++-}++--------------------------------------------------------------------------------++-- | Naive infinite list of number of partitions of @0,1,2,...@+--+-- > partitionCountListNaive == map countPartitionsNaive [0..]+--+-- This is very slow.+--+partitionCountListNaive :: [Integer]+partitionCountListNaive = map countPartitionsNaive [0..]++--------------------------------------------------------------------------------+-- * Counting all partitions++countAllPartitions :: Int -> Integer+countAllPartitions d = sum' [ countPartitions i | i <- [0..d] ]++-- | Count all partitions fitting into a rectangle.+-- # = \\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++--------------------------------------------------------------------------------+-- * Counting fitting into a rectangle++-- | Number of of d, fitting into a given rectangle. Naive recursive algorithm.+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 with given number of parts++-- | Count partitions of @n@ into @k@ parts.+--+-- Naive recursive algorithm.+--+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))] ]++--------------------------------------------------------------------------------+-- Partitions with only odd\/distinct parts++{-+-- | Partitions of @n@ with only odd parts+partitionsWithOddParts :: Int -> [Partition]+partitionsWithOddParts d = map Partition (go d d) where+  go _  0  = [[]]+  go !h !n = [ a:as | a<-[1,3..min n h], as <- go a (n-a) ]+-}++{-+-- > length (partitionsWithDistinctParts d) == length (partitionsWithOddParts d)+--+partitionsWithDistinctParts :: Int -> [Partition]+partitionsWithDistinctParts d = map Partition (go d d) where+  go _  0  = [[]]+  go !h !n = [ a:as | a<-[1..min n h], as <- go (a-1) (n-a) ]+-}++--------------------------------------------------------------------------------
+ Math/Combinat/Partitions/Integer/IntList.hs view
@@ -0,0 +1,398 @@++-- | Partition functions working on lists of integers.+-- +-- It's not recommended to use this module directly.++{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables #-}+module Math.Combinat.Partitions.Integer.IntList where++--------------------------------------------------------------------------------++import Data.List+import Control.Monad ( liftM , replicateM )++import Math.Combinat.Numbers ( factorial , binomial , multinomial )+import Math.Combinat.Helper++import Data.Array+import System.Random++import Math.Combinat.Partitions.Integer.Count ( countPartitions )++--------------------------------------------------------------------------------+-- * Type and basic stuff++-- | Sorts the input, and cuts the nonpositive elements.+_mkPartition :: [Int] -> [Int]+_mkPartition xs = sortBy (reverseCompare) $ filter (>0) xs+ +-- | This returns @True@ if the input is non-increasing sequence of +-- /positive/ integers (possibly empty); @False@ otherwise.+--+_isPartition :: [Int] -> Bool+_isPartition []  = True+_isPartition [x] = x > 0+_isPartition (x:xs@(y:_)) = (x >= y) && _isPartition xs+++_dualPartition :: [Int] -> [Int]+_dualPartition [] = []+_dualPartition xs = go 0 (_diffSequence xs) [] where+  go !i (d:ds) acc = go (i+1) ds (d:acc)+  go n  []     acc = finish n acc +  finish !j (k:ks) = replicate k j ++ finish (j-1) ks+  finish _  []     = []++--------------------------------------------------------------------------------++{-+-- more variations:++_dualPartition_b :: [Int] -> [Int]+_dualPartition_b [] = []+_dualPartition_b xs = go 1 (diffSequence xs) [] where+  go !i (d:ds) acc = go (i+1) ds ((d,i):acc)+  go _  []     acc = concatMap (\(d,i) -> replicate d i) acc++_dualPartition_c :: [Int] -> [Int]+_dualPartition_c [] = []+_dualPartition_c xs = reverse $ concat $ zipWith f [1..] (diffSequence xs) where+  f _ 0 = []+  f k d = replicate d k+-}++-- | A simpler, but bit slower (about twice?) implementation of dual partition+_dualPartitionNaive :: [Int] -> [Int]+_dualPartitionNaive [] = []+_dualPartitionNaive xs@(k:_) = [ length $ filter (>=i) xs | i <- [1..k] ]++-- | From a sequence @[a1,a2,..,an]@ computes the sequence of differences+-- @[a1-a2,a2-a3,...,an-0]@+_diffSequence :: [Int] -> [Int]+_diffSequence = go where+  go (x:ys@(y:_)) = (x-y) : go ys +  go [x] = [x]+  go []  = []++-- | Example:+--+-- > _elements [5,4,1] ==+-- >   [ (1,1), (1,2), (1,3), (1,4), (1,5)+-- >   , (2,1), (2,2), (2,3), (2,4)+-- >   , (3,1)+-- >   ]+--++_elements :: [Int] -> [(Int,Int)]+_elements shape = [ (i,j) | (i,l) <- zip [1..] shape, j<-[1..l] ] ++---------------------------------------------------------------------------------+-- * Exponential form++-- | We convert a partition to exponential form.+-- @(i,e)@ mean @(i^e)@; for example @[(1,4),(2,3)]@ corresponds to @(1^4)(2^3) = [2,2,2,1,1,1,1]@. Another example:+--+-- > toExponentialForm (Partition [5,5,3,2,2,2,2,1,1]) == [(1,2),(2,4),(3,1),(5,2)]+--+_toExponentialForm :: [Int] -> [(Int,Int)]+_toExponentialForm = reverse . map (\xs -> (head xs,length xs)) . group++_fromExponentialForm :: [(Int,Int)] -> [Int]+_fromExponentialForm = sortBy reverseCompare . go where+  go ((j,e):rest) = replicate e j ++ go rest+  go []           = []   ++---------------------------------------------------------------------------------+-- * Generating partitions++-- | Partitions of @d@, as lists+_partitions :: Int -> [[Int]]+_partitions d = go d d where+  go _  0  = [[]]+  go !h !n = [ a:as | a<-[1..min n h], as <- go a (n-a) ]++-- | All integer partitions up to a given degree (that is, all integer partitions whose sum is less or equal to @d@)+_allPartitions :: Int -> [[Int]]+_allPartitions d = concat [ _partitions i | i <- [0..d] ]++-- | All integer partitions up to a given degree (that is, all integer partitions whose sum is less or equal to @d@),+-- grouped by weight+_allPartitionsGrouped :: Int -> [[[Int]]]+_allPartitionsGrouped d = [ _partitions i | i <- [0..d] ]++---------------------------------------------------------------------------------++-- | 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 = +  [ i:xs | i <- [1..min d h] , xs <- _partitions' (i,w-1) (d-i) ]++---------------------------------------------------------------------------------+-- * Random partitions++-- | Uniformly random partition of the given weight. +--+-- NOTE: This algorithm is effective for small @n@-s (say @n@ up to a few hundred \/ one thousand it should work nicely),+-- and the first time it is executed may be slower (as it needs to build the table 'partitionCountList' first)+--+-- Algorithm of Nijenhuis and Wilf (1975); see+--+-- * Knuth Vol 4A, pre-fascicle 3B, exercise 47;+--+-- * Nijenhuis and Wilf: Combinatorial Algorithms for Computers and Calculators, chapter 10+--+_randomPartition :: RandomGen g => Int -> g -> ([Int], g)+_randomPartition n g = (p, g') where+  ([p], g') = _randomPartitions 1 n g++-- | Generates several uniformly random partitions of @n@ at the same time.+-- Should be a little bit faster then generating them individually.+--+_randomPartitions +  :: forall g. RandomGen g +  => Int   -- ^ number of partitions to generate+  -> Int   -- ^ the weight of the partitions+  -> g -> ([[Int]], g)+_randomPartitions howmany n = runRand $ replicateM howmany (worker n []) where++  cnt = countPartitions+ +  finish :: [(Int,Int)] -> [Int]+  finish = _mkPartition . concatMap f where f (j,d) = replicate j d++  fi :: Int -> Integer +  fi = fromIntegral++  find_jd :: Int -> Integer -> (Int,Int)+  find_jd m capm = go 0 [ (j,d) | j<-[1..n], d<-[1..div m j] ] where+    go :: Integer -> [(Int,Int)] -> (Int,Int)+    go !s []   = (1,1)       -- ??+    go !s [jd] = jd          -- ??+    go !s (jd@(j,d):rest) = +      if s' > capm +        then jd +        else go s' rest+      where+        s' = s + fi d * cnt (m - j*d)++  worker :: Int -> [(Int,Int)] -> Rand g [Int]+  worker  0 acc = return $ finish acc+  worker !m acc = do+    capm <- randChoose (0, (fi m) * cnt m - 1)+    let jd@(!j,!d) = find_jd m capm+    worker (m - j*d) (jd:acc)+++---------------------------------------------------------------------------------+-- * Dominance order ++-- | @q \`dominates\` p@ returns @True@ if @q >= p@ in the dominance order of partitions+-- (this is partial ordering on the set of partitions of @n@).+--+-- See <http://en.wikipedia.org/wiki/Dominance_order>+--+_dominates :: [Int] -> [Int] -> Bool+_dominates qs ps+  = and $ zipWith (>=) (sums (qs ++ repeat 0)) (sums ps)+  where+    sums = scanl (+) 0++-- | Lists all partitions of the same weight as @lambda@ and also dominated by @lambda@+-- (that is, all partial sums are less or equal):+--+-- > dominatedPartitions lam == [ mu | mu <- partitions (weight lam), lam `dominates` mu ]+-- +_dominatedPartitions :: [Int] -> [[Int]]+_dominatedPartitions []     = [[]]+_dominatedPartitions lambda = go (head lambda) w dsums 0 where++  n = length lambda+  w = sum    lambda+  dsums = scanl1 (+) (lambda ++ repeat 0)++  go _   0 _       _  = [[]]+  go !h !w (!d:ds) !e  +    | w >  0  = [ (a:as) | a <- [1..min h (d-e)] , as <- go a (w-a) ds (e+a) ] +    | w == 0  = [[]]+    | w <  0  = error "_dominatedPartitions: fatal error; shouldn't happen"++-- | Lists all partitions of the sime weight as @mu@ and also dominating @mu@+-- (that is, all partial sums are greater or equal):+--+-- > dominatingPartitions mu == [ lam | lam <- partitions (weight mu), lam `dominates` mu ]+-- +_dominatingPartitions :: [Int] -> [[Int]]+_dominatingPartitions []     = [[]]+_dominatingPartitions mu     = go w w dsums 0 where++  n = length mu+  w = sum    mu+  dsums = scanl1 (+) (mu ++ repeat 0)++  go _   0 _       _  = [[]]+  go !h !w (!d:ds) !e  +    | w >  0  = [ (a:as) | a <- [max 0 (d-e)..min h w] , as <- go a (w-a) ds (e+a) ] +    | w == 0  = [[]]+    | w <  0  = error "_dominatingPartitions: fatal error; shouldn't happen"++--------------------------------------------------------------------------------+-- * 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+  -> [[Int]]+_partitionsWithKParts k n = 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) ]++--------------------------------------------------------------------------------+-- * Partitions with only odd\/distinct parts++-- | Partitions of @n@ with only odd parts+_partitionsWithOddParts :: Int -> [[Int]]+_partitionsWithOddParts d = (go d d) where+  go _  0  = [[]]+  go !h !n = [ a:as | a<-[1,3..min n h], as <- go a (n-a) ]++{-+-- | Partitions of @n@ with only even parts+--+-- Note: this is not very interesting, it's just @(map.map) (2*) $ _partitions (div n 2)@+--+_partitionsWithEvenParts :: Int -> [[Int]]+_partitionsWithEvenParts d = (go d d) where+  go _  0  = [[]]+  go !h !n = [ a:as | a<-[2,4..min n h], as <- go a (n-a) ]+-}++-- | Partitions of @n@ with distinct parts.+-- +-- Note:+--+-- > length (partitionsWithDistinctParts d) == length (partitionsWithOddParts d)+--+_partitionsWithDistinctParts :: Int -> [[Int]]+_partitionsWithDistinctParts d = (go d d) where+  go _  0  = [[]]+  go !h !n = [ a:as | a<-[1..min n h], as <- go (a-1) (n-a) ]++--------------------------------------------------------------------------------+-- * Sub- and super-partitions of a given partition++-- | Returns @True@ of the first partition is a subpartition (that is, fit inside) of the second.+-- This includes equality+_isSubPartitionOf :: [Int] -> [Int] -> Bool+_isSubPartitionOf ps qs = and $ zipWith (<=) ps (qs ++ repeat 0)++-- | This is provided for convenience\/completeness only, as:+--+-- > isSuperPartitionOf q p == isSubPartitionOf p q+--+_isSuperPartitionOf :: [Int] -> [Int] -> Bool+_isSuperPartitionOf qs ps = and $ zipWith (<=) ps (qs ++ repeat 0)+++-- | Sub-partitions of a given partition with the given weight:+--+-- > sort (subPartitions d q) == sort [ p | p <- partitions d, isSubPartitionOf p q ]+--+_subPartitions :: Int -> [Int] -> [[Int]]+_subPartitions d big+  | null big       = if d==0 then [[]] else []+  | d > sum' big   = []+  | d < 0          = []+  | otherwise      = go d (head big) big+  where+    go :: Int -> Int -> [Int] -> [[Int]]+    go !k !h []      = if k==0 then [[]] else []+    go !k !h (b:bs) +      | k<0 || h<0   = []+      | k==0         = [[]]+      | h==0         = []+      | otherwise    = [ this:rest | this <- [1..min h b] , rest <- go (k-this) this bs ]++----------------------------------------++-- | All sub-partitions of a given partition+_allSubPartitions :: [Int] -> [[Int]]+_allSubPartitions big +  | null big   = [[]]+  | otherwise  = go (head big) big+  where+    go _  [] = [[]]+    go !h (b:bs) +      | h==0         = []+      | otherwise    = [] : [ this:rest | this <- [1..min h b] , rest <- go this bs ]++----------------------------------------++-- | Super-partitions of a given partition with the given weight:+--+-- > sort (superPartitions d p) == sort [ q | q <- partitions d, isSubPartitionOf p q ]+--+_superPartitions :: Int -> [Int] -> [[Int]]+_superPartitions dd small+  | dd < w0     = []+  | null small  = _partitions dd+  | otherwise   = go dd w1 dd (small ++ repeat 0)+  where+    w0 = sum' small+    w1 = w0 - head small+    -- d = remaining weight of the outer partition we are constructing+    -- w = remaining weight of the inner partition (we need to reserve at least this amount)+    -- h = max height (decreasing)+    go !d !w !h (!a:as@(b:_)) +      | d < 0     = []+      | d == 0    = if a == 0 then [[]] else []+      | otherwise = [ this:rest | this <- [max 1 a .. min h (d-w)] , rest <- go (d-this) (w-b) this as ]+    +--------------------------------------------------------------------------------+-- * The Pieri rule++-- | The Pieri rule computes @s[lambda]*h[n]@ as a sum of @s[mu]@-s (each with coefficient 1).+--+-- See for example <http://en.wikipedia.org/wiki/Pieri's_formula>+--+-- | We assume here that @lambda@ is a partition (non-increasing sequence of /positive/ integers)! +_pieriRule :: [Int] -> Int -> [[Int]] +_pieriRule lambda n+    | n == 0     = [lambda]+    | n <  0     = [] +    | otherwise  = go n diffs dsums (lambda++[0]) +    where+      diffs = n : _diffSequence lambda                 -- maximum we can add to a given row+      dsums = reverse $ scanl1 (+) (reverse diffs)    -- partial sums of remaining total we can add+      go !k (d:ds) (p:ps@(q:_)) (l:ls) +        | k > p     = []+        | otherwise = [ h:tl | a <- [ max 0 (k-q) .. min d k ] , let h = l+a , tl <- go (k-a) ds ps ls ]+      go !k [d]    _      [l]    = if k <= d +                                     then if l+k>0 then [[l+k]] else [[]]+                                     else []+      go !k []     _      _      = if k==0 then [[]] else []++-- | The dual Pieri rule computes @s[lambda]*e[n]@ as a sum of @s[mu]@-s (each with coefficient 1)+_dualPieriRule :: [Int] -> Int -> [[Int]] +_dualPieriRule lam n = map _dualPartition $ _pieriRule (_dualPartition lam) n++--------------------------------------------------------------------------------
+ Math/Combinat/Partitions/Integer/Naive.hs view
@@ -0,0 +1,202 @@++-- | Naive implementation of partitions of integers, encoded as list of @Int@-s.+--+-- Integer partitions are nonincreasing sequences of positive integers.+--+-- This is an internal module, you are not supposed to import it directly.+--+ ++{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables, PatternSynonyms, ViewPatterns #-}+module Math.Combinat.Partitions.Integer.Naive where++--------------------------------------------------------------------------------++import Data.List +import Control.Monad ( liftM , replicateM )++-- import Data.Map (Map)+-- import qualified Data.Map as Map++import Math.Combinat.Classes+import Math.Combinat.ASCII as ASCII+import Math.Combinat.Numbers (factorial,binomial,multinomial)+import Math.Combinat.Helper++import Data.Array+import System.Random++import Math.Combinat.Partitions.Integer.IntList+import Math.Combinat.Partitions.Integer.Count ( countPartitions )++--------------------------------------------------------------------------------+-- * Type and basic stuff++-- | A partition of an integer. The additional invariant enforced here is that partitions +-- are monotone decreasing sequences of /positive/ integers. The @Ord@ instance is lexicographical.+newtype Partition = Partition [Int] deriving (Eq,Ord,Show,Read)++instance HasNumberOfParts Partition where+  numberOfParts (Partition p) = length p++---------------------------------------------------------------------------------++isEmptyPartition :: Partition -> Bool+isEmptyPartition (Partition p) = null p++emptyPartition :: Partition+emptyPartition = Partition []++instance CanBeEmpty Partition where+  empty   = emptyPartition+  isEmpty = isEmptyPartition++-- | The first element of the sequence.+partitionHeight :: Partition -> Int+partitionHeight (Partition part) = case part of+  (p:_) -> p+  []    -> 0+  +-- | The length of the sequence (that is, the number of parts).+partitionWidth :: Partition -> Int+partitionWidth (Partition part) = length part++instance HasHeight Partition where+  height = partitionHeight+ +instance HasWidth Partition where+  width = partitionWidth++heightWidth :: Partition -> (Int,Int)+heightWidth part = (height part, width part)++-- | The weight of the partition +--   (that is, the sum of the corresponding sequence).+partitionWeight :: Partition -> Int+partitionWeight (Partition part) = sum' part++instance HasWeight Partition where +  weight = partitionWeight++-- | The dual (or conjugate) partition.+dualPartition :: Partition -> Partition+dualPartition (Partition part) = Partition (_dualPartition part)++instance HasDuality Partition where +  dual = dualPartition++-- | Example:+--+-- > elements (toPartition [5,4,1]) ==+-- >   [ (1,1), (1,2), (1,3), (1,4), (1,5)+-- >   , (2,1), (2,2), (2,3), (2,4)+-- >   , (3,1)+-- >   ]+--+elements :: Partition -> [(Int,Int)]+elements (Partition part) = _elements part++--------------------------------------------------------------------------------+-- * Pattern synonyms ++-- | Pattern sysnonyms allows us to use existing code with minimal modifications+pattern Nil :: Partition+pattern Nil <- (isEmpty -> True) where+        Nil =  empty++pattern Cons :: Int -> Partition -> Partition+pattern Cons x xs  <- (unconsPartition -> Just (x,xs)) where+        Cons x (Partition xs) = Partition (x:xs)++-- | Simulated newtype constructor +pattern Partition_ :: [Int] -> Partition+pattern Partition_ xs = Partition xs++pattern Head :: Int -> Partition +pattern Head h <- (head . toDescList -> h)++pattern Tail :: Partition -> Partition+pattern Tail xs <- (Partition . tail . toDescList -> xs)++pattern Length :: Int -> Partition +pattern Length n <- (partitionWidth -> n)        + +---------------------------------------------------------------------------------+-- * Exponential form++-- | We convert a partition to exponential form.+-- @(i,e)@ mean @(i^e)@; for example @[(1,4),(2,3)]@ corresponds to @(1^4)(2^3) = [2,2,2,1,1,1,1]@. Another example:+--+-- > toExponentialForm (Partition [5,5,3,2,2,2,2,1,1]) == [(1,2),(2,4),(3,1),(5,2)]+--+toExponentialForm :: Partition -> [(Int,Int)]+toExponentialForm = _toExponentialForm . toDescList++fromExponentialForm :: [(Int,Int)] -> Partition+fromExponentialForm = Partition . _fromExponentialForm where++--------------------------------------------------------------------------------+-- * List-like operations++-- | From a sequence @[a1,a2,..,an]@ computes the sequence of differences+-- @[a1-a2,a2-a3,...,an-0]@+diffSequence :: Partition -> [Int]+diffSequence = go . toDescList where+  go (x:ys@(y:_)) = (x-y) : go ys +  go [x] = [x]+  go []  = []++unconsPartition :: Partition -> Maybe (Int,Partition)+unconsPartition (Partition xs) = case xs of+  (y:ys) -> Just (y, Partition ys)+  []     -> Nothing++toDescList :: Partition -> [Int]+toDescList (Partition xs) = xs++---------------------------------------------------------------------------------+-- * Dominance order ++-- | @q \`dominates\` p@ returns @True@ if @q >= p@ in the dominance order of partitions+-- (this is partial ordering on the set of partitions of @n@).+--+-- See <http://en.wikipedia.org/wiki/Dominance_order>+--+dominates :: Partition -> Partition -> Bool+dominates (Partition qs) (Partition ps) +  = and $ zipWith (>=) (sums (qs ++ repeat 0)) (sums ps)+  where+    sums = scanl (+) 0++--------------------------------------------------------------------------------+-- * Containment partial ordering++-- | Returns @True@ of the first partition is a subpartition (that is, fit inside) of the second.+-- This includes equality+isSubPartitionOf :: Partition -> Partition -> Bool+isSubPartitionOf (Partition ps) (Partition qs) = and $ zipWith (<=) ps (qs ++ repeat 0)++-- | This is provided for convenience\/completeness only, as:+--+-- > isSuperPartitionOf q p == isSubPartitionOf p q+--+isSuperPartitionOf :: Partition -> Partition -> Bool+isSuperPartitionOf (Partition qs) (Partition ps) = and $ zipWith (<=) ps (qs ++ repeat 0)+    +--------------------------------------------------------------------------------+-- * The Pieri rule++-- | The Pieri rule computes @s[lambda]*h[n]@ as a sum of @s[mu]@-s (each with coefficient 1).+--+-- See for example <http://en.wikipedia.org/wiki/Pieri's_formula>+--+pieriRule :: Partition -> Int -> [Partition] +pieriRule (Partition lambda) n = map Partition (_pieriRule lambda n) where++-- | The dual Pieri rule computes @s[lambda]*e[n]@ as a sum of @s[mu]@-s (each with coefficient 1)+dualPieriRule :: Partition -> Int -> [Partition] +dualPieriRule lam n = map dualPartition $ pieriRule (dualPartition lam) n++--------------------------------------------------------------------------------++
Math/Combinat/Partitions/Skew.hs view
@@ -82,6 +82,13 @@ instance HasDuality SkewPartition where   dual = dualSkewPartition +-- | See "partitionElements"+skewPartitionElements :: SkewPartition -> [(Int, Int)]+skewPartitionElements (SkewPartition abs) = concat+  [ [ (i,j) | j <- [a+1 .. a+b] ]+  | (i,(a,b)) <- zip [1..] abs+  ]+ -------------------------------------------------------------------------------- -- * Listing skew partitions @@ -109,6 +116,17 @@   where     outerWeight = innerWeight + skewWeight      innerWeight = weight inner ++--------------------------------------------------------------------------------+-- connected components++{-+connectedComponents :: SkewPartition -> [((Int,Int),SkewPartition)]+connectedComponents = error "connectedComponents: not implemented yet"++isConnectedSkewPartition :: SkewPartition -> Bool+isConnectedSkewPartition skewp = length (connectedComponents skewp) == 1+-}  -------------------------------------------------------------------------------- -- * ASCII
+ Math/Combinat/Partitions/Skew/Ribbon.hs view
@@ -0,0 +1,364 @@++-- | Ribbons (also called border strips, skew hooks, skew rim hooks, etc...).+--+-- Ribbons are skew partitions that are 1) connected, 2) do not contain+-- 2x2 blocks. Intuitively, they are 1-box wide continuous strips on+-- the boundary.+--+-- An alternative definition that they are skew partitions whose projection+-- to the diagonal line is a continuous segment of width 1.++{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}+module Math.Combinat.Partitions.Skew.Ribbon where++--------------------------------------------------------------------------------++import Data.Array+import Data.List+import Data.Maybe++import qualified Data.Map as Map++import Math.Combinat.Sets+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Integer.IntList ( _diffSequence )+import Math.Combinat.Partitions.Skew+import Math.Combinat.Tableaux+import Math.Combinat.Tableaux.LittlewoodRichardson+import Math.Combinat.Tableaux.GelfandTsetlin+import Math.Combinat.Helper++--------------------------------------------------------------------------------+-- * Corners (TODO: move to Partitions - but we also want to refactor that)++-- | The coordinates of the outer corners +outerCorners :: Partition -> [(Int,Int)]+outerCorners = outerCornerBoxes++-- | The coordinates of the inner corners, including the two on the two coordinate+-- axes. For the partition @[5,4,1]@ the result should be @[(0,5),(1,4),(2,1),(3,0)]@+extendedInnerCorners:: Partition -> [(Int,Int)]+extendedInnerCorners (Partition_ ps) = (0, head ps') : catMaybes mbCorners where+  ps' = ps ++ [0]+  mbCorners = zipWith3 f [1..] (tail ps') (_diffSequence ps') +  f !y !x !k = if k > 0 then Just (y,x) else Nothing++-- | Sequence of all the (extended) corners+extendedCornerSequence :: Partition -> [(Int,Int)]+extendedCornerSequence (Partition_ ps) = {- if null ps then [(0,0)] else -} interleave inner outer where+  inner = (0, head ps') : [ (y,x) | (y,x,k) <- zip3 [1..] (tail ps') diff , k>0 ]+  outer =                 [ (y,x) | (y,x,k) <- zip3 [1..] ps'        diff , k>0 ]+  diff = _diffSequence ps'+  ps' = ps ++ [0]++-- | The inner corner /boxes/ of the partition. Coordinates are counted from 1+-- (cf.the 'elements' function), and the first coordinate is the row, the second+-- the column (in English notation).+--+-- For the partition @[5,4,1]@ the result should be @[(1,4),(2,1)]@+--+-- > innerCornerBoxes lambda == (tail $ init $ extendedInnerCorners lambda)+--+innerCornerBoxes :: Partition -> [(Int,Int)]+innerCornerBoxes (Partition_ ps) = +  case ps of+    []  -> []+    _   -> catMaybes mbCorners +  where+    mbCorners = zipWith3 f [1..] (tail ps) (_diffSequence ps) +    f !y !x !k = if k > 0 then Just (y,x) else Nothing++-- | The outer corner /boxes/ of the partition. Coordinates are counted from 1+-- (cf.the 'elements' function), and the first coordinate is the row, the second+-- the column (in English notation).+--+-- For the partition @[5,4,1]@ the result should be @[(1,5),(2,4),(3,1)]@+outerCornerBoxes :: Partition -> [(Int,Int)]+outerCornerBoxes (Partition_ ps) = catMaybes mbCorners where+  mbCorners = zipWith3 f [1..] ps (_diffSequence ps) +  f !y !x !k = if k > 0 then Just (y,x) else Nothing++-- | The outer and inner corner boxes interleaved, so together they form +-- the turning points of the full border strip+cornerBoxSequence :: Partition -> [(Int,Int)]+cornerBoxSequence (Partition_ ps) = if null ps then [] else interleave outer inner where+  inner = [ (y,x) | (y,x,k) <- zip3 [1..] tailps diff , k>0 ]+  outer = [ (y,x) | (y,x,k) <- zip3 [1..] ps     diff , k>0 ]+  diff = _diffSequence ps+  tailps = case ps of { [] -> [] ; _-> tail ps }++--------------------------------------------------------------------------------++-- | Naive (and very slow) implementation of @innerCornerBoxes@, for testing purposes+innerCornerBoxesNaive :: Partition -> [(Int,Int)]+innerCornerBoxesNaive part = filter f boxes where+  boxes = elements part+  f (y,x) =       elem (y+1,x  ) boxes+          &&      elem (y  ,x+1) boxes+          && not (elem (y+1,x+1) boxes)++-- | Naive (and very slow) implementation of @outerCornerBoxes@, for testing purposes+outerCornerBoxesNaive :: Partition -> [(Int,Int)]+outerCornerBoxesNaive part = filter f boxes where+  boxes = elements part+  f (y,x) =  not (elem (y+1,x  ) boxes)+          && not (elem (y  ,x+1) boxes)+          && not (elem (y+1,x+1) boxes)++--------------------------------------------------------------------------------+-- * Ribbon++-- | A skew partition is a a ribbon (or border strip) if and only if projected+-- to the diagonals the result is an interval.+isRibbon :: SkewPartition -> Bool+isRibbon skewp = go Nothing proj where+  proj = Map.toList +       $ Map.fromListWith (+) [ (x-y , 1) | (y,x) <- skewPartitionElements skewp ]+  go Nothing   []            = False+  go (Just _)  []            = True+  go Nothing   ((a,h):rest)  = (h == 1) &&               go (Just a) rest  +  go (Just b)  ((a,h):rest)  = (h == 1) && (a == b+1) && go (Just a) rest++{-+-- | Naive (and slow) reference implementation of "isRibbon"+isRibbonNaive :: SkewPartition -> Bool+isRibbonNaive skewp = isConnectedSkewPartition skewp && no2x2 where+  boxes = skewPartitionElements skewp+  no2x2 = and +    [ not ( elem (y+1,x  ) boxes &&             +            elem (y  ,x+1) boxes &&  +            elem (y+1,x+1) boxes )        -- no 2x2 blocks +    | (y,x) <- boxes +    ]+-}++toRibbon :: SkewPartition -> Maybe Ribbon+toRibbon skew = +  if not (isRibbon skew)+    then Nothing+    else Just ribbon +  where+    ribbon =  Ribbon+      { rbShape  = skew+      , rbLength = skewPartitionWeight skew+      , rbHeight = height+      , rbWidth  = width+      }+    elems  = skewPartitionElements skew+    height = (length $ group $ sort $ map fst elems) - 1    -- TODO: optimize these+    width  = (length $ group $ sort $ map snd elems) - 1++-- | Border strips (or ribbons) are defined to be skew partitions which are +-- connected and do not contain 2x2 blocks.+-- +-- The /length/ of a border strip is the number of boxes it contains,+-- and its /height/ is defined to be one less than the number of rows+-- (in English notation) it occupies. The /width/ is defined symmetrically to +-- be one less than the number of columns it occupies.+--+data Ribbon = Ribbon+  { rbShape  :: SkewPartition+  , rbLength :: Int+  , rbHeight :: Int+  , rbWidth  :: Int+  }+  deriving (Eq,Ord,Show)++--------------------------------------------------------------------------------+-- * Inner border strips++-- | Ribbons (or border strips) are defined to be skew partitions which are +-- connected and do not contain 2x2 blocks. This function returns the+-- border strips whose outer partition is the given one.+innerRibbons :: Partition -> [Ribbon]+innerRibbons part@(Partition ps) = if null ps then [] else strips where++  strips  = [ mkStrip i j +            | i<-[1..n] , _canStartStrip (annArr!i)+            , j<-[i..n] , _canEndStrip   (annArr!j)+            ]++  n       = length annList+  annList = annotatedInnerBorderStrip part+  annArr  = listArray (1,n) annList++  mkStrip !i1 !i2 = Ribbon shape len height width where+    ps'   = ps ++ [0]+    shape = SkewPartition [ (p-k,k) | (i,p,q) <- zip3 [1..] ps (tail ps') , let k = indent i p q ] +    indent !i !p !q +      | i <  y1    = 0+      | i >  y2    = 0+      | i == y2    = p - x2 + 1     -- the order is important here !!!+      | otherwise  = p - q  + 1     -- because of the case y1 == y2 == i++    len    = i2 - i1 + 1+    height = y2 - y1+    width  = x1 - x2+    BorderBox _ _ y1 x1 = annArr ! i1+    BorderBox _ _ y2 x2 = annArr ! i2++-- | Inner border strips (or ribbons) of the given length+innerRibbonsOfLength :: Partition -> Int -> [Ribbon]+innerRibbonsOfLength part@(Partition ps) givenLength = if null ps then [] else strips where++  strips  = [ mkStrip i j +            | i<-[1..n] , _canStartStrip (annArr!i)+            , j<-[i..n] , _canEndStrip   (annArr!j)+            , j-i+1 == givenLength+            ]++  n       = length annList+  annList = annotatedInnerBorderStrip part+  annArr  = listArray (1,n) annList++  mkStrip !i1 !i2 = Ribbon shape givenLength height width where+    ps'   = ps ++ [0]+    shape = SkewPartition [ (p-k,k) | (i,p,q) <- zip3 [1..] ps (tail ps') , let k = indent i p q ] +    indent !i !p !q +      | i <  y1    = 0+      | i >  y2    = 0+      | i == y2    = p - x2 + 1     -- the order is important here !!!+      | otherwise  = p - q  + 1     -- because of the case y1 == y2 == i++    height = y2 - y1+    width  = x1 - x2+    BorderBox _ _ y1 x1 = annArr ! i1+    BorderBox _ _ y2 x2 = annArr ! i2+++--------------------------------------------------------------------------------+-- * Outer border strips++-- | Hooks of length @n@ (TODO: move to the partition module)+listHooks :: Int -> [Partition]+listHooks 0 = []+listHooks 1 = [ Partition [1] ]+listHooks n = [ Partition (k : replicate (n-k) 1) | k<-[1..n] ]++-- | Outer border strips (or ribbons) of the given length+outerRibbonsOfLength :: Partition -> Int -> [Ribbon]+outerRibbonsOfLength part@(Partition ps) givenLength = result where++  result = if null ps +    then [ Ribbon shape givenLength ht wd+         | p <- listHooks givenLength+         , let shape = mkSkewPartition (p,part)+         , let ht = partitionWidth  p - 1        -- pretty inconsistent names here :(((+         , let wd = partitionHeight p - 1+         ]+    else strips ++  strips  = [ mkStrip i j +            | i<-[1..n] , _canStartStrip (annArr!i)+            , j<-[i..n] , _canEndStrip   (annArr!j)+            , j-i+1 == givenLength+            ]+ +  ysize = partitionWidth  part+  xsize = partitionHeight part+ +  annList  =  [ BorderBox True False 1 x | x <- reverse [xsize+2 .. xsize+givenLength ] ]+           ++ annList0 +           ++ [ BorderBox False True y 1 | y <-         [ysize+2 .. ysize+givenLength ] ]+ +  n        = length annList+  annList0 = annotatedOuterBorderStrip part+  annArr   = listArray (1,n) annList++  mkStrip !i1 !i2 = Ribbon shape len height width where+    ps'   = (-666) : ps ++ replicate (givenLength) 0+    shape = SkewPartition [ (p,k) | (i,p,q) <- zip3 [1..max ysize y2] (tail ps') ps' , let k = indent i p q ] +    indent !i !p !q +      | i <  y1    = 0+      | i >  y2    = 0+      | i == y1    = x1 - p    -- the order is important here !!!+--      | i == y2    = x2 - p     +      | otherwise  = q - p  + 1   ++    len    = i2 - i1 + 1+    height = y2 - y1+    width  = x1 - x2+    BorderBox _ _ y1 x1 = annArr ! i1+    BorderBox _ _ y2 x2 = annArr ! i2++--------------------------------------------------------------------------------+-- * Naive implementations (for testing)++-- | Naive (and slow) implementation listing all inner border strips+innerRibbonsNaive :: Partition -> [Ribbon]+innerRibbonsNaive outer = list where+  list = [ Ribbon skew (len skew) (ht skew) (wt skew)+         | skew <- allSkewPartitionsWithOuterShape outer+         , isRibbon skew+         ]+  len skew = length (skewPartitionElements skew)+  ht  skew = (length $ group $ sort $ map fst $ skewPartitionElements skew) - 1+  wt  skew = (length $ group $ sort $ map snd $ skewPartitionElements skew) - 1+++-- | Naive (and slow) implementation listing all inner border strips of the given length+innerRibbonsOfLengthNaive :: Partition -> Int -> [Ribbon]+innerRibbonsOfLengthNaive outer givenLength = list where+  pweight = partitionWeight outer+  list = [ Ribbon skew (len skew) (ht skew) (wt skew)+         | skew <- skewPartitionsWithOuterShape outer givenLength+         , isRibbon skew+         ]+  len skew = length (skewPartitionElements skew)+  ht  skew = (length $ group $ sort $ map fst $ skewPartitionElements skew) - 1+  wt  skew = (length $ group $ sort $ map snd $ skewPartitionElements skew) - 1++-- | Naive (and slow) implementation listing all outer border strips of the given length+outerRibbonsOfLengthNaive :: Partition -> Int -> [Ribbon]+outerRibbonsOfLengthNaive inner givenLength = list where+  pweight = partitionWeight inner+  list = [ Ribbon skew (len skew) (ht skew) (wt skew)+         | skew <- skewPartitionsWithInnerShape inner givenLength+         , isRibbon skew+         ]+  len skew = length (skewPartitionElements skew)+  ht  skew = (length $ group $ sort $ map fst $ skewPartitionElements skew) - 1+  wt  skew = (length $ group $ sort $ map snd $ skewPartitionElements skew) - 1++--------------------------------------------------------------------------------+-- * Annotated borders++-- | A box on the border of a partition+data BorderBox = BorderBox+  { _canStartStrip :: !Bool+  , _canEndStrip   :: !Bool+  , _yCoord :: !Int+  , _xCoord :: !Int+  }+  deriving Show+ +-- | The boxes of the full inner border strip, annotated with whether a border strip +-- can start or end there.+annotatedInnerBorderStrip :: Partition -> [BorderBox]+annotatedInnerBorderStrip partition = if isEmptyPartition partition then [] else list where+  list    = goVert (head corners) (tail corners) +  corners = extendedCornerSequence partition  ++  goVert  (y1,x ) ((y2,_ ):rest) = [ BorderBox True (y==y2) y x | y<-[y1+1..y2] ] ++ goHoriz (y2,x) rest+  goVert  _       []             = [] ++  goHoriz (y ,x1) ((_, x2):rest) = case rest of+    [] -> [ BorderBox False True    y x | x<-[x1-1,x1-2..x2+1] ]+    _  -> [ BorderBox False (x/=x2) y x | x<-[x1-1,x1-2..x2  ] ] ++ goVert (y,x2) rest++-- | The boxes of the full outer border strip, annotated with whether a border strip +-- can start or end there.+annotatedOuterBorderStrip :: Partition -> [BorderBox]+annotatedOuterBorderStrip partition = if isEmptyPartition partition then [] else list where+  list    = goVert (head corners) (tail corners) +  corners = extendedCornerSequence partition  ++  goVert  (y1,x ) ((y2,_ ):rest) = [ BorderBox (y==y1) (y/=y2) (y+1) (x+1) | y<-[y1..y2] ] ++ goHoriz (y2,x) rest+  goVert  _       []             = [] ++  goHoriz (y ,x1) ((_, x2):rest) = case rest of+    [] -> [ BorderBox True (x==0) (y+1) (x+1) | x<-[x1-1,x1-2..x2  ] ]+    _  -> [ BorderBox True False  (y+1) (x+1) | x<-[x1-1,x1-2..x2+1] ] ++ goVert (y,x2) rest+++--------------------------------------------------------------------------------
Math/Combinat/Permutations.hs view
@@ -28,6 +28,7 @@   , permutationToDisjointCycles   , disjointCyclesToPermutation   , numberOfCycles+  , concatPermutations     -- * Queries   , isIdentityPermutation   , isReversePermutation@@ -63,6 +64,9 @@   , permuteList   , permuteLeft , permuteRight   , permuteLeftList , permuteRightList+    -- * Sorting+  , sortingPermutationAsc +  , sortingPermutationDesc     -- * ASCII drawing   , asciiPermutation   , asciiDisjointCycles@@ -224,6 +228,17 @@ isIdentityPermutation (Permutation ar) = (elems ar == [1..n]) where   (1,n) = bounds ar +-- | Given a permutation of @n@ and a permutation of @m@, we return+-- a permutation of @n+m@ resulting by putting them next to each other.+-- This should satisfy+--+-- > permuteList p1 xs ++ permuteList p2 ys == permuteList (concatPermutations p1 p2) (xs++ys)+--+concatPermutations :: Permutation -> Permutation -> Permutation +concatPermutations perm1 perm2 = toPermutationUnsafe list where+  n    = permutationSize perm1+  list = fromPermutation perm1 ++ map (+n) (fromPermutation perm2)+ -------------------------------------------------------------------------------- -- * ASCII @@ -738,6 +753,32 @@ permuteLeftList perm xs = elems $ permuteLeft perm $ arr where   arr = listArray (1,n) xs :: Array Int a   n   = permutationSize perm++--------------------------------------------------------------------------------++-- | Given a list of things, we return a permutation which sorts them into+-- ascending order, that is:+--+-- > permuteList (sortingPermutationAsc xs) xs == sort xs+--+-- Note: if the things are not unique, then the sorting permutations is not+-- unique either; we just return one of them.+--+sortingPermutationAsc :: Ord a => [a] -> Permutation+sortingPermutationAsc xs = toPermutation (map fst sorted) where+  sorted = sortBy (comparing snd) $ zip [1..] xs++-- | Given a list of things, we return a permutation which sorts them into+-- descending order, that is:+--+-- > permuteList (sortingPermutationDesc xs) xs == reverse (sort xs)+--+-- Note: if the things are not unique, then the sorting permutations is not+-- unique either; we just return one of them.+--+sortingPermutationDesc :: Ord a => [a] -> Permutation+sortingPermutationDesc xs = toPermutation (map fst sorted) where+  sorted = sortBy (reverseComparing snd) $ zip [1..] xs  -------------------------------------------------------------------------------- -- * Permutations of distinct elements
+ Math/Combinat/Sets/VennDiagrams.hs view
@@ -0,0 +1,150 @@++-- | Venn diagrams. See <https://en.wikipedia.org/wiki/Venn_diagram>+--+-- TODO: write a more efficient implementation (for example an array of size @2^n@)+--++{-# LANGUAGE BangPatterns #-}+module Math.Combinat.Sets.VennDiagrams where++--------------------------------------------------------------------------------++import Data.List++import GHC.TypeLits+import Data.Proxy++import qualified Data.Map as Map+import Data.Map (Map)++import Math.Combinat.Compositions+import Math.Combinat.ASCII++--------------------------------------------------------------------------------++-- | Venn diagrams of @n@ sets. Each possible zone is annotated with a value+-- of type @a@. A typical use case is to annotate with the cardinality of the+-- given zone.+--+-- Internally this is representated by a map from @[Bool]@, where @True@ means element +-- of the set, @False@ means not.+--+-- TODO: write a more efficient implementation (for example an array of size 2^n)+newtype VennDiagram a = VennDiagram { vennTable :: Map [Bool] a } deriving (Eq,Ord,Show)++-- | How many sets are in the Venn diagram+vennDiagramNumberOfSets :: VennDiagram a -> Int+vennDiagramNumberOfSets (VennDiagram table) = length $ fst $ Map.findMin table++-- | How many zones are in the Venn diagram+--+-- > vennDiagramNumberOfZones v == 2 ^ (vennDiagramNumberOfSets v)+--+vennDiagramNumberOfZones :: VennDiagram a -> Int+vennDiagramNumberOfZones venn = 2 ^ (vennDiagramNumberOfSets venn)++-- | How many /nonempty/ zones are in the Venn diagram+vennDiagramNumberOfNonemptyZones :: VennDiagram Int -> Int+vennDiagramNumberOfNonemptyZones (VennDiagram table) = length $ filter (/=0) $ Map.elems table++unsafeMakeVennDiagram :: [([Bool],a)] -> VennDiagram a+unsafeMakeVennDiagram = VennDiagram . Map.fromList++-- | We call venn diagram trivial if all the intersection zones has zero cardinality+-- (that is, the original sets are all disjoint)+isTrivialVennDiagram :: VennDiagram Int -> Bool+isTrivialVennDiagram (VennDiagram table) = and [ c == 0 | (bs,c) <- Map.toList table , isIntersection bs ] where+  isIntersection bs = case filter id bs of+    []  -> False+    [_] -> False+    _   -> True++printVennDiagram :: Show a => VennDiagram a -> IO ()+printVennDiagram = putStrLn . prettyVennDiagram++prettyVennDiagram :: Show a => VennDiagram a -> String+prettyVennDiagram = unlines . asciiLines . asciiVennDiagram++asciiVennDiagram :: Show a => VennDiagram a -> ASCII+asciiVennDiagram (VennDiagram table) = asciiFromLines $ map f (Map.toList table) where+  f (bs,a) = "{" ++ extendTo (length bs) [ if b then z else ' ' | (b,z) <- zip bs abc ] ++ "} -> " ++ show a+  extendTo k str = str ++ replicate (k - length str) ' '+  abc = ['A'..'Z']++instance Show a => DrawASCII (VennDiagram a) where+  ascii = asciiVennDiagram++-- | Given a Venn diagram of cardinalities, we compute the cardinalities of the+-- original sets (note: this is slow!)+vennDiagramSetCardinalities :: VennDiagram Int -> [Int]+vennDiagramSetCardinalities (VennDiagram table) = go n list where+  list = Map.toList table+  n = length $ fst $ head list+  go :: Int -> [([Bool],Int)] -> [Int]+  go !0 _  = []+  go !k xs = this : go (k-1) (map xtail xs) where+    this = foldl' (+) 0 [ c | ((True:_) , c) <- xs ]+  xtail (bs,c) = (tail bs,c)++--------------------------------------------------------------------------------++-- | Given the cardinalities of some finite sets, we list all possible+-- Venn diagrams.+--+-- Note: we don't include the empty zone in the tables, because it's always empty.+--+-- Remark: if each sets is a singleton set, we get back set partitions:+--+-- > > [ length $ enumerateVennDiagrams $ replicate k 1 | k<-[1..8] ]+-- > [1,2,5,15,52,203,877,4140]+-- >+-- > > [ countSetPartitions k | k<-[1..8] ]+-- > [1,2,5,15,52,203,877,4140]+--+-- Maybe this could be called multiset-partitions?+--+-- Example:+--+-- > autoTabulate RowMajor (Right 6) $ map ascii $ enumerateVennDiagrams [2,3,3]+--+enumerateVennDiagrams :: [Int] -> [VennDiagram Int]+enumerateVennDiagrams dims = +  case dims of+    []     -> []+    [d]    -> venns1 d+    (d:ds) -> concatMap (worker (length ds) d) $ enumerateVennDiagrams ds+  where++    worker !n !d (VennDiagram table) = result where++      list   = Map.toList table+      falses = replicate n False++      comps k = compositions' (map snd list) k+      result = +        [ unsafeMakeVennDiagram $ +            [ (False:tfs    , m-c) | ((tfs,m),c) <- zip list comp ] +++            [ (True :tfs    ,   c) | ((tfs,m),c) <- zip list comp ] +++            [ (True :falses , d-k) ]+        | k <- [0..d]+        , comp <- comps k+        ]++    venns1 :: Int -> [VennDiagram Int]+    venns1 p = [ theVenn ] where +      theVenn = unsafeMakeVennDiagram [ ([True],p) ] ++--------------------------------------------------------------------------------++{-++-- | for testing only+venns2 :: Int -> Int -> [Venn Int]+venns2 p q = +  [ mkVenn [ ([t,f],p-k) , ([f,t],q-k) , ([t,t],k) ]+  | k <- [0..min p q] +  ]+  where+    t = True+    f = False+-}
Math/Combinat/Sign.hs view
@@ -1,12 +1,19 @@  -- | Signs -{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP, BangPatterns #-} module Math.Combinat.Sign where  --------------------------------------------------------------------------------  import Data.Monoid++-- Semigroup became a superclass of Monoid+#if MIN_VERSION_base(4,11,0)     +import Data.Foldable+import Data.Semigroup+#endif+ import System.Random  --------------------------------------------------------------------------------@@ -16,10 +23,29 @@   | Minus   deriving (Eq,Ord,Show,Read) +--------------------------------------------------------------------------------++-- Semigroup became a superclass of Monoid+#if MIN_VERSION_base(4,11,0)        ++instance Semigroup Sign where+  (<>)    = mulSign+  sconcat = foldl1 mulSign+ instance Monoid Sign where   mempty  = Plus+  mconcat = productOfSigns++#else++instance Monoid Sign where+  mempty  = Plus   mappend = mulSign   mconcat = productOfSigns++#endif++--------------------------------------------------------------------------------  instance Random Sign where   random        g = let (b,g') = random g in (if b    then Plus else Minus, g')
Math/Combinat/Tableaux.hs view
@@ -31,8 +31,9 @@ import Data.List  import Math.Combinat.Classes-import Math.Combinat.Numbers (factorial,binomial)-import Math.Combinat.Partitions+import Math.Combinat.Numbers ( factorial , binomial )+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Integer.IntList ( _dualPartition ) import Math.Combinat.ASCII import Math.Combinat.Helper 
Math/Combinat/Tableaux/Skew.hs view
@@ -16,6 +16,7 @@  import Math.Combinat.Classes import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Integer.IntList ( _diffSequence ) import Math.Combinat.Partitions.Skew import Math.Combinat.Tableaux import Math.Combinat.ASCII@@ -118,7 +119,7 @@    stuff = worker as bs ds (repeat 1)    (as,bs) = unzip abs-  ds = diffSequence as+  ds = _diffSequence as      -- | @worker inner outerMinusInner innerdiffs lowerbound   worker :: [Int] -> [Int] -> [Int] -> [Int] -> [[(Int,[Int])]]
+ cbits/c_compact_partition.c view
@@ -0,0 +1,24 @@++#include <stdint.h>++// -----------------------------------------------------------------------------++uint64_t c_dual_nibble(uint64_t word)+{+  uint64_t n    = (word & 15);    // length+  uint64_t h    = (word >> 60);   // height+  uint64_t dual = h;              // length of dual = height of original+  uint64_t w    = word - n;       // zero out the low nibble++  uint64_t o = 60;+  for(uint64_t i=0; i<n; i++)+  { uint64_t k = ( (w >> (64-4*(n-i))) +                 - (w >> (60-4*(n-i))) ) & 15 ;   // diff+    for(uint64_t j=0;j<k;j++) { dual |= (n-i) << o ; o -= 4 ; } +  }++  return dual;+}++// -----------------------------------------------------------------------------+
combinat.cabal view
@@ -1,5 +1,5 @@ Name:                combinat-Version:             0.2.8.2+Version:             0.2.9.0 Synopsis:            Generate and manipulate various combinatorial objects. Description:         A collection of functions to generate, count, manipulate                      and visualize all kinds of combinatorial objects like @@ -8,13 +8,13 @@ License:             BSD3 License-file:        LICENSE Author:              Balazs Komuves-Copyright:           (c) 2008-2016 Balazs Komuves+Copyright:           (c) 2008-2018 Balazs Komuves Maintainer:          bkomuves (plus) hackage (at) gmail (dot) com-Homepage:            http://code.haskell.org/~bkomuves/+Homepage:            http://moire.be/haskell/ Stability:           Experimental Category:            Math-Tested-With:         GHC == 7.10.3-Cabal-Version:       >= 1.18+Tested-With:         GHC == 8.0.2+Cabal-Version:       1.24 Build-Type:          Simple  extra-doc-files:     svg/*.svg @@ -22,7 +22,12 @@ extra-source-files:  svg/*.svg                      svg/src/gen_figures.hs                      - +source-repository head+  type:                darcs +  location:            http://moire.be/haskell/projects/combinat/++--------------------------------------------------------------------------------+ Library    Build-Depends:       base >= 4 && < 5, array >= 0.5, containers, random, transformers@@ -30,10 +35,13 @@   Exposed-Modules:     Math.Combinat                        Math.Combinat.Classes                        Math.Combinat.Numbers-                       Math.Combinat.Numbers.Series+                       Math.Combinat.Numbers.Integers+                       Math.Combinat.Numbers.Sequences                        Math.Combinat.Numbers.Primes+                       Math.Combinat.Numbers.Series                        Math.Combinat.Sign                        Math.Combinat.Sets+                       Math.Combinat.Sets.VennDiagrams                        Math.Combinat.Tuples                         Math.Combinat.Compositions                        Math.Combinat.Groups.Thompson.F@@ -42,7 +50,12 @@                        Math.Combinat.Groups.Braid.NF                        Math.Combinat.Partitions                        Math.Combinat.Partitions.Integer+                       Math.Combinat.Partitions.Integer.Count+                       Math.Combinat.Partitions.Integer.Compact+                       Math.Combinat.Partitions.Integer.Naive+                       Math.Combinat.Partitions.Integer.IntList                        Math.Combinat.Partitions.Skew+                       Math.Combinat.Partitions.Skew.Ribbon                        Math.Combinat.Partitions.Set                        Math.Combinat.Partitions.NonCrossing                        Math.Combinat.Partitions.Plane@@ -72,8 +85,12 @@    Hs-Source-Dirs:      . +  C-Sources:           cbits/c_compact_partition.c+   ghc-options:         -fwarn-tabs -fno-warn-unused-matches -fno-warn-name-shadowing -fno-warn-unused-imports+     +--------------------------------------------------------------------------------  test-suite combinat-tests                       @@ -89,12 +106,19 @@                        Tests.SkewTableaux                        Tests.Thompson                        Tests.Partitions.Integer+                       Tests.Partitions.Compact                        Tests.Partitions.Skew+                       Tests.Partitions.Ribbon -  build-depends:       base >= 4 && < 5, array >= 0.5, containers, random, transformers,+  build-depends:       base >= 4 && < 5, array >= 0.5, containers >= 0.5, random, transformers,                        combinat,-                       QuickCheck >= 2, test-framework, test-framework-quickcheck2+                       test-framework, +                       test-framework-quickcheck2, QuickCheck >= 2,+                       tasty, tasty-quickcheck, tasty-hunit    Default-Language:    Haskell2010   Default-Extensions:  CPP, BangPatterns++--------------------------------------------------------------------------------+ 
test/TestSuite.hs view
@@ -9,6 +9,7 @@ import Tests.Permutations       ( testgroup_Permutations      ) import Tests.Partitions.Integer ( testgroup_IntegerPartitions ) import Tests.Partitions.Skew    ( testgroup_SkewPartitions    )+import Tests.Partitions.Ribbon  ( testgroup_Ribbon      ) import Tests.Braid              ( testgroup_Braid                                  , testgroup_Braid_NF          ) import Tests.Series             ( testgroup_PowerSeries       )@@ -24,9 +25,11 @@ tests :: [Test] tests =    [ testgroup_Permutations+  , testgroup_PowerSeries     , testGroup "Partitions"        [ testgroup_IntegerPartitions       , testgroup_SkewPartitions+      , testgroup_Ribbon       ]   , testgroup_SkewTableaux   , testgroup_ThompsonF@@ -35,7 +38,6 @@       [ testgroup_Braid        , testgroup_Braid_NF        ]-  , testgroup_PowerSeries     ]  --------------------------------------------------------------------------------
test/Tests/Common.hs view
@@ -29,6 +29,10 @@ myMkGen fun = MkGen (\r _ -> let (x,_) = fun r in x)
 
 -- | Generates a random element.
+myMkGen' :: (a -> b) -> (forall g. RandomGen g => g -> (a,g)) -> Gen b
+myMkGen' h fun = MkGen (\r _ -> let (x,_) = fun r in h x)
+
+-- | Generates a random element.
 myMkSizedGen :: (forall g. RandomGen g => Int -> g -> (a,g)) -> Gen a
 myMkSizedGen fun = MkGen (\r siz -> let (x,_) = fun siz r in x)
 
+ test/Tests/Partitions/Compact.hs view
@@ -0,0 +1,390 @@++module Tests.Partitions.Compact where ++--------------------------------------------------------------------------------++import Data.List hiding ( uncons )+import Data.Ord++import Test.Tasty+import Test.Tasty.HUnit      as U+import Test.Tasty.QuickCheck as Q ++import Math.Combinat.Partitions.Integer.Compact+import Math.Combinat.Partitions.Integer as P+-- import qualified Math.Combinat.Parititions.Integer.IntList as P ++--------------------------------------------------------------------------------++main = defaultMain tests++tests :: TestTree+tests = testGroup "Tests" [properties, unitTests]++--------------------------------------------------------------------------------++unitTests :: TestTree+unitTests = testGroup "Unit tests"+  [ testCase "toList . fromList == id /1" $ allTrue [ xs == toList (fromDescList xs) | xs <- _testPartitions ]+  , testCase "toList . fromList == id /2" $ allTrue [ xs == toList (fromDescList xs) | xs <- _allparts 18    ]+  , testCase "toAscList . fromList == reverse /1" $ allTrue [ reverse xs == toAscList (fromDescList xs) | xs <- _testPartitions ]+  , testCase "toAscList . fromList == reverse /2" $ allTrue [ reverse xs == toAscList (fromDescList xs) | xs <- _allparts 18    ]+  , testCase "fromList . toList == id"    $ allTrue [ p ==  fromDescList (toList p ) | p  <- testPartitions  ]+  , testCase "singleton"               $ allTrue [ toList (singleton n) == [n] | n <- [1..300] ]+  , testCase "singleton 0 is empty"    $ allTrue [ toList (singleton 0) == [] ]+  , testCase "uncons empty"            $ allTrue [ uncons empty == Nothing ]+  , testCase "uncons singleton"        $ allTrue [ uncons (singleton x) == Just (x,empty) | x <- [1..300] ]+  , testCase "cons/snoc 0 empty"       $ allTrue [ (cons 0 empty) == empty , (snoc empty 0) == empty ] +  , testCase "cons empty"              $ allTrue [ toList (cons n empty) == [n] | n <- [1..300] ]+  , testCase "snoc empty"              $ allTrue [ toList (snoc empty n) == [n] | n <- [1..300] ]+  , testCase "width/height of empty"   $ allTrue [ width empty == 0 , height empty == 0 ]+  , testCase "width of all "           $ allTrue [ length   xs == width  p | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "height of all"           $ allTrue [ safeHead xs == height p | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "(width,height)"          $ allTrue [ widthHeight p == (width p, height p) | p <- testPartitions ]+  , testCase "tail of all"             $ allTrue [ safeTail xs == toList (partitionTail p) | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "toList using uncons"     $ allTrue [ xs == toListViaUncons p                      | xs <- _testPartitionsSmall , let p = fromDescList xs ] +  , testCase "fromList using cons"     $ allTrue [ xs == toList (fromListViaCons (DescList xs)) | xs <- _testPartitionsSmall ]+  , testCase "fromList using snoc"     $ allTrue [ xs == toList (fromListViaSnoc (DescList xs)) | xs <- _testPartitionsSmall ]+  , testCase "reflexivity"             $ allTrue [ (fromDescList xs == p) | xs <- _testPartitions , let p = fromDescList xs]+  , testCase "snoc1"                   $ allTrue [ toList (snoc     p 1)  == xs ++ [1]           | xs <- _testPartitions , let p = fromDescList xs]+  , testCase "snocN/2..5"              $ allTrue [ toList (snocN n (p,1)) == xs ++ replicate n 1 | xs <- _testPartitions , let p = fromDescList xs , n <- [2..5] ]+  , testCase "compare/staircase"       $ allTrue [ compare xs1 xs2 == cmp p1 p2 | n1<-[0..100] , n2<-[0..100], let xs1 = _staircase n1 , let xs2 = _staircase n2 , let p1 = staircase n1 , let p2 = staircase n2 ]+  , testCase "compare/slope"           $ allTrue [ compare xs1 xs2 == cmp p1 p2 | n1<-[0..100] , n2<-[0..100], let xs1 = _slope n1 , let xs2 = _slope n2 , let p1 = slope n1 , let p2 = slope n2 ]+  , testCase "compare/steep"           $ allTrue [ compare xs1 xs2 == cmp p1 p2 | n1<-[0..100] , n2<-[0..100], let xs1 = _steep n1 , let xs2 = _steep n2 , let p1 = steep n1 , let p2 = steep n2 ]+  , testCase "compare/small"           $ allTrue [ compare xs1 xs2 == cmp p1 p2 | xs1 <- _allparts 12 , xs2 <- _allparts 12 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "compare/15"              $ allTrue [ compare xs1 xs2 == cmp p1 p2 | xs1 <- _parts    15 , xs2 <- _parts    15 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "compare/16"              $ allTrue [ compare xs1 xs2 == cmp p1 p2 | xs1 <- _parts    16 , xs2 <- _parts    16 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "compare/17"              $ allTrue [ compare xs1 xs2 == cmp p1 p2 | xs1 <- _parts    17 , xs2 <- _parts    17 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "ineq/small"              $ allTrue [ ineqTestPartition p1 p2 | xs1 <- _allparts 13 , xs2 <- _allparts 13 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "consN 15 / staircase"    $ allTrue [ (replicate k 15  ++ xs) == toList (consN k (15,p)) | n<-[0..15] , let xs = _staircase n , let p = fromDescList xs , k <- [1..80] ]+  , testCase "consN 15 / slope"        $ allTrue [ (replicate k 15  ++ xs) == toList (consN k (15,p)) | n<-[0..15] , let xs = _slope n , let p = fromDescList xs , k <- [1..80] ]+  , testCase "consN 15 / steep"        $ allTrue [ (replicate k 15  ++ xs) == toList (consN k (15,p)) | n<-[0..15] , let xs = _steep n , let p = fromDescList xs , k <- [1..40] ]+  , testCase "consN 16 / staircase"    $ allTrue [ (replicate k  16 ++ xs) == toList (consN k (16,p)) | n<-[0..16] , let xs = _staircase n , let p = fromDescList xs , k <- [1..80] ]+  , testCase "consN 16 / slope"        $ allTrue [ (replicate k  16 ++ xs) == toList (consN k (16,p)) | n<-[0..16] , let xs = _slope n , let p = fromDescList xs , k <- [1..80] ]+  , testCase "consN 16 / steep"        $ allTrue [ (replicate k  16 ++ xs) == toList (consN k (16,p)) | n<-[0..16] , let xs = _steep n , let p = fromDescList xs , k <- [1..40] ]+  , testCase "consN 256 / staircase"   $ allTrue [ (replicate k 256 ++ xs) == toList (consN k (256,p)) | n<-[0..40] , let xs = _staircase n , let p = fromDescList xs , k <- [1..40] ]+  , testCase "consN 256 / slope"       $ allTrue [ (replicate k 256 ++ xs) == toList (consN k (256,p)) | n<-[0..40] , let xs = _slope n , let p = fromDescList xs , k <- [1..35] ]+  , testCase "consN 256 / steep"       $ allTrue [ (replicate k 256 ++ xs) == toList (consN k (256,p)) | n<-[0..40] , let xs = _steep n , let p = fromDescList xs , k <- [1..35] ]+  , testCase "diffSequence"            $ allTrue [ diffSequence p == refDiffSeq xs | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "reverseDiffSequence"     $ allTrue [ reverseDiffSequence p == reverse (refDiffSeq xs) | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "dual . dual == id"       $ allTrue [ dualPartition (dualPartition p) == p | p <- testPartitions ]+  , testCase "dual == reference impl." $ allTrue [ toList (dualPartition p) == P._dualPartition xs | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "toExponentialForm"       $ allTrue [ toExponentialForm p == P._toExponentialForm xs | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "fromExponentialForm"     $ allTrue [ toList (fromExponentialForm ef) == xs | xs <- _testPartitions , let p = fromDescList xs , let ef = P._toExponentialForm xs ]+  , testCase "to / from expo. form"    $ allTrue [ toList (fromExponentialForm $ toExponentialForm p) == xs | xs <- _testPartitions , let p = fromDescList xs ]+  , testCase "isSubPartitionOf/small"  $ allTrue [ P._isSubPartitionOf xs1 xs2 == isSubPartitionOf p1 p2 | xs1 <- _allparts 12 , xs2 <- _allparts 12 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "isSubPartitionOf/15"     $ allTrue [ P._isSubPartitionOf xs1 xs2 == isSubPartitionOf p1 p2 | xs1 <- _parts    15 , xs2 <- _parts    15 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "isSubPartitionOf/16"     $ allTrue [ P._isSubPartitionOf xs1 xs2 == isSubPartitionOf p1 p2 | xs1 <- _parts    16 , xs2 <- _parts    16 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "isSubPartitionOf/17"     $ allTrue [ P._isSubPartitionOf xs1 xs2 == isSubPartitionOf p1 p2 | xs1 <- _parts    17 , xs2 <- _parts    17 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "dominates/small"         $ allTrue [ P._dominates xs1 xs2 == dominates p1 p2 | xs1 <- _allparts 12 , xs2 <- _allparts 12 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "dominates/15"            $ allTrue [ P._dominates xs1 xs2 == dominates p1 p2 | xs1 <- _parts    15 , xs2 <- _parts    15 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "dominates/16"            $ allTrue [ P._dominates xs1 xs2 == dominates p1 p2 | xs1 <- _parts    16 , xs2 <- _parts    16 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "dominates/17"            $ allTrue [ P._dominates xs1 xs2 == dominates p1 p2 | xs1 <- _parts    17 , xs2 <- _parts    17 , let p1 = fromDescList xs1 , let p2 = fromDescList xs2 ]+  , testCase "pieriRuleSingleBox"      $ allTrue [ pieriRuleSingleBox p =%%= map fromDescList (P._pieriRule xs 1) | xs <- _testPartitions      , let p = fromDescList xs ] +  , testCase "pieriRule"               $ allTrue [ pieriRule p k        =%%= map fromDescList (P._pieriRule xs k) | xs <- every10th _testPartitionsSmall , let p = fromDescList xs , k <- [1..2] ] +  ]++--------------------------------------------------------------------------------++properties :: TestTree+properties = localOption (QuickCheckTests 1000)  -- 200+           $ testGroup "Properties" +  [ prop "toList . fromList == id" $ \(DescList xs) -> (toList (fromDescList xs) == xs)+  , prop "toAscList . fromList == reverse" $ \(DescList xs) -> (toAscList (fromDescList xs) == reverse xs)+  , prop "snoc1/list"              $ \(DescList xs) -> toList (snoc (fromDescList xs) 1) == xs ++ [1]+  , prop "snocN/list"              $ \(DescList xs) (SmallN n) -> toList (snocN n (fromDescList xs,1)) == xs ++ replicate n 1+  , prop "fromList . toList == id" $ \p    -> (fromDescList (toList p ) == p )+  , prop "compare"                 $ \p q  -> cmp p q == compare (toList p) (toList q)+  , prop "uncons"                  $ \p    -> (unconsTest p) == unconsList (toList p)+  , prop "width"                   $ \p    -> width  p == length   (toList p)+  , prop "height"                  $ \p    -> height p == safeHead (toList p)+  , prop "(width,height)"          $ \p    -> let xs = toList p in widthHeight p == (length xs, safeHead xs)+  , prop "snoc1"                   $ \p    -> toList (snoc p 1) == toList p ++ [1]+  , prop "snocN"                   $ \p (SmallN n) -> toList (snocN n (p,1)) == toList p ++ replicate n 1+  , prop "cons/head"               $ \p            -> let a = max 1 (height p) in toList (cons a p) == a : toList p +  , prop "cons/head+1"             $ \p            -> let a = height p + 1     in toList (cons a p) == a : toList p +  , prop "cons/head+k"             $ \p (SmallN k) -> let a = height p + k     in toList (cons a p) == a : toList p +  , prop "consN/head"              $ \p (SmallN n) -> let a = max 1 (height p) in toList (consN n (a,p)) == replicate n a ++ toList p +  , prop "consN/head+1"            $ \p (SmallN n) -> let a = height p + 1     in toList (consN n (a,p)) == replicate n a ++ toList p +  , prop "consN/head+k"            $ \p (SmallN n) (SmallN k) -> let a = height p + k  in toList (consN n (a,p)) == replicate n a ++ toList p +  , prop "tailN"                   $ \p (SmallN n) -> toList (tailN n p) == drop n (toList p)+  , prop "isEmpty of tail length  "  $ \p ->                      isEmpty (tailN (width p    ) p)  +  , prop "isEmpty of tail length-1"  $ \p -> width p == 0 || not (isEmpty (tailN (width p - 1) p))+  , prop "toList using uncons"     $ \p  -> toList p == toListViaUncons p+  , prop "fromList using cons"     $ \dlist@(DescList xs) -> fromDescList xs == fromListViaCons dlist+  , prop "fromList using snoc"     $ \dlist@(DescList xs) -> fromDescList xs == fromListViaSnoc dlist+  , prop "cmp a b vs. cmp b a"     $ \p q -> cmp p q == reverseOrdering (cmp q p)+  , prop "ineq"                    $ \p q -> ineqTestPartition p q+  , prop "diffSequence"            $ \p -> diffSequence p == refDiffSeq (toList p)+  , prop "reverseDiffSequence"     $ \p -> reverseDiffSequence p == reverse (refDiffSeq (toList p))+  , prop "dual . dual == id"       $ \p -> dualPartition (dualPartition p) == p+  , prop "dual = reference impl."  $ \p -> toList (dualPartition p) == P._dualPartition (toList p)+  , prop "fromExpo . toExpo == id" $ \p -> fromExponentialForm (toExponentialForm p) == p+  , prop "isSubPartitionOf"        $ \p q -> isSubPartitionOf p q == P._isSubPartitionOf (toList p) (toList q)+  , prop "dominates"               $ \p q -> dominates p q == P._dominates (toList p) (toList q)+  , prop "pieriRuleSingleBox"      $ \p -> map toList (pieriRuleSingleBox p) =%%= P._pieriRule (toList p) 1 ++  , localOption (QuickCheckTests 100) +  $ prop "pieriRule /1"            $ \p (PieriK k) -> map toList (pieriRule p k) =%%= P._pieriRule (toList p) k +  , localOption (QuickCheckTests 100) +  $ prop "pieriRule /2"            $ \p (PieriK k) -> (pieriRule p k) =%%= map fromDescList (P._pieriRule (toList p) k) +  ]++ineqTestPartition :: Partition -> Partition -> Bool+ineqTestPartition = ineqTest++--------------------------------------------------------------------------------++ineqTest :: Ord a => a -> a -> Bool+ineqTest a b = case (a<b , a==b , a>b) of+  (True ,False,False) -> True+  (False,True ,False) -> True+  (False,False,True ) -> True+  _                   -> False++every10th :: [a] -> [a]+every10th = everyNth 10++everyNth :: Int -> [a] -> [a]+everyNth k = go where+  go []     = []+  go (x:xs) = x : drop (k-1) xs++infix 4 =%%=+(=%%=) :: Ord a => [a] -> [a] -> Bool+(=%%=) xs ys = (sort xs == sort ys)++allTrue :: [Bool] -> Assertion+allTrue bools = (and bools @=? True)++prop :: Testable a => TestName -> a -> TestTree+prop = Q.testProperty++(<#>) :: (a -> c) -> (b -> d) -> (a,b) -> (c,d)+(<#>) f g (x,y) = (f x, g y)++reverseOrdering :: Ordering -> Ordering+reverseOrdering ord = case ord of+  LT -> GT+  GT -> LT+  EQ -> EQ++--------------------------------------------------------------------------------++newtype SmallN = SmallN Int deriving (Eq,Ord,Show)++instance Arbitrary SmallN where+  arbitrary = SmallN <$> choose (1,80)++newtype PieriK = PieriK Int deriving (Eq,Ord,Show)++instance Arbitrary PieriK where+  arbitrary = PieriK <$> choose (1,3)++newtype DescList = DescList [Int] deriving (Eq,Ord,Show)++instance Arbitrary DescList where+  arbitrary = (DescList . reverse . sort . map getPositive) <$> arbitrary++instance Arbitrary Partition where+  arbitrary = do+    DescList xs <- arbitrary+    return $ fromDescList xs++--------------------------------------------------------------------------------++_allparts n = P._allPartitions n+_parts    n = P._partitions    n ++_staircase n   = [n,n-1..1]+_rectangle h n = replicate n h++_slope  n =         concatMap (\x->[x,x]) [n,n-1..1]+_slope1 n =         concatMap (\x->[x,x]) [n,n-1..1] ++ [1]+_slope2 n = (n+1) : concatMap (\x->[x,x]) [n,n-1..1] +_slope3 n = (n+1) : concatMap (\x->[x,x]) [n,n-1..1] ++ [1]++_steep  n = [n,n-2..1]++--------------------------------------------------------------------------------++allparts = map fromDescList . _allparts+parts    = map fromDescList . _parts++staircase n   = fromDescList $ _staircase n +rectangle h n = fromDescList $ _rectangle h n ++slope n = fromDescList $ _slope n+steep n = fromDescList $ _steep n++--------------------------------------------------------------------------------++testPartitionsSmall = map fromDescList _testPartitionsSmall+testPartitions      = map fromDescList _testPartitions++_testPartitionsSmall = concat+  [ _allparts 25+  , [ _rectangle 1   n | n <- [1..75] ]+  , [ _rectangle 15  n | n <- [1..75] ]+  , [ _rectangle 16  n | n <- [1..75] ]+  , [ _rectangle 255 n | n <- [1..75] ]+  , [ _rectangle 256 n | n <- [1..75] ]+  , [ _staircase n     | n <- [1..75] ]+  , [ _slope  n        | n <- [1..75] ]+  , [ _slope1 n        | n <- [1..75] ]+  , [ _slope2 n        | n <- [1..75] ]+  , [ _slope3 n        | n <- [1..75] ]+  , [ _steep  n        | n <- [1..75] ] +  , [ _staircase n     | n <- [200,255,256,257,258] ]+  ]++_testPartitions = _testPartitionsSmall ++ _testPartRandom++_testPartRandom = concat+  [ [ drop n seq       | seq <- randomSequences , n<-[0..79] ] +  , [ take n seq       | seq <- randomSequences , n<-[0..79] ] +  ]++--------------------------------------------------------------------------------+-- * reference++snocN :: Int -> (Partition,Int) -> Partition+snocN n (p,x) +  | n <= 0    = p+  | otherwise = snocN (n-1) (snoc p x, x)++consN :: Int -> (Int,Partition) -> Partition+consN n (x,p) +  | n <= 0    = p+  | otherwise = consN (n-1) (x, cons x p)++tailN :: Int -> Partition -> Partition+tailN n p +  | n <= 0    = p +  | otherwise = tailN (n-1) (partitionTail p)++unconsTest :: Partition -> Maybe (Int,[Int])+unconsTest xs = case uncons xs of+  Nothing    -> Nothing+  Just (x,p) -> Just (x, toList p)++unconsList :: [Int] -> Maybe (Int,[Int])+unconsList xs = case xs of+  []     -> Nothing+  (x:xs) -> Just (x,xs)++safeHead :: [Int] -> Int+safeHead xs = case xs of+  []     -> 0+  (x:xs) -> x++refDiffSeq :: [Int] -> [Int]+refDiffSeq = go where+  go (x:ys@(y:_)) = (x-y) : go ys +  go [x] = [x]+  go []  = []++--------------------------------------------------------------------------------++toListViaUncons :: Partition -> [Int]+toListViaUncons = go where+  go p = case uncons p of+    Nothing    -> []+    Just (x,p) -> x : go p+  +fromListViaCons :: DescList -> Partition+fromListViaCons (DescList list) = go list where+  go xs = case xs of+    []     -> empty+    (x:xs) -> cons x (go xs)++fromListViaSnoc :: DescList -> Partition+fromListViaSnoc (DescList list) = go (reverse list) where+  go xs = case xs of+    []     -> empty+    (x:xs) -> snoc (go xs) x++--------------------------------------------------------------------------------++{- +-- generated by:+import Data.List ; import Control.Monad ; import System.Random+genseq = (reverse . sort) <$> (replicateM 80 $ randomRIO (1::Int,255))+main = do+  seqs <- replicateM 64 genseq+  writeFile "rnd.txt" $ unlines $ map show seqs+-}++randomSequences =   +  [ [255,255,251,249,245,239,238,235,233,232,224,222,214,214,213,209,202,197,197,194,193,189,181,168,165,164,164,162,156,152,152,152,151,148,147,142,136,132,130,127,124,123,120,119,117,115,112,112,107,105,90,84,81,75,74,69,64,57,56,55,53,49,48,47,44,43,39,38,31,20,19,18,18,17,17,15,14,10,9,7]+  , [252,246,241,240,238,233,232,230,229,228,227,221,219,214,212,212,204,203,201,195,192,192,188,186,186,182,180,179,176,174,170,166,162,162,153,149,147,141,140,140,139,139,135,133,128,127,126,126,125,125,124,124,114,114,113,112,108,102,94,91,82,82,80,73,71,67,57,56,51,41,36,34,24,22,18,9,8,7,1,1]+  , [255,254,250,250,248,247,245,243,239,236,223,217,215,209,208,205,203,200,199,198,196,194,191,187,184,174,174,172,164,161,159,158,157,153,152,150,149,149,144,135,133,128,127,122,119,119,118,115,115,113,111,103,98,91,88,86,86,74,72,72,67,65,65,56,55,52,51,49,48,38,38,37,34,32,20,17,14,13,8,1]+  , [249,224,224,218,210,206,204,196,193,189,188,188,182,177,174,174,173,173,170,163,151,151,150,147,147,145,142,139,138,134,132,129,126,124,123,121,120,113,112,112,112,109,109,108,106,103,98,89,89,85,85,85,82,82,82,79,75,72,70,66,64,63,56,56,47,45,45,42,27,24,22,20,20,19,16,13,4,4,1,1]+  , [255,254,252,247,246,240,238,233,232,227,226,225,223,213,213,212,209,203,200,195,194,193,193,188,188,185,182,180,175,172,171,170,166,161,158,154,150,146,146,144,142,140,133,131,128,125,119,118,117,115,114,110,109,103,96,91,89,88,81,76,74,59,57,46,37,32,31,24,24,23,16,12,12,9,8,6,6,6,5,2]+  , [253,248,241,234,230,228,226,225,224,222,220,219,217,213,212,207,200,196,183,179,179,173,173,165,162,157,154,147,147,142,137,136,135,134,134,132,128,127,118,113,106,105,104,104,102,94,90,89,81,77,73,68,65,63,63,59,56,54,46,45,44,40,32,32,31,28,26,26,25,22,21,21,16,13,12,11,11,10,5,3]+  , [253,253,253,252,252,246,245,243,241,236,235,234,232,227,224,222,219,210,209,205,200,198,198,195,194,194,188,184,177,175,171,170,169,167,163,162,162,155,138,138,131,125,119,114,106,99,97,95,87,85,85,83,79,71,71,69,65,57,56,49,46,40,37,33,31,29,28,24,23,16,16,16,15,13,12,11,8,8,4,2]+  , [254,252,252,248,233,231,230,228,225,224,218,194,190,190,186,184,177,177,176,171,170,166,165,164,151,149,147,143,136,134,134,133,128,124,122,121,115,114,107,106,105,101,100,98,94,92,92,91,86,84,81,80,76,76,74,71,70,67,67,67,65,58,54,54,53,53,52,52,48,46,46,43,41,37,36,24,19,14,12,7]+  , [255,254,253,251,249,248,248,245,242,236,231,224,221,214,212,205,203,198,195,194,194,190,184,183,183,178,175,163,154,154,149,148,147,145,144,136,134,127,120,117,115,113,112,109,107,107,104,102,91,86,86,84,83,81,81,80,78,77,76,74,73,69,58,57,55,46,39,39,39,38,37,33,32,31,29,27,21,21,15,8]+  , [253,252,252,252,247,242,236,227,227,224,218,214,213,211,209,207,203,202,198,196,191,189,183,183,176,170,169,168,166,164,163,159,157,157,151,145,138,133,130,128,123,119,112,111,109,106,105,101,100,99,96,94,91,76,74,69,69,69,66,66,65,64,61,60,59,45,44,43,41,39,30,28,26,24,21,16,11,6,1,1]+  , [254,253,250,248,238,236,235,232,231,228,228,216,213,213,211,210,207,205,201,200,198,187,182,180,180,178,175,171,168,159,157,157,152,150,143,139,138,138,133,124,123,122,120,120,118,117,115,114,112,111,111,105,105,98,92,92,86,83,80,78,76,70,69,66,65,57,55,54,45,41,36,36,34,21,20,19,12,6,5,3]+  , [252,252,250,249,245,239,229,228,223,218,211,210,207,204,202,201,200,197,189,187,185,181,180,177,175,173,170,168,159,158,158,156,152,145,140,140,137,135,134,133,132,111,108,105,100,97,91,90,89,83,79,78,76,68,67,66,61,58,57,56,50,48,48,47,41,37,33,33,27,27,26,14,13,10,9,9,8,8,8,5]+  , [255,255,246,238,236,235,231,227,226,224,217,214,214,207,204,203,200,200,198,196,191,189,189,187,185,181,179,177,173,172,167,164,164,163,159,154,149,149,143,142,140,136,135,135,126,125,120,112,112,101,100,98,96,96,93,92,89,89,80,79,77,76,76,56,50,48,41,41,40,37,32,29,21,19,19,19,17,11,7,4]+  , [248,246,242,237,235,233,233,232,231,229,229,227,222,222,214,213,208,204,203,199,197,194,192,192,192,190,189,184,183,179,175,175,174,173,171,166,162,160,155,155,153,149,146,145,144,137,127,119,103,100,99,99,96,95,93,87,86,86,84,82,80,80,79,74,66,65,63,59,57,49,47,45,39,32,31,29,25,13,9,3]+  , [252,251,246,243,236,232,228,226,225,217,214,212,206,204,202,201,198,195,194,193,189,187,184,181,177,170,170,165,164,161,157,156,156,145,142,138,136,136,129,128,118,117,116,115,106,97,96,96,96,94,88,84,84,83,83,78,76,75,74,71,70,67,67,64,54,51,47,37,34,31,26,19,14,10,9,9,6,5,3,1]+  , [254,253,247,245,244,244,241,240,237,234,234,233,231,222,217,205,202,199,196,195,192,192,190,184,181,180,179,166,166,162,161,160,157,156,155,149,140,137,134,130,130,129,122,122,111,109,101,100,98,96,96,90,84,83,83,81,74,69,68,64,54,51,51,50,41,41,37,36,34,30,23,21,20,20,16,12,9,5,4,2]+  , [247,241,241,240,240,237,236,231,230,222,216,206,202,201,200,187,185,179,174,170,169,168,165,160,158,155,154,153,147,145,140,137,136,133,132,132,116,111,108,100,98,94,92,90,89,87,87,87,87,84,77,74,74,71,71,70,67,65,63,58,57,56,49,48,47,46,43,43,42,38,37,33,26,19,17,17,17,11,6,3]+  , [253,250,250,248,246,244,235,229,228,225,223,222,219,219,218,218,217,217,214,213,212,210,210,208,206,197,194,190,184,181,179,173,171,169,164,162,159,143,133,132,130,114,112,107,107,106,105,100,88,87,86,85,83,79,78,78,78,78,66,64,62,61,61,52,49,35,31,28,25,24,22,21,20,18,18,16,15,8,2,1]+  , [252,243,243,234,232,231,219,219,218,210,208,194,193,191,186,184,181,178,172,171,169,168,162,154,148,148,144,143,131,129,126,125,121,119,115,114,111,106,103,101,99,97,92,88,84,82,79,74,71,66,66,63,58,47,47,47,44,43,42,41,39,38,33,33,32,31,29,29,27,24,24,20,20,19,17,16,15,13,11,9]+  , [255,255,245,240,240,236,236,236,236,234,232,227,225,221,218,214,213,207,206,199,192,190,190,186,181,176,168,167,165,164,162,162,156,155,155,151,150,149,143,143,143,142,139,136,136,132,131,130,125,121,121,120,117,100,95,88,88,88,87,82,81,73,70,67,66,64,57,54,46,44,41,35,30,30,19,15,13,12,9,6]+  , [254,252,249,249,248,247,247,241,239,232,231,228,224,220,214,214,213,206,202,200,198,195,194,192,185,184,183,180,179,176,157,149,144,142,138,138,136,132,130,125,123,123,123,117,117,117,113,112,105,103,97,84,82,79,78,72,71,67,61,57,53,53,52,51,44,41,36,34,30,28,27,27,26,23,22,21,13,5,5,3]+  , [253,250,243,239,235,228,228,225,218,217,217,211,209,209,206,202,199,196,188,185,181,179,178,174,173,172,170,170,168,166,153,153,149,146,146,145,143,139,138,122,118,117,110,109,107,106,98,95,93,88,86,85,83,77,68,66,63,62,62,62,59,55,50,49,48,47,47,47,41,35,34,33,32,26,24,16,15,12,11,9]+  , [254,252,248,245,244,243,238,238,238,232,231,227,225,220,219,218,217,216,214,211,211,209,207,205,204,203,201,200,195,193,186,180,178,174,173,173,170,170,165,157,151,150,148,140,134,123,116,109,105,105,105,96,95,94,91,89,86,81,76,73,71,57,53,50,47,47,47,47,46,45,42,38,34,27,25,19,17,14,7,7]+  , [253,250,246,245,241,241,239,238,235,231,230,230,223,213,205,199,199,198,197,195,193,190,187,184,184,175,174,173,172,170,169,168,167,165,163,154,152,140,140,139,134,131,130,128,126,119,118,112,112,101,95,94,94,91,88,86,86,83,76,75,75,75,70,58,58,57,49,46,42,41,41,34,33,32,31,29,28,17,16,7]+  , [253,253,251,246,246,240,232,228,225,223,218,218,212,211,210,202,197,192,192,192,192,189,186,186,182,180,177,168,163,163,158,155,150,149,141,134,130,130,130,126,118,115,115,110,103,103,103,92,90,85,81,79,75,70,69,69,54,54,51,49,47,44,42,38,35,35,30,27,18,13,11,11,10,8,7,6,4,3,3,3]+  , [254,251,242,239,238,233,230,227,225,225,215,215,212,209,207,205,205,203,195,195,189,187,187,187,186,182,175,172,171,169,165,160,158,157,157,149,148,143,143,142,142,136,132,129,120,119,117,112,111,110,108,107,100,99,93,91,88,88,86,80,80,77,76,73,70,70,69,67,62,60,51,49,29,25,19,18,16,9,8,1]+  , [251,250,250,249,239,238,233,233,227,227,224,222,221,220,220,218,212,203,199,199,195,193,193,189,186,182,176,175,168,163,162,147,145,145,139,138,136,130,128,128,126,124,122,114,109,106,99,98,90,87,87,83,82,76,72,71,68,65,64,63,62,62,59,56,55,46,41,40,35,31,29,29,28,14,13,10,10,8,7,6]+  , [250,245,239,237,235,235,232,231,224,224,222,219,218,215,211,206,191,190,190,188,179,177,173,170,169,167,166,162,162,160,159,158,155,145,142,140,140,135,131,129,121,116,116,108,106,102,101,96,95,91,89,88,84,80,77,75,70,70,68,60,58,55,54,52,49,44,43,42,39,36,33,32,32,29,23,21,18,17,14,11]+  , [254,254,250,247,241,241,239,232,230,223,221,217,214,200,197,196,194,194,188,185,184,183,183,174,172,171,168,164,164,158,148,146,144,141,133,131,126,125,124,124,123,122,120,114,113,111,110,106,104,104,99,99,92,88,84,74,71,70,67,66,66,59,57,56,55,52,51,50,44,41,39,37,32,29,28,27,25,9,6,3]+  , [248,243,241,232,227,226,225,225,220,218,218,218,214,211,206,203,201,198,196,195,190,189,186,175,174,163,155,150,146,142,141,139,137,136,135,135,133,126,123,118,118,113,110,108,107,106,105,102,102,102,101,100,100,99,96,95,95,91,87,84,80,79,74,73,73,72,60,55,54,54,52,49,44,38,20,19,19,18,14,5]+  , [255,253,253,250,249,245,243,242,239,237,233,233,224,224,222,219,218,210,208,204,192,180,176,168,164,160,160,158,156,155,154,151,150,149,149,142,141,139,138,131,129,126,123,123,114,114,110,110,110,103,99,98,92,92,88,88,87,85,81,79,76,72,67,65,63,63,62,59,57,52,51,50,46,44,41,36,23,15,7,1]+  , [251,248,246,243,236,235,230,227,226,224,221,219,218,216,215,214,214,207,204,202,202,196,192,186,181,179,179,178,176,175,174,169,164,152,149,147,144,139,136,135,134,134,129,125,123,114,105,102,99,89,84,84,81,80,78,75,62,62,59,59,58,58,57,56,55,54,45,38,35,30,29,22,22,16,15,13,11,7,6,4]+  , [255,254,253,243,241,230,230,228,228,227,225,223,223,213,213,205,204,203,198,192,192,190,186,180,180,177,177,174,173,161,156,155,134,127,125,123,120,111,108,102,100,100,97,89,86,80,78,76,75,74,74,74,71,71,70,70,66,66,62,60,59,56,49,47,44,42,38,35,30,30,17,17,17,15,13,13,9,9,6,3]+  , [255,251,249,245,239,239,237,235,230,229,225,224,221,219,213,211,209,207,204,201,194,194,190,186,185,185,183,171,168,166,164,160,159,153,148,140,137,136,133,128,125,121,121,121,118,112,112,109,108,108,106,100,95,94,90,88,88,87,85,84,81,70,68,67,67,66,56,48,43,38,36,35,33,32,32,24,22,19,17,5]+  , [252,252,252,249,245,243,240,236,228,227,224,222,222,216,212,209,206,204,201,192,191,190,185,179,173,172,169,169,165,162,158,158,149,148,147,140,133,128,124,122,122,121,116,115,114,108,103,102,101,98,97,93,93,92,88,87,86,86,78,69,64,63,57,52,45,43,37,35,34,31,26,22,21,18,16,13,9,5,3,2]+  , [254,254,251,248,248,247,245,235,223,222,207,207,206,204,197,194,192,188,184,182,180,178,175,175,173,167,167,165,164,163,163,160,157,155,150,144,141,138,135,131,125,124,121,114,109,101,99,96,91,90,88,85,79,76,67,66,65,59,57,57,57,53,47,34,32,27,26,26,24,22,20,18,18,10,6,5,4,3,2,1]+  , [254,253,250,249,241,240,239,238,234,233,230,229,226,226,226,225,222,219,218,212,207,207,202,199,196,194,189,189,188,184,175,170,166,165,161,160,158,157,154,136,132,128,125,124,122,119,118,116,112,108,108,104,94,91,90,86,80,78,76,72,72,69,58,57,56,52,52,45,44,41,34,27,26,24,18,12,11,5,3,3]+  , [251,245,242,240,237,236,234,227,226,225,225,225,224,223,221,219,209,206,206,206,200,200,198,197,195,195,195,194,192,190,189,186,180,172,169,163,161,155,150,150,148,146,145,135,135,128,120,118,116,113,112,108,108,105,103,102,102,94,92,86,82,80,76,72,61,61,54,52,52,49,46,42,38,34,31,30,26,24,16,14]+  , [255,254,246,245,242,241,239,236,234,233,231,229,227,226,219,217,217,216,214,213,212,205,203,197,195,194,192,191,186,182,179,166,160,158,157,156,156,148,146,138,133,131,129,119,113,112,111,108,107,106,105,103,101,97,86,86,78,77,77,74,63,61,59,55,47,45,45,40,39,36,35,33,31,26,24,18,17,15,11,8]+  , [255,245,245,244,240,239,233,232,228,227,225,224,217,211,211,209,206,205,203,201,200,198,197,192,187,174,172,161,161,157,153,152,151,146,146,145,144,142,139,135,131,128,127,123,121,114,113,112,110,97,90,87,85,82,78,78,78,76,75,70,69,69,68,68,66,56,49,45,45,43,43,34,34,33,32,27,26,19,15,7]+  , [252,246,244,234,223,218,218,217,215,209,206,202,201,198,197,196,196,192,190,183,179,178,176,176,172,163,162,162,159,153,150,149,142,141,134,134,133,128,127,117,114,112,110,109,108,105,102,97,92,87,84,79,77,75,74,71,70,66,65,56,56,53,53,50,44,36,36,33,27,22,20,14,10,9,9,8,7,5,4,1]+  , [254,252,251,251,250,248,247,238,235,235,231,227,225,216,212,212,208,193,189,188,186,179,162,160,158,157,156,150,148,148,141,141,140,134,133,133,131,123,118,116,112,109,106,106,106,106,94,91,88,86,84,80,79,72,71,71,61,56,55,53,49,43,40,36,33,33,29,29,29,22,21,18,16,11,11,8,7,4,4,4]+  , [254,250,248,246,238,238,237,237,229,225,225,224,221,220,216,216,214,212,210,209,208,197,193,192,181,181,179,170,168,166,161,159,156,156,148,146,139,127,125,125,124,120,115,113,109,101,96,85,82,81,77,71,71,67,65,59,59,57,51,51,48,47,46,45,45,44,43,43,41,38,36,31,24,24,11,9,8,7,4,3]+  , [252,237,235,230,228,223,221,220,209,206,206,203,200,195,191,189,185,176,174,168,166,166,159,159,159,156,155,151,149,146,146,143,143,138,137,131,129,120,118,117,116,115,111,108,105,104,103,102,98,98,97,96,95,91,85,70,62,60,55,54,54,47,45,38,37,35,26,25,25,21,18,17,14,12,12,11,10,6,4,3]+  , [247,247,247,245,238,234,234,230,229,227,225,224,223,221,219,215,209,207,206,204,202,200,199,199,193,185,184,182,181,174,171,171,166,162,162,158,156,155,153,151,148,145,136,134,132,122,116,115,111,106,104,97,95,94,93,89,82,73,70,63,63,60,56,51,47,47,45,42,40,39,38,33,31,29,24,18,18,18,12,3]+  , [254,252,249,247,241,239,236,230,228,228,228,228,223,222,222,219,212,205,203,202,201,199,196,195,194,194,191,183,177,169,168,167,166,164,159,157,155,153,151,147,145,144,136,132,129,121,118,110,110,108,106,104,102,98,96,96,95,93,84,80,73,65,64,62,55,53,48,46,44,43,43,40,33,30,27,26,20,18,14,9]+  , [253,245,245,245,244,238,236,235,230,230,230,223,221,220,220,217,213,210,203,201,193,182,165,163,162,161,161,155,154,153,152,148,147,140,133,132,128,120,118,116,114,114,113,96,91,89,81,80,79,76,76,68,68,67,65,63,55,51,50,49,46,44,41,40,39,37,32,32,30,29,21,21,20,18,15,13,13,10,7,5]+  , [253,242,239,238,238,237,234,233,229,228,227,225,222,222,221,217,212,208,203,197,197,191,190,190,187,185,184,182,178,175,173,169,164,164,163,158,146,145,144,140,134,131,127,125,113,111,107,106,98,97,97,97,96,95,89,89,83,82,77,71,60,60,59,55,54,51,39,37,35,31,28,22,22,21,19,14,14,8,4,3]+  , [253,245,243,237,237,227,226,224,222,221,218,217,216,214,213,206,201,192,192,191,190,189,188,188,182,179,169,167,159,148,140,139,138,135,132,126,125,124,122,117,116,114,100,96,90,85,82,81,80,79,77,75,72,69,69,64,61,58,53,53,51,50,49,49,47,44,43,39,38,38,37,37,33,26,17,16,11,8,5,2]+  , [254,252,248,245,244,242,238,235,235,233,233,228,227,219,208,205,202,200,199,194,190,190,188,183,181,178,177,173,166,163,162,153,143,138,136,128,126,120,119,118,117,114,110,109,108,107,104,103,96,95,94,92,84,80,78,72,70,69,68,67,64,64,63,59,54,50,48,43,40,35,28,27,26,25,22,18,17,16,6,3]+  , [254,250,249,242,239,239,234,233,219,219,218,215,215,205,201,201,199,199,198,198,195,194,191,187,184,184,184,183,182,179,175,175,162,161,161,158,158,154,153,153,149,147,138,127,126,123,119,114,113,108,106,106,105,104,101,101,100,99,98,92,90,88,88,86,86,82,77,71,68,68,60,53,44,42,37,30,23,9,4,1]+  , [255,255,250,249,247,243,242,234,233,229,228,228,227,225,223,218,213,212,211,210,210,198,190,186,184,184,175,173,171,166,160,156,155,152,151,151,147,143,138,134,131,131,118,117,115,115,105,97,95,95,91,90,83,77,73,70,70,68,66,54,50,49,45,38,33,32,30,25,24,20,17,13,13,13,10,8,7,6,5,2]+  , [253,251,249,247,245,243,237,231,230,224,223,222,218,217,214,212,212,209,202,201,186,179,174,171,169,166,164,164,162,157,155,152,148,142,139,134,128,123,120,110,106,104,104,101,100,98,97,97,93,85,80,80,78,77,76,74,70,65,65,54,54,54,43,42,37,32,28,27,26,26,25,22,16,15,14,14,11,5,3,1]+  , [252,250,243,241,238,232,232,223,211,211,211,208,207,206,205,204,201,201,201,199,190,189,188,179,166,158,156,155,152,150,148,148,147,146,144,139,135,132,131,128,118,116,115,114,114,107,99,94,93,89,85,83,82,80,77,73,71,70,68,66,60,58,57,55,53,49,43,40,39,33,28,28,27,27,13,7,6,6,3,1]+  , [255,252,250,250,249,249,244,237,233,232,231,231,228,227,227,218,217,211,201,199,198,198,196,189,189,189,189,181,181,178,173,168,168,167,162,160,160,158,156,155,149,145,145,143,141,137,137,130,130,126,120,116,112,109,105,103,102,100,92,90,89,88,86,82,73,71,71,70,67,66,65,63,50,49,46,26,22,18,17,8]+  , [255,252,246,245,239,237,237,233,233,232,231,231,220,220,218,214,210,206,206,203,199,197,196,194,194,188,185,184,179,156,156,154,149,146,146,143,138,136,136,135,133,130,130,110,109,108,108,102,98,94,93,91,88,88,87,83,79,79,78,78,75,75,74,74,69,58,53,51,50,47,33,31,31,22,15,10,8,5,1,1]+  , [253,247,246,244,244,242,241,235,234,228,225,212,210,209,207,204,203,201,199,194,192,187,185,184,180,180,177,174,172,171,170,167,165,155,155,154,150,148,144,141,139,137,130,118,117,116,114,112,102,102,96,90,83,81,79,74,70,68,61,57,49,48,47,46,45,45,42,40,34,32,28,27,19,17,14,9,8,3,2,1]+  , [242,239,237,234,232,229,225,221,214,212,210,202,202,199,196,196,194,193,184,183,182,181,177,176,175,170,167,167,166,164,161,157,155,155,152,146,144,138,137,132,130,130,124,115,115,114,114,111,101,97,92,87,78,78,78,73,70,68,62,58,57,55,51,51,50,43,43,40,39,36,34,33,32,31,24,23,22,16,11,9]+  , [255,253,251,251,251,249,249,246,245,244,242,236,224,216,210,210,206,205,199,199,197,195,193,192,191,190,189,182,181,180,173,171,170,169,160,159,149,144,142,140,139,136,130,125,123,117,95,92,91,85,79,77,76,75,63,61,59,57,57,53,48,47,41,41,38,29,28,27,27,24,17,17,17,15,13,9,6,5,4,4]+  , [252,252,246,245,237,232,232,228,221,218,215,214,211,208,206,202,201,200,198,198,194,191,191,180,178,174,169,166,166,164,163,162,159,159,158,149,146,144,138,132,127,125,123,122,121,118,115,113,107,107,106,105,102,101,100,92,86,83,80,75,74,73,72,72,65,61,59,55,54,47,47,43,31,24,17,14,14,9,8,4]+  , [253,250,249,246,242,241,236,230,226,223,219,213,201,199,198,191,182,182,179,174,171,168,168,166,161,156,155,153,149,144,140,137,136,132,129,129,126,123,121,118,106,102,101,100,99,95,93,89,89,87,86,81,80,78,74,73,73,72,66,62,59,57,55,49,49,43,41,38,35,32,28,27,24,20,17,15,11,6,5,2]+  , [254,253,249,246,240,229,223,216,212,210,207,206,206,203,203,201,197,195,189,184,183,182,178,175,172,170,166,164,154,151,145,142,141,140,138,125,124,118,117,116,114,107,103,103,94,92,89,86,84,83,81,78,68,66,64,56,56,54,50,47,46,44,40,35,29,27,27,26,26,25,24,24,18,17,12,8,8,7,3,2]+  , [255,248,244,243,238,237,237,231,229,228,228,219,214,211,208,202,202,199,195,192,191,184,183,179,174,170,168,166,163,159,158,158,154,133,130,130,127,126,125,123,121,119,114,98,98,89,89,88,87,83,79,73,69,65,62,58,57,56,51,49,49,48,43,43,40,36,34,33,31,26,23,22,20,19,18,17,17,14,11,7]+  , [254,247,246,246,242,240,237,236,236,229,224,224,219,217,217,215,214,202,201,197,193,189,177,172,172,170,168,164,161,156,155,153,152,152,146,145,144,144,140,138,127,124,123,121,115,110,106,99,99,98,94,91,90,90,89,77,77,73,72,70,69,68,66,65,63,60,58,56,54,47,47,41,40,35,34,22,19,18,12,2]+    ----+  , [510,509,496,489,477,476,462,455,452,443,442,426,424,422,407,406,394,380,377,376,375,335,333,328,323,314,309,299,292,288,287,285,271,265,232,231,212,204,192,191,190,184,182,181,181,164,163,156,154,145,141,141,139,136,128,123,122,112,112,97,97,94,91,86,84,72,67,65,58,56,56,55,50,49,48,47,38,24,14,13]+  , [505,488,475,470,467,466,462,461,437,423,419,399,395,390,390,386,384,381,379,378,372,371,369,365,355,344,344,336,332,322,306,298,296,292,285,278,268,264,252,241,236,229,227,225,219,213,211,205,205,192,189,189,185,172,167,161,156,151,150,150,146,144,139,132,128,123,117,96,80,72,63,43,42,37,37,37,24,22,20,4]+  , [508,498,496,482,476,473,468,460,435,433,427,423,423,402,393,392,387,381,367,360,357,353,353,348,343,335,324,313,311,299,298,297,291,281,263,263,258,258,246,245,239,223,220,213,211,205,198,195,190,181,180,151,150,147,133,125,122,111,109,108,98,89,87,84,82,77,72,67,64,63,62,57,42,34,33,32,15,9,5,4]+  , [506,505,495,488,487,485,485,483,450,448,443,440,435,427,426,422,400,398,396,389,375,369,367,366,358,358,353,350,338,334,326,316,316,306,296,291,288,287,271,237,234,228,221,214,210,207,202,192,192,190,190,183,182,181,175,170,165,159,155,150,145,139,136,134,132,114,113,105,103,83,82,71,70,59,34,24,12,7,5,4]+  ]++--------------------------------------------------------------------------------
test/Tests/Partitions/Integer.hs view
@@ -1,7 +1,7 @@  -- | Tests for integer partitions. -{-# LANGUAGE CPP, BangPatterns #-}+{-# LANGUAGE CPP, BangPatterns, DataKinds, KindSignatures, ScopedTypeVariables #-} module Tests.Partitions.Integer where  --------------------------------------------------------------------------------@@ -13,6 +13,7 @@ import Tests.Common  import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Integer.Count  import Data.List import Control.Monad@@ -24,7 +25,30 @@ import Math.Combinat.Numbers ( factorial , binomial , multinomial ) import Math.Combinat.Helper +import Data.Proxy+import GHC.TypeLits+ --------------------------------------------------------------------------------++-- | Partitions of size at most n+newtype Part (n :: Nat) = Part (Partition) deriving (Eq,Show)++-- | usage: fromPart @20+fromPart :: Part n -> Partition+fromPart (Part p) = p++fromPart20 :: Part 20 -> Partition+fromPart20 (Part p) = p++fromPart30 :: Part 30 -> Partition+fromPart30 (Part p) = p ++instance forall n. KnownNat n => Arbitrary (Part n) where+  arbitrary = do+    n <- choose (0, fromInteger (natVal (Proxy :: Proxy n)))+    myMkGen' Part (randomPartition n)++-------------------------------------------------------------------------------- -- * Types and instances  newtype PartitionWeight     = PartitionWeight     Int              deriving (Eq,Show)@@ -69,6 +93,7 @@   , testProperty "dominated partitions"            prop_dominated_list   , testProperty "dominating partitions"           prop_dominating_list   , testProperty "counting partitions"             prop_countParts+  , testProperty "union/sum duality"               prop_union_sum_duality   ]  --------------------------------------------------------------------------------@@ -102,6 +127,9 @@  prop_countParts :: Bool prop_countParts = (take 50 partitionCountList == take 50 partitionCountListNaive)++prop_union_sum_duality :: Partition -> Partition -> Bool+prop_union_sum_duality p q = dualPartition (sumOfPartitions p q) == unionOfPartitions (dualPartition p) (dualPartition q)  -------------------------------------------------------------------------------- 
+ test/Tests/Partitions/Ribbon.hs view
@@ -0,0 +1,86 @@++-- | Tests for ribbons (border strip skew partitions).+--++{-# LANGUAGE CPP, BangPatterns #-}+module Tests.Partitions.Ribbon where++--------------------------------------------------------------------------------++import Test.Framework+import Test.Framework.Providers.QuickCheck2+import Test.QuickCheck++import Tests.Common+import Tests.Partitions.Integer ( Part(..) , fromPart20 , fromPart30 )     -- Arbitrary instances++import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Skew+import Math.Combinat.Partitions.Skew.Ribbon++import Data.List++import Math.Combinat.Classes++--------------------------------------------------------------------------------+-- * instances++data Inner = Inner Partition Int deriving (Eq,Show)++data Outer = Outer Partition Int deriving (Eq,Show)++instance Arbitrary Inner where+  arbitrary = do+    p <- arbitrary+    let (w,h) = (partitionWidth p, partitionHeight p)+        n = w+h-1+    d <- choose (1,n)+    return $ Inner p d++instance Arbitrary Outer where+  arbitrary = do+    pp <- arbitrary+    let p = fromPart30 pp    -- smaller partitions+    let (w,h) = (partitionWidth p, partitionHeight p)+        n = w+h+10   +    d <- choose (1,n)+    return $ Outer p d++--------------------------------------------------------------------------------+-- * test group++testgroup_Ribbon :: Test+testgroup_Ribbon = testGroup "Ribbons and Corners" +  [ testGroup "Ribbons"  +      [ testProperty "all inner ribbons vs. naive"        prop_inner_all+      , testProperty "inner ribbons of length vs. naive"  prop_inner_length+      , testProperty "outer ribbons of length vs. naive"  prop_outer_length+      ]+  , testGroup "Corners"+      [ testProperty "inner corner boxes vs. naive" prop_innerCornerBoxes+      , testProperty "outer corner boxes vs. naive" prop_outerCornerBoxes +      ]+  ]++--------------------------------------------------------------------------------+-- * ribbon properties++prop_inner_all :: Partition -> Bool+prop_inner_all p = sort (innerRibbons p) == sort (innerRibbonsNaive p)++prop_inner_length :: Inner -> Bool+prop_inner_length (Inner p n) = sort (innerRibbonsOfLength p n) == sort (innerRibbonsOfLengthNaive p n)++prop_outer_length :: Outer -> Bool+prop_outer_length (Outer p n) = sort (outerRibbonsOfLength p n) == sort (outerRibbonsOfLengthNaive p n)++--------------------------------------------------------------------------------+-- * corner properties++prop_innerCornerBoxes :: Partition -> Bool+prop_innerCornerBoxes p  =  (innerCornerBoxes p == innerCornerBoxesNaive p)++prop_outerCornerBoxes :: Partition -> Bool+prop_outerCornerBoxes p  =  (outerCornerBoxes p == outerCornerBoxesNaive p)++--------------------------------------------------------------------------------
test/Tests/Partitions/Skew.hs view
@@ -2,7 +2,7 @@ -- | Tests for skew partitions. -- -{-# LANGUAGE CPP, BangPatterns #-}+{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables, DataKinds, KindSignatures #-} module Tests.Partitions.Skew where  --------------------------------------------------------------------------------@@ -12,7 +12,7 @@ import Test.QuickCheck  import Tests.Common-import Tests.Partitions.Integer ()     -- Arbitrary instances+import Tests.Partitions.Integer ( Part(..) , fromPart20 , fromPart30 )     -- Arbitrary instances  import Math.Combinat.Partitions.Integer import Math.Combinat.Partitions.Skew@@ -21,6 +21,9 @@  import Math.Combinat.Classes +import Data.Proxy+import GHC.TypeLits+ -------------------------------------------------------------------------------- -- * instances @@ -34,6 +37,32 @@     k <- choose (0,ln-1)     let q = qs !! k     return $ mkSkewPartition (p,q) ++--------------------------------------------------------------------------------++-- | Skew partitions of size at most n+newtype Skew (n :: Nat) = Skew (SkewPartition) deriving (Eq,Show)++-- | usage: fromSkew @20+fromSkew :: Skew n -> SkewPartition+fromSkew (Skew p) = p++fromSkew20 :: Skew 20 -> SkewPartition+fromSkew20 (Skew p) = p++fromSkew30 :: Skew 30 -> SkewPartition+fromSkew30 (Skew p) = p ++instance forall nn. KnownNat nn => Arbitrary (Skew nn) where+  arbitrary = do+    Part p <- arbitrary :: Gen (Part nn)+    let n = partitionWeight p+    d <- choose (0,n)+    let qs = subPartitions d p+        ln = length qs+    k <- choose (0,ln-1)+    let q = qs !! k+    return $ Skew $ mkSkewPartition (p,q)   -------------------------------------------------------------------------------- -- * test group
test/Tests/Permutations.hs view
@@ -56,6 +56,8 @@  data SameSize = SameSize Permutation Permutation deriving Show +data PermWithList = PWL Permutation [Int] deriving (Show)+ instance Random Permutation where   random g = randomPermutation size g1 where     (size,g1) = randomR (minPermSize,maxPermSize) g@@ -81,6 +83,20 @@     (prm2,g3) = randomPermutation size g2   randomR _ = random +randomRList :: (RandomGen g, Random a) => Int -> (a, a) -> g -> ([a],g)+randomRList n ab g0 = go n g0 where+  go 0   g = ([],g)+  go !k !g = let (x ,g' ) = randomR ab g +                 (xs,g'') = go (k-1) g'+             in  (x:xs,g'')++instance Random PermWithList where+  random g = (PWL prm xs, g3) where+    (size,g1) = randomR (minPermSize,maxPermSize) g+    (prm ,g2) = randomPermutation size g1 +    (xs  ,g3) = randomRList size (-100,100) g2+  randomR _ = random+ instance Arbitrary Nat where   arbitrary = choose (Nat 0 , Nat 50)      @@ -88,6 +104,7 @@ instance Arbitrary CyclicPermutation where arbitrary = choose undefined instance Arbitrary DisjointCycles    where arbitrary = choose undefined instance Arbitrary SameSize          where arbitrary = choose undefined+instance Arbitrary PermWithList      where arbitrary = choose undefined  -------------------------------------------------------------------------------- -- * test group@@ -129,6 +146,9 @@   , testProperty "number of inversions is the same for the inverse permutation"  prop_ninversions_inverse   , testProperty "merge sort algorithm = naive inversion count"                  prop_merge_inversions +  , testProperty "sortingPermutationAsc"    prop_sortingPermAsc+  , testProperty "sortingPermutationDesc"   prop_sortingPermDesc+  , testProperty "concatPermutations"       prop_concatPerm   ]  --------------------------------------------------------------------------------@@ -214,6 +234,14 @@ prop_ninversions_inverse perm = numberOfInversions perm == numberOfInversions (inverse perm)  prop_merge_inversions perm = (numberOfInversionsMerge perm == numberOfInversionsNaive perm)++prop_sortingPermAsc :: [Int] -> Bool +prop_sortingPermAsc xs = permuteList (sortingPermutationAsc xs) xs == sort xs++prop_sortingPermDesc :: [Int] ->  Bool+prop_sortingPermDesc xs = permuteList (sortingPermutationDesc xs) xs == reverse (sort xs)++prop_concatPerm (PWL p1 xs) (PWL p2 ys) = permuteList p1 xs ++ permuteList p2 ys == permuteList (concatPermutations p1 p2) (xs++ys)  -------------------------------------------------------------------------------- 
test/Tests/Series.hs view
@@ -2,7 +2,7 @@ -- | Tests for power series -- -{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, DataKinds, KindSignatures #-} module Tests.Series where  --------------------------------------------------------------------------------@@ -15,7 +15,11 @@ import System.Random  import Data.List+import Data.Ratio +import GHC.TypeLits+import Data.Proxy+ import Math.Combinat.Sign import Math.Combinat.Numbers import Math.Combinat.Partitions.Integer@@ -123,25 +127,89 @@ swap (x,y) = (y,x) -} --- compare the first 500 elements of the infinite lists+-- compare the first N elements of the infinite lists+(=..=) :: (Eq a, Num a) => Int -> [a] -> [a] -> Bool+(=..=) n xs1 ys1 = take n xs == take n ys where+  xs = xs1 ++ repeat 0+  ys = ys1 ++ repeat 0++infix 4 =..=++-- compare the first 100 elements of the infinite lists (=!=) :: (Eq a, Num a) => [a] -> [a] -> Bool (=!=) xs1 ys1 = (take m xs == take m ys) where -  m = 500+  m = 100   xs = xs1 ++ repeat 0   ys = ys1 ++ repeat 0  infix 4 =!= -newtype Nat = Nat { fromNat :: Int } deriving (Eq,Ord,Show,Num,Random)-newtype Ser = Ser { fromSer :: [Integer] } deriving (Eq,Ord,Show)+-- compare the first 500 elements of the infinite lists+(=!!=) :: (Eq a, Num a) => [a] -> [a] -> Bool+(=!!=) xs1 ys1 = (take m xs == take m ys) where +  m = 500+  xs = xs1 ++ repeat 0+  ys = ys1 ++ repeat 0++infix 4 =!!=++newtype XNat   = XNat   { fromXNat   :: Int      } deriving (Eq,Ord,Show,Num,Random)++newtype Rat    = Rat    { fromRat    :: Rational } deriving (Eq,Ord,Show,Num,Fractional)+newtype NZRat  = NZRat  { fromNZRat  :: Rational } deriving (Eq,Ord,Show,Num,Fractional)++-- type parameter is for controlling the size (length), because some tests are too slow+newtype Ser  (n :: Nat) = Ser  { fromSer'  :: [Integer] } deriving (Eq,Ord,Show)+newtype SerR (n :: Nat) = SerR { fromSerR' :: [Rational] } deriving (Eq,Ord,Show)+ newtype Exp  = Exp  { fromExp  ::  Int  } deriving (Eq,Ord,Show,Num,Random) newtype Exps = Exps { fromExps :: [Int] } deriving (Eq,Ord,Show) newtype CoeffExp  = CoeffExp  { fromCoeffExp  ::  (Integer,Int)  } deriving (Eq,Ord,Show) newtype CoeffExps = CoeffExps { fromCoeffExps :: [(Integer,Int)] } deriving (Eq,Ord,Show) -minSerSize = 0    :: Int-maxSerSize = 1000 :: Int+---------------------------------------- +serProxy :: f (n :: Nat) -> Proxy n+serProxy _ = Proxy++seriesSize :: KnownNat (n :: Nat) => f (n :: Nat) -> Int+seriesSize ser = fromInteger $ natVal (serProxy ser) where ++----------------------------------------++fromSer  = fromSer500+fromSerR = fromSerR500++fromSer25 :: Ser 25 -> [Integer]+fromSer25 = fromSer'++fromSer100 :: Ser 100 -> [Integer]+fromSer100 = fromSer'++fromSer500 :: Ser 500 -> [Integer]+fromSer500 = fromSer'++----------------------------------------++fromSerR25 :: SerR 25 -> [Rational]+fromSerR25 = fromSerR'++fromSerR50 :: SerR 50 -> [Rational]+fromSerR50 = fromSerR'++fromSerR100 :: SerR 100 -> [Rational]+fromSerR100 = fromSerR'++fromSerR500 :: SerR 500 -> [Rational]+fromSerR500 = fromSerR'++----------------------------------------++{-+minSerSize = 0   :: Int+maxSerSize = 500 :: Int+-}+ minSerValue = -10000 :: Int maxSerValue =  10000 :: Int @@ -149,9 +217,20 @@ rndList n minmax g = swap $ mapAccumL f g [1..n] where   f g _ = swap $ randomR minmax g  -instance Arbitrary Nat where-  arbitrary = choose (Nat 0 , Nat 750)+instance Random Rat where+  random g = (Rat (fromIntegral x % fromIntegral y), g'') where+    (x,g' ) = randomR (-100,100::Int) g+    (y,g'') = randomR (   1, 25::Int) g'        -- hackety hack hack+  randomR _ g = random g +instance Random NZRat where+  random g = let (Rat q , g') = random g+             in  if q /= 0 then (NZRat q, g') else random g'            +  randomR _ g = random g++instance Arbitrary XNat where+  arbitrary = choose (XNat 0 , XNat 750)+ instance Arbitrary Exp where   arbitrary = choose (Exp 1 , Exp 32) @@ -161,14 +240,24 @@     exp   <- arbitrary :: Gen Exp     return $ CoeffExp (fromIntegral coeff, fromExp exp)    -instance Random Ser where-  random g = (Ser $ map fi list, g2) where-    (size,g1) = randomR (minSerSize,maxSerSize) g+instance KnownNat (n :: Nat) => Random (Ser n) where+  random g = (series, g2) where+    maxSerSize = seriesSize series+    series     = Ser (map fi list) +    (size,g1) = randomR (0,maxSerSize) g     (list,g2) = rndList size (minSerValue,maxSerValue) g1     fi :: Int -> Integer     fi = fromIntegral    randomR _ = random +instance KnownNat (n :: Nat) => Random (SerR n) where+  random g = (series, g2) where+    maxSerSize = seriesSize series+    series    = SerR (map fromRat list) +    (size,g1) = randomR (0,maxSerSize) g+    (list,g2) = rndList size (fromIntegral minSerValue, fromIntegral maxSerValue) g1+  randomR _ = random+ instance Random Exps where   random g = (Exps list, g2) where     (size,g1) = randomR (0,10) g@@ -181,10 +270,19 @@     (list1,g2) = rndList size (1,32) g1     (list2,g3) = rndList size (minSerValue,maxSerValue) g2   randomR _ = random++instance Arbitrary Rat where+  arbitrary = choose undefined++instance Arbitrary NZRat where+  arbitrary = choose undefined   -instance Arbitrary Ser where+instance KnownNat n => Arbitrary (Ser n) where   arbitrary = choose undefined +instance KnownNat n => Arbitrary (SerR n) where+  arbitrary = choose undefined+ instance Arbitrary Exps where   arbitrary = choose undefined @@ -197,7 +295,26 @@ testgroup_PowerSeries :: Test testgroup_PowerSeries = testGroup "Power series"   [ -    testProperty "convPSeries1 vs generic"     prop_conv1_vs_gen+    testProperty "mulSeries  == mulSeriesNaive"   prop_mulSeries_vs_naive+  , testProperty "divSeries  == mulWithRecip"     prop_divSeries_vs_mult_with_recip+  , testProperty "recip xs   == 1 / xs"           prop_recipSeries_vs_one_over+  , testProperty "compose    == composeNaive"     prop_compose_vs_naive+  , testProperty "substitute == substituteNaive"  prop_substitute_vs_naive+  , testProperty "inversion  == inversionNaive"   prop_inversion_vs_naive++  , testProperty "lagrange inversion works /1"       prop_lagrange_inversion1+  , testProperty "lagrange inversion works /2"       prop_lagrange_inversion2+  , testProperty "naive lagrange inversion works /1"       prop_lagrange_inversion_naive1+  , testProperty "naive lagrange inversion works /2"       prop_lagrange_inversion_naive2+  , testProperty "integral naive lagrange inversion works /1"       prop_lagrange_inversion_int_naive1+  , testProperty "integral naive lagrange inversion works /2"       prop_lagrange_inversion_int_naive2++  , testProperty "diff . int == id"            prop_diff_integrate+  , testProperty "tail (int . diff) == tail"   prop_integrate_diff+  , testProperty "sin vs sin2"                 prop_sin_vs_sin2+  , testProperty "cos vs cos2"                 prop_cos_vs_cos2++  , testProperty "convPSeries1 vs generic"     prop_conv1_vs_gen   , testProperty "convPSeries2 vs generic"     prop_conv2_vs_gen   , testProperty "convPSeries3 vs generic"     prop_conv3_vs_gen   , testProperty "convPSeries1' vs generic"    prop_conv1_vs_gen'@@ -217,23 +334,69 @@  -------------------------------------------------------------------------------- -- * properties++prop_mulSeries_vs_naive ser1 ser2 = (mulSeries xs ys =!= mulSeriesNaive xs ys) where+  xs = fromSer ser1+  ys = fromSer ser2++prop_divSeries_vs_mult_with_recip (NZRat q) ser1 ser2 = (=..=) 60 (divSeries xs ys) (mulSeries xs (reciprocalSeries ys)) where+  xs =     fromSerR100 ser1+  ys = q : fromSerR100 ser2++prop_recipSeries_vs_one_over (NZRat q) ser = (reciprocalSeries xs =!= divSeries unitSeries xs) where+  xs = q : fromSerR100 ser++prop_compose_vs_naive ser1 ser2 = (=..=) 25 (composeSeries xs ys) (composeSeriesNaive xs ys) where+  xs =     fromSer25 ser1+  ys = 0 : fromSer25 ser2++prop_substitute_vs_naive ser1 ser2 = (=..=) 25 (substitute xs ys) (substituteNaive xs ys) where+  xs = 0 : fromSer25 ser1+  ys =     fromSer25 ser2++prop_inversion_vs_naive (NZRat q) ser = (=..=) 25 (lagrangeInversion xs) (lagrangeInversionNaive xs) where+  xs = 0 : q : fromSerR25 ser++prop_lagrange_inversion1 (NZRat q) ser = (=..=) 35 (substitute f (lagrangeInversion f)) (0 : 1 : repeat 0) where f = 0 : q : fromSerR50 ser+prop_lagrange_inversion2 (NZRat q) ser = (=..=) 35 (substitute (lagrangeInversion f) f) (0 : 1 : repeat 0) where f = 0 : q : fromSerR50 ser++prop_lagrange_inversion_naive1 (NZRat q) ser = (=..=) 20 (substituteNaive f (lagrangeInversionNaive f)) (0 : 1 : repeat 0) where f = 0 : q : fromSerR25 ser+prop_lagrange_inversion_naive2 (NZRat q) ser = (=..=) 20 (substituteNaive (lagrangeInversionNaive f) f) (0 : 1 : repeat 0) where f = 0 : q : fromSerR25 ser++prop_lagrange_inversion_int_naive1 ser = (=..=) 20 (substituteNaive f (integralLagrangeInversionNaive f)) (0 : 1 : repeat 0) where f = 0 : 1 : fromSer25 ser+prop_lagrange_inversion_int_naive2 ser = (=..=) 20 (substituteNaive (integralLagrangeInversionNaive f) f) (0 : 1 : repeat 0) where f = 0 : 1 : fromSer25 ser++--------------------------------------------------------------------------------++prop_diff_integrate ser = (xs =!= differentiateSeries (integrateSeries xs)) where+  xs = fromSerR ser++prop_integrate_diff ser = (0 : tail xs =!= integrateSeries (differentiateSeries xs)) where+  xs = fromSerR ser++prop_cos_vs_cos2 = (cosSeries =!= (cosSeries2 :: [Rational])) +prop_sin_vs_sin2 = (sinSeries =!= (sinSeries2 :: [Rational])) ++--------------------------------------------------------------------------------       prop_leftIdentity ser = ( xs =!= unitSeries `convolve` xs ) where -  xs = fromSer ser +  xs = fromSer100 ser   prop_rightIdentity ser = ( unitSeries `convolve` xs =!= xs ) where -  xs = fromSer ser +  xs = fromSer100 ser   prop_commutativity ser1 ser2 = ( xs `convolve` ys =!= ys `convolve` xs ) where -  xs = fromSer ser1-  ys = fromSer ser2+  xs = fromSer100 ser1+  ys = fromSer100 ser2  prop_associativity ser1 ser2 ser3 = ( one =!= two ) where   one = (xs `convolve` ys) `convolve` zs   two = xs `convolve` (ys `convolve` zs)-  xs = fromSer ser1-  ys = fromSer ser2-  zs = fromSer ser3+  xs = fromSer100 ser1+  ys = fromSer100 ser2+  zs = fromSer100 ser3++--------------------------------------------------------------------------------    prop_conv1_vs_gen exp1 ser = ( one =!= two ) where   one = convolveWithPSeries1 k1 xs 
test/Tests/SkewTableaux.hs view
@@ -1,7 +1,7 @@ 
 -- | Tests for skew tableaux
 
-{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleInstances, TypeApplications, DataKinds #-}
 module Tests.SkewTableaux where
 
 --------------------------------------------------------------------------------
@@ -14,7 +14,7 @@ import Test.QuickCheck.Gen
 
 import Tests.Partitions.Integer ()
-import Tests.Partitions.Skew    ()      -- arbitrary instances
+import Tests.Partitions.Skew ( Skew(..) , fromSkew20 , fromSkew30 )     -- Arbitrary instances
 
 import Math.Combinat.Tableaux
 import Math.Combinat.Tableaux.Skew
@@ -52,7 +52,8 @@ 
 instance Arbitrary (SkewTableau Int) where
   arbitrary = do
-    shape <- arbitrary
+    pshape <- arbitrary
+    let shape = fromSkew20 pshape      -- skew partition of size at most 20
     let w = skewPartitionWeight shape
     content <- replicateM w $ choose (1,1000)
     return $ fillSkewPartitionWithRowWord shape content
@@ -90,8 +91,8 @@   tableau = fillSkewPartitionWithColumnWord shape [1..]
   shape'  = skewTableauShape tableau
 
-prop_semistandard :: SkewPartition -> Bool
-prop_semistandard shape = and 
+prop_semistandard :: Skew 20 -> Bool
+prop_semistandard (Skew shape) = and 
   [ isSemiStandardSkewTableau st 
   | n  <- [kk..nn] 
   , st <- take 500 (semiStandardSkewTableaux n shape)         -- we only take the first 500 because impossibly slow otherwise