packages feed

jackpolynomials 1.1.2.0 → 1.2.0.0

raw patch · 9 files changed

+498/−136 lines, 9 filesdep −math-functionsdep ~hsprayPVP ok

version bump matches the API change (PVP)

Dependencies removed: math-functions

Dependency ranges changed: hspray

API changes (from Hackage documentation)

+ Math.Algebra.Jack: jack' :: [Rational] -> Partition -> Rational -> Char -> Rational
+ Math.Algebra.Jack: schur' :: [Rational] -> Partition -> Rational
+ Math.Algebra.Jack: skewSchur' :: [Rational] -> Partition -> Partition -> Rational
+ Math.Algebra.Jack: zonal' :: [Rational] -> Partition -> Rational
+ Math.Algebra.JackPol: jackPol' :: Int -> Partition -> Rational -> Char -> Spray Rational
+ Math.Algebra.JackPol: schurPol' :: Int -> Partition -> Spray Rational
+ Math.Algebra.JackPol: skewSchurPol' :: Int -> Partition -> Partition -> Spray Rational
+ Math.Algebra.JackPol: zonalPol' :: Int -> Partition -> Spray Rational
+ Math.Algebra.JackSymbolicPol: jackSymbolicPol :: forall a. (Eq a, C a) => Int -> Partition -> Char -> SymbolicSpray a
+ Math.Algebra.JackSymbolicPol: jackSymbolicPol' :: Int -> Partition -> Char -> SymbolicQSpray
- Math.Algebra.Jack: jack :: forall a. (Fractional a, Ord a) => [a] -> Partition -> a -> a
+ Math.Algebra.Jack: jack :: forall a. C a => [a] -> Partition -> a -> Char -> a
- Math.Algebra.Jack: zonal :: (Fractional a, Ord a) => [a] -> Partition -> a
+ Math.Algebra.Jack: zonal :: C a => [a] -> Partition -> a
- Math.Algebra.Jack.HypergeoPQ: hypergeoPQ :: (Fractional a, Ord a) => Int -> [a] -> [a] -> [a] -> a
+ Math.Algebra.Jack.HypergeoPQ: hypergeoPQ :: C a => Int -> [a] -> [a] -> [a] -> a
- Math.Algebra.JackPol: jackPol :: forall a. (Fractional a, Ord a, C a) => Int -> Partition -> a -> Spray a
+ Math.Algebra.JackPol: jackPol :: forall a. (Eq a, C a) => Int -> Partition -> a -> Char -> Spray a
- Math.Algebra.JackPol: zonalPol :: (Fractional a, Ord a, C a) => Int -> Partition -> Spray a
+ Math.Algebra.JackPol: zonalPol :: forall a. (Eq a, C a) => Int -> Partition -> Spray a

Files

CHANGELOG.md view
@@ -27,4 +27,11 @@ 
 1.1.2.0
 -------
-* skew Schur polynomials (functions `skewSchur` and `skewSchurPol`)+* skew Schur polynomials (functions `skewSchur` and `skewSchurPol`)
+
+1.2.0.0
+-------
+* it is now possible to choose which Jack polynomial to get or evaluate, `J`, `C`, `P` or `Q` 
+(the previous versions returned `J` only)
+
+* it is now possible to get Jack polynomials with a symbolic Jack parameter
README.md view
@@ -16,21 +16,41 @@ 
 ```haskell
 import Math.Algebra.Jack
-import Data.Ratio
-jack [1, 1] [3, 1] (2%1)
+jack' [1, 1] [3, 1] 2 'J'
 -- 48 % 1
 ```
 
 ```haskell
 import Math.Algebra.JackPol
-import Data.Ratio
 import Math.Algebra.Hspray
-jp = jackPol 2 [3, 1] (2%1)
+jp = jackPol' 2 [3, 1] 2 'J'
 putStrLn $ prettySpray' jp
 -- (18 % 1) x1^3x2 + (12 % 1) x1^2x2^2 + (18 % 1) x1x2^3
 evalSpray jp [1, 1]
 -- 48 % 1
 ```
+
+As of version `1.2.0.0`, it is possible to get Jack polynomials with a symbolic Jack parameter:
+
+```haskell
+import Math.Algebra.JackSymbolicPol
+import Math.Algebra.Hspray
+jp = jackSymbolicPol' 2 [3, 1] 'J'
+putStrLn $ prettySymbolicQSpray "a" jp
+-- ((2) + (4)a + (2)a^2)*x1^3x2 + ((4) + (4)a)*x1^2x2^2 + ((2) + (4)a + (2)a^2)*x1x2^3
+putStrLn $ prettySpray' $ evalSymbolicSpray jp 2
+-- (18 % 1) x1^3x2 + (12 % 1) x1^2x2^2 + (18 % 1) x1x2^3
+```
+
+From the definition of Jack polynomials, as well as from their implementation in this package, 
+the coefficients of the Jack polynomials are fractions of polynomials in the Jack parameter. 
+However, in the above example, one can see that the coefficients of the Jack polynomial `jp` 
+are *polynomials* in the Jack parameter `a`. 
+This fact actually is always true for the $J$-Jack polynomials (not for $C$, $P$ and $Q$). 
+This is a consequence of the Knop & Sahi combinatorial formula.
+But be aware that in spite of this fact, the coefficients of the polynomials returned by 
+Haskell are *fractions* of polynomials (the type of these polynomials is `SymbolicSpray`, 
+defined in the **hspray** package).
 
 
 ## References
jackpolynomials.cabal view
@@ -1,5 +1,5 @@ name:                jackpolynomials
-version:             1.1.2.0
+version:             1.2.0.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
@@ -19,13 +19,13 @@   exposed-modules:     Math.Algebra.Jack.HypergeoPQ
                      , Math.Algebra.Jack
                      , Math.Algebra.JackPol
+                     , Math.Algebra.JackSymbolicPol
   other-modules:       Math.Algebra.Jack.Internal
   build-depends:       base >= 4.7 && < 5
                      , ilist >= 0.4.0.1 && < 0.4.1
                      , array >= 0.5.4.0 && < 0.6
                      , lens >= 5.0.1 && < 5.3
-                     , math-functions >= 0.3.4.2 && < 0.3.5
-                     , hspray >= 0.2.2.0 && < 1
+                     , hspray >= 0.2.5.0 && < 1
                      , numeric-prelude >= 0.4.4 && < 0.5
                      , combinat >= 0.2.10 && < 0.3
                      , containers >= 0.6.4.1 && < 0.8
@@ -50,9 +50,17 @@                       , tasty >= 1.4 && < 1.6
                       , tasty-hunit >= 0.10 && < 0.11
                       , jackpolynomials
-                      , hspray >= 0.2.2.0 && < 1
+                      , hspray >= 0.2.5.0 && < 1
                       , hypergeomatrix >= 1.1.0.2 && < 2
   Default-Language:     Haskell2010
+  ghc-options:         -Wall
+                       -Wcompat
+                       -Widentities
+                       -Wincomplete-record-updates
+                       -Wincomplete-uni-patterns
+                       -Wmissing-home-modules
+                       -Wpartial-fields
+                       -Wredundant-constraints
 
 source-repository head
   type:     git
src/Math/Algebra/Jack.hs view
@@ -12,51 +12,70 @@ {-# LANGUAGE BangPatterns        #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 module Math.Algebra.Jack
-  (jack, zonal, schur, skewSchur)
+  (jack', zonal', schur', skewSchur', jack, zonal, schur, skewSchur)
   where
-import qualified Algebra.Additive as AA
-import qualified Algebra.Ring     as AR
-import Control.Lens               ( (.~), element )
-import Data.Array                 ( Array, (!), (//), listArray )
-import Data.Maybe                 ( fromJust, isJust )
-import qualified Data.Map.Strict  as DM
-import Math.Algebra.Jack.Internal ( _N, hookLengths
-                                  , _betaratio, _isPartition
-                                  , Partition, skewSchurLRCoefficients
-                                  , isSkewPartition, _fromInt )
-import Numeric.SpecFunctions      ( factorial )
+import           Prelude 
+  hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger)
+import           Algebra.Additive           ( (+), (-), sum, zero )
+import           Algebra.Ring               ( (*), product, one, (^), fromInteger )
+import           Algebra.ToInteger          ( fromIntegral ) 
+import qualified Algebra.Field              as AlgField
+import qualified Algebra.Ring               as AlgRing
+import           Control.Lens               ( (.~), element )
+import           Data.Array                 ( Array, (!), (//), listArray )
+import           Data.Maybe                 ( fromJust, isJust )
+import qualified Data.Map.Strict            as DM
+import           Math.Algebra.Jack.Internal ( (.^), _N, jackCoeffC
+                                            , jackCoeffP, jackCoeffQ
+                                            , _betaratio, _isPartition
+                                            , Partition, skewSchurLRCoefficients
+                                            , isSkewPartition, _fromInt )
 
 -- | Evaluation of Jack polynomial
-jack :: forall a. (Fractional a, Ord a) 
+jack' 
+  :: [Rational] -- ^ values of the variables
+  -> Partition  -- ^ partition of integers
+  -> Rational   -- ^ Jack parameter
+  -> Char       -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
+  -> Rational
+jack' = jack
+
+-- | Evaluation of Jack polynomial
+jack :: forall a. AlgField.C a
   => [a]       -- ^ values of the variables
   -> Partition -- ^ partition of integers
-  -> a         -- ^ alpha parameter
+  -> a         -- ^ Jack parameter
+  -> Char      -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
   -> a
-jack []       _      _     = error "jack: empty list of variables"
-jack x@(x0:_) lambda alpha =
-  case _isPartition lambda && alpha > 0 of
-    False -> if _isPartition lambda
-      then error "jack: alpha must be strictly positive"
-      else error "jack: invalid integer partition"
-    True -> jac (length x) 0 lambda lambda arr0 1
+jack []       _      _     _     = error "jack: empty list of variables"
+jack x@(x0:_) lambda alpha which =
+  case _isPartition lambda of
+    False -> error "jack: invalid integer partition"
+    True -> case which of 
+      'J' -> resultJ
+      'C' -> jackCoeffC lambda alpha * resultJ
+      'P' -> jackCoeffP lambda alpha * resultJ
+      'Q' -> jackCoeffQ lambda alpha * resultJ
+      _   -> error "jack: please use 'J', 'C', 'P' or 'Q' for last argument"
       where
+      resultJ = jac (length x) 0 lambda lambda arr0 one
       nll = _N lambda lambda
       n = length x
       arr0 = listArray ((1, 1), (nll, n)) (replicate (nll * n) Nothing)
       theproduct :: Int -> a
       theproduct nu0 = if nu0 <= 1
-        then 1
-        else product $ map (\i -> alpha * fromIntegral i + 1) [1 .. nu0-1]
+        then one
+        else product $ map (\i -> one + i .^ alpha) [1 .. nu0-1]
       jac :: Int -> Int -> [Int] -> [Int] -> Array (Int,Int) (Maybe a) -> a -> a
       jac m k mu nu arr beta
-        | null nu || nu!!0 == 0 || m == 0 = 1
-        | length nu > m && nu!!m > 0 = 0
-        | m == 1 = x0 ^ (nu!!0) * theproduct (nu!!0)
+        | null nu || nu!!0 == 0 || m == 0 = one
+        | length nu > m && nu!!m > 0      = zero
+        | m == 1 = x0 ^ (fromIntegral $ nu!!0) * theproduct (nu!!0)
         | k == 0 && isJust (arr ! (_N lambda nu, m)) =
                       fromJust $ arr ! (_N lambda nu, m)
         | otherwise = s
           where
-            s = go (jac (m-1) 0 nu nu arr 1 * beta * x!!(m-1) ^ (sum mu - sum nu))
+            s = go (jac (m-1) 0 nu nu arr one * beta * x!!(m-1) ^ (fromIntegral $ sum mu - sum nu))
                 (max 1 k)
             go :: a -> Int -> a
             go !ss ii
@@ -73,30 +92,41 @@                       else
                         if nu' !! 0 == 0
                           then
-                            go (ss + gamma * x!!(m-1)^ sum mu) (ii + 1)
+                            go (ss + gamma * x!!(m-1)^ (fromIntegral $ sum mu)) (ii + 1)
                           else
                             let arr' = arr // [((_N lambda nu, m), Just ss)] in
-                            let jck = jac (m-1) 0 nu' nu' arr' 1 in
+                            let jck = jac (m-1) 0 nu' nu' arr' one in
                             let jck' = jck * gamma *
-                                        x!!(m-1) ^ (sum mu - sum nu') in
-                            go (ss+jck') (ii+1)
+                                        x!!(m-1) ^ (fromIntegral $ sum mu - sum nu') in
+                            go (ss + jck') (ii + 1)
                   else
-                    go ss (ii+1)
+                    go ss (ii + 1)
 
 -- | Evaluation of zonal polynomial
-zonal :: (Fractional a, Ord a) 
+zonal' 
+  :: [Rational] -- ^ values of the variables
+  -> Partition  -- ^ partition of integers
+  -> Rational
+zonal' = zonal
+
+-- | Evaluation of zonal polynomial
+zonal :: AlgField.C a
   => [a]       -- ^ values of the variables
   -> Partition -- ^ partition of integers
   -> a
-zonal x lambda = c * jck
+zonal x lambda = jackCoeffC lambda alpha * jack x lambda alpha 'J'
   where
-    k = sum lambda
-    jlambda = product (hookLengths lambda 2)
-    c = 2^k * realToFrac (factorial k) / jlambda
-    jck = jack x lambda 2
+    alpha = fromInteger 2
 
 -- | Evaluation of Schur polynomial
-schur :: forall a. AR.C a 
+schur'
+  :: [Rational] -- ^ values of the variables
+  -> Partition  -- ^ partition of integers 
+  -> Rational
+schur' = schur
+
+-- | Evaluation of Schur polynomial
+schur :: forall a. AlgRing.C a 
   => [a]       -- ^ values of the variables
   -> Partition -- ^ partition of integers 
   -> a
@@ -111,9 +141,9 @@         arr0 = listArray ((1, 1), (nll, n)) (replicate (nll * n) Nothing)
         sch :: Int -> Int -> [Int] -> Array (Int,Int) (Maybe a) -> a
         sch m k nu arr
-          | null nu || nu!!0 == 0 || m == 0 = AR.one
-          | length nu > m && nu!!m > 0 = AA.zero
-          | m == 1 = AR.product (replicate (nu!!0) x0)
+          | null nu || nu!!0 == 0 || m == 0 = one
+          | length nu > m && nu!!m > 0 = zero
+          | m == 1 = product (replicate (nu!!0) x0)
           | isJust (arr ! (_N lambda nu, m)) = fromJust $ arr ! (_N lambda nu, m)
           | otherwise = s
             where
@@ -128,29 +158,37 @@                       let nu' = (element (ii-1) .~ u-1) nu in
                       if u > 1
                         then
-                          go (ss AA.+ x!!(m-1) AR.* sch m ii nu' arr) (ii + 1)
+                          go (ss + x!!(m-1) * sch m ii nu' arr) (ii + 1)
                         else
                           if nu' !! 0 == 0
                             then
-                              go (ss AA.+ x!!(m-1)) (ii + 1)
+                              go (ss + x!!(m-1)) (ii + 1)
                             else
                               let arr' = arr // [((_N lambda nu, m), Just ss)] in
-                              go (ss AA.+ x!!(m-1) AR.* sch (m-1) 1 nu' arr') (ii + 1)
+                              go (ss + x!!(m-1) * sch (m-1) 1 nu' arr') (ii + 1)
                     else
-                      go ss (ii+1)
+                      go ss (ii + 1)
 
 -- | Evaluation of a skew Schur polynomial
-skewSchur :: forall a. AR.C a 
+skewSchur' 
+  :: [Rational] -- ^ values of the variables
+  -> Partition  -- ^ the outer partition of the skew partition
+  -> Partition  -- ^ the inner partition of the skew partition
+  -> Rational
+skewSchur' = skewSchur
+
+-- | Evaluation of a skew Schur polynomial
+skewSchur :: forall a. AlgRing.C a 
   => [a]       -- ^ values of the variables
   -> Partition -- ^ the outer partition of the skew partition
   -> Partition -- ^ the inner partition of the skew partition
   -> a
 skewSchur xs lambda mu = 
   if isSkewPartition lambda mu 
-    then DM.foldlWithKey' f AA.zero lrCoefficients
+    then DM.foldlWithKey' f zero lrCoefficients
     else error "skewSchur: invalid skew partition"
   where
     lrCoefficients = skewSchurLRCoefficients lambda mu
     f :: a -> Partition -> Int -> a
-    f x nu k = x AA.+ (_fromInt k) AR.* (schur xs nu)
+    f x nu k = x + (_fromInt k) * (schur xs nu)
 
src/Math/Algebra/Jack/HypergeoPQ.hs view
@@ -1,17 +1,23 @@ module Math.Algebra.Jack.HypergeoPQ
   ( hypergeoPQ
   ) where
+import Prelude hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger)
+import           Algebra.Additive           
+import           Algebra.Field              
+import           Algebra.Ring
+import           Algebra.ToInteger           
+import qualified Algebra.Field                  as AlgField
 import           Math.Algebra.Jack              ( zonal )
 
-gpochhammer :: Fractional a => a -> [Int] -> a -> a
+gpochhammer :: AlgField.C a => a -> [Int] -> a -> a
 gpochhammer a kappa alpha = product $ map
   (\i -> product $ map
-    (\j -> a - (fromIntegral i - 1) / alpha + fromIntegral j - 1)
+    (\j -> a - (fromIntegral (i - 1)) / alpha + fromIntegral (j - 1))
     [1 .. kappa !! (i - 1)]
   )
   [1 .. length kappa]
 
-hcoeff :: Fractional a => [a] -> [a] -> [Int] -> a -> a
+hcoeff :: AlgField.C a => [a] -> [a] -> [Int] -> a -> a
 hcoeff a b kappa alpha = numerator / denominator / 
   fromIntegral (factorial (sum kappa))
  where
@@ -26,8 +32,8 @@   parts n = [n] : [ x : p | x <- [1 .. n], p <- ps !! (n - x), x <= p!!0 ]
 
 -- | Inefficient hypergeometric function of a matrix argument (for testing purpose)
-hypergeoPQ :: (Fractional a, Ord a) => Int -> [a] -> [a] -> [a] -> a
+hypergeoPQ :: AlgField.C a => Int -> [a] -> [a] -> [a] -> a
 hypergeoPQ m a b x = sum $ map (\kappa -> coeff kappa * zonal x kappa) kappas
  where
   kappas      = filter (\kap -> length kap <= length x) (_allPartitions m)
-  coeff kappa = hcoeff a b kappa 2
+  coeff kappa = hcoeff a b kappa (fromInteger 2)
src/Math/Algebra/Jack/Internal.hs view
@@ -1,33 +1,55 @@-{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BangPatterns        #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 module Math.Algebra.Jack.Internal
   (Partition
-  , hookLengths
+  , jackCoeffP
+  , jackCoeffQ
+  , jackCoeffC
+  , jackSymbolicCoeffC
+  , jackSymbolicCoeffPinv
+  , jackSymbolicCoeffQinv
   , _betaratio
+  , _betaRatioOfPolynomials
   , _isPartition
   , _N
+  , (.^)
   , _fromInt
   , skewSchurLRCoefficients
   , isSkewPartition)
   where
-import qualified Algebra.Additive                            as AA
-import qualified Algebra.Ring                                as AR
+import           Prelude 
+  hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger, recip)
+import           Algebra.Additive                            ( (+), (-), sum )
+import           Algebra.Field                               ( (/), recip )
+import           Algebra.Ring                                ( (*), product, one, (^), fromInteger )
+import           Algebra.ToInteger                           ( fromIntegral )
+import qualified Algebra.Additive                            as AlgAdd
+import qualified Algebra.Field                               as AlgField
+import qualified Algebra.Ring                                as AlgRing
 import           Data.List.Index                             ( iconcatMap )
-import qualified Math.Combinat.Partitions.Integer            as MCP
-import           Math.Combinat.Tableaux.LittlewoodRichardson (_lrRule)
 import qualified Data.Map.Strict                             as DM
+import           Math.Algebra.Hspray                         ( 
+                                                               RatioOfPolynomials
+                                                             , Polynomial
+                                                             , outerVariable
+                                                             , constPoly
+                                                             )
+import qualified Math.Combinat.Partitions.Integer            as MCP
+import           Math.Combinat.Tableaux.LittlewoodRichardson ( _lrRule )
+import           Number.Ratio                                ( T( (:%) ) )
 
 type Partition = [Int]
 
 _isPartition :: Partition -> Bool
-_isPartition []  = True
-_isPartition [x] = x > 0
+_isPartition []           = True
+_isPartition [x]          = x > 0
 _isPartition (x:xs@(y:_)) = (x >= y) && _isPartition xs
 
 _diffSequence :: [Int] -> [Int]
 _diffSequence = go where
   go (x:ys@(y:_)) = (x-y) : go ys 
-  go [x] = [x]
-  go []  = []
+  go [x]          = [x]
+  go []           = []
 
 _dualPartition :: Partition -> Partition
 _dualPartition [] = []
@@ -44,7 +66,7 @@     concatMap (\a -> [1 .. a]) (filter (>0) lambda)
   )
 
-_convParts :: Num b => [Int] -> ([b], [b])
+_convParts :: AlgRing.C b => [Int] -> ([b], [b])
 _convParts lambda =
   (map fromIntegral lambda, map fromIntegral (_dualPartition lambda))
 
@@ -53,42 +75,136 @@   where
   prods = map (\i -> product $ drop i (map (+1) lambda)) [1 .. length lambda]
 
-hookLengths :: Fractional a => Partition -> a -> [a]
-hookLengths lambda alpha = upper ++ lower
+hookLengths :: AlgRing.C a => Partition -> a -> ([a], [a])
+hookLengths lambda alpha = (lower, upper)
   where
     (i, j) = _ij lambda
     (lambda', lambdaConj') = _convParts lambda
     upper = zipWith (fup lambdaConj' lambda') i j
       where
         fup x y ii jj =
-          x!!(jj-1) - fromIntegral ii + alpha * (y!!(ii-1) - fromIntegral jj + 1)
+          x!!(jj-1) - fromIntegral ii + alpha * (y!!(ii-1) - fromIntegral (jj - 1))
     lower = zipWith (flow lambdaConj' lambda') i j
       where
         flow x y ii jj =
-          x!!(jj-1) - fromIntegral ii + 1 + alpha * (y!!(ii-1) - fromIntegral jj)
+          x!!(jj-1) - (fromIntegral $ ii - 1) + alpha * (y!!(ii-1) - fromIntegral jj)
 
-_betaratio :: Fractional a => Partition -> Partition -> Int -> a -> a
+_productHookLengths :: AlgRing.C a => Partition -> a -> a
+_productHookLengths lambda alpha = product lower * product upper
+  where
+    (lower, upper) = hookLengths lambda alpha
+
+jackCoeffC :: AlgField.C a => Partition -> a -> a
+jackCoeffC lambda alpha = 
+  alpha^k * fromInteger (product [2 .. k]) * recip jlambda
+  where
+    k = fromIntegral (sum lambda)
+    jlambda = _productHookLengths lambda alpha
+
+jackCoeffP :: AlgField.C a => Partition -> a -> a
+jackCoeffP lambda alpha = one / product lower
+  where
+    (lower, _) = hookLengths lambda alpha
+
+jackCoeffQ :: AlgField.C a => Partition -> a -> a
+jackCoeffQ lambda alpha = one / product upper
+  where
+    (_, upper) = hookLengths lambda alpha
+
+symbolicHookLengthsProducts :: forall a. AlgRing.C a 
+  => Partition -> (Polynomial a, Polynomial a)
+symbolicHookLengthsProducts lambda = (product lower, product upper)
+  where
+    alpha = outerVariable :: Polynomial a
+    (i, j) = _ij lambda
+    (lambda', lambdaConj') = _convParts lambda
+    upper = zipWith (fup lambdaConj' lambda') i j
+      where
+        fup x y ii jj =
+          constPoly (x!!(jj-1) - fromIntegral ii) 
+            + constPoly (y!!(ii-1) - fromIntegral (jj - 1)) * alpha
+    lower = zipWith (flow lambdaConj' lambda') i j
+      where
+        flow x y ii jj =
+          constPoly (x!!(jj-1) - fromIntegral (ii - 1)) 
+            + constPoly (y!!(ii-1) - fromIntegral jj) * alpha
+
+symbolicHookLengthsProduct :: AlgRing.C a => Partition -> Polynomial a
+symbolicHookLengthsProduct lambda = fst hlproducts * snd hlproducts
+  where
+    hlproducts = symbolicHookLengthsProducts lambda
+
+jackSymbolicCoeffC :: forall a. AlgField.C a => Partition -> RatioOfPolynomials a
+jackSymbolicCoeffC lambda = 
+  (constPoly (fromInteger factorialk) * alpha^k) :% jlambda
+  where
+    alpha      = outerVariable :: Polynomial a
+    k          = fromIntegral (sum lambda)
+    factorialk = product [2 .. k]
+    jlambda    = symbolicHookLengthsProduct lambda
+
+jackSymbolicCoeffPinv :: AlgField.C a => Partition -> Polynomial a
+jackSymbolicCoeffPinv lambda = fst $ symbolicHookLengthsProducts lambda
+
+jackSymbolicCoeffQinv :: AlgField.C a => Partition -> Polynomial a 
+jackSymbolicCoeffQinv lambda = snd $ symbolicHookLengthsProducts lambda
+
+_betaratio :: AlgField.C a => Partition -> Partition -> Int -> a -> a
 _betaratio kappa mu k alpha = alpha * prod1 * prod2 * prod3
   where
     mukm1 = mu !! (k-1)
     t = fromIntegral k - alpha * fromIntegral mukm1
-    u = zipWith (\s kap -> t + 1 - fromIntegral s + alpha * fromIntegral kap)
+    u = zipWith (\s kap -> t + one - fromIntegral s + alpha * fromIntegral kap)
                 [1 .. k] kappa 
     v = zipWith (\s m -> t - fromIntegral s + alpha * fromIntegral m)
                 [1 .. k-1] mu 
     w = zipWith (\s m -> fromIntegral m - t - alpha * fromIntegral s)
                 [1 .. mukm1-1] (_dualPartition mu)
-    prod1 = product $ map (\x -> x / (x + alpha - 1)) u
+    prod1 = product $ map (\x -> x / (x + alpha - one)) u
     prod2 = product $ map (\x -> (x + alpha) / x) v
     prod3 = product $ map (\x -> (x + alpha) / x) w
 
-(.^) :: AA.C a => Int -> a -> a
+_betaRatioOfPolynomials :: forall a. AlgField.C a
+  => Partition -> Partition -> Int -> RatioOfPolynomials a
+_betaRatioOfPolynomials kappa mu k = 
+  ((x * num1 * num2 * num3) :% (den1 * den2 * den3))
+  where
+    mukm1 = mu !! (k-1)
+    x = outerVariable :: Polynomial a
+    t = constPoly (fromIntegral k) - constPoly (fromIntegral mukm1) * x
+    u = zipWith 
+        (
+        \s kap -> 
+          t - constPoly (fromIntegral $ s-1) + constPoly (fromIntegral kap) * x
+        )
+        [1 .. k] kappa 
+    v = zipWith 
+        (
+        \s m -> t - constPoly (fromIntegral s) + constPoly (fromIntegral m) * x
+        )
+        [1 .. k-1] mu 
+    w = zipWith 
+        (
+        \s m -> constPoly (fromIntegral m) - t - constPoly (fromIntegral s) * x
+        )
+        [1 .. mukm1-1] (_dualPartition mu)
+    num1 = product u
+    den1 = product $ map (\p -> p + x - constPoly one) u
+    num2 = product $ map (\p -> p + x) v
+    den2 = product v
+    num3 = product $ map (\p -> p + x) w
+    den3 = product w
+    -- prod1 = product $ map (\x -> x / (x + alpha - one)) u
+    -- prod2 = product $ map (\x -> (x + alpha) / x) v
+    -- prod3 = product $ map (\x -> (x + alpha) / x) w
+
+(.^) :: AlgAdd.C a => Int -> a -> a
 (.^) k x = if k >= 0
-  then AA.sum (replicate k x)
-  else AA.negate $ AA.sum (replicate (-k) x)
+  then AlgAdd.sum (replicate k x)
+  else AlgAdd.negate $ AlgAdd.sum (replicate (-k) x)
 
-_fromInt :: AR.C a => Int -> a
-_fromInt k = k .^ AR.one
+_fromInt :: AlgRing.C a => Int -> a
+_fromInt k = k .^ AlgRing.one
 
 skewSchurLRCoefficients :: Partition -> Partition -> DM.Map Partition Int
 skewSchurLRCoefficients lambda mu = 
src/Math/Algebra/JackPol.hs view
@@ -12,53 +12,74 @@ {-# LANGUAGE BangPatterns        #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 module Math.Algebra.JackPol
-  (jackPol, zonalPol, schurPol, skewSchurPol)
+  ( jackPol', zonalPol', schurPol', skewSchurPol'
+  , jackPol, zonalPol, schurPol, skewSchurPol )
   where
-import qualified Algebra.Module             as AM
-import qualified Algebra.Ring               as AR
+import           Prelude 
+  hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger)
+import           Algebra.Additive           ( (+), (-), sum )
+import           Algebra.Module             ( (*>) )
+import           Algebra.Ring               ( (*), product, one, fromInteger )
+import qualified Algebra.Module             as AlgMod
+import qualified Algebra.Field              as AlgField
+import qualified Algebra.Ring               as AlgRing
 import           Control.Lens               ( (.~), element )
 import           Data.Array                 ( Array, (!), (//), listArray )
 import qualified Data.Map.Strict            as DM
 import           Data.Maybe                 ( fromJust, isJust )
-import           Math.Algebra.Jack.Internal ( _betaratio, hookLengths, _N
-                                            , _isPartition, Partition
+import           Math.Algebra.Jack.Internal ( (.^), _betaratio, jackCoeffC
+                                            , _N, _isPartition, Partition
+                                            , jackCoeffP, jackCoeffQ
                                             , skewSchurLRCoefficients
                                             , isSkewPartition, _fromInt )
 import           Math.Algebra.Hspray        ( (*^), (^**^), (^*^), (^+^)
                                             , lone, Spray
                                             , zeroSpray, unitSpray )
-import           Numeric.SpecFunctions      ( factorial )
 
 -- | Symbolic Jack polynomial
-jackPol :: forall a. (Fractional a, Ord a, AR.C a) 
+jackPol' 
+  :: Int       -- ^ number of variables
+  -> Partition -- ^ partition of integers
+  -> Rational  -- ^ Jack parameter
+  -> Char      -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
+  -> Spray Rational
+jackPol' = jackPol
+
+-- | Symbolic Jack polynomial
+jackPol :: forall a. (Eq a, AlgField.C a)
   => Int       -- ^ number of variables
   -> Partition -- ^ partition of integers
-  -> a         -- ^ alpha parameter
+  -> a         -- ^ Jack parameter
+  -> Char      -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
   -> Spray a
-jackPol n lambda alpha =
-  case _isPartition lambda && alpha > 0 of
-    False -> if _isPartition lambda
-      then error "jackPol: alpha must be strictly positive"
-      else error "jackPol: invalid integer partition"
-    True -> jac (length x) 0 lambda lambda arr0 1
+jackPol n lambda alpha which =
+  case _isPartition lambda of
+    False -> error "jackPol: invalid integer partition"
+    True -> case which of 
+      'J' -> resultJ
+      'C' -> jackCoeffC lambda alpha *> resultJ
+      'P' -> jackCoeffP lambda alpha *> resultJ
+      'Q' -> jackCoeffQ lambda alpha *> resultJ
+      _   -> error "jackPol: please use 'J', 'C', 'P' or 'Q' for last argument"
       where
+      resultJ = jac (length x) 0 lambda lambda arr0 one
       nll = _N lambda lambda
       x = map lone [1 .. n] :: [Spray a]
       arr0 = listArray ((1, 1), (nll, n)) (replicate (nll * n) Nothing)
       theproduct :: Int -> a
       theproduct nu0 = if nu0 <= 1
-        then 1
-        else product $ map (\i -> alpha * fromIntegral i + 1) [1 .. nu0-1]
+        then one
+        else product $ map (\i -> i .^ alpha + one) [1 .. nu0-1]
       jac :: Int -> Int -> Partition -> Partition -> Array (Int,Int) (Maybe (Spray a)) -> a -> Spray a
       jac m k mu nu arr beta
         | null nu || nu!!0 == 0 || m == 0 = unitSpray
-        | length nu > m && nu!!m > 0 = zeroSpray
-        | m == 1 = theproduct (nu!!0) *^ (x!!0 ^**^ nu!!0) 
+        | length nu > m && nu!!m > 0      = zeroSpray
+        | m == 1                          = theproduct (nu!!0) *^ (x!!0 ^**^ nu!!0) 
         | k == 0 && isJust (arr ! (_N lambda nu, m)) =
                       fromJust $ arr ! (_N lambda nu, m)
         | otherwise = s
           where
-            s = go (beta *^ (jac (m-1) 0 nu nu arr 1 ^*^ ((x!!(m-1)) ^**^ (sum mu - sum nu))))
+            s = go (beta *^ (jac (m-1) 0 nu nu arr one ^*^ ((x!!(m-1)) ^**^ (sum mu - sum nu))))
                 (max 1 k)
             go :: Spray a -> Int -> Spray a
             go !ss ii
@@ -67,7 +88,7 @@                 let u = nu!!(ii-1) in
                 if length nu == ii && u > 0 || u > nu!!ii
                   then
-                    let nu' = (element (ii-1) .~ u-1) nu in
+                    let nu'   = (element (ii-1) .~ u-1) nu in
                     let gamma = beta * _betaratio mu nu ii alpha in
                     if u > 1
                       then
@@ -78,27 +99,39 @@                             go (ss ^+^ (gamma *^ (x!!(m-1) ^**^ sum mu))) (ii + 1)
                           else
                             let arr' = arr // [((_N lambda nu, m), Just ss)] in
-                            let jck = jac (m-1) 0 nu' nu' arr' 1 in
+                            let jck  = jac (m-1) 0 nu' nu' arr' one in
                             let jck' = gamma *^ (jck ^*^ 
                                         (x!!(m-1) ^**^ (sum mu - sum nu'))) in
-                            go (ss ^+^ jck') (ii+1)
+                            go (ss ^+^ jck') (ii + 1)
                   else
-                    go ss (ii+1)
+                    go ss (ii + 1)
 
 -- | Symbolic zonal polynomial
-zonalPol :: (Fractional a, Ord a, AR.C a) 
+zonalPol' 
+  :: Int       -- ^ number of variables
+  -> Partition -- ^ partition of integers
+  -> Spray Rational
+zonalPol' = zonalPol
+
+-- | Symbolic zonal polynomial
+zonalPol :: forall a. (Eq a, AlgField.C a) 
   => Int       -- ^ number of variables
   -> Partition -- ^ partition of integers
   -> Spray a
-zonalPol n lambda = c *^ jck
+zonalPol n lambda = 
+  jackCoeffC lambda alpha *> jackPol n lambda alpha 'J'
   where
-    k = sum lambda
-    jlambda = product (hookLengths lambda 2)
-    c = 2^k * realToFrac (factorial k) / jlambda
-    jck = jackPol n lambda 2
+    alpha = fromInteger 2
 
 -- | Symbolic Schur polynomial
-schurPol :: forall a. (Ord a, AR.C a)
+schurPol' 
+  :: Int       -- ^ number of variables
+  -> Partition -- ^ partition of integers
+  -> Spray Rational
+schurPol' = schurPol
+
+-- | Symbolic Schur polynomial
+schurPol :: forall a. (Ord a, AlgRing.C a)
   => Int       -- ^ number of variables
   -> Partition -- ^ partition of integers
   -> Spray a
@@ -138,10 +171,18 @@                               let arr' = arr // [((_N lambda nu, m), Just ss)] in
                               go (ss ^+^ ((x!!(m-1)) ^*^ sch (m-1) 1 nu' arr')) (ii + 1)
                     else
-                      go ss (ii+1)
+                      go ss (ii + 1)
 
 -- | Symbolic skew Schur polynomial
-skewSchurPol :: forall a. (Ord a, AR.C a)
+skewSchurPol' 
+  :: Int       -- ^ number of variables
+  -> Partition -- ^ outer partition of the skew partition
+  -> Partition -- ^ inner partition of the skew partition
+  -> Spray Rational
+skewSchurPol' = skewSchurPol
+
+-- | Symbolic skew Schur polynomial
+skewSchurPol :: forall a. (Ord a, AlgRing.C a)
   => Int       -- ^ number of variables
   -> Partition -- ^ outer partition of the skew partition
   -> Partition -- ^ inner partition of the skew partition
@@ -153,7 +194,7 @@   where
     lrCoefficients = skewSchurLRCoefficients lambda mu
     f :: Spray a -> Partition -> Int -> Spray a
-    f spray nu k = spray ^+^ (_fromInt' k) AM.*> (schurPol n nu)
+    f spray nu k = spray ^+^ (_fromInt' k) AlgMod.*> (schurPol n nu)
     _fromInt' :: Int -> a
     _fromInt' = _fromInt
 
+ src/Math/Algebra/JackSymbolicPol.hs view
@@ -0,0 +1,109 @@+{-|
+Module      : Math.Algebra.JackSymbolicPol
+Description : Jack polynomials with symbolic Jack parameter.
+Copyright   : (c) Stéphane Laurent, 2024
+License     : GPL-3
+Maintainer  : laurent_step@outlook.fr
+
+Computation of Jack polynomials with a symbolic Jack parameter. 
+See README for examples and references.
+-}
+
+{-# LANGUAGE BangPatterns        #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module Math.Algebra.JackSymbolicPol
+  (jackSymbolicPol', jackSymbolicPol)
+  where
+import           Prelude 
+  hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger, recip)
+import           Algebra.Additive           ( (+), (-), sum )
+import           Algebra.Ring               ( (*), product, one )
+import           Algebra.ToInteger          ( fromIntegral ) 
+import qualified Algebra.Field              as AlgField
+import           Control.Lens               ( (.~), element )
+import           Data.Array                 ( Array, (!), (//), listArray )
+import           Data.Maybe                 ( fromJust, isJust )
+import           Math.Algebra.Jack.Internal ( _betaRatioOfPolynomials
+                                            , jackSymbolicCoeffC
+                                            , jackSymbolicCoeffPinv
+                                            , jackSymbolicCoeffQinv
+                                            , _N, _isPartition, Partition )
+import           Math.Algebra.Hspray        ( (*^), (^**^), (^*^), (^+^)
+                                            , lone, SymbolicSpray, SymbolicQSpray
+                                            , Polynomial, outerVariable
+                                            , constPoly, RatioOfPolynomials
+                                            , zeroSpray, unitSpray )
+import           Number.Ratio               ( fromValue, recip )
+
+-- | Jack polynomial with symbolic Jack parameter
+jackSymbolicPol' 
+  :: Int       -- ^ number of variables
+  -> Partition -- ^ partition of integers
+  -> Char      -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
+  -> SymbolicQSpray
+jackSymbolicPol' = jackSymbolicPol
+
+-- | Jack polynomial with symbolic Jack parameter
+jackSymbolicPol :: forall a. (Eq a, AlgField.C a) 
+  => Int       -- ^ number of variables
+  -> Partition -- ^ partition of integers
+  -> Char      -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
+  -> SymbolicSpray a
+jackSymbolicPol n lambda which =
+  case _isPartition lambda of
+    False -> error "jackSymbolicPol: invalid integer partition"
+    True -> case which of 
+      'J' -> resultJ
+      'C' -> jackSymbolicCoeffC lambda *^ resultJ
+      'P' -> recip (fromValue (jackSymbolicCoeffPinv lambda)) *^ resultJ 
+      'Q' -> recip (fromValue (jackSymbolicCoeffQinv lambda)) *^ resultJ
+      _   -> error "jackSymbolicPol: please use 'J', 'C', 'P' or 'Q' for last argument"
+      where
+      alpha = outerVariable :: Polynomial a
+      resultJ = jac (length x) 0 lambda lambda arr0 one
+      nll = _N lambda lambda
+      x = map lone [1 .. n] :: [SymbolicSpray a]
+      arr0 = listArray ((1, 1), (nll, n)) (replicate (nll * n) Nothing)
+      theproduct :: Int -> RatioOfPolynomials a
+      theproduct nu0 = if nu0 <= 1
+        then fromValue (constPoly one)
+        else fromValue $ product $ map 
+              (\i -> constPoly (fromIntegral i) * alpha + constPoly one) 
+              [1 .. nu0-1]
+      jac :: Int -> Int -> Partition -> Partition 
+             -> Array (Int,Int) (Maybe (SymbolicSpray a)) -> RatioOfPolynomials a -> SymbolicSpray a
+      jac m k mu nu arr beta
+        | null nu || nu!!0 == 0 || m == 0 = unitSpray
+        | length nu > m && nu!!m > 0      = zeroSpray
+        | m == 1                          = theproduct (nu!!0) *^ (x!!0 ^**^ nu!!0) 
+        | k == 0 && isJust (arr ! (_N lambda nu, m)) =
+                      fromJust $ arr ! (_N lambda nu, m)
+        | otherwise = s
+          where
+            s = go (beta *^ (jac (m-1) 0 nu nu arr one ^*^ ((x!!(m-1)) ^**^ (sum mu - sum nu))))
+                (max 1 k)
+            go :: SymbolicSpray a -> Int -> SymbolicSpray a
+            go !ss ii
+              | length nu < ii || nu!!(ii-1) == 0 = ss
+              | otherwise =
+                let u = nu!!(ii-1) in
+                if length nu == ii && u > 0 || u > nu!!ii
+                  then
+                    let nu'   = (element (ii-1) .~ u-1) nu in
+                    let gamma = _betaRatioOfPolynomials mu nu ii * beta in
+                    if u > 1
+                      then
+                        go (ss ^+^ jac m ii mu nu' arr gamma) (ii + 1)
+                      else
+                        if nu'!!0 == 0
+                          then
+                            go (ss ^+^ (gamma *^ (x!!(m-1) ^**^ sum mu))) (ii + 1)
+                          else
+                            let arr' = arr // [((_N lambda nu, m), Just ss)] in
+                            let jck  = jac (m-1) 0 nu' nu' arr' one in
+                            let jck' = gamma *^ (jck ^*^ 
+                                        (x!!(m-1) ^**^ (sum mu - sum nu'))) in
+                            go (ss ^+^ jck') (ii + 1)
+                  else
+                    go ss (ii + 1)
+
tests/Main.hs view
@@ -1,10 +1,15 @@ module Main where
 import Data.Ratio                               ( (%) )
 import Math.Algebra.Hspray                      ( (^+^), (*^), (^*^), (^**^), Spray, lone
-                                                , evalSpray, isSymmetricSpray )
-import Math.Algebra.Jack                        ( jack, zonal, schur, skewSchur )
+                                                , evalSpray, isSymmetricSpray
+                                                , evalSymbolicSpray, evalSymbolicSpray'
+                                                , Rational' )
+import Math.Algebra.Jack                        ( schur, skewSchur 
+                                                , jack', zonal' )
 import Math.Algebra.Jack.HypergeoPQ             ( hypergeoPQ )
-import Math.Algebra.JackPol                     ( zonalPol, jackPol, schurPol, skewSchurPol )
+import Math.Algebra.JackPol                     ( zonalPol, zonalPol', jackPol'
+                                                , schurPol, schurPol', skewSchurPol' )
+import Math.Algebra.JackSymbolicPol             ( jackSymbolicPol' )
 import Math.HypergeoMatrix                      ( hypergeomat )
 import Test.Tasty                               ( defaultMain
                                                 , testGroup
@@ -19,17 +24,29 @@ 
   "Tests"
 
-  [ testCase "jackPol" $ do
-    let jp = jackPol 2 [3, 1] (2 % 1) :: Spray Rational
+  [ 
+  testCase "jackSymbolicPol" $ do
+    let jp = jackSymbolicPol' 3 [3, 1] 'J'
+        v  = evalSymbolicSpray' jp 2 [-3, 4, 5]
+    assertEqual "" v 1488
+
+  , testCase "jackSymbolicPol C" $ do
+    let jp = jackSymbolicPol' 4 [3, 1] 'C'
+        zp = zonalPol 4 [3, 1] :: Spray Rational'
+        p  = evalSymbolicSpray jp 2 
+    assertEqual "" zp p
+
+  , testCase "jackPol" $ do
+    let jp = jackPol' 2 [3, 1] (2 % 1) 'J'
         v  = evalSpray jp [1, 1]
-    assertEqual "" v (48 % 1)
+    assertEqual "" v 48
 
   , testCase "jackPol is symmetric" $ do
-    let jp = jackPol 3 [3, 2, 1] (2 % 1) :: Spray Rational
+    let jp = jackPol' 3 [3, 2, 1] (2 % 1) 'J'
     assertBool "" (isSymmetricSpray jp)
 
   , testCase "jack" $ do
-    assertEqual "" (jack [1, 1] [3, 1] (2 % 1)) (48 % 1 :: Rational)
+    assertEqual "" (jack' [1, 1] [3, 1] (2 % 1) 'J') 48
 
   , testCase "schurPol" $ do
     let sp1 = schurPol 4 [4]
@@ -41,7 +58,7 @@     assertEqual "" v 4096
 
   , testCase "schurPol is symmetric" $ do
-    let sp = schurPol 3 [3, 2, 1] :: Spray Rational
+    let sp = schurPol' 3 [3, 2, 1] 
     assertBool "" (isSymmetricSpray sp)
 
   , testCase "schur" $ do
@@ -60,26 +77,26 @@     let x = lone 1 :: Spray Rational
         y = lone 2 :: Spray Rational
         z = lone 3 :: Spray Rational
-        skp = skewSchurPol 3 [2, 2, 1] [1, 1]
+        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
     assertEqual "" skp p 
 
   , testCase "skewSchurPol is symmetric" $ do
-    let skp = skewSchurPol 3 [3, 2, 1] [1, 1] :: Spray Rational
+    let skp = skewSchurPol' 3 [3, 2, 1] [1, 1]
     assertBool "" (isSymmetricSpray skp)
 
   , testCase "zonalPol" $ do
-    let zp1 = zonalPol 4 [3]       :: Spray Rational
-        zp2 = zonalPol 4 [2, 1]    :: Spray Rational
-        zp3 = zonalPol 4 [1, 1, 1] :: Spray Rational
+    let zp1 = zonalPol' 4 [3]       
+        zp2 = zonalPol' 4 [2, 1]    
+        zp3 = zonalPol' 4 [1, 1, 1] 
         v   = evalSpray (zp1 ^+^ zp2 ^+^ zp3) [2, 2, 2, 2]
     assertEqual "" v 512
 
   , testCase "zonal" $ do
-    let zp1 = zonal [2 % 1, 2 % 1, 2 % 1, 2 % 1] [3]
-        zp2 = zonal [2 % 1, 2 % 1, 2 % 1, 2 % 1] [2, 1]
-        zp3 = zonal [2 % 1, 2 % 1, 2 % 1, 2 % 1] [1, 1, 1] :: Rational
+    let zp1 = zonal' [2 % 1, 2 % 1, 2 % 1, 2 % 1] [3]
+        zp2 = zonal' [2 % 1, 2 % 1, 2 % 1, 2 % 1] [2, 1]
+        zp3 = zonal' [2 % 1, 2 % 1, 2 % 1, 2 % 1] [1, 1, 1] 
     assertEqual "" (zp1 + zp2 + zp3) 512
 
   , testCase "hypergeometric function" $ do