packages feed

coincident-root-loci-0.3: src/Math/RootLoci/Segre/Equivariant.hs

-- | The equivariant Segre-Schwartz-MacPherson classes
--
-- We can recover the Segre-SM classes by dividing the CSM class
-- by the total Chern class of the tangent bundle of the (smooth)
-- ambient variety.
--
-- The Segre-SM class is useful because it behaves well wrt. pullback.
--

{-# LANGUAGE ScopedTypeVariables, BangPatterns #-}
module Math.RootLoci.Segre.Equivariant where

--------------------------------------------------------------------------------

import Math.Combinat.Classes
import Math.Combinat.Numbers
import Math.Combinat.Sign
import Math.Combinat.Compositions
import Math.Combinat.Partitions.Integer
import Math.Combinat.Numbers.Series

import Data.Array (Array)
import Data.Array.IArray

import Math.RootLoci.Algebra
import Math.RootLoci.Geometry
import Math.RootLoci.Misc

import qualified Math.Algebra.Polynomial.FreeModule as ZMod

import Math.RootLoci.CSM.Equivariant.Umbral       -- this is the fastest one

--------------------------------------------------------------------------------
-- * The total Chern class

-- | Total Chern class of the representation @Sym^m C^2@ 
--
-- > c(Sym^m C^2) = \prod_{i=0}^m (1 + i*a + (m-i)*b)
--
affTotalChernClass :: ChernBase base => Int -> ZMod base
affTotalChernClass m = select1 (total , abToChern total) where
  total = product [ 1 + w | w <- affineWeights m ]

-- | Parts of the total Chern class, separated by degree
affTotalChernClassByDegree :: ChernBase base => Int -> [ZMod base]
affTotalChernClassByDegree = elems . separateGradedParts . affTotalChernClass

--------------------------------------------------------------------------------
-- * Inverse of the total Chern class

-- | Infinite power series expansion (by degree) of the multiplicative
-- inverse of the total Chern class of the representation @Sym^m C^2@
--
-- This is just the sum of all complete symmetric polynomials of the sums.
--
recipTotalChernClass :: forall base. ChernBase base => Int -> [ZMod base]
recipTotalChernClass m = pseries' coeffs where

  coeffs      = zip (map ZMod.neg prodWeights) [1..]
  prodWeights = tail (affTotalChernClassByDegree m)

-- | Another implementation of 'recipTotalChernClass'
recipTotalChernClass2 :: forall base. ChernBase base => Int -> [ZMod base]
recipTotalChernClass2 m = integralReciprocalSeries (affTotalChernClassByDegree m) where

-- | A third, very slow implementation of 'recipTotalChernClass'
recipTotalChernClassSlow :: forall base. ChernBase base => Int -> [ZMod base]
recipTotalChernClassSlow m = select2 (list , map abToChern list) where

  weights = affineWeights m
  list    = [ grade d | d <- [0..] ]

  grade :: Int -> ZMod AB
  grade d = negateIfOdd d 
          $ ZMod.sum (map mkProduct $ compositions (m+1) d)

  mkProduct es = ZMod.product [ (weightPowers!i) !! e | (i,e) <- zip [0..m] es ]

  -- much faster to cache to powers of the weights!
  weightPowers :: Array Int [ZMod AB]
  weightPowers = listArray (0,m) [ wtPowList (weights !! i) | i <- [0..m] ] 

  wtPowList :: ZMod AB -> [ZMod AB]
  wtPowList w = go 1 where { go !x = x : go (x*w) }


--------------------------------------------------------------------------------

-- | Divides a polynomial with the total chern class. As the result is an
-- infinite power series, we return it's homogeneous parts as an infinite list.
--
-- Equivalent (but should be faster than) to:
--
-- > separeteGradedParts what `mulSeries` (recipTotalChernClass m)
-- 
divideByTotalChernClass :: ChernBase base => Int -> ZMod base -> [ZMod base]
divideByTotalChernClass m what = convolveWithPSeries' coeffs numerList where

  numerArr  = separateGradedParts what
  numerList = elems numerArr

  coeffs      = zip (map ZMod.neg prodWeights) [1..]
  prodWeights = tail (affTotalChernClassByDegree m)

-- | Another, very slow implementation of 'divideByTotalChernClass'
divideByTotalChernClassSlow :: ChernBase base => Int -> ZMod base -> [ZMod base]
divideByTotalChernClassSlow m what = final where
  (0,n)     = bounds numerArr
  numerArr  = separateGradedParts what
  denomList = recipTotalChernClassSlow m
  final     = [ part d | d <- [0..] ]
  part deg  = ZMod.sum 
    [ (numerArr ! i) * (denomList !! j)   
    | j <- [ max 0 (deg-n) .. deg ] 
    , let i = deg - j 
    ]

--------------------------------------------------------------------------------
-- * Affine Segre-SM classes

-- | Affine equivariant Segre-SM class of the open strata
affineOpenSegreSM :: ChernBase base => Partition -> [ZMod base]
affineOpenSegreSM part = divideByTotalChernClass m (umbralAffOpenCSM part) where
  m = weight part

-- | Affine equivariant Segre-SM class of the zero orbit
affineZeroSegreSM :: ChernBase base => Int -> [ZMod base]
affineZeroSegreSM m = divideByTotalChernClass m (affineZeroCSM m)

-- | Affine equivariant Segre-SM class of the closure of the strata (including the zero orbit!)
affineClosedSegreSM :: ChernBase base => Partition -> [ZMod base]
affineClosedSegreSM part = divideByTotalChernClass m (umbralAffClosedCSM part) where
  m = weight part

--------------------------------------------------------------------------------