packages feed

jackpolynomials-1.4.6.0: src/Math/Algebra/JackPol.hs

{-|
Module      : Math.Algebra.JackPol
Description : Symbolic Jack polynomials.
Copyright   : (c) Stéphane Laurent, 2024
License     : GPL-3
Maintainer  : laurent_step@outlook.fr

Computation of Jack polynomials, skew Jack polynomials, zonal polynomials, 
skew zonal polynomials, Schur polynomials and skew Schur polynomials. 
See README for examples and references.
-}

{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Math.Algebra.JackPol
  ( 
  -- * Jack and skew Jack polynomials
    jackPol
  , jackPol'
  , skewJackPol
  , skewJackPol'
  -- * Zonal and skew zonal polynomials
  , zonalPol
  , zonalPol'
  , skewZonalPol
  , skewZonalPol'
  -- * Schur and skew Schur polynomials
  , schurPol
  , schurPol'
  , skewSchurPol 
  , skewSchurPol'
  )
  where
import           Prelude 
  hiding ((*), (+), (-), (/), (^), (*>), product, sum, fromIntegral, fromInteger)
import           Algebra.Additive           ( (+), (-), sum )
import qualified Algebra.Field              as AlgField
import           Algebra.Ring               ( (*), product, one, fromInteger )
import qualified Algebra.Ring               as AlgRing
import           Control.Lens               ( (.~), element )
import           Data.Array                 ( Array, (!), (//), listArray )
import qualified Data.HashMap.Strict        as HM
import qualified Data.Map.Strict            as DM
import           Data.Maybe                 ( fromJust, isJust )
import           Math.Algebra.Jack.Internal ( _betaratio, jackCoeffC
                                            , _N, _isPartition, Partition
                                            , jackCoeffP, jackCoeffQ
                                            , skewSchurLRCoefficients
                                            , isSkewPartition, _fromInt
                                            , skewJackInMSPbasis )
import           Math.Algebra.Hspray        ( FunctionLike (..), (.^)
                                            , lone, lone', Spray, QSpray
                                            , zeroSpray, unitSpray
                                            , fromList )
import           Math.Combinat.Permutations ( permuteMultiset )

-- | Jack polynomial.
jackPol' 
  :: Int       -- ^ number of variables
  -> Partition -- ^ integer partition 
  -> Rational  -- ^ Jack parameter
  -> Char      -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
  -> QSpray
jackPol' = jackPol

-- | Jack polynomial.
jackPol :: forall a. (Eq a, AlgField.C a)
  => Int       -- ^ number of variables
  -> Partition -- ^ integer partition 
  -> a         -- ^ Jack parameter
  -> Char      -- ^ which Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
  -> Spray a
jackPol n lambda alpha which 
  | n < 0 = error "jackPol: negative number of variables."
  | not (_isPartition lambda) = error "jackPol: invalid integer partition."
  | not (which `elem` ['J', 'C', 'P', 'Q']) = 
      error "jackPol: please use 'J', 'C', 'P' or 'Q' for last argument."
  | n == 0 = if null lambda
      then unitSpray
      else zeroSpray
  | otherwise =
    case which of 
      'J' -> resultJ
      'C' -> jackCoeffC lambda alpha *^ resultJ
      'P' -> jackCoeffP lambda alpha *^ resultJ
      _   -> jackCoeffQ lambda alpha *^ resultJ
      where
      jck m kappa arr = jac m 0 kappa kappa arr 
      resultJ = jck n lambda arr0 
      nll = _N lambda lambda
      arr0 = listArray ((1, 1), (nll, n)) (replicate (nll * n) Nothing)
      jac :: Int -> Int -> Partition -> Partition 
             -> Array (Int,Int) (Maybe (Spray a)) 
             -> Spray a
      jac m k mu nu arr 
        | null nu || nu0 == 0 || m == 0 = unitSpray
        | ellNu > m && nu !! m > 0      = zeroSpray
        | m == 1                        = 
            if nu0 == 1
              then 
                lone 1
              else 
                let as = [i .^ alpha + one | i <- [1 .. nu0-1]] in
                product as *^ x nu0
        | k == 0 && isJust maybe_spray =
            fromJust $ maybe_spray
        | otherwise = s
          where
            nu0 = nu !! 0
            ellNu = length nu
            x = lone' m
            _N_lambda_nu_m = (_N lambda nu, m)
            maybe_spray = arr ! _N_lambda_nu_m
            wMu = sum mu
            jck' kappa array = jck (m-1) kappa array ^*^ x (wMu - sum kappa)
            s = go (jck' nu arr) (max 1 k)
            go :: Spray a -> Int -> Spray a
            go !ss ii
              | ellNu < ii || u == 0 = 
                  ss
              | ellNu == ii && u > 0 || u > nu !! ii = 
                  go (ss ^+^ tt) (ii + 1)
              | otherwise = 
                  go ss (ii + 1)
                where
                  jj = ii - 1
                  u = nu !! jj
                  nu' = (element jj .~ u - 1) nu
                  gamma = _betaratio mu nu ii alpha
                  tt = gamma *^ spray
                    where
                      spray
                        | u > 1 =
                            jac m ii mu nu' arr 
                        | nu' !! 0 == 0 =
                            x wMu
                        | otherwise =
                            jck' nu' (arr // [(_N_lambda_nu_m, Just ss)]) 

-- | Skew Jack polynomial.
skewJackPol :: 
    (Eq a, AlgField.C a) 
  => Int       -- ^ number of variables
  -> Partition -- ^ outer partition of the skew partition
  -> Partition -- ^ inner partition of the skew partition
  -> a         -- ^ Jack parameter
  -> Char      -- ^ which skew Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
  -> Spray a
skewJackPol n lambda mu alpha which 
  | n < 0 = 
      error "skewJackPol: negative number of variables."
  | not (isSkewPartition lambda mu) = 
      error "skewJackPol: invalid skew partition."
  | not (which `elem` ['J', 'C', 'P', 'Q']) = 
      error "skewJackPol: please use 'J', 'C', 'P' or 'Q' for last argument."
  | n == 0 = 
      if lambda == mu then unitSpray else zeroSpray
  | otherwise =
      HM.unions sprays
  where
    msCombo = 
      DM.filter
        ((<= n) . fst)
          (skewJackInMSPbasis alpha which lambda mu)
    sprays = 
      map (
        \(kappa, (l, coeff)) -> 
            fromList
              (zip 
                (permuteMultiset (kappa ++ replicate (n - l) 0)) 
                (repeat coeff))
        ) (DM.assocs msCombo)

-- | Skew Jack polynomial.
skewJackPol' :: 
     Int       -- ^ number of variables
  -> Partition -- ^ outer partition of the skew partition
  -> Partition -- ^ inner partition of the skew partition
  -> Rational  -- ^ Jack parameter
  -> Char      -- ^ which skew Jack polynomial, @'J'@, @'C'@, @'P'@ or @'Q'@
  -> QSpray
skewJackPol' = skewJackPol

-- | Zonal polynomial. The zonal polynomials are the 
-- Jack \(C\)-polynomials with Jack parameter \(\alpha=2\).
zonalPol' 
  :: Int       -- ^ number of variables
  -> Partition -- ^ partition of integers
  -> QSpray
zonalPol' = zonalPol

-- | Zonal polynomial. The zonal polynomials are the 
-- Jack \(C\)-polynomials with Jack parameter \(\alpha=2\).
zonalPol :: (Eq a, AlgField.C a) 
  => Int       -- ^ number of variables
  -> Partition -- ^ partition of integers
  -> Spray a
zonalPol n lambda = 
  jackPol n lambda (fromInteger 2) 'C'

-- | Skew zonal polynomial.
skewZonalPol' 
  :: Int       -- ^ number of variables
  -> Partition -- ^ outer partition of the skew partition
  -> Partition -- ^ inner partition of the skew partition
  -> QSpray
skewZonalPol' = skewZonalPol

-- | Skew zonal polynomial.
skewZonalPol :: (Eq a, AlgField.C a) 
  => Int       -- ^ number of variables
  -> Partition -- ^ outer partition of the skew partition
  -> Partition -- ^ inner partition of the skew partition
  -> Spray a
skewZonalPol n lambda mu = 
  skewJackPol n lambda mu (fromInteger 2) 'C'

-- | Schur polynomial. The Schur polynomials are the 
-- Jack \(P\)-polynomials with Jack parameter \(\alpha=1\).
schurPol' 
  :: Int       -- ^ number of variables
  -> Partition -- ^ partition of integers
  -> QSpray 
schurPol' = schurPol

-- | Schur polynomial. The Schur polynomials are the 
-- Jack \(P\)-polynomials with Jack parameter \(\alpha=1\).
schurPol :: forall a. (Eq a, AlgRing.C a)
  => Int       -- ^ number of variables
  -> Partition -- ^ partition of integers
  -> Spray a
schurPol n lambda 
  | n < 0 = error "schurPol: negative number of variables."
  | not (_isPartition lambda) = 
      error "schurPol: invalid integer partition."
  | n == 0 = if null lambda then unitSpray else zeroSpray
  | otherwise = sch n 1 lambda arr0
      where
        nll = _N lambda lambda
        arr0 = listArray ((1, 1), (nll, n)) (replicate (nll * n) Nothing)
        sch :: 
          Int -> Int -> [Int] -> Array (Int,Int) (Maybe (Spray a)) -> Spray a
        sch m k nu arr
          | null nu || nu0 == 0 || m == 0 = unitSpray
          | ellNu > m && nu !! m > 0 = zeroSpray
          | m == 1 = lone' 1 nu0
          | isJust maybe_spray = 
              fromJust maybe_spray
          | otherwise = s
            where
              nu0 = nu !! 0
              ellNu = length nu
              x = lone m
              _N_lambda_nu_m = (_N lambda nu, m)
              maybe_spray = arr ! _N_lambda_nu_m
              sch' kappa array = sch (m-1) 1 kappa array 
              s = go (sch' nu arr) k
              go :: Spray a -> Int -> Spray a
              go !ss ii
                | ellNu < ii || u == 0 = 
                    ss
                | ellNu == ii && u > 0 || u > nu !! ii = 
                    go (ss ^+^ tt) (ii + 1)
                | otherwise = 
                    go ss (ii + 1)
                  where
                    jj = ii - 1
                    u = nu !! jj
                    nu' = (element jj .~ u - 1) nu
                    tt 
                      | u > 1 =
                          x ^*^ sch m ii nu' arr
                      | nu' !! 0 == 0 =
                          x 
                      | otherwise =
                          x ^*^ sch' nu' (arr // [(_N_lambda_nu_m, Just ss)]) 

-- | Skew Schur polynomial
skewSchurPol' 
  :: Int       -- ^ number of variables
  -> Partition -- ^ outer partition of the skew partition
  -> Partition -- ^ inner partition of the skew partition
  -> QSpray
skewSchurPol' = skewSchurPol

-- | Skew Schur polynomial
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
  -> Spray a
skewSchurPol n lambda mu =
  case isSkewPartition lambda mu of
    False -> error "skewSchurPol: invalid skew partition."
    True  -> DM.foldlWithKey' f zeroSpray lrCoefficients
  where
    lrCoefficients = skewSchurLRCoefficients lambda mu
    f :: Spray a -> Partition -> Int -> Spray a
    f spray nu k = spray ^+^ (_fromInt k) *^ (schurPol n nu)