jackpolynomials 1.4.0.0 → 1.4.1.0
raw patch · 9 files changed
+713/−208 lines, 9 filesdep +extradep +unordered-containersPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: extra, unordered-containers
API changes (from Hackage documentation)
- Math.Algebra.Jack.SymmetricPolynomials: calogeroSutherland :: (Eq a, C a) => a -> Spray a -> Spray a
- Math.Algebra.Jack.SymmetricPolynomials: isSymmetricSpray :: (C a, Eq a) => Spray a -> Bool
- Math.Algebra.Jack.SymmetricPolynomials: laplaceBeltrami :: (Eq a, C a) => a -> Spray a -> Spray a
- Math.Algebra.Jack.SymmetricPolynomials: msCombination :: C a => Spray a -> Map Partition a
- Math.Algebra.Jack.SymmetricPolynomials: msPolynomial :: (C a, Eq a) => Int -> Partition -> Spray a
- Math.Algebra.Jack.SymmetricPolynomials: prettySymmetricNumSpray :: (Num a, Ord a, Show a, C a) => Spray a -> String
- Math.Algebra.Jack.SymmetricPolynomials: prettySymmetricParametricQSpray :: [String] -> ParametricQSpray -> String
- Math.Algebra.Jack.SymmetricPolynomials: prettySymmetricQSpray :: QSpray -> String
- Math.Algebra.Jack.SymmetricPolynomials: prettySymmetricQSpray' :: QSpray' -> String
+ Math.Algebra.Jack: type Partition = [Int]
+ Math.Algebra.SymmetricPolynomials: calogeroSutherland :: (Eq a, C a) => a -> Spray a -> Spray a
+ Math.Algebra.SymmetricPolynomials: hallInnerProduct :: forall a. (Eq a, C a) => Spray a -> Spray a -> a -> a
+ Math.Algebra.SymmetricPolynomials: hallInnerProduct' :: forall a. (Eq a, C Rational a, C a) => Spray a -> Spray a -> a -> a
+ Math.Algebra.SymmetricPolynomials: hallInnerProduct'' :: forall a. Real a => Spray a -> Spray a -> a -> Rational
+ Math.Algebra.SymmetricPolynomials: hallInnerProduct''' :: forall b. (Eq b, C b, C (BaseRing b) b) => Spray b -> Spray b -> BaseRing b -> b
+ Math.Algebra.SymmetricPolynomials: hallInnerProduct'''' :: forall b. (Eq b, C b, C Rational b, C (BaseRing b) b) => Spray b -> Spray b -> BaseRing b -> b
+ Math.Algebra.SymmetricPolynomials: isSymmetricSpray :: (C a, Eq a) => Spray a -> Bool
+ Math.Algebra.SymmetricPolynomials: laplaceBeltrami :: (Eq a, C a) => a -> Spray a -> Spray a
+ Math.Algebra.SymmetricPolynomials: msCombination :: C a => Spray a -> Map Partition a
+ Math.Algebra.SymmetricPolynomials: msPolynomial :: (C a, Eq a) => Int -> Partition -> Spray a
+ Math.Algebra.SymmetricPolynomials: prettySymmetricNumSpray :: (Num a, Ord a, Show a, C a) => Spray a -> String
+ Math.Algebra.SymmetricPolynomials: prettySymmetricParametricQSpray :: [String] -> ParametricQSpray -> String
+ Math.Algebra.SymmetricPolynomials: prettySymmetricQSpray :: QSpray -> String
+ Math.Algebra.SymmetricPolynomials: prettySymmetricQSpray' :: QSpray' -> String
+ Math.Algebra.SymmetricPolynomials: psCombination :: forall a. (Eq a, C a) => Spray a -> Map Partition a
+ Math.Algebra.SymmetricPolynomials: psCombination' :: forall a. (Eq a, C Rational a, C a) => Spray a -> Map Partition a
+ Math.Algebra.SymmetricPolynomials: psPolynomial :: (C a, Eq a) => Int -> Partition -> Spray a
+ Math.Algebra.SymmetricPolynomials: symbolicHallInnerProduct :: (Eq a, C a) => Spray a -> Spray a -> Spray a
+ Math.Algebra.SymmetricPolynomials: symbolicHallInnerProduct' :: (Eq a, C Rational (Spray a), C a) => Spray a -> Spray a -> Spray a
+ Math.Algebra.SymmetricPolynomials: symbolicHallInnerProduct'' :: forall a. Real a => Spray a -> Spray a -> QSpray
Files
- CHANGELOG.md +13/−1
- README.md +72/−2
- jackpolynomials.cabal +6/−2
- src/Math/Algebra/Jack.hs +2/−2
- src/Math/Algebra/Jack/SymmetricPolynomials.hs +0/−189
- src/Math/Algebra/JackPol.hs +3/−3
- src/Math/Algebra/JackSymbolicPol.hs +2/−3
- src/Math/Algebra/SymmetricPolynomials.hs +500/−0
- tests/Main.hs +115/−6
CHANGELOG.md view
@@ -57,4 +57,16 @@ version) * added the Laplace-Beltrami operator and the Calogero-Sutherland operator; -the Jack polynomials are eigenpolynomials of these operators+the Jack polynomials are eigenpolynomials of these operators + +1.4.1.0 +------- +* new function `psPolynomial`, to get a power sum symmetric polynomial + +* new function `psCombination`, to get a symmetric polynomial as a linear +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
README.md view
@@ -88,7 +88,7 @@ ```haskell import Math.Algebra.JackPol -import Math.Algebra.Jack.SymmetricPolynomials +import Math.Algebra.SymmetricPolynomials jp = jackPol' 3 [3, 1, 1] 2 'J' putStrLn $ prettySymmetricQSpray jp -- 42*M[3,1,1] + 28*M[2,2,1] @@ -98,7 +98,7 @@ ```haskell import Math.Algebra.JackSymbolicPol -import Math.Algebra.Jack.SymmetricPolynomials +import Math.Algebra.SymmetricPolynomials jp = jackSymbolicPol' 3 [3, 1, 1] 'J' putStrLn $ prettySymmetricParametricQSpray ["a"] jp -- { [ 4*a^2 + 10*a + 6 ] }*M[3,1,1] + { [ 8*a + 12 ] }*M[2,2,1] @@ -108,6 +108,76 @@ they do not check the symmetry. This new module provides the function `isSymmetricSpray` to check the symmetry of a polynomial, much more efficient than the function with the same name in the **hspray** package. + + +### Hall inner product + +As of version 1.4.1.0, the package provides an implementation of the Hall +inner product with parameter. It is known that the Jack polynomials with +Jack parameter $\alpha$ are orthogonal for the Hall inner product with +parameter $\alpha$. + +There is a function `hallInnerProduct` as well as a function +`symbolicHallInnerProduct`. The latter allows to get the Hall inner product +of two symmetric polynomials without substituting a value to the parameter +$\alpha$. The Hall inner product of two symmetric polynomials is a polynomial +in $\alpha$, so the result of `symbolicHallInnerProduct` is a `Spray` object. + +Let's see a first example with a power sum polynomial. These symmetric +polynomials are implemented in the package. We display the result by using +`alpha` to denote the parameter of the Hall product. + +```haskell +import Math.Algebra.SymmetricPolynomials +import Math.Algebra.Hspray hiding (psPolynomial) +psPoly = psPolynomial 4 [2, 1, 1] :: QSpray +hip = symbolicHallInnerProduct psPoly psPoly +putStrLn $ prettyQSprayXYZ ["alpha"] hip +-- 4*alpha^3 +``` + +Now let's consider the following situation. We want to get the symbolic Hall +inner product of a Jack polynomial with itself, and we deal with a symbolic +Jack parameter in this polynomial. We denote it by `t` to distinguish it from +the parameter of the Hall product that we still denote by `alpha`. + +The signature of the `symbolicHallInnerProduct` is a bit misleading: +```haskell +Spray a -> Spray a -> Spray a +``` +because the `Spray a` of the output is not of the same family as the two +`Spray a` inputs: this is a univariate polynomial in $\alpha$. + +We use the function `jackSymbolicPol'` to compute a Jack polynomial. It +returns a `ParametricQSpray` spray, a type alias of `Spray RatioOfQSprays`. + +```haskell +import Math.Algebra.JackSymbolicPol +import Math.Algebra.SymmetricPolynomials +import Math.Algebra.Hspray +jp = jackSymbolicPol' 2 [3, 1] 'P' +hip = symbolicHallInnerProduct jp jp +putStrLn $ prettyParametricQSprayABCXYZ ["t"] ["alpha"] hip +-- { [ 3*t^2 + 6*t + 11 ] %//% [ t^2 + 2*t + 1 ] }*alpha^2 + { [ 4*t^2 + 16*t + 16 ] %//% [ t^2 + 2*t + 1 ] }*alpha +``` + +One could be interested in computing the Hall inner product of a Jack +polynomial with itself when the Jack parameter and the parameter of the +Hall product are identical. That is, we want to take `alpha = t` in the +above expression. Since the symbolic Hall product is a `ParametricQSpray` +spray, one can substitute its variable `alpha` by a `RatioOfQSprays` +object. On the other hand, `t` represents a `QSpray` object, but one can +identify a `QSpray` to a `RatioOfQSprays` by taking the unit spray as the +denominator, that is, by applying the `asRatioOfSprays` function. Finally +we get the desired result if we evaluate the symbolic Hall product by +replacing `alpha` with `asRatioOfSprays (qlone 1)`, since `t` is the +first polynomial variable, `qlone 1`. + +```haskell +prettyRatioOfQSpraysXYZ ["t"] $ evaluate hip [asRatioOfSprays (qlone 1)] +-- [ 3*t^4 + 10*t^3 + 27*t^2 + 16*t ] %//% [ t^2 + 2*t + 1 ] +``` + ## References
jackpolynomials.cabal view
@@ -1,5 +1,5 @@ name: jackpolynomials -version: 1.4.0.0 +version: 1.4.1.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. homepage: https://github.com/stla/jackpolynomials#readme @@ -17,7 +17,7 @@ library hs-source-dirs: src exposed-modules: Math.Algebra.Jack.HypergeoPQ - , Math.Algebra.Jack.SymmetricPolynomials + , Math.Algebra.SymmetricPolynomials , Math.Algebra.Jack , Math.Algebra.JackPol , Math.Algebra.JackSymbolicPol @@ -30,8 +30,11 @@ , numeric-prelude >= 0.4.4 && < 0.5 , combinat >= 0.2.10 && < 0.3 , containers >= 0.6.4.1 && < 0.8 + , unordered-containers >= 0.2.17.0 && < 0.3 + , extra >= 1.7 && < 1.8 other-extensions: ScopedTypeVariables , BangPatterns + , FlexibleContexts default-language: Haskell2010 ghc-options: -Wall -Wcompat @@ -54,6 +57,7 @@ , hspray >= 0.5.0.0 && < 0.6.0.0 , hypergeomatrix >= 1.1.0.2 && < 2 , combinat >= 0.2.10 && < 0.3 + , containers >= 0.6.4.1 && < 0.8 Default-Language: Haskell2010 ghc-options: -Wall -Wcompat
src/Math/Algebra/Jack.hs view
@@ -12,7 +12,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE ScopedTypeVariables #-} module Math.Algebra.Jack - (jack', zonal', schur', skewSchur', jack, zonal, schur, skewSchur) + (Partition, jack', zonal', schur', skewSchur', jack, zonal, schur, skewSchur) where import Prelude hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger) @@ -66,7 +66,7 @@ theproduct :: Int -> a theproduct nu0 = if nu0 <= 1 then one - else product $ map (\i -> one + i .^ alpha) [1 .. nu0-1] + else product [one + i .^ alpha | i <- [1 .. nu0-1]] jac :: Int -> Int -> [Int] -> [Int] -> Array (Int,Int) (Maybe a) -> a -> a jac m k mu nu arr beta
− src/Math/Algebra/Jack/SymmetricPolynomials.hs
@@ -1,189 +0,0 @@-{-| -Module : Math.Algebra.Jack.SymmetricPolynomials -Description : Some utilities for Jack polynomials. -Copyright : (c) Stéphane Laurent, 2024 -License : GPL-3 -Maintainer : laurent_step@outlook.fr - -A Jack polynomial can have a very long expression in the canonical basis. -A considerably shorter expression is obtained by writing the polynomial as -a linear combination of the monomial symmetric polynomials instead, which is -always possible since Jack polynomials are symmetric. This is the motivation -of this module. --} - -module Math.Algebra.Jack.SymmetricPolynomials - ( isSymmetricSpray - , msPolynomial - , msCombination - , prettySymmetricNumSpray - , prettySymmetricQSpray - , prettySymmetricQSpray' - , prettySymmetricParametricQSpray - , laplaceBeltrami - , calogeroSutherland - ) where -import qualified Algebra.Additive as AlgAdd -import qualified Algebra.Field as AlgField -import qualified Algebra.Ring as AlgRing -import qualified Data.Foldable as DF -import Data.List ( foldl1', nub ) -import Data.Map.Strict ( Map ) -import qualified Data.Map.Strict as DM -import Data.Sequence ( Seq ) -import Math.Algebra.Hspray ( - FunctionLike (..) - , (/^) - , Spray - , QSpray - , QSpray' - , ParametricQSpray - , lone - , lone' - , fromList - , getCoefficient - , isConstant - , (%//%) - , RatioOfSprays (..) - , prettyRatioOfQSpraysXYZ - , showNumSpray - , showQSpray - , showQSpray' - , showSpray - , toList - , zeroSpray - ) -import Math.Algebra.Jack.Internal ( Partition , _isPartition ) -import Math.Combinat.Permutations ( permuteMultiset ) -import Math.Combinat.Partitions.Integer ( fromPartition, mkPartition ) - --- | Monomial symmetric polynomials --- --- >>> putStrLn $ prettySpray' (msPolynomial 3 [2, 1]) --- (1) x1^2.x2 + (1) x1^2.x3 + (1) x1.x2^2 + (1) x1.x3^2 + (1) x2^2.x3 + (1) x2.x3^2 -msPolynomial :: (AlgRing.C a, Eq a) - => Int -- ^ number of variables - -> Partition -- ^ integer partition - -> Spray a -msPolynomial n lambda - | n < 0 = - 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 - --- | 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 -isSymmetricSpray :: (AlgRing.C a, Eq a) => Spray a -> Bool -isSymmetricSpray spray = spray == spray' - where - assocs = msCombination' spray - n = numberOfVariables spray - spray' = foldl1' (^+^) - ( - map (\(lambda, x) -> x *^ msPolynomial n lambda) assocs - ) - --- | 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 - where - lambdas = nub $ map (fromPartition . mkPartition . fst) (toList spray) - --- helper function for the showing stuff -makeMSpray :: (Eq a, AlgRing.C a) => Spray a -> Spray a -makeMSpray = fromList . msCombination' - --- show symmetric monomial like M[3,2,1] -showSymmetricMonomials :: [Seq Int] -> [String] -showSymmetricMonomials = map showSymmetricMonomial - where - showSymmetricMonomial :: Seq Int -> String - showSymmetricMonomial lambda = 'M' : show (DF.toList lambda) - --- | Prints a symmetric spray as a linear combination of monomial symmetric polynomials --- --- >>> putStrLn $ prettySymmetricNumSpray $ schurPol' 3 [3, 1, 1] --- M[3,1,1] + M[2,2,1] -prettySymmetricNumSpray :: - (Num a, Ord a, Show a, AlgRing.C a) => Spray a -> String -prettySymmetricNumSpray spray = - showNumSpray showSymmetricMonomials show mspray - where - mspray = makeMSpray spray - --- | Prints a symmetric spray as a linear combination of monomial symmetric polynomials --- --- >>> putStrLn $ prettySymmetricQSpray $ jackPol' 3 [3, 1, 1] 2 'J' --- 42*M[3,1,1] + 28*M[2,2,1] -prettySymmetricQSpray :: QSpray -> String -prettySymmetricQSpray spray = showQSpray showSymmetricMonomials mspray - where - mspray = makeMSpray spray - --- | Same as `prettySymmetricQSpray` but for a `QSpray'` symmetric spray -prettySymmetricQSpray' :: QSpray' -> String -prettySymmetricQSpray' spray = showQSpray' showSymmetricMonomials mspray - where - mspray = makeMSpray spray - --- | Prints a symmetric parametric spray as a linear combination of monomial --- symmetric polynomials --- --- >>> putStrLn $ prettySymmetricParametricQSpray ["a"] $ jackSymbolicPol' 3 [3, 1, 1] 'J' --- { [ 4*a^2 + 10*a + 6 ] }*M[3,1,1] + { [ 8*a + 12 ] }*M[2,2,1] -prettySymmetricParametricQSpray :: [String] -> ParametricQSpray -> String -prettySymmetricParametricQSpray letters spray = - showSpray (prettyRatioOfQSpraysXYZ letters) ("{ ", " }") - showSymmetricMonomials mspray - where - mspray = makeMSpray spray - --- Laplace-Beltrami operator on the space of homogeneous symmetric polynomials; --- neither symmetry and homogeneity are checked -laplaceBeltrami :: (Eq a, AlgField.C a) => a -> Spray a -> Spray a -laplaceBeltrami alpha spray = - if isConstant spray - then zeroSpray - else alpha' *^ spray1 ^+^ spray2 - where - alpha' = alpha AlgField./ AlgRing.fromInteger 2 - n = numberOfVariables spray - range = [1 .. n] - dsprays = map (`derivative` spray) range - op1 i = lone' i 2 ^*^ derivative i (dsprays !! (i-1)) - spray1 = AlgAdd.sum (map op1 range) - spray2 = _numerator $ AlgAdd.sum - [(lone' i 2 ^*^ dsprays !! (i-1)) %//% (lone i ^-^ lone j) - | i <- range, j <- range, i /= j] - --- Calogero-Sutherland operator on the space of homogeneous symmetric polynomials; --- neither symmetry and homogeneity are checked -calogeroSutherland :: (Eq a, AlgField.C a) => a -> Spray a -> Spray a -calogeroSutherland alpha spray = - if isConstant spray - then zeroSpray - else halfSpray $ alpha *^ spray1 ^+^ spray2 - where - halfSpray p = p /^ AlgRing.fromInteger 2 - n = numberOfVariables spray - range = [1 .. n] - dsprays = map (`derivative` spray) range - op0 p i = lone i ^*^ derivative i p - op1 p i = op0 (op0 p i) i - spray1 = AlgAdd.sum (map (op1 spray) range) - spray2 = _numerator $ AlgAdd.sum - [let (xi, xj, dxi, dxj) = - (lone i, lone j, dsprays !! (i-1), dsprays !! (j-1)) in - (xi ^+^ xj) ^*^ (xi ^*^ dxi ^-^ xj ^*^ dxj) %//% (xi ^-^ xj) - | i <- range, j <- [i+1 .. n]]
src/Math/Algebra/JackPol.hs view
@@ -67,7 +67,7 @@ theproduct :: Int -> a theproduct nu0 = if nu0 <= 1 then one - else product $ map (\i -> i .^ alpha + one) [1 .. nu0-1] + else product [i .^ alpha + one | i <- [1 .. nu0-1]] jac :: Int -> Int -> Partition -> Partition -> Array (Int,Int) (Maybe (Spray a)) -> a -> Spray a jac m k mu nu arr beta @@ -146,8 +146,8 @@ Int -> Int -> [Int] -> Array (Int,Int) (Maybe (Spray a)) -> Spray a sch m k nu arr | null nu || nu!!0 == 0 || m == 0 = unitSpray - | length nu > m && nu!!m > 0 = zeroSpray - | m == 1 = x!!0 ^**^ nu!!0 + | length nu > m && nu !! m > 0 = zeroSpray + | m == 1 = x !! 0 ^**^ nu !! 0 | isJust (arr ! (_N lambda nu, m)) = fromJust $ arr ! (_N lambda nu, m) | otherwise = s
src/Math/Algebra/JackSymbolicPol.hs view
@@ -68,9 +68,8 @@ theproduct :: Int -> RatioOfSprays a theproduct nu0 = if nu0 <= 1 then unitRatioOfSprays - else asRatioOfSprays $ product $ map - (\i -> i .^ alpha ^+^ unitSpray) - [1 .. nu0-1] + else asRatioOfSprays $ product + [i .^ alpha ^+^ unitSpray | i <- [1 .. nu0-1]] jac :: Int -> Int -> Partition -> Partition -> Array (Int,Int) (Maybe (ParametricSpray a)) -> RatioOfSprays a -> ParametricSpray a
+ src/Math/Algebra/SymmetricPolynomials.hs view
@@ -0,0 +1,500 @@+{-| +Module : Math.Algebra.Jack.SymmetricPolynomials +Description : Some utilities for Jack polynomials. +Copyright : (c) Stéphane Laurent, 2024 +License : GPL-3 +Maintainer : laurent_step@outlook.fr + +A Jack polynomial can have a very long expression in the canonical basis. +A considerably shorter expression is obtained by writing the polynomial as +a linear combination of the monomial symmetric polynomials instead, which is +always possible since Jack polynomials are symmetric. This is the initial +motivation of this module. But now it contains more stuff dealing with +symmetric polynomials. +-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Math.Algebra.SymmetricPolynomials + ( + -- * Checking symmetry + isSymmetricSpray + -- * Classical symmetric polynomials + , msPolynomial + , psPolynomial + -- * Decomposition of symmetric polynomials + , msCombination + , psCombination + , psCombination' + -- * Printing symmetric polynomials + , prettySymmetricNumSpray + , prettySymmetricQSpray + , prettySymmetricQSpray' + , prettySymmetricParametricQSpray + -- * Operators on the space of symmetric polynomials + , laplaceBeltrami + , calogeroSutherland + -- * Hall inner product of symmetric polynomials + , hallInnerProduct + , hallInnerProduct' + , hallInnerProduct'' + , hallInnerProduct''' + , hallInnerProduct'''' + , symbolicHallInnerProduct + , symbolicHallInnerProduct' + , symbolicHallInnerProduct'' + ) where +import Prelude hiding ( fromIntegral, fromRational ) +import qualified Algebra.Additive as AlgAdd +import Algebra.Field ( fromRational ) +import qualified Algebra.Field as AlgField +import qualified Algebra.Module as AlgMod +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 ( foldl1', nub ) +import Data.List.Extra ( unsnoc ) +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.Ratio ( (%) ) +import Data.Sequence ( + Seq + , (|>) + ) +import qualified Data.Sequence as S +import Data.Tuple.Extra ( second ) +import Math.Algebra.Hspray ( + FunctionLike (..) + , (/^) + , Spray + , Powers (..) + , QSpray + , QSpray' + , ParametricQSpray + , lone + , qlone + , lone' + , fromList + , getCoefficient + , getConstantTerm + , isConstant + , (%//%) + , RatioOfSprays (..) + , prettyRatioOfQSpraysXYZ + , showNumSpray + , showQSpray + , showQSpray' + , showSpray + , toList + , zeroSpray + , unitSpray + , productOfSprays + , constantSpray + ) +import Math.Algebra.Jack.Internal ( Partition , _isPartition ) +import Math.Combinat.Compositions ( compositions1 ) +import Math.Combinat.Partitions.Integer ( + fromPartition + , mkPartition + , partitions + ) +import Math.Combinat.Permutations ( permuteMultiset ) + +-- | Monomial symmetric polynomial +-- +-- >>> putStrLn $ prettySpray' (msPolynomial 3 [2, 1]) +-- (1) x1^2.x2 + (1) x1^2.x3 + (1) x1.x2^2 + (1) x1.x3^2 + (1) x2^2.x3 + (1) x2.x3^2 +msPolynomial :: (AlgRing.C a, Eq a) + => Int -- ^ number of variables + -> Partition -- ^ integer partition + -> Spray a +msPolynomial n lambda + | n < 0 = + 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 + +-- | 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 +isSymmetricSpray :: (AlgRing.C a, Eq a) => Spray a -> Bool +isSymmetricSpray spray = spray == spray' + where + assocs = msCombination' spray + n = numberOfVariables spray + spray' = foldl1' (^+^) + ( + map (\(lambda, x) -> x *^ msPolynomial n lambda) assocs + ) + +-- | 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 + where + lambdas = nub $ map (fromPartition . mkPartition . fst) (toList spray) + +-- helper function for the showing stuff +makeMSpray :: (Eq a, AlgRing.C a) => Spray a -> Spray a +makeMSpray = fromList . msCombination' + +-- show symmetric monomial like M[3,2,1] +showSymmetricMonomials :: [Seq Int] -> [String] +showSymmetricMonomials = map showSymmetricMonomial + where + showSymmetricMonomial :: Seq Int -> String + showSymmetricMonomial lambda = 'M' : show (DF.toList lambda) + +-- | Prints a symmetric spray as a linear combination of monomial symmetric polynomials +-- +-- >>> putStrLn $ prettySymmetricNumSpray $ schurPol' 3 [3, 1, 1] +-- M[3,1,1] + M[2,2,1] +prettySymmetricNumSpray :: + (Num a, Ord a, Show a, AlgRing.C a) => Spray a -> String +prettySymmetricNumSpray spray = + showNumSpray showSymmetricMonomials show mspray + where + mspray = makeMSpray spray + +-- | Prints a symmetric spray as a linear combination of monomial symmetric polynomials +-- +-- >>> putStrLn $ prettySymmetricQSpray $ jackPol' 3 [3, 1, 1] 2 'J' +-- 42*M[3,1,1] + 28*M[2,2,1] +prettySymmetricQSpray :: QSpray -> String +prettySymmetricQSpray spray = showQSpray showSymmetricMonomials mspray + where + mspray = makeMSpray spray + +-- | Same as `prettySymmetricQSpray` but for a `QSpray'` symmetric spray +prettySymmetricQSpray' :: QSpray' -> String +prettySymmetricQSpray' spray = showQSpray' showSymmetricMonomials mspray + where + mspray = makeMSpray spray + +-- | Prints a symmetric parametric spray as a linear combination of monomial +-- symmetric polynomials +-- +-- >>> putStrLn $ prettySymmetricParametricQSpray ["a"] $ jackSymbolicPol' 3 [3, 1, 1] 'J' +-- { [ 4*a^2 + 10*a + 6 ] }*M[3,1,1] + { [ 8*a + 12 ] }*M[2,2,1] +prettySymmetricParametricQSpray :: [String] -> ParametricQSpray -> String +prettySymmetricParametricQSpray letters spray = + showSpray (prettyRatioOfQSpraysXYZ letters) ("{ ", " }") + showSymmetricMonomials mspray + where + mspray = makeMSpray spray + +-- | Laplace-Beltrami operator on the space of homogeneous symmetric polynomials; +-- neither symmetry and homogeneity are checked +laplaceBeltrami :: (Eq a, AlgField.C a) => a -> Spray a -> Spray a +laplaceBeltrami alpha spray = + if isConstant spray + then zeroSpray + else alpha' *^ spray1 ^+^ spray2 + where + alpha' = alpha AlgField./ AlgRing.fromInteger 2 + n = numberOfVariables spray + range = [1 .. n] + dsprays = map (`derivative` spray) range + op1 i = lone' i 2 ^*^ derivative i (dsprays !! (i-1)) + spray1 = AlgAdd.sum (map op1 range) + spray2 = _numerator $ AlgAdd.sum + [(lone' i 2 ^*^ dsprays !! (i-1)) %//% (lone i ^-^ lone j) + | i <- range, j <- range, i /= j] + +-- | Calogero-Sutherland operator on the space of homogeneous symmetric polynomials; +-- neither symmetry and homogeneity are checked +calogeroSutherland :: (Eq a, AlgField.C a) => a -> Spray a -> Spray a +calogeroSutherland alpha spray = + if isConstant spray + then zeroSpray + else halfSpray $ alpha *^ spray1 ^+^ spray2 + where + halfSpray p = p /^ AlgRing.fromInteger 2 + n = numberOfVariables spray + range = [1 .. n] + dsprays = map (`derivative` spray) range + op0 p i = lone i ^*^ derivative i p + op1 p i = op0 (op0 p i) i + spray1 = AlgAdd.sum (map (op1 spray) range) + spray2 = _numerator $ AlgAdd.sum + [let (xi, xj, dxi, dxj) = + (lone i, lone j, dsprays !! (i-1), dsprays !! (j-1)) in + (xi ^+^ xj) ^*^ (xi ^*^ dxi ^-^ xj ^*^ dxj) %//% (xi ^-^ xj) + | i <- range, j <- [i+1 .. n]] + +-- | Power sum polynomial +-- +-- >>> putStrLn $ prettyQSpray (psPolynomial 3 [2, 1]) +-- x^3 + x^2.y + x^2.z + x.y^2 + x.z^2 + y^3 + y^2.z + y.z^2 + z^3 +psPolynomial :: (AlgRing.C a, Eq a) + => Int -- ^ number of variables + -> Partition -- ^ integer partition + -> Spray a +psPolynomial n lambda + | n < 0 = + error "psPolynomial: negative number of variables." + | not (_isPartition lambda) = + error "psPolynomial: invalid partition." + | null lambda' = unitSpray + | 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'] + 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) + 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] + ---- + partitionSequences :: [Int] -> Partition -> [Int] -> [Partition] + partitionSequences lambda mu 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] ] + | i <- [0 .. length compo - 1] + ] + nuWeights = [sum nu | nu <- nus] + decreasing xs = + and [xs !! i >= xs !! (i+1) | i <- [0 .. length xs - 2]] + test = and (zipWith (==) mu nuWeights) && all decreasing nus + ---- + eMuNus :: Partition -> [Partition] -> Rational + eMuNus mu nus = product toMultiply + where + w :: Int -> Partition -> Rational + w k nu = + let table = [sum [fromEnum (i == j) | i <- nu] | j <- nub nu] in + (toInteger $ k * factorial (length nu - 1)) % + (toInteger $ product (map factorial table)) + factorial n = product [2 .. n] + toMultiply = zipWith w mu nus + +-- | the factor in the Hall inner product +zlambda :: Partition -> Int +zlambda lambda = p + where + parts = nub lambda + table = [sum [fromEnum (k == j) | k <- lambda] | j <- parts] + p = + 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 = + if constantTerm == AlgAdd.zero + then psMap + else insert [] constantTerm psMap + where + constantTerm = getConstantTerm spray + assocs = msCombination' (spray <+ (AlgAdd.negate constantTerm)) + f :: (Partition, a) -> [(Partition, a)] + f (lambda, coeff) = + map (second (func coeff)) (DM.toList psCombo) + where + psCombo = mspInPSbasis lambda :: Map Partition Rational + psMap = DM.filter (/= AlgAdd.zero) + (unionsWith (AlgAdd.+) (map (DM.fromList . f) assocs)) + +-- | Symmetric polynomial as a linear combination of power sum polynomials. +-- Symmetry is not checked. +psCombination :: + forall a. (Eq a, AlgField.C a) => Spray a -> Map Partition a +psCombination = + _psCombination (\coef r -> coef AlgRing.* fromRational r) + +-- | Symmetric polynomial as a linear combination of power sum polynomials. +-- Same as @psCombination@ but with other constraints on the base ring of the spray. +psCombination' :: + forall a. (Eq a, AlgMod.C Rational a, AlgRing.C a) + => Spray a -> Map Partition a +psCombination' = _psCombination (flip (AlgMod.*>)) + +-- | the Hall inner product with parameter +_hallInnerProduct :: + forall a b. (AlgRing.C b, AlgRing.C a) + => (Spray b -> Map Partition b) + -> (a -> b -> b) + -> Spray b -- ^ spray + -> Spray b -- ^ spray + -> a -- ^ parameter + -> b +_hallInnerProduct psCombinationFunc multabFunc spray1 spray2 alpha = + AlgAdd.sum $ DM.elems + (merge dropMissing dropMissing (zipWithMatched f) psCombo1 psCombo2) + where + psCombo1 = psCombinationFunc spray1 :: Map Partition b + psCombo2 = psCombinationFunc spray2 :: Map Partition b + zlambda' :: Partition -> a + zlambda' lambda = fromIntegral (zlambda lambda) + AlgRing.* alpha AlgRing.^ (toInteger $ length lambda) + f :: Partition -> b -> b -> b + 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. +hallInnerProduct :: + forall a. (Eq a, AlgField.C a) + => Spray a -- ^ spray + -> Spray a -- ^ spray + -> a -- ^ parameter + -> a +hallInnerProduct = _hallInnerProduct psCombination (AlgRing.*) + +-- | Hall inner product with parameter. Same as @hallInnerProduct@ but +-- with other constraints on the base ring of the sprays. +hallInnerProduct' :: + forall a. (Eq a, AlgMod.C Rational a, AlgRing.C a) + => Spray a -- ^ spray + -> Spray a -- ^ spray + -> a -- ^ parameter + -> a +hallInnerProduct' = _hallInnerProduct psCombination' (AlgRing.*) + +-- | Hall inner product with parameter. Same as @hallInnerProduct@ but +-- with other constraints on the base ring of the sprays. It is applicable +-- to @Spray Int@ sprays. +hallInnerProduct'' :: + forall a. (Real a) + => Spray a -- ^ spray + -> Spray a -- ^ spray + -> a -- ^ parameter + -> Rational +hallInnerProduct'' spray1 spray2 alpha = + _hallInnerProduct + (_psCombination (*)) (*) qspray1 qspray2 (toRational alpha) + where + asQSpray :: Spray a -> QSpray + asQSpray = HM.map toRational + qspray1 = asQSpray spray1 + qspray2 = asQSpray spray2 + +-- | Hall inner product with parameter for parametric sprays, because the +-- type of the parameter in @hallInnerProduct@ is strange. For example, a +-- @ParametricQSpray@ spray is a @Spray RatioOfQSprays@ spray, and it makes +-- more sense to compute the Hall product with a @Rational@ parameter then +-- to compute the Hall product with a @RatioOfQSprays@ parameter. +-- +-- >>> import Math.Algebra.Jack.SymmetricPolynomials +-- >>> import Math.Algebra.JackSymbolicPol +-- >>> import Math.Algebra.Hspray +-- >>> jp = jackSymbolicPol 3 [2, 1] 'P' +-- >>> hallInnerProduct''' jp jp 5 == hallInnerProduct jp jp (constantRatioOfSprays 5) +hallInnerProduct''' :: + forall b. (Eq b, AlgField.C b, AlgMod.C (BaseRing b) b) + => Spray b -- ^ parametric spray + -> Spray b -- ^ parametric spray + -> BaseRing b -- ^ parameter + -> b +hallInnerProduct''' = _hallInnerProduct psCombination (AlgMod.*>) + +-- | Hall inner product with parameter for parametric sprays. Same as +-- @hallInnerProduct'''@ but with other constraints on the types. It is +-- applicable to @SimpleParametricQSpray@ sprays, while @hallInnerProduct'''@ +-- is not. +hallInnerProduct'''' :: + forall b. (Eq b, AlgRing.C b, AlgMod.C Rational b, AlgMod.C (BaseRing b) b) + => Spray b -- ^ parametric spray + -> Spray b -- ^ parametric spray + -> BaseRing b -- ^ parameter + -> b +hallInnerProduct'''' = _hallInnerProduct psCombination' (AlgMod.*>) + +-- | the Hall inner product with symbolic parameter +_symbolicHallInnerProduct :: + (Eq a, AlgRing.C a) + => (Spray (Spray a) -> Spray (Spray a) -> Spray a -> Spray a) + -> Spray a -> Spray a -> Spray a +_symbolicHallInnerProduct func spray1 spray2 = func spray1' spray2' (lone 1) + where + spray1' = HM.map constantSpray spray1 + spray2' = HM.map constantSpray spray2 + +-- | Hall inner product with symbolic parameter. See README for some examples. +symbolicHallInnerProduct :: + (Eq a, AlgField.C a) => Spray a -> Spray a -> Spray a +symbolicHallInnerProduct = + _symbolicHallInnerProduct + ( + _hallInnerProduct + (_psCombination (\spray_a r -> fromRational r *^ spray_a)) (^*^) + ) + +-- | Hall inner product with symbolic parameter. Same as @symbolicHallInnerProduct@ +-- but with other type constraints. +symbolicHallInnerProduct' :: + (Eq a, AlgMod.C Rational (Spray a), AlgRing.C a) + => Spray a -> Spray a -> Spray a +symbolicHallInnerProduct' = _symbolicHallInnerProduct (hallInnerProduct') + +-- | Hall inner product with symbolic parameter. Same as @symbolicHallInnerProduct@ +-- but with other type constraints. It is applicable to @Spray Int@ sprays. +symbolicHallInnerProduct'' :: forall a. Real a => Spray a -> Spray a -> QSpray +symbolicHallInnerProduct'' spray1 spray2 = + _hallInnerProduct + (_psCombination (\qspray r -> r *^ qspray)) (^*^) + qspray1' qspray2' (qlone 1) + where + asQSpray :: Spray a -> QSpray + asQSpray = HM.map toRational + qspray1' = HM.map constantSpray (asQSpray spray1) + qspray2' = HM.map constantSpray (asQSpray spray2) + + +-- test'' :: (String, String) +-- test'' = (prettyParametricQSpray result, prettyParametricQSprayABCXYZ ["a"] ["b"] $ result) +-- where +-- jsp = jackSymbolicPol' 3 [2, 1] 'P' +-- result = hallSymbolic'' jsp jsp
tests/Main.hs view
@@ -1,21 +1,33 @@ module Main ( main ) where +import qualified Data.Map.Strict as DM import Data.Ratio ( (%) ) import Math.Algebra.Hspray ( FunctionLike (..) - , Spray, lone + , Spray, QSpray + , lone, qlone , evalSpray , evalParametricSpray' , substituteParameters , canCoerceToSimpleParametricSpray , isHomogeneousSpray + , asRatioOfSprays + , (%//%) + , (/^) ) import qualified Math.Algebra.Hspray as Hspray import Math.Algebra.Jack ( schur, skewSchur , jack', zonal' ) import Math.Algebra.Jack.HypergeoPQ ( hypergeoPQ ) -import Math.Algebra.Jack.SymmetricPolynomials ( isSymmetricSpray +import Math.Algebra.SymmetricPolynomials ( isSymmetricSpray , prettySymmetricParametricQSpray , laplaceBeltrami - , calogeroSutherland ) + , calogeroSutherland + , hallInnerProduct + , hallInnerProduct'' + , symbolicHallInnerProduct + , symbolicHallInnerProduct'' + , psPolynomial + , psCombination + ) import Math.Algebra.JackPol ( zonalPol, zonalPol', jackPol' , schurPol, schurPol', skewSchurPol' ) import Math.Algebra.JackSymbolicPol ( jackSymbolicPol' ) @@ -130,7 +142,8 @@ sp3 = schurPol 4 [2, 2] sp4 = schurPol 4 [2, 1, 1] sp5 = schurPol 4 [1, 1, 1, 1] :: Spray Int - v = evalSpray (sp1 ^+^ 3 *^ sp2 ^+^ 2 *^ sp3 ^+^ 3 *^ sp4 ^+^ sp5) [2, 2, 2, 2] + v = evalSpray (sp1 ^+^ 3 *^ sp2 ^+^ 2 *^ sp3 ^+^ 3 *^ sp4 ^+^ sp5) + [2, 2, 2, 2] assertEqual "" v 4096 , testCase "schurPol is symmetric (Groebner)" $ do @@ -154,8 +167,9 @@ y = lone 2 :: Spray Rational z = lone 3 :: Spray Rational skp = skewSchurPol' 3 [2, 2, 1] [1, 1] - p = x^**^2 ^*^ y ^+^ x^**^2 ^*^ z ^+^ x ^*^ y^**^2 ^+^ 3 *^ (x ^*^ y ^*^ z) - ^+^ x ^*^ z^**^2 ^+^ y^**^2 ^*^ z ^+^ y ^*^ z^**^2 + p = x^**^2 ^*^ y ^+^ x^**^2 ^*^ z ^+^ x ^*^ y^**^2 + ^+^ 3 *^ (x ^*^ y ^*^ z) ^+^ x ^*^ z^**^2 + ^+^ y^**^2 ^*^ z ^+^ y ^*^ z^**^2 assertEqual "" skp p , testCase "skewSchurPol is symmetric (Groebner)" $ do @@ -182,4 +196,99 @@ h1 = hypergeoPQ 10 a b x :: Rational h2 <- hypergeomat 10 2 a b x assertEqual "" h1 h2 + + , testCase "Hall inner product" $ do + let + alpha = 2 + poly1 = psPolynomial 4 [4] + poly2 = psPolynomial 4 [3, 1] + poly3 = psPolynomial 4 [2, 2] + poly4 = psPolynomial 4 [2, 1, 1] + poly5 = psPolynomial 4 [1, 1, 1, 1] + h1 = hallInnerProduct poly1 poly1 alpha + h2 = hallInnerProduct poly2 poly2 alpha + h3 = hallInnerProduct poly3 poly3 alpha + h4 = hallInnerProduct poly4 poly4 alpha + h5 = hallInnerProduct poly5 poly5 alpha + pow :: Rational -> Int -> Rational + pow = (^) + assertEqual "" + (h1, h2, h3, h4, h5) + ( + 4 * alpha + , 3 * pow alpha 2 + , 8 * pow alpha 2 + , 4 * pow alpha 3 + , 24 * pow alpha 4 + ) + + , testCase "Hall inner product of Schur polynomials" $ do + let + sp1 = schurPol 7 [4, 2, 1] :: Spray Int + sp2 = schurPol 7 [2, 2, 2, 1] :: Spray Int + h1 = hallInnerProduct'' sp1 sp1 1 + h2 = hallInnerProduct'' sp2 sp2 1 + h12 = hallInnerProduct'' sp1 sp2 1 + assertEqual "" (h1, h2, h12) (1, 1, 0) + + , testCase "Symbolic Hall inner product" $ do + let + poly1 = psPolynomial 4 [4] :: QSpray + poly2 = psPolynomial 4 [3, 1] :: QSpray + poly3 = psPolynomial 4 [2, 2] :: QSpray + poly4 = psPolynomial 4 [2, 1, 1] :: QSpray + poly5 = psPolynomial 4 [1, 1, 1, 1] :: QSpray + h1 = symbolicHallInnerProduct poly1 poly1 + h2 = symbolicHallInnerProduct poly2 poly2 + h3 = symbolicHallInnerProduct poly3 poly3 + h4 = symbolicHallInnerProduct poly4 poly4 + h5 = symbolicHallInnerProduct poly5 poly5 + alpha = qlone 1 + assertEqual "" + (h1, h2, h3, h4, h5) + ( + 4 *^ alpha + , 3 *^ alpha^**^2 + , 8 *^ alpha^**^2 + , 4 *^ alpha^**^3 + , 24 *^ alpha^**^4 + ) + + , testCase "Symbolic Hall inner product of Schur polynomials" $ do + let + sp1 = schurPol 7 [4, 2, 1] :: Spray Int + sp2 = schurPol 7 [2, 2, 2, 1] :: Spray Int + h1 = evaluateAt [1] (symbolicHallInnerProduct'' sp1 sp1) + h2 = evaluateAt [1] (symbolicHallInnerProduct'' sp2 sp2) + h12 = evaluateAt [1] (symbolicHallInnerProduct'' sp1 sp2) + assertEqual "" (h1, h2, h12) (1, 1, 0) + + , testCase "Symbolic Hall inner product with parametric sprays" $ do + let + jp1 = jackSymbolicPol' 3 [1, 1, 1] 'P' + jp2 = jackSymbolicPol' 3 [2, 1] 'P' + jp3 = jackSymbolicPol' 3 [3] 'P' + t = qlone 1 + t' = asRatioOfSprays t + h1 = hallInnerProduct jp1 jp1 t' + h2 = hallInnerProduct jp2 jp2 t' + h3 = hallInnerProduct jp3 jp3 t' + assertEqual "" + (h1, h2, h3) + ( + asRatioOfSprays (t^**^3 /^ 6 ^+^ t^**^2 /^ 2 ^+^ t /^ 3) + , (2*^t^**^3 ^+^ t^**^2) %//% (t <+ 2) + , (3*^t^**^3) %//% ((t^**^2 ^+^ (3%2)*^t) <+ (1%2)) + ) + + , testCase "Power sum polynomial and power sum combination" $ do + let + psPoly = 3*^psPolynomial 4 [2, 1, 1] ^-^ psPolynomial 4 [2, 1] :: QSpray + psCombo = psCombination psPoly + assertEqual "" + psCombo + ( + DM.fromList [([2, 1, 1], 3), ([2, 1], -1)] + ) + ]