packages feed

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 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
 
   ]