jackpolynomials 1.4.1.0 → 1.4.2.0
raw patch · 7 files changed
+1056/−94 lines, 7 filesdep +matrixdep +vector
Dependencies added: matrix, vector
Files
- CHANGELOG.md +27/−3
- README.md +2/−1
- jackpolynomials.cabal +5/−2
- src/Math/Algebra/Jack/Internal.hs +278/−10
- src/Math/Algebra/JackPol.hs +2/−2
- src/Math/Algebra/SymmetricPolynomials.hs +487/−69
- tests/Main.hs +255/−7
CHANGELOG.md view
@@ -67,6 +67,30 @@ combination of some power sum polynomials * new function `hallInnerProduct`, to compute the Hall inner product between -two symmetric polynomials, and there is also the function -`symbolicHallInnerProduct`, to get the Hall inner product with a symbolic -parameter+two symmetric polynomials, aka the Jack-scalar product or the deformed Hall +inner product; there is also the function `symbolicHallInnerProduct`, to get +the Hall inner product with a symbolic parameter + +1.4.2.0 +------- +* new function `cshPolynomial`, to get a complete symmetric homogeneous polynomial + +* new function `cshCombination`, to get a symmetric polynomial as a linear +combination of some complete symmetric homogeneous polynomials + +* new function `esPolynomial`, to get an elementary symmetric polynomial + +* new function `esCombination`, to get a symmetric polynomial as a linear +combination of some elementary symmetric polynomials + +* new function `schurCombination`, to get a symmetric polynomial as a linear +combination of some Schur polynomials + +* new function `jackCombination`, to get a symmetric polynomial as a linear +combination of some Jack polynomials + +* new function `jackSymbolicCombination`, to get a symmetric polynomial as a linear +combination of some Jack polynomials with symbolic Jack parameter + +* new functions `kostkaNumbers` and `symbolicKostkaNumbers`, to get the Kostka +numbers with parameter
README.md view
@@ -10,7 +10,8 @@ Schur polynomials have applications in combinatorics and zonal polynomials have applications in multivariate statistics. They are particular cases of [Jack polynomials](https://en.wikipedia.org/wiki/Jack_function). This package -allows to evaluate these polynomials and to compute them in symbolic form. +allows to evaluate these polynomials and to compute them in symbolic form. It +also provides some utilities for symmetric polynomials. ___
jackpolynomials.cabal view
@@ -1,7 +1,7 @@ name: jackpolynomials -version: 1.4.1.0 +version: 1.4.2.0 synopsis: Jack, zonal, Schur and skew Schur polynomials -description: This library can evaluate Jack polynomials, zonal polynomials, Schur and skew Schur polynomials. It is also able to compute them in symbolic form. +description: This library can compute Jack polynomials, zonal polynomials, Schur and skew Schur polynomials. It also provides some utilities for symmetric polynomials. homepage: https://github.com/stla/jackpolynomials#readme license: GPL-3 license-file: LICENSE @@ -32,6 +32,8 @@ , containers >= 0.6.4.1 && < 0.8 , unordered-containers >= 0.2.17.0 && < 0.3 , extra >= 1.7 && < 1.8 + , matrix >= 0.3.6.0 && < 0.4 + , vector >= 0.10.0 && < 0.13.2 other-extensions: ScopedTypeVariables , BangPatterns , FlexibleContexts @@ -58,6 +60,7 @@ , hypergeomatrix >= 1.1.0.2 && < 2 , combinat >= 0.2.10 && < 0.3 , containers >= 0.6.4.1 && < 0.8 + , numeric-prelude >= 0.4.4 && < 0.5 Default-Language: Haskell2010 ghc-options: -Wall -Wcompat
src/Math/Algebra/Jack/Internal.hs view
@@ -14,31 +14,294 @@ , _N , _fromInt , skewSchurLRCoefficients - , isSkewPartition ) + , isSkewPartition + , sprayToMap + , comboToSpray + , _kostkaNumbers + , _inverseKostkaMatrix + , _symbolicKostkaNumbers + , _inverseSymbolicKostkaMatrix + ) where import Prelude hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger, recip) +import qualified Prelude as P import Algebra.Additive ( (+), (-), sum ) +import qualified Algebra.Additive as AlgAdd import Algebra.Field ( (/), recip ) import qualified Algebra.Field as AlgField +import Algebra.Module ( (*>) ) import Algebra.Ring ( (*), product, one , (^), fromInteger ) import qualified Algebra.Ring as AlgRing import Algebra.ToInteger ( fromIntegral ) +import qualified Data.Foldable as DF +import qualified Data.HashMap.Strict as HM +import Data.List.Extra ( unsnoc ) import Data.List.Index ( iconcatMap ) +import Data.Map.Strict ( Map ) import qualified Data.Map.Strict as DM +import Data.Matrix ( + Matrix + , nrows + , getCol + , getRow + , minorMatrix + , (<|>) + , (<->) + , rowVector + , colVector + , getElem + , fromLists + ) +import Data.Maybe ( fromJust ) +import Data.Sequence ( Seq ) +import qualified Data.Sequence as S +import Data.Tuple.Extra ( fst3 ) +import qualified Data.Vector as V import Math.Algebra.Hspray ( - RatioOfSprays, (%:%) + RatioOfSprays, (%:%), (%//%), (%/%) + , unitRatioOfSprays + , zeroRatioOfSprays + , asRatioOfSprays , Spray, (.^) + , Powers (..) , lone, unitSpray + , sumOfSprays , FunctionLike (..) ) +import Math.Combinat.Partitions.Integer ( + fromPartition + , dualPartition + , partitions + , dominates + , partitionWidth + ) import qualified Math.Combinat.Partitions.Integer as MCP import Math.Combinat.Tableaux.LittlewoodRichardson ( _lrRule ) type Partition = [Int] + +_e :: AlgRing.C a => MCP.Partition -> a -> a +_e lambda alpha = + alpha * fromIntegral (_n (dualPartition lambda)) - fromIntegral (_n lambda) + where + _n mu = sum (zipWith (P.*) [0 .. ] (fromPartition mu)) + +_eSymbolic :: (Eq a, AlgRing.C a) => MCP.Partition -> Spray a +_eSymbolic lambda = + _n (dualPartition lambda) .^ alpha <+ fromIntegral (- _n lambda) + where + alpha = lone 1 + _n mu = sum (zipWith (P.*) [0 .. ] (fromPartition mu)) + +_inverseKostkaMatrix :: + forall a. (Eq a, AlgField.C a) + => Int -> Int -> a -> Char -> (Matrix a, [Partition]) +_inverseKostkaMatrix n weight alpha which = + (inverseTriangularMatrix (fromLists (map row lambdas)), lambdas) + where + kostkaNumbers = _kostkaNumbers n weight alpha which + lambdas = reverse $ DM.keys kostkaNumbers + msCombo lambda = kostkaNumbers DM.! lambda + row lambda = + map (flip (DM.findWithDefault AlgAdd.zero) (msCombo lambda)) lambdas + +_kostkaNumbers :: + forall a. (AlgField.C a) + => Int -> Int -> a -> Char -> Map Partition (Map Partition a) +_kostkaNumbers nv weight alpha which = kostkaMatrix' + where + coeffsP = DM.fromDistinctDescList + [(kappa, recip (jackCoeffP kappa alpha))| kappa <- lambdas'] + coeffsC = DM.fromDistinctDescList + [(kappa, jackCoeffC kappa alpha / jackCoeffP kappa alpha) + | kappa <- lambdas'] + coeffsQ = DM.fromDistinctDescList + [(kappa, jackCoeffQ kappa alpha / jackCoeffP kappa alpha) + | kappa <- lambdas'] + kostkaMatrix = DM.mapKeys fromPartition (rec (length lambdas)) + kostkaMatrix' = case which of + 'J' -> DM.mapWithKey (\kappa m -> DM.map ((*) (coeffsP DM.! kappa)) m) + kostkaMatrix + 'P' -> kostkaMatrix + 'C' -> DM.mapWithKey (\kappa m -> DM.map ((*) (coeffsC DM.! kappa)) m) + kostkaMatrix + 'Q' -> DM.mapWithKey (\kappa m -> DM.map ((*) (coeffsQ DM.! kappa)) m) + kostkaMatrix + _ -> error "_kostkaNumbers: should not happen." + mu_r_plus :: + Seq Int -> (Int, Int) -> Int -> (MCP.Partition, (Int, Int), Int) + mu_r_plus mu pair@(i, j) r = + ( + MCP.Partition $ + DF.toList $ S.dropWhileR (== 0) $ S.reverse $ S.sort $ + S.adjust' ((P.+) r) i (S.adjust' (subtract r) j mu) + , pair + , r + ) + lambdas = reverse $ + filter (\part -> partitionWidth part <= nv) (partitions weight) + lambdas' = map fromPartition lambdas + rec :: Int -> Map MCP.Partition (Map Partition a) + rec n = if n == 1 + then DM.singleton (MCP.Partition [weight]) + (DM.singleton [weight] AlgRing.one) + else DM.insert mu (DM.singleton mu' AlgRing.one) + ( + DM.fromDistinctDescList + [( + kappa + , DM.insert mu' (newColumn DM.! kappa) (previous DM.! kappa) + ) | kappa <- kappas] + ) + where + previous = rec (n - 1) + parts = take n lambdas + (kappas, mu) = fromJust (unsnoc parts) + _e_mu_alpha = _e mu alpha + mu' = fromPartition mu + mu'' = S.fromList mu' + l = S.length mu'' + pairs = [(i, j) | i <- [0 .. l-2], j <- [i+1 .. l-1]] + triplets = [mu_r_plus mu'' (i, j) r + | (i, j) <- pairs, r <- [1 .. S.index mu'' j]] + newColumn = + DM.fromDistinctDescList [(kappa, f kappa) | kappa <- kappas] + f kappa = AlgAdd.sum xs + where + previousRow = previous DM.! kappa + triplets' = filter ((dominates kappa) . fst3) triplets + ee = _e kappa alpha - _e_mu_alpha + xs = [ + fromIntegral (S.index mu'' i P.- S.index mu'' j P.+ 2 P.* r) + * (previousRow DM.! (fromPartition nu)) / ee + | (nu, (i, j), r) <- triplets' + ] + +_symbolicKostkaNumbers :: + forall a. (Eq a, AlgField.C a) + => Int -> Int -> Char -> Map Partition (Map Partition (RatioOfSprays a)) +_symbolicKostkaNumbers nv weight which = kostkaMatrix' + where + coeffsP = DM.fromDistinctDescList + [(kappa, asRatioOfSprays (jackSymbolicCoeffPinv kappa)) + | kappa <- lambdas'] + coeffsC = DM.fromDistinctDescList + [( + kappa + , (jackSymbolicCoeffPinv kappa :: Spray a) *> jackSymbolicCoeffC kappa + ) | kappa <- lambdas'] + coeffsQ = DM.fromDistinctDescList + [( + kappa + , jackSymbolicCoeffPinv kappa %//% jackSymbolicCoeffQinv kappa + ) | kappa <- lambdas'] + kostkaMatrix = DM.mapKeys fromPartition (rec (length lambdas)) + kostkaMatrix' = case which of + 'J' -> DM.mapWithKey (\kappa m -> DM.map ((*) (coeffsP DM.! kappa)) m) + kostkaMatrix + 'P' -> kostkaMatrix + 'C' -> DM.mapWithKey (\kappa m -> DM.map ((*) (coeffsC DM.! kappa)) m) + kostkaMatrix + 'Q' -> DM.mapWithKey (\kappa m -> DM.map ((*) (coeffsQ DM.! kappa)) m) + kostkaMatrix + _ -> error "_symbolicKostkaNumbers: should not happen." + mu_r_plus :: + Seq Int -> (Int, Int) -> Int -> (MCP.Partition, (Int, Int), Int) + mu_r_plus mu pair@(i, j) r = + ( + MCP.Partition $ + DF.toList $ S.dropWhileR (== 0) $ S.reverse $ S.sort $ + S.adjust' ((P.+) r) i (S.adjust' (subtract r) j mu) + , pair + , r + ) + lambdas = reverse $ + filter (\part -> partitionWidth part <= nv) (partitions weight) + lambdas' = map fromPartition lambdas + rec :: Int -> Map MCP.Partition (Map Partition (RatioOfSprays a)) + rec n = if n == 1 + then DM.singleton (MCP.Partition [weight]) + (DM.singleton [weight] unitRatioOfSprays) + else DM.insert mu (DM.singleton mu' unitRatioOfSprays) + ( + DM.fromDistinctDescList + [ + ( + kappa + , DM.insert mu' (newColumn DM.! kappa) (previous DM.! kappa) + ) + | kappa <- kappas + ] + ) + where + previous = rec (n - 1) + parts = take n lambdas + (kappas, mu) = fromJust (unsnoc parts) + _eSymbolic_mu = _eSymbolic mu + mu' = fromPartition mu + mu'' = S.fromList mu' + l = S.length mu'' + pairs = [(i, j) | i <- [0 .. l-2], j <- [i+1 .. l-1]] + triplets = [mu_r_plus mu'' (i, j) r + | (i, j) <- pairs, r <- [1 .. S.index mu'' j]] + newColumn = + DM.fromDistinctDescList [(kappa, f kappa) | kappa <- kappas] + f kappa = AlgAdd.sum xs + where + previousRow = previous DM.! kappa + triplets' = filter ((dominates kappa) . fst3) triplets + ee = _eSymbolic kappa - _eSymbolic_mu + xs = [ + ( + (S.index mu'' i P.- S.index mu'' j P.+ 2 P.* r) + .^ (previousRow DM.! (fromPartition nu)) + ) %/% ee + | (nu, (i, j), r) <- triplets' + ] + +_inverseSymbolicKostkaMatrix :: + forall a. (Eq a, AlgField.C a) + => Int -> Int -> Char -> (Matrix (RatioOfSprays a), [Partition]) +_inverseSymbolicKostkaMatrix n weight which = +-- (inverseTriangularMatrix (fromLists (map (\lambda -> map (row lambda) lambdas) lambdas)), lambdas) + ( + inverseTriangularMatrix (fromLists [map (row mu) lambdas | mu <- lambdas]) + , lambdas + ) + where + kostkaNumbers = _symbolicKostkaNumbers n weight which + lambdas = reverse $ DM.keys kostkaNumbers + msCombo lambda = kostkaNumbers DM.! lambda + row = flip (DM.findWithDefault zeroRatioOfSprays) . msCombo + -- row lambda = + -- map (flip (DM.findWithDefault zeroRatioOfSprays) (msCombo lambda)) lambdas + +inverseTriangularMatrix :: (Eq a, AlgField.C a) => Matrix a -> Matrix a +inverseTriangularMatrix mat = + if d == 1 then fromLists [[recip (getElem 1 1 mat)]] else invmat + where + d = nrows mat + invminor = inverseTriangularMatrix (minorMatrix d d mat) + lastColumn = V.init (getCol d mat) + vectors = [ + ( + V.drop (i-1) (getRow i invminor) + , V.drop (i-1) lastColumn + ) + | i <- [1 .. d-1] + ] + lastEntry = recip (getElem d d mat) + newColumn = colVector (V.fromList + [AlgAdd.negate (lastEntry * V.foldl1 (AlgAdd.+) (V.zipWith (*) u v)) + | (u, v) <- vectors] + ) + newRow = rowVector (V.snoc (V.replicate (d - 1) AlgAdd.zero) lastEntry) + invmat = (invminor <|> newColumn) <-> newRow + _isPartition :: Partition -> Bool _isPartition [] = True _isPartition [x] = x > 0 @@ -205,15 +468,20 @@ skewSchurLRCoefficients :: Partition -> Partition -> DM.Map Partition Int skewSchurLRCoefficients lambda mu = - DM.mapKeys toPartition (_lrRule lambda' mu') + DM.mapKeys fromPartition (_lrRule lambda' mu') where - toPartition :: MCP.Partition -> Partition - toPartition (MCP.Partition part) = part - fromPartition :: Partition -> MCP.Partition - fromPartition part = MCP.Partition part - lambda' = fromPartition lambda - mu' = fromPartition mu + lambda' = MCP.Partition lambda + mu' = MCP.Partition mu isSkewPartition :: Partition -> Partition -> Bool isSkewPartition lambda mu = - _isPartition lambda && _isPartition mu && all (>= 0) (zipWith (-) lambda mu)+ _isPartition lambda && _isPartition mu && all (>= 0) (zipWith (-) lambda mu) + +sprayToMap :: Spray a -> Map [Int] a +sprayToMap spray = + DM.fromList (HM.toList $ HM.mapKeys (DF.toList . exponents) spray) + +comboToSpray :: (Eq a, AlgRing.C a) => Map Partition a -> Spray a +comboToSpray combo = sumOfSprays + [ let part' = S.fromList part in HM.singleton (Powers part' (S.length part')) c + | (part, c) <- DM.toList combo ]
src/Math/Algebra/JackPol.hs view
@@ -130,7 +130,7 @@ schurPol' = schurPol -- | Symbolic Schur polynomial -schurPol :: forall a. (Ord a, AlgRing.C a) +schurPol :: forall a. (Eq a, AlgRing.C a) => Int -- ^ number of variables -> Partition -- ^ partition of integers -> Spray a @@ -186,7 +186,7 @@ skewSchurPol' = skewSchurPol -- | Symbolic skew Schur polynomial -skewSchurPol :: forall a. (Ord a, AlgRing.C a) +skewSchurPol :: forall a. (Eq a, AlgRing.C a) => Int -- ^ number of variables -> Partition -- ^ outer partition of the skew partition -> Partition -- ^ inner partition of the skew partition
src/Math/Algebra/SymmetricPolynomials.hs view
@@ -22,10 +22,21 @@ -- * Classical symmetric polynomials , msPolynomial , psPolynomial + , cshPolynomial + , esPolynomial -- * Decomposition of symmetric polynomials , msCombination , psCombination , psCombination' + , cshCombination + , cshCombination' + , esCombination + , esCombination' + , schurCombination + , schurCombination' + , jackCombination + , jackSymbolicCombination + , jackSymbolicCombination' -- * Printing symmetric polynomials , prettySymmetricNumSpray , prettySymmetricQSpray @@ -43,6 +54,9 @@ , symbolicHallInnerProduct , symbolicHallInnerProduct' , symbolicHallInnerProduct'' + -- * Kostka numbers + , kostkaNumbers + , symbolicKostkaNumbers ) where import Prelude hiding ( fromIntegral, fromRational ) import qualified Algebra.Additive as AlgAdd @@ -55,24 +69,30 @@ import qualified Data.HashMap.Strict as HM import Data.List ( foldl1', nub ) import Data.List.Extra ( unsnoc ) +import qualified Data.IntMap.Strict as IM +import Data.Map.Merge.Strict ( + merge + , dropMissing + , zipWithMatched + ) import Data.Map.Strict ( Map , unionsWith , insert ) import qualified Data.Map.Strict as DM -import Data.Maybe ( fromJust ) -import Data.Map.Merge.Strict ( - merge - , dropMissing - , zipWithMatched +import Data.Matrix ( + getRow ) +import Data.Maybe ( fromJust ) import Data.Ratio ( (%) ) import Data.Sequence ( Seq - , (|>) + , (|>) + , index ) import qualified Data.Sequence as S +import qualified Data.Vector as V import Data.Tuple.Extra ( second ) import Math.Algebra.Hspray ( FunctionLike (..) @@ -81,6 +101,7 @@ , Powers (..) , QSpray , QSpray' + , ParametricSpray , ParametricQSpray , lone , qlone @@ -91,26 +112,54 @@ , isConstant , (%//%) , RatioOfSprays (..) + , RatioOfQSprays + , constantRatioOfSprays + , zeroRatioOfSprays , prettyRatioOfQSpraysXYZ , showNumSpray , showQSpray , showQSpray' , showSpray - , toList , zeroSpray , unitSpray , productOfSprays + , sumOfSprays , constantSpray + , allExponents ) -import Math.Algebra.Jack.Internal ( Partition , _isPartition ) +import Math.Algebra.Jack.Internal ( + Partition + , _isPartition + , sprayToMap + , comboToSpray + , _inverseKostkaMatrix + , _kostkaNumbers + , _symbolicKostkaNumbers + , _inverseSymbolicKostkaMatrix + ) import Math.Combinat.Compositions ( compositions1 ) import Math.Combinat.Partitions.Integer ( fromPartition , mkPartition , partitions + , partitionWidth ) import Math.Combinat.Permutations ( permuteMultiset ) +import Math.Combinat.Tableaux.GelfandTsetlin ( kostkaNumbersWithGivenMu ) + +-- | monomial symmetric polynomial +msPolynomialUnsafe :: (AlgRing.C a, Eq a) + => Int -- ^ number of variables + -> Partition -- ^ integer partition + -> Spray a +msPolynomialUnsafe n lambda + = fromList $ zip permutations coefficients + where + llambda = length lambda + permutations = permuteMultiset (lambda ++ replicate (n-llambda) 0) + coefficients = repeat AlgRing.one + -- | Monomial symmetric polynomial -- -- >>> putStrLn $ prettySpray' (msPolynomial 3 [2, 1]) @@ -124,16 +173,15 @@ error "msPolynomial: negative number of variables." | not (_isPartition lambda) = error "msPolynomial: invalid partition." - | llambda > n = zeroSpray - | otherwise = fromList $ zip permutations coefficients - where - llambda = length lambda - permutations = permuteMultiset (lambda ++ replicate (n-llambda) 0) - coefficients = repeat AlgRing.one + | length lambda > n = zeroSpray + | otherwise = msPolynomialUnsafe n lambda --- | Checks whether a spray defines a symmetric polynomial; this is useless for --- Jack polynomials because they always are symmetric, but this module contains --- everything needed to build this function which can be useful in another context +-- | Checks whether a spray defines a symmetric polynomial. +-- +-- >>> -- note that the sum of two symmetric polynomials is not symmetric +-- >>> -- if they have different numbers of variables: +-- >>> spray = schurPol' 4 [2, 2] ^+^ schurPol' 3 [2, 1] +-- >>> isSymmetricSpray spray isSymmetricSpray :: (AlgRing.C a, Eq a) => Spray a -> Bool isSymmetricSpray spray = spray == spray' where @@ -144,15 +192,18 @@ map (\(lambda, x) -> x *^ msPolynomial n lambda) assocs ) --- | Symmetric polynomial as a linear combination of monomial symmetric polynomials +-- | Symmetric polynomial as a linear combination of monomial symmetric polynomials. msCombination :: AlgRing.C a => Spray a -> Map Partition a msCombination spray = DM.fromList (msCombination' spray) msCombination' :: AlgRing.C a => Spray a -> [(Partition, a)] msCombination' spray = - map (\lambda -> (lambda, getCoefficient lambda spray)) lambdas + map (\lambda -> let mu = DF.toList lambda in (mu, getCoefficient mu spray)) + lambdas where - lambdas = nub $ map (fromPartition . mkPartition . fst) (toList spray) + decreasing ys = + and [ys `index` i >= ys `index` (i+1) | i <- [0 .. S.length ys - 2]] + lambdas = filter decreasing (allExponents spray) -- helper function for the showing stuff makeMSpray :: (Eq a, AlgRing.C a) => Spray a -> Spray a @@ -255,61 +306,50 @@ error "psPolynomial: negative number of variables." | not (_isPartition lambda) = error "psPolynomial: invalid partition." - | null lambda' = unitSpray - | llambda > n = zeroSpray + | null lambda = unitSpray +-- | any (> n) lambda = zeroSpray +-- | llambda > n = zeroSpray | otherwise = productOfSprays sprays where - lambda' = fromPartition $ mkPartition lambda - llambda = length lambda' - sprays = [HM.fromList $ [f i k | i <- [1 .. n]] | k <- lambda'] + -- llambda = length lambda + sprays = [HM.fromList $ [f i k | i <- [1 .. n]] | k <- lambda] f j k = (Powers expts j, AlgRing.one) where expts = S.replicate (j-1) 0 |> k --- | monomial symmetric polynomial as a linear combination of --- power sum polynomials -mspInPSbasis :: Partition -> Map Partition Rational -mspInPSbasis kappa = DM.fromList (zipWith f weights lambdas) +eLambdaMu :: Partition -> Partition -> Rational +eLambdaMu lambda mu + | ellLambda < ellMu = 0 + | otherwise = if even (ellLambda - ellMu) + then sum xs + else - sum xs where - parts = map fromPartition (partitions (sum kappa)) - (weights, lambdas) = unzip $ filter ((/= 0) . fst) - [(eLambdaMu kappa lambda, lambda) | lambda <- parts] - f weight lambda = - (lambda, weight / toRational (zlambda lambda)) - ---- - eLambdaMu :: Partition -> Partition -> Rational - eLambdaMu lambda mu - | ellLambda < ellMu = 0 - | otherwise = if even (ellLambda - ellMu) - then sum xs - else - sum xs - where - ellLambda = length lambda - ellMu = length mu - compos = compositions1 ellMu ellLambda - lambdaPerms = permuteMultiset lambda - sequencesOfPartitions = filter (not . null) - [partitionSequences perm mu compo - | perm <- lambdaPerms, compo <- compos] - xs = [eMuNus mu nus | nus <- sequencesOfPartitions] + ellLambda = length lambda + ellMu = length mu + compos = compositions1 ellMu ellLambda + lambdaPerms = permuteMultiset lambda + sequencesOfPartitions = filter (not . null) + [partitionSequences perm compo + | perm <- lambdaPerms, compo <- compos] + xs = [eMuNus nus | nus <- sequencesOfPartitions] ---- - partitionSequences :: [Int] -> Partition -> [Int] -> [Partition] - partitionSequences lambda mu compo = if test then nus else [] + partitionSequences :: [Int] -> [Int] -> [Partition] + partitionSequences kappa compo = if test then nus else [] where headOfCompo = fst $ fromJust (unsnoc compo) starts = scanl (+) 0 headOfCompo ends = zipWith (+) starts compo nus = [ - [ lambda !! k | k <- [starts !! i .. ends !! i - 1] ] + [ kappa !! k | k <- [starts !! i .. ends !! i - 1] ] | i <- [0 .. length compo - 1] ] nuWeights = [sum nu | nu <- nus] - decreasing xs = - and [xs !! i >= xs !! (i+1) | i <- [0 .. length xs - 2]] + decreasing ys = + and [ys !! i >= ys !! (i+1) | i <- [0 .. length ys - 2]] test = and (zipWith (==) mu nuWeights) && all decreasing nus ---- - eMuNus :: Partition -> [Partition] -> Rational - eMuNus mu nus = product toMultiply + eMuNus :: [Partition] -> Rational + eMuNus nus = product toMultiply where w :: Int -> Partition -> Rational w k nu = @@ -319,6 +359,58 @@ factorial n = product [2 .. n] toMultiply = zipWith w mu nus +-- | monomial symmetric polynomial as a linear combination of +-- power sum polynomials +mspInPSbasis :: Partition -> Map Partition Rational +mspInPSbasis kappa = DM.fromList (zipWith f weights lambdas) + where + parts = partitions (sum kappa) + (weights, lambdas) = unzip $ filter ((/= 0) . fst) + [let lambda = fromPartition part in (eLambdaMu kappa lambda, lambda) | part <- parts] + f weight lambda = + (lambda, weight / toRational (zlambda lambda)) + +-- mspInPSbasis :: Partition -> Map Partition Rational +-- mspInPSbasis mu = +-- maps (1 + (fromJust $ elemIndex mu lambdas)) +-- where +-- weight = sum mu +-- lambdas = map fromPartition (partitions weight) +-- msCombo lambda = msCombination (psPolynomial 3 lambda) +-- row lambda = map (flip (DM.findWithDefault 0) (msCombo lambda)) lambdas +-- kostkaMatrix = fromLists (map row lambdas) +-- matrix = case inverse kostkaMatrix of +-- Left _ -> error "mspInJackBasis: should not happen:" +-- Right m -> m +-- maps i = DM.fromList (zip lambdas (filter (/= 0) $ V.toList (getRow i matrix))) + +-- km :: Int -> Partition -> (Matrix Rational, Maybe (Matrix Rational)) +-- km n mu = +-- (kostkaMatrix, matrix) +-- where +-- weight = sum mu +-- lambdas = map fromPartition (partitions weight) +-- msCombo lambda = msCombination (psPolynomial n lambda) +-- row lambda = map (flip (DM.findWithDefault 0) (msCombo lambda)) lambdas +-- kostkaMatrix = fromLists (map row lambdas) +-- matrix = case inverse kostkaMatrix of +-- Left _ -> Nothing +-- Right m -> Just m + +-- mspInPSbasis' :: Int -> Partition -> Map Partition Rational +-- mspInPSbasis' n mu = +-- DM.filter (/= 0) (maps (1 + (fromJust $ elemIndex mu lambdas))) +-- where +-- weight = sum mu +-- lambdas = filter (\lambda -> length lambda <= n) (map fromPartition (partitions weight)) +-- msCombo lambda = msCombination (psPolynomial n lambda) +-- row lambda = map (flip (DM.findWithDefault 0) (msCombo lambda)) lambdas +-- kostkaMatrix = fromLists (map row lambdas) +-- matrix = case inverse kostkaMatrix of +-- Left _ -> error "mspInJackBasis: should not happen:" +-- Right m -> m +-- maps i = DM.fromList (zip lambdas (V.toList (getRow i matrix))) + -- | the factor in the Hall inner product zlambda :: Partition -> Int zlambda lambda = p @@ -329,24 +421,53 @@ product [factorial mj * part^mj | (part, mj) <- zip parts table] factorial n = product [2 .. n] --- | symmetric polynomial as a linear combination of power sum polynomials -_psCombination :: - forall a. (Eq a, AlgRing.C a) => (a -> Rational -> a) -> Spray a -> Map Partition a -_psCombination func spray = +_symmPolyCombination :: + forall a b. (Eq a, AlgRing.C a) + => (Partition -> Map Partition b) + -> (a -> b -> a) + -> Spray a + -> Map Partition a +_symmPolyCombination mspInSymmPolyBasis func spray = if constantTerm == AlgAdd.zero - then psMap - else insert [] constantTerm psMap + then symmPolyMap + else insert [] constantTerm symmPolyMap where constantTerm = getConstantTerm spray - assocs = msCombination' (spray <+ (AlgAdd.negate constantTerm)) + assocs = msCombination' (spray <+ (AlgAdd.negate constantTerm)) :: [(Partition, a)] f :: (Partition, a) -> [(Partition, a)] f (lambda, coeff) = - map (second (func coeff)) (DM.toList psCombo) + map (second (func coeff)) (DM.toList symmPolyCombo) where - psCombo = mspInPSbasis lambda :: Map Partition Rational - psMap = DM.filter (/= AlgAdd.zero) + symmPolyCombo = mspInSymmPolyBasis lambda :: Map Partition b + symmPolyMap = DM.filter (/= AlgAdd.zero) (unionsWith (AlgAdd.+) (map (DM.fromList . f) assocs)) +-- _symmPolyCombination' :: +-- forall a. (Eq a, AlgRing.C a) +-- => (Partition -> Map Partition Rational) +-- -> (a -> Rational -> a) +-- -> Spray a +-- -> Map Partition a +-- _symmPolyCombination' mspInSymmPolyBasis func spray = +-- if constantTerm == AlgAdd.zero +-- then symmPolyMap +-- else insert [] constantTerm symmPolyMap +-- where +-- constantTerm = getConstantTerm spray +-- assocs = msCombination' (spray <+ (AlgAdd.negate constantTerm)) +-- f :: (Partition, a) -> [(Partition, a)] +-- f (lambda, coeff) = +-- map (second (func coeff)) (DM.toList symmPolyCombo) +-- where +-- symmPolyCombo = mspInSymmPolyBasis lambda :: Map Partition Rational +-- symmPolyMap = DM.filter (/= AlgAdd.zero) +-- (unionsWith (AlgAdd.+) (map (DM.fromList . f) assocs)) + +-- | symmetric polynomial as a linear combination of power sum polynomials +_psCombination :: + forall a. (Eq a, AlgRing.C a) => (a -> Rational -> a) -> Spray a -> Map Partition a +_psCombination = _symmPolyCombination mspInPSbasis + -- | Symmetric polynomial as a linear combination of power sum polynomials. -- Symmetry is not checked. psCombination :: @@ -383,8 +504,8 @@ f lambda coeff1 coeff2 = multabFunc (zlambda' lambda) (coeff1 AlgRing.* coeff2) --- | Hall inner product with parameter. It makes sense only for symmetric sprays, --- and the symmetry is not checked. +-- | Hall inner product with parameter, aka Jack-scalar product. It makes sense +-- only for symmetric sprays, and the symmetry is not checked. hallInnerProduct :: forall a. (Eq a, AlgField.C a) => Spray a -- ^ spray @@ -492,6 +613,303 @@ qspray1' = HM.map constantSpray (asQSpray spray1) qspray2' = HM.map constantSpray (asQSpray spray2) +-- | Complete symmetric homogeneous polynomial +-- +-- >>> putStrLn $ prettyQSpray (cshPolynomial 3 [2, 1]) +-- x^3 + 2*x^2.y + 2*x^2.z + 2*x.y^2 + 3*x.y.z + 2*x.z^2 + y^3 + 2*y^2.z + 2*y.z^2 + z^3 +cshPolynomial :: (AlgRing.C a, Eq a) + => Int -- ^ number of variables + -> Partition -- ^ integer partition + -> Spray a +cshPolynomial n lambda + | n < 0 = + error "cshPolynomial: negative number of variables." + | not (_isPartition lambda) = + error "cshPolynomial: invalid partition." + | null lambda = unitSpray +-- | llambda > n = zeroSpray + | otherwise = productOfSprays (map cshPolynomialK lambda) + where + -- llambda = length lambda + cshPolynomialK k = sumOfSprays msSprays + where + parts = partitions k + msSprays = + [msPolynomialUnsafe n (fromPartition part) | part <- parts, partitionWidth part <= n] + +-- | power sum polynomial as a linear combination of +-- complete symmetric homogeneous polynomials +pspInCSHbasis :: Partition -> Map Partition Rational +pspInCSHbasis mu = DM.fromList (zipWith f weights lambdas) + where + parts = partitions (sum mu) + assoc kappa = + let kappa' = fromPartition kappa in (eLambdaMu kappa' mu, kappa') + (weights, lambdas) = unzip $ filter ((/= 0) . fst) (map assoc parts) + f weight lambda = (lambda, weight) + +-- | monomial symmetric polynomial as a linear combination of +-- complete symmetric homogeneous polynomials +mspInCSHbasis :: Partition -> Map Partition Rational +mspInCSHbasis mu = sprayToMap (sumOfSprays sprays) + where + psAssocs = DM.toList (mspInPSbasis mu) + sprays = + [c *^ comboToSpray (pspInCSHbasis lambda) | (lambda, c) <- psAssocs] + +-- | symmetric polynomial as a linear combination of +-- complete symmetric homogeneous polynomials +_cshCombination :: + forall a. (Eq a, AlgRing.C a) + => (a -> Rational -> a) -> Spray a -> Map Partition a +_cshCombination = _symmPolyCombination mspInCSHbasis + +-- | Symmetric polynomial as a linear combination of complete symmetric +-- homogeneous polynomials. Symmetry is not checked. +cshCombination :: + forall a. (Eq a, AlgField.C a) => Spray a -> Map Partition a +cshCombination = + _cshCombination (\coef r -> coef AlgRing.* fromRational r) + +-- | Symmetric polynomial as a linear combination of complete symmetric homogeneous polynomials. +-- Same as @cshCombination@ but with other constraints on the base ring of the spray. +cshCombination' :: + forall a. (Eq a, AlgMod.C Rational a, AlgRing.C a) + => Spray a -> Map Partition a +cshCombination' = _cshCombination (flip (AlgMod.*>)) + +-- | Elementary symmetric polynomial. +-- +-- >>> putStrLn $ prettyQSpray (esPolynomial 3 [2, 1]) +-- x^2.y + x^2.z + x.y^2 + 3*x.y.z + x.z^2 + y^2.z + y.z^2 +esPolynomial :: (AlgRing.C a, Eq a) + => Int -- ^ number of variables + -> Partition -- ^ integer partition + -> Spray a +esPolynomial n lambda + | n < 0 = + error "esPolynomial: negative number of variables." + | not (_isPartition lambda) = + error "esPolynomial: invalid partition." + | null lambda = unitSpray + | l > n || any (>n) lambda = zeroSpray + | otherwise = productOfSprays (map esPolynomialK lambda) + where + l = length lambda + esPolynomialK k = msPolynomialUnsafe n (replicate k 1) + +-- | power sum polynomial as a linear combination of +-- elementary symmetric polynomials +pspInESbasis :: Partition -> Map Partition Rational +pspInESbasis mu = DM.fromList (zipWith f weights lambdas) + where + wmu = sum mu + parts = partitions wmu + e = wmu - length mu + e_is_even = even e + negateIf = if e_is_even then id else negate + pair kappa = (negateIf (eLambdaMu kappa mu), kappa) + (weights, lambdas) = unzip $ filter ((/= 0) . fst) + [let lambda = fromPartition part in pair lambda | part <- parts] + f weight lambda = (lambda, weight) + +-- | monomial symmetric polynomial as a linear combination of +-- elementary symmetric polynomials +mspInESbasis :: Partition -> Map Partition Rational +mspInESbasis mu = sprayToMap (sumOfSprays sprays) + where + psAssocs = DM.toList (mspInPSbasis mu) + sprays = + [c *^ comboToSpray (pspInESbasis lambda) | (lambda, c) <- psAssocs] + +-- | symmetric polynomial as a linear combination of +-- elementary symmetric polynomials +_esCombination :: + forall a. (Eq a, AlgRing.C a) + => (a -> Rational -> a) -> Spray a -> Map Partition a +_esCombination = _symmPolyCombination mspInESbasis + +-- | Symmetric polynomial as a linear combination of elementary symmetric polynomials. +-- Symmetry is not checked. +esCombination :: + forall a. (Eq a, AlgField.C a) => Spray a -> Map Partition a +esCombination = + _esCombination (\coef r -> coef AlgRing.* fromRational r) + +-- | Symmetric polynomial as a linear combination of elementary symmetric polynomials. +-- Same as @esCombination@ but with other constraints on the base ring of the spray. +esCombination' :: + forall a. (Eq a, AlgMod.C Rational a, AlgRing.C a) + => Spray a -> Map Partition a +esCombination' = _esCombination (flip (AlgMod.*>)) + +-- | complete symmetric homogeneous polynomial as a linear combination of +-- Schur polynomials +cshInSchurBasis :: Int -> Partition -> Map Partition Rational +cshInSchurBasis n mu = + DM.filterWithKey (\k _ -> length k <= n) + (DM.mapKeys fromPartition kNumbers) + where + kNumbers = DM.map toRational (kostkaNumbersWithGivenMu (mkPartition mu)) + +-- | symmetric polynomial as a linear combination of Schur polynomials +_schurCombination :: + forall a. (Eq a, AlgRing.C a) + => (a -> Rational -> a) -> Spray a -> Map Partition a +_schurCombination func spray = + if constantTerm == AlgAdd.zero + then schurMap + else insert [] constantTerm schurMap + where + constantTerm = getConstantTerm spray + assocs = + DM.toList $ _cshCombination func (spray <+ (AlgAdd.negate constantTerm)) + f :: (Partition, a) -> [(Partition, a)] + f (lambda, coeff) = + map (second (func coeff)) (DM.toList schurCombo) + where + schurCombo = cshInSchurBasis (numberOfVariables spray) lambda + schurMap = DM.filter (/= AlgAdd.zero) + (unionsWith (AlgAdd.+) (map (DM.fromList . f) assocs)) + +-- | Symmetric polynomial as a linear combination of Schur polynomials. +-- Symmetry is not checked. +schurCombination :: + forall a. (Eq a, AlgField.C a) => Spray a -> Map Partition a +schurCombination = + _schurCombination (\coef r -> coef AlgRing.* fromRational r) + +-- | Symmetric polynomial as a linear combination of Schur polynomials. +-- Same as @schurCombination@ but with other constraints on the base ring of the spray. +schurCombination' :: + forall a. (Eq a, AlgMod.C Rational a, AlgRing.C a) + => Spray a -> Map Partition a +schurCombination' = _schurCombination (flip (AlgMod.*>)) + +-- | Kostka numbers \(K_{\lambda,\mu}(\alpha)\) for a given weight of the +-- partitions \(\lambda\) and \(\mu\) and a given parameter +-- \(\alpha\) (these are the standard Kostka numbers when +-- \(\alpha=1\)). This returns a map whose keys represent the +-- partitions \(\lambda\) and the value attached to a partition \(\lambda\) +-- represents the map \(\mu \mapsto K_{\lambda,\mu}(\alpha)\) where the +-- partition \(\mu\) is included in the keys of this map if and only if +-- \(K_{\lambda,\mu}(\alpha) \neq 0\). +kostkaNumbers :: + Int -- ^ weight of the partitions + -> Rational -- Jack parameter + -> Map Partition (Map Partition Rational) +kostkaNumbers weight alpha = _kostkaNumbers weight weight alpha 'P' + +-- | Kostka numbers \(K_{\lambda,\mu}(\alpha)\) with symbolic parameter \(\alpha\) +-- for a given weight of the partitions \(\lambda\) and \(\mu\). This returns a map +-- whose keys represent the +-- partitions \(\lambda\) and the value attached to a partition \(\lambda\) +-- represents the map \(\mu \mapsto K_{\lambda,\mu}(\alpha)\) where the +-- partition \(\mu\) is included in the keys of this map if and only if +-- \(K_{\lambda,\mu}(\alpha) \neq 0\). +symbolicKostkaNumbers :: Int -> Map Partition (Map Partition RatioOfQSprays) +symbolicKostkaNumbers weight = _symbolicKostkaNumbers weight weight 'P' + +-- | monomial symmetric polynomials in Jack polynomials basis +msPolynomialsInJackBasis :: + forall a. (Eq a, AlgField.C a) + => a -> Char -> Int -> Int -> Map Partition (Map Partition a) +msPolynomialsInJackBasis alpha which n weight = + DM.fromDistinctDescList (zip lambdas [maps i | i <- [1 .. length lambdas]]) + where + (matrix, lambdas) = _inverseKostkaMatrix n weight alpha which + maps i = DM.filter (/= AlgAdd.zero) + (DM.fromDistinctDescList (zip lambdas (V.toList (getRow i matrix)))) + +-- | monomial symmetric polynomials in Jack polynomials basis +msPolynomialsInJackSymbolicBasis :: + (Eq a, AlgField.C a) + => Char -> Int -> Int -> Map Partition (Map Partition (RatioOfSprays a)) +msPolynomialsInJackSymbolicBasis which n weight = + DM.fromDistinctDescList (zip lambdas [maps i | i <- [1 .. length lambdas]]) + where + (matrix, lambdas) = _inverseSymbolicKostkaMatrix n weight which + maps i = DM.filter (/= zeroRatioOfSprays) + (DM.fromDistinctDescList (zip lambdas (V.toList (getRow i matrix)))) + +-- | Symmetric polynomial as a linear combination of Jack polynomials with a +-- given Jack parameter. Symmetry is not checked. +jackCombination :: + (Eq a, AlgField.C a) + => a -- ^ Jack parameter + -> Char -- ^ which Jack polynomials, @'J'@, @'C'@, @'P'@ or @'Q'@ + -> Spray a -- ^ spray representing a symmetric polynomial + -> Map Partition a -- ^ map representing the linear combination; a partition @lambda@ in the keys of this map corresponds to the term @coeff *^ jackPol' n lambda alpha which@, where @coeff@ is the value attached to this key and @n@ is the number of variables of the spray +jackCombination alpha which spray = + _symmPolyCombination + (\lambda -> (combos IM.! (sum lambda)) DM.! lambda) + (AlgRing.*) spray + where + weights = filter (/= 0) (map DF.sum (allExponents spray)) + n = numberOfVariables spray + combos = + IM.fromList + (zip weights (map (msPolynomialsInJackBasis alpha which n) weights)) + +-- | Symmetric polynomial as a linear combination of Jack polynomials with +-- symbolic parameter. Symmetry is not checked. +jackSymbolicCombination :: + Char -- ^ which Jack polynomials, @'J'@, @'C'@, @'P'@ or @'Q'@ + -> QSpray -- ^ spray representing a symmetric polynomial + -> Map Partition RatioOfQSprays -- ^ map representing the linear combination; a partition @lambda@ in the keys of this map corresponds to the term @coeff *^ jackSymbolicPol' n lambda which@, where @coeff@ is the value attached to this key and @n@ is the number of variables of the spray +jackSymbolicCombination which qspray = + _symmPolyCombination + (\lambda -> (combos IM.! (sum lambda)) DM.! lambda) + (AlgRing.*) (HM.map constantRatioOfSprays qspray) + where + weights = filter (/= 0) (map DF.sum (allExponents qspray)) + n = numberOfVariables qspray + combos = + IM.fromList + (zip weights (map (msPolynomialsInJackSymbolicBasis which n) weights)) + +-- | Symmetric parametric polynomial as a linear combination of Jack polynomials +-- with symbolic parameter. +-- Similar to @jackSymbolicCombination@ but for a parametric spray. +jackSymbolicCombination' :: + (Eq a, AlgField.C a) + => Char -- ^ which Jack polynomials, @'J'@, @'C'@, @'P'@ or @'Q'@ + -> ParametricSpray a -- ^ parametric spray representing a symmetric polynomial + -> Map Partition (RatioOfSprays a) -- ^ map representing the linear combination; a partition @lambda@ in the keys of this map corresponds to the term @coeff *^ jackSymbolicPol' n lambda which@, where @coeff@ is the value attached to this key and @n@ is the number of variables of the spray +jackSymbolicCombination' which spray = + _symmPolyCombination + (\lambda -> (combos IM.! (sum lambda)) DM.! lambda) + (AlgRing.*) spray + where + weights = filter (/= 0) (map DF.sum (allExponents spray)) + n = numberOfVariables spray + combos = + IM.fromList + (zip weights (map (msPolynomialsInJackSymbolicBasis which n) weights)) + + +-- test :: Bool +-- test = poly == sumOfSprays sprays +-- where +-- which = 'J' +-- alpha = 4 +-- mu = [3, 1, 1] +-- poly = msPolynomial 5 mu ^+^ psPolynomial 5 mu ^+^ cshPolynomial 5 mu ^+^ esPolynomial 5 mu :: QSpray +-- sprays = [c *^ jackPol' 5 lambda alpha which | (lambda, c) <- DM.toList (jackCombination which alpha poly)] + +-- test :: Bool +-- test = psp == sumOfSprays esps +-- where +-- mu = [3, 2, 1, 1] +-- psp = psPolynomial 7 mu :: QSpray +-- esps = [c *^ esPolynomial 7 lambda | (lambda, c) <- DM.toList (pspInESbasis mu)] + +-- test :: Bool +-- test = poly == sumOfSprays ess +-- where +-- mu = [3, 1, 1] +-- poly = msPolynomial 5 mu ^+^ psPolynomial 5 mu ^+^ cshPolynomial 5 mu ^+^ esPolynomial 5 mu :: QSpray +-- ess = [c *^ esPolynomial 5 lambda | (lambda, c) <- DM.toList (esCombination poly)] -- test'' :: (String, String) -- test'' = (prettyParametricQSpray result, prettyParametricQSprayABCXYZ ["a"] ["b"] $ result)
tests/Main.hs view
@@ -1,22 +1,30 @@ module Main ( main ) where +import qualified Algebra.Module as AlgMod import qualified Data.Map.Strict as DM import Data.Ratio ( (%) ) import Math.Algebra.Hspray ( FunctionLike (..) , Spray, QSpray , lone, qlone + , unitSpray , evalSpray , evalParametricSpray' , substituteParameters , canCoerceToSimpleParametricSpray , isHomogeneousSpray , asRatioOfSprays + , constantRatioOfSprays , (%//%) , (/^) + , sumOfSprays ) import qualified Math.Algebra.Hspray as Hspray import Math.Algebra.Jack ( schur, skewSchur - , jack', zonal' ) + , jack', zonal' + , Partition ) import Math.Algebra.Jack.HypergeoPQ ( hypergeoPQ ) +import Math.Algebra.JackPol ( zonalPol, zonalPol', jackPol' + , schurPol, schurPol', skewSchurPol' ) +import Math.Algebra.JackSymbolicPol ( jackSymbolicPol' ) import Math.Algebra.SymmetricPolynomials ( isSymmetricSpray , prettySymmetricParametricQSpray , laplaceBeltrami @@ -25,14 +33,30 @@ , hallInnerProduct'' , symbolicHallInnerProduct , symbolicHallInnerProduct'' + , msPolynomial , psPolynomial , psCombination + , cshPolynomial + , cshCombination + , esPolynomial + , esCombination + , schurCombination + , jackCombination + , jackSymbolicCombination + , jackSymbolicCombination' + , kostkaNumbers + , symbolicKostkaNumbers ) -import Math.Algebra.JackPol ( zonalPol, zonalPol', jackPol' - , schurPol, schurPol', skewSchurPol' ) -import Math.Algebra.JackSymbolicPol ( jackSymbolicPol' ) -import Math.Combinat.Classes ( HasDuality (..) ) -import Math.Combinat.Partitions.Integer ( toPartition, fromPartition ) +import Math.Combinat.Partitions.Integer ( + toPartition + , fromPartition + , mkPartition + , partitions + , dualPartition + ) +import qualified Math.Combinat.Partitions.Integer as PI +import Math.Combinat.Tableaux.GelfandTsetlin ( kostkaNumber ) +import qualified Math.Combinat.Tableaux.GelfandTsetlin as GT import Math.HypergeoMatrix ( hypergeomat ) import Test.Tasty ( defaultMain , testGroup @@ -42,6 +66,24 @@ , testCase ) +b_lambda_mu :: [Int] -> [Int] -> Int +b_lambda_mu lambda mu = sum $ DM.elems wholeMap -- zipWith (*) k1 k2 + where + parts = partitions (sum lambda) + zeros = DM.fromList (zip parts (repeat 0)) + map1 = DM.union (GT.kostkaNumbersWithGivenMu (mkPartition lambda)) zeros + map2 = DM.union (GT.kostkaNumbersWithGivenMu (mkPartition mu)) zeros + wholeMap = DM.unionWithKey (\part kn1 _ -> kn1 * (map2 DM.! (dualPartition part))) map1 map2 + -- k1 = map ((flip kostkaNumber) (mkPartition lambda)) parts + -- k2 = map (((flip kostkaNumber) (mkPartition mu)) . dualPartition) parts + +a_lambda_mu :: [Int] -> [Int] -> Int +a_lambda_mu lambda mu = sum $ zipWith (*) k1 k2 + where + parts = partitions (sum lambda) + k1 = map ((flip kostkaNumber) (mkPartition lambda)) parts + k2 = map ((flip kostkaNumber) (mkPartition mu)) parts + main :: IO () main = defaultMain $ testGroup @@ -107,7 +149,7 @@ b mu = toRational $ sum $ zipWith (*) mu [0 .. ] eigenvalue :: Int -> Rational -> [Int] -> Rational eigenvalue n a mu = - let mu' = fromPartition $ dual (toPartition mu) in + let mu' = fromPartition $ dualPartition (toPartition mu) in a * b mu' - b mu + toRational ((n-1) * sum mu) ev = eigenvalue 4 alpha lambda jp = jackPol' 4 lambda alpha 'J' @@ -222,6 +264,33 @@ , 24 * pow alpha 4 ) + , testCase "Hall inner product of Jack P-polynomial and Jack Q-polynomial" $ do + let + jp1 = jackPol' 7 [4, 2, 1] 3 'P' + jp2 = jackPol' 7 [4, 2, 1] 3 'Q' + h = hallInnerProduct jp1 jp2 3 + assertEqual "" h 1 + + , testCase "Hall inner product and b_lambda_mu" $ do + let + lambda = [4, 2, 1, 1] + mu = [2, 2, 2, 2] + h = cshPolynomial 8 lambda :: QSpray + e = esPolynomial 8 mu :: QSpray + assertEqual "" + (hallInnerProduct h e 1) + (toRational $ b_lambda_mu lambda mu) + + , testCase "Hall inner product and a_lambda_mu" $ do + let + lambda = [4, 2, 2, 1] + mu = [5, 4] + hlambda = cshPolynomial 9 lambda :: QSpray + hmu = cshPolynomial 9 mu :: QSpray + assertEqual "" + (hallInnerProduct hlambda hmu 1) + (toRational $ a_lambda_mu lambda mu) + , testCase "Hall inner product of Schur polynomials" $ do let sp1 = schurPol 7 [4, 2, 1] :: Spray Int @@ -231,6 +300,31 @@ h12 = hallInnerProduct'' sp1 sp2 1 assertEqual "" (h1, h2, h12) (1, 1, 0) + , testCase "Hall inner product with 'degenerate' symmetric polynomials" $ do + let + sp1 = schurPol' 3 [3,1] + sp2 = schurPol' 3 [2,2] + h1 = hallInnerProduct sp1 sp1 1 + h2 = hallInnerProduct sp2 sp2 1 + h12 = hallInnerProduct sp1 sp2 1 + assertEqual "" (h1, h2, h12) (10, 5, 6) + + , testCase "Symbolic Hall inner product with 'degenerate' symmetric polynomials" $ do + let + sp1 = schurPol' 3 [3,1] + sp2 = schurPol' 3 [2,2] + h1 = symbolicHallInnerProduct sp1 sp1 + h2 = symbolicHallInnerProduct sp2 sp2 + h12 = symbolicHallInnerProduct sp1 sp2 + alpha = qlone 1 + assertEqual "" + (h1, h2, h12) + ( + 4*^alpha^**^3 ^+^ 5*^alpha^**^2 ^+^ alpha + , alpha^**^3 ^+^ 3*^alpha^**^2 ^+^ alpha + , 2*^alpha^**^3 ^+^ 3*^alpha^**^2 ^+^ alpha + ) + , testCase "Symbolic Hall inner product" $ do let poly1 = psPolynomial 4 [4] :: QSpray @@ -290,5 +384,159 @@ ( DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] ) + + , testCase "Complete symmetric homogeneous combination" $ do + let + cshPoly = 3*^cshPolynomial 4 [2, 1, 1] ^-^ cshPolynomial 4 [2, 1] :: QSpray + cshCombo = cshCombination cshPoly + assertEqual "" + cshCombo + ( + DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] + ) + + , testCase "Elementary symmetric polynomials combination" $ do + let + esPoly = 3*^esPolynomial 4 [2, 1, 1] ^-^ esPolynomial 4 [2, 1] :: QSpray + esCombo = esCombination esPoly + assertEqual "" + esCombo + ( + DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] + ) + + , testCase "Schur polynomials combination" $ do + let + poly = 3*^schurPol' 4 [2, 1, 1] ^-^ schurPol' 4 [2, 1] + combo = schurCombination poly + assertEqual "" + combo + ( + DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] + ) + + , testCase "Schur polynomials combination of 'degenerate' symmetric polynomial" $ do + let + poly = psPolynomial 3 [4] :: QSpray + schurCombo = schurCombination poly + jackCombo = jackCombination 1 'P' poly + expected = DM.fromList [([2, 1, 1], 1), ([3, 1], -1), ([4], 1)] + assertEqual "" + (schurCombo, jackCombo) + (expected, expected) + + , testCase "Schur polynomials combination of a parametric spray" $ do + let + jpol = jackSymbolicPol' 4 [2, 2] 'J' + schurCombo = schurCombination jpol + alpha = qlone 1 + expected = [ + ([1, 1, 1, 1], asRatioOfSprays ((2*^alpha^**^2 ^-^ 6*^alpha) <+ 4) ) + , ([2, 1, 1], asRatioOfSprays (((-2)*^alpha^**^2 ^-^ 2*^alpha) <+ 4)) + , ([2, 2], asRatioOfSprays ((2*^alpha^**^2 ^+^ 6*^alpha) <+ 4) ) + ] + jpol' = sumOfSprays $ map (\(lambda, c) -> c *^ schurPol 4 lambda) expected + assertEqual "" + (schurCombo, jpol) + ( + DM.fromList expected + , jpol' + ) + + , testCase "Jack J-polynomials combination" $ do + let + alpha = 3 + which = 'J' + poly = 3*^jackPol' 4 [2, 1, 1] alpha which ^-^ jackPol' 4 [2, 1] alpha which + combo = jackCombination alpha which poly + assertEqual "" + combo + ( + DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] + ) + + , testCase "Jack C-polynomials combination" $ do + let + alpha = 7 + which = 'C' + poly = 3*^jackPol' 4 [2, 1, 1] alpha which ^-^ jackPol' 4 [2, 1] alpha which + combo = jackCombination alpha which poly + assertEqual "" + combo + ( + DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] + ) + + , testCase "Jack Q-polynomials combination" $ do + let + which = 'Q' + alpha = 4 + p = msPolynomial 5 [3, 1, 1] ^+^ psPolynomial 5 [3, 1] ^+^ + cshPolynomial 5 [2, 1] ^+^ esPolynomial 5 [2] ^+^ unitSpray :: QSpray + sprays = [ + c *^ jackPol' 5 lambda alpha which + | (lambda, c) <- DM.toList (jackCombination alpha which p) + ] + assertEqual "" + p (sumOfSprays sprays) + + , testCase "jackSymbolicCombination" $ do + let + alpha = 3 + which = 'J' + poly = 3*^jackPol' 4 [2, 1, 1] alpha which ^-^ jackPol' 4 [2, 1] alpha which + combo = jackSymbolicCombination which poly + combo' = DM.filter (/= 0) (DM.map (evaluateAt [alpha]) combo) + assertEqual "" + combo' + ( + DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] + ) + + , testCase "jackSymbolicCombination - 2" $ do + let + which = 'Q' + p = 4 *^ msPolynomial 5 [3, 1, 1] ^+^ psPolynomial 5 [3, 1] ^-^ + 5 *^ cshPolynomial 5 [2, 1] ^+^ unitSpray :: QSpray + alpha = 7 + sprays = [ + (evaluateAt [alpha] c) *^ jackPol' 5 lambda alpha which + | (lambda, c) <- DM.toList (jackSymbolicCombination which p) + ] + assertEqual "" + p (sumOfSprays sprays) + + , testCase "jackSymbolicCombination' (ParametricQSpray)" $ do + let + n = 4 + which = 'J' + qspray = 7 *^ qlone 1 + poly = (3::Rational) AlgMod.*> jackSymbolicPol' n [2, 1, 1] which + ^+^ qspray AlgMod.*> jackSymbolicPol' n [2, 1] which + combo = jackSymbolicCombination' which poly + lambdas = DM.keys combo + coeffs = DM.elems combo + assertEqual "" + (lambdas, coeffs) + ( + [[2, 1], [2, 1, 1]] + , [asRatioOfSprays qspray, constantRatioOfSprays 3] + ) + + , testCase "Kostka numbers" $ do + let + lambda = [4, 3, 1] + kn1 = (kostkaNumbers (sum lambda) 1) DM.! lambda + kn2 = DM.mapKeys fromPartition + (GT.kostkaNumbersWithGivenLambda (mkPartition lambda) :: DM.Map PI.Partition Rational) + assertEqual "" kn1 kn2 + + , testCase "Symbolic Kostka numbers" $ do + let + lambda = [4, 3, 1] + kn1 = DM.map (evaluateAt [1]) (symbolicKostkaNumbers (sum lambda) DM.! lambda) :: DM.Map Partition Rational + kn2 = DM.mapKeys fromPartition + (GT.kostkaNumbersWithGivenLambda (mkPartition lambda) :: DM.Map PI.Partition Rational) + assertEqual "" kn1 kn2 ]