coincident-root-loci (empty) → 0.2
raw patch · 37 files changed
+4354/−0 lines, 37 filesdep +arraydep +basedep +coincident-root-locisetup-changed
Dependencies added: array, base, coincident-root-loci, combinat, containers, random, tasty, tasty-hunit, transformers
Files
- LICENSE +29/−0
- Setup.hs +2/−0
- coincident-root-loci.cabal +100/−0
- src/Math/RootLoci/Algebra.hs +23/−0
- src/Math/RootLoci/Algebra/FreeMod.hs +214/−0
- src/Math/RootLoci/Algebra/Polynomial.hs +102/−0
- src/Math/RootLoci/Algebra/SymmPoly.hs +366/−0
- src/Math/RootLoci/CSM/Aluffi.hs +105/−0
- src/Math/RootLoci/CSM/Equivariant/Direct.hs +65/−0
- src/Math/RootLoci/CSM/Equivariant/Ordered.hs +412/−0
- src/Math/RootLoci/CSM/Equivariant/PushForward.hs +305/−0
- src/Math/RootLoci/CSM/Equivariant/Recursive.hs +97/−0
- src/Math/RootLoci/CSM/Equivariant/Umbral.hs +214/−0
- src/Math/RootLoci/CSM/Projective.hs +218/−0
- src/Math/RootLoci/Classic.hs +91/−0
- src/Math/RootLoci/Dual/Localization.hs +115/−0
- src/Math/RootLoci/Dual/Restriction.hs +223/−0
- src/Math/RootLoci/Geometry.hs +13/−0
- src/Math/RootLoci/Geometry/Cohomology.hs +279/−0
- src/Math/RootLoci/Geometry/Forget.hs +111/−0
- src/Math/RootLoci/Geometry/Mobius.hs +224/−0
- src/Math/RootLoci/Misc.hs +13/−0
- src/Math/RootLoci/Misc/Common.hs +132/−0
- src/Math/RootLoci/Misc/PTable.hs +130/−0
- src/Math/RootLoci/Misc/Pretty.hs +137/−0
- test/Tests/CSM/Equivariant.hs +91/−0
- test/Tests/CSM/Projective.hs +54/−0
- test/Tests/Common.hs +35/−0
- test/Tests/Dual.hs +54/−0
- test/Tests/Pushforward.hs +49/−0
- test/Tests/RootVsClass/Check.hs +93/−0
- test/Tests/RootVsClass/Direct.hs +36/−0
- test/Tests/RootVsClass/Ordered.hs +46/−0
- test/Tests/RootVsClass/PushForward.hs +41/−0
- test/Tests/RootVsClass/Recursive.hs +44/−0
- test/Tests/RootVsClass/Umbral.hs +42/−0
- test/testSuite.hs +49/−0
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2015-2017, Balazs Komuves+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- Neither names of the copyright holders nor the names of the contributors+may be used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ coincident-root-loci.cabal view
@@ -0,0 +1,100 @@+Name: coincident-root-loci+Version: 0.2+Synopsis: Equivariant CSM classes of coincident root loci++Description: This library contians a set of function to compute, among+ others, the @GL(2)@-equivariant Chern-Schwartz-MacPherson+ classes of coincident root loci, which are subvarieties+ of the space of unordered @n@-tuples of points in the complex+ projective line. To such an @n@-tuples we can associate + a partition of @n@ given by the multiplicities of the distinct+ points; this stratifies the set of all @n@-tuples, and we+ call these strata \"coincident root loci\".++ This package is supplementary software for a forthcoming paper.++License: BSD3+License-file: LICENSE+Author: Balazs Komuves+Copyright: (c) 2015-2017 Balazs Komuves+Maintainer: bkomuves (plus) hackage (at) gmail (dot) com+Homepage: http://code.haskell.org/~bkomuves/+Stability: Experimental+Category: Math+Tested-With: GHC == 8.0.2+Cabal-Version: >= 1.18+Build-Type: Simple++--------------------------------------------------------------------------------++Library++ Build-Depends: base >= 4 && < 5, + array >= 0.5, containers, random, transformers,+ combinat >= 0.2.8.2++ Exposed-Modules: + -- Math.RootLoci+ Math.RootLoci.Classic+ -- Math.RootLoci.Dual+ Math.RootLoci.Dual.Restriction+ Math.RootLoci.Dual.Localization+ -- Math.RootLoci.CSM+ -- Math.RootLoci.CSM.Equivariant+ Math.RootLoci.CSM.Equivariant.Direct+ Math.RootLoci.CSM.Equivariant.Recursive+ Math.RootLoci.CSM.Equivariant.Ordered+ Math.RootLoci.CSM.Equivariant.PushForward+ Math.RootLoci.CSM.Equivariant.Umbral+ Math.RootLoci.CSM.Aluffi+ Math.RootLoci.CSM.Projective+ Math.RootLoci.Geometry+ Math.RootLoci.Geometry.Forget+ Math.RootLoci.Geometry.Cohomology+ Math.RootLoci.Geometry.Mobius+ -- Math.RootLoci.Applications+ -- Math.RootLoci.Applications.FlexLines+ Math.RootLoci.Algebra+ Math.RootLoci.Algebra.FreeMod+ Math.RootLoci.Algebra.Polynomial+ Math.RootLoci.Algebra.SymmPoly+ Math.RootLoci.Misc+ Math.RootLoci.Misc.Pretty+ Math.RootLoci.Misc.PTable+ Math.RootLoci.Misc.Common++ Default-Extensions: CPP, BangPatterns+ Other-Extensions: MultiParamTypeClasses, ScopedTypeVariables, + GeneralizedNewtypeDeriving++ Default-Language: Haskell2010++ Hs-Source-Dirs: src++ ghc-options: -fwarn-tabs -fno-warn-unused-matches -fno-warn-name-shadowing -fno-warn-unused-imports+ +--------------------------------------------------------------------------------+ +test-suite test++ default-language: Haskell2010+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: testSuite.hs+ + build-depends: base >= 4 && < 5, containers >= 0.4, array >= 0.5,+ tasty >= 0.11, tasty-hunit >= 0.9,+ combinat >= 0.2.8.2,+ coincident-root-loci >= 0.2+ + other-modules: Tests.Common+ Tests.Dual+ Tests.Pushforward + Tests.CSM.Equivariant + Tests.CSM.Projective + Tests.RootVsClass.Check + Tests.RootVsClass.Direct + Tests.RootVsClass.Ordered + Tests.RootVsClass.PushForward + Tests.RootVsClass.Recursive + Tests.RootVsClass.Umbral
+ src/Math/RootLoci/Algebra.hs view
@@ -0,0 +1,23 @@++-- | Re-exporting the Algebra.* modules.+-- +-- Because of limitations of the import-export mechanism, you still have+-- to do+--+-- > import Math.RootLoci.Algebra+-- > import qualified Math.RootLoci.Algebra.FreeMod as ZMod+--++module Math.RootLoci.Algebra+ ( ZMod , QMod , FreeMod + , module Math.RootLoci.Algebra.Polynomial+ , module Math.RootLoci.Algebra.SymmPoly+-- , module ZMod -- apparently this does not work+ )+ where++import Math.RootLoci.Algebra.FreeMod ( ZMod , QMod , FreeMod )+import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Algebra.Polynomial+import Math.RootLoci.Algebra.SymmPoly
+ src/Math/RootLoci/Algebra/FreeMod.hs view
@@ -0,0 +1,214 @@++-- | Free modules. +--+-- This module should be imported qualified++{-# LANGUAGE BangPatterns, FlexibleInstances, TypeSynonymInstances #-}+module Math.RootLoci.Algebra.FreeMod where++--------------------------------------------------------------------------------++import Prelude hiding ( sum , product )+import Data.List hiding ( sum , product )++import Data.Monoid+import Data.Ratio+import Data.Maybe++import Math.Combinat.Sets ( choose )++import qualified Data.Map.Strict as Map+import Data.Map.Strict (Map)++--------------------------------------------------------------------------------++-- | Free module over a coefficient ring with the given base. Internally a map+-- storing the coefficients. We maintain the invariant that the coefficients+-- are never zero.+newtype FreeMod coeff base = FreeMod { unFreeMod :: Map base coeff } deriving (Eq,Show)++-- | Free module with integer coefficients+type ZMod base = FreeMod Integer base++-- | Free module with rational coefficients+type QMod base = FreeMod Rational base++--------------------------------------------------------------------------------++instance (Monoid b, Ord b, Eq c, Num c) => Num (FreeMod c b) where+ (+) = add+ (-) = sub+ negate = neg+ (*) = mul+ fromInteger = konst . fromInteger+ abs = error "FreeMod/abs"+ signum = error "FreeMod/signum"++--------------------------------------------------------------------------------+-- * Sanity checking++-- | Should be the identity function+normalize :: (Ord b, Eq c, Num c) => FreeMod c b -> FreeMod c b+normalize = FreeMod . Map.filter (/=0) . unFreeMod++-- | Safe equality testing (should be identical to @==@)+safeEq :: (Ord b, Eq b, Eq c, Num c) => FreeMod c b -> FreeMod c b -> Bool+safeEq x y = normalize x == normalize y++--------------------------------------------------------------------------------+-- * Constructing and deconstructing++-- | The additive unit+zero :: FreeMod c b+zero = FreeMod $ Map.empty++-- | A module generator+generator :: Num c => b -> FreeMod c b +generator x = FreeMod $ Map.singleton x 1++-- | A single generator with a coefficient+singleton :: (Ord b) => b -> c -> FreeMod c b+singleton b c = FreeMod $ Map.singleton b c++-- | Conversion from list. +-- Note that we assume here that each generator appears at most once!+fromList :: (Eq c, Num c, Ord b) => [(b,c)] -> FreeMod c b+fromList = FreeMod . Map.fromList . filter cond where+ cond (b,x) = (x/=0)++-- | Conversion to list +toList :: FreeMod c b -> [(b,c)]+toList = Map.toList . unFreeMod++-- | Extract the coefficient of a generator+coeffOf :: (Ord b, Num c) => b -> FreeMod c b -> c+coeffOf b (FreeMod x) = case Map.lookup b x of+ Just c -> c+ Nothing -> 0++-- | Finds the term with the largest generator (in the natural ordering of the generators)+findMaxTerm :: (Ord b) => FreeMod c b -> Maybe (b,c)+findMaxTerm (FreeMod m) = if Map.null m+ then Nothing+ else Just (Map.findMax m)++-- | Finds the term with the smallest generator (in the natural ordering of the generators)+findMinTerm :: (Ord b) => FreeMod c b -> Maybe (b,c)+findMinTerm (FreeMod m) = if Map.null m+ then Nothing+ else Just (Map.findMin m)++--------------------------------------------------------------------------------+-- * Basic operations++-- | Negation+neg :: Num c => FreeMod c b -> FreeMod c b +neg (FreeMod m) = FreeMod (Map.map negate m)++-- | Additions+add :: (Ord b, Eq c, Num c) => FreeMod c b -> FreeMod c b -> FreeMod c b+add (FreeMod m1) (FreeMod m2) = FreeMod (Map.mergeWithKey f id id m1 m2) where+ f _ x y = case x+y of { 0 -> Nothing ; z -> Just z }++-- | Subtraction+sub :: (Ord b, Eq c, Num c) => FreeMod c b -> FreeMod c b -> FreeMod c b+sub (FreeMod m1) (FreeMod m2) = FreeMod (Map.mergeWithKey f id (Map.map negate) m1 m2) where+ f _ x y = case x-y of { 0 -> Nothing ; z -> Just z }++-- | Scaling by a number+scale :: (Ord b, Eq c, Num c) => c -> FreeMod c b -> FreeMod c b+scale 0 _ = zero+scale x (FreeMod m) = FreeMod (Map.mapMaybe f m) where+ f y = case x*y of { 0 -> Nothing ; z -> Just z }++-- | Dividing by a number (assuming that the coefficient ring is integral, and each coefficient+-- is divisible by the given number)+invScale :: (Ord b, Eq c, Integral c, Show c) => c -> FreeMod c b -> FreeMod c b+invScale d (FreeMod m) = FreeMod (Map.mapMaybe f m) where+ f a = case divMod a d of+ (b,0) -> case b of { 0 -> Nothing ; z -> Just z }+ _ -> error $ "FreeMod/invScale: not divisible by " ++ show d++--------------------------------------------------------------------------------++-- | Summation+sum :: (Ord b, Eq c, Num c) => [FreeMod c b] -> FreeMod c b+sum [] = zero+sum zms = (foldl1' add) zms++-- | Linear combination+linComb :: (Ord b, Eq c, Num c) => [(c, FreeMod c b)] -> FreeMod c b+linComb = sumWith where++ sumWith :: (Ord b, Eq c, Num c) => [(c, FreeMod c b)] -> FreeMod c b+ sumWith [] = zero+ sumWith zms = sum [ scale c zm | (c,zm) <- zms ]++-- | Expand each generator into a term in another module and then sum the results+flatMap :: (Ord b1, Ord b2, Eq c, Num c) => (b1 -> FreeMod c b2) -> FreeMod c b1 -> FreeMod c b2+flatMap f = sum . map g . Map.assocs . unFreeMod where+ g (x,c) = scale c (f x)++flatMap' :: (Ord b1, Ord b2, Eq c2, Num c2) => (c1 -> c2) -> (b1 -> FreeMod c2 b2) -> FreeMod c1 b1 -> FreeMod c2 b2+flatMap' embed f = sum . map g . Map.assocs . unFreeMod where+ g (x,c) = scale (embed c) (f x)++-- | The histogram of a multiset of generators is naturally an element of the given Z-module.+{-# SPECIALIZE histogram :: Ord b => [b] -> ZMod b #-} +histogram :: (Ord b, Num c) => [b] -> FreeMod c b+histogram xs = FreeMod $ foldl' f Map.empty xs where+ f old x = Map.insertWith (+) x 1 old+ +--------------------------------------------------------------------------------+-- * Rings++-- | The multiplicative unit+one :: (Monoid b, Num c) => FreeMod c b+one = konst 1++-- | A constant+konst :: (Monoid b) => c -> FreeMod c b+konst c = FreeMod (Map.singleton mempty c)++-- | Multiplying two ring elements+mul :: (Ord b, Monoid b, Eq c, Num c) => FreeMod c b -> FreeMod c b -> FreeMod c b+mul xx yy = sum [ (f x c) | (x,c) <- toList xx ] where+ f x c = FreeMod $ Map.fromList [ (x<>y, cd) | (y,d) <- ylist , let cd = c*d , cd /= 0 ]+ ylist = toList yy++-- | Product+product :: (Ord b, Monoid b, Eq c, Num c) => [FreeMod c b] -> FreeMod c b+product [] = generator mempty+product xs = foldl1' mul xs++-- | Multiplies by a monomial+mulMonom :: (Ord b, Monoid b) => b -> FreeMod c b -> FreeMod c b+mulMonom monom = FreeMod . Map.mapKeys (mappend monom) . unFreeMod++--------------------------------------------------------------------------------+-- * Misc++-- | A symmetric polynomial of some generators+symPoly :: (Ord a, Monoid a) => Int -> [a] -> ZMod a+symPoly k xs = fromList $ map (\x -> (x,1)) $ (map mconcat $ choose k xs) ++-- | Changing the base set+mapBase :: (Ord a, Ord b) => (a -> b) -> FreeMod c a -> FreeMod c b+mapBase f = onFreeMod (Map.mapKeys f)++-- | Changing the coefficient ring+mapCoeff :: (Ord b) => (c1 -> c2) -> FreeMod c1 b -> FreeMod c2 b+mapCoeff f = onFreeMod' (Map.map f)++-- | Extract a subset of terms+filterBase :: (Ord a, Ord b) => (a -> Maybe b) -> FreeMod c a -> FreeMod c b+filterBase f = onFreeMod (Map.fromList . mapMaybe g . Map.toList) where+ g (k,x) = case f k of { Just k' -> Just (k',x) ; Nothing -> Nothing }++onFreeMod :: (Ord a, Ord b) => (Map a c -> Map b c) -> FreeMod c a -> FreeMod c b+onFreeMod f = FreeMod . f . unFreeMod++onFreeMod' :: (Ord a, Ord b) => (Map a c -> Map b d) -> FreeMod c a -> FreeMod d b+onFreeMod' f = FreeMod . f . unFreeMod++--------------------------------------------------------------------------------
+ src/Math/RootLoci/Algebra/Polynomial.hs view
@@ -0,0 +1,102 @@++-- | Univariate polynomials++{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Math.RootLoci.Algebra.Polynomial where++--------------------------------------------------------------------------------++import Data.Array ( assocs ) ++import Math.Combinat.Numbers++import Math.RootLoci.Misc++import qualified Math.RootLoci.Algebra.FreeMod as ZMod+import Math.RootLoci.Algebra.FreeMod ( FreeMod , ZMod , QMod )++--------------------------------------------------------------------------------+-- * Polynomials++-- | Standard univariate polynomials+newtype Poly coeff = Poly { fromPoly :: FreeMod coeff X } deriving (Eq,Num,Show)++-- | Univariate polynomials using /rising factorials/ as a basis function+newtype RisingPoly coeff = RisingPoly { fromRisingPoly :: FreeMod coeff RisingF } deriving (Eq,Show)++-- | Univariate polynomials using /falling factorials/ as a basis function+newtype FallingPoly coeff = FallingPoly { fromFallingPoly :: FreeMod coeff FallingF } deriving (Eq,Show)++instance (Num c, Show c, Eq c, IsSigned c) => Pretty (Poly c) where pretty (Poly p) = pretty p +instance (Num c, Show c, Eq c, IsSigned c) => Pretty (RisingPoly c) where pretty (RisingPoly p) = pretty p +instance (Num c, Show c, Eq c, IsSigned c) => Pretty (FallingPoly c) where pretty (FallingPoly p) = pretty p ++--------------------------------------------------------------------------------+-- * Monomials ++-- | A power of @x@ (that is, a monomial of the form @x^i@)+newtype X = X Int deriving (Eq,Ord,Show)++instance Monoid X where+ mempty = X 0+ mappend (X e) (X f) = X (e+f)++instance Pretty X where+ pretty (X e) = case e of+ 0 -> "1"+ 1 -> "x"+ _ -> "x^" ++ show e++--------------------------------------------------------------------------------+-- * Rising and falling factorials ++-- | Rising factorial @x^(k) = x(x+1)(x+2)...(x+k-1)@+newtype RisingF = RF Int deriving (Eq,Ord,Show)++-- | Falling factorial @x_(k) = x(x-1)(x-2)...(x-k+1)@+newtype FallingF = FF Int deriving (Eq,Ord,Show)++instance Pretty RisingF where+ pretty (RF k) = case k of+ 0 -> "1"+ 1 -> "x"+ _ -> "x^(" ++ show k ++ ")"++instance Pretty FallingF where+ pretty (FF k) = case k of+ 0 -> "1"+ 1 -> "x"+ _ -> "x_(" ++ show k ++ ")"++risingPoly :: RisingF -> Poly Integer+risingPoly (RF k) = Poly $ ZMod.fromList+ [ (X p, abs c) | (p,c) <- assocs (signedStirling1stArray k) ]++fallingPoly :: FallingF -> Poly Integer+fallingPoly (FF k) = Poly $ ZMod.fromList+ [ (X p, c) | (p,c) <- assocs (signedStirling1stArray k) ]++--------------------------------------------------------------------------------+-- * Lagrange interpolation++lagrangeInterp :: [(Rational,Rational)] -> Poly Rational+lagrangeInterp = Poly . lagrangeInterp'++lagrangeInterp' :: [(Rational,Rational)] -> QMod X+lagrangeInterp' xys = final where+ final = ZMod.sum [ ZMod.scale (ys!!j) (lagrangePoly' xs j) | j<-[0..m-1] ] where+ m = length xys+ (xs,ys) = unzip xys++lagrangePoly' :: [Rational] -> Int -> QMod X+lagrangePoly' xs j = ZMod.scale (1/denom) numer where+ numer = ZMod.product [ term i | i<-[0..m-1] , i /= j ]+ denom = product [ x j - x i | i<-[0..m-1] , i /= j ]+ m = length xs+ x i = xs !! i+ term i = ZMod.fromList + [ (X 1 , 1 )+ , (X 0 , - x i )+ ]++--------------------------------------------------------------------------------
+ src/Math/RootLoci/Algebra/SymmPoly.hs view
@@ -0,0 +1,366 @@++-- | Symmetric polynomials in two variables @alpha@ and @beta@.+--+-- We provide three representation:+--+-- * symmetric polynomials in @alpha@ and @beta@ (Chern roots)+--+-- * polynomials in the elementary symmetric polynomials @c1=alpha+beta@ and @c2=alpha*beta@ (Chern classes)+--+-- * Schur polynomials @s[i,j]@+--+-- The monomials of the first two of these form monoids (the product of +-- monomials is again a monomial), and can be used uniformly with the+-- help of some type-level hackery.+--+-- How to use the unified interface?+-- Suppose you have a function like this:+--+-- > tau :: ChernBase base => Int -> ZMod base+--+-- When calling it, you want to specify the output type (either @ZMod AB@ or @ZMod Chern@).+-- You can do that three ways:+--+-- > x = tau @AB 10 -- this needs -XTypeApplications+-- > x = (tau 10 :: ZMod AB)+-- > x = spec1' ChernRoot $ tau 10+--+-- The first one is the most convenient, but it only works with GHC 8 and later.+-- The other two work with older GHC versions, too.+--+++{-# LANGUAGE DataKinds, TypeFamilies, Rank2Types, GADTs, StandaloneDeriving #-}+module Math.RootLoci.Algebra.SymmPoly where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Sign+import Math.Combinat.Numbers++import qualified Data.Map.Strict as Map++import Control.Monad+import System.Random++import Math.RootLoci.Algebra.FreeMod (ZMod)+import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Misc.Pretty++import Unsafe.Coerce as Unsafe++--------------------------------------------------------------------------------+-- * Base monomials++-- | Chern roots: @alpha^i * beta^j@, monomial base of @Z[alpha,beta]@+data AB = AB !Int !Int deriving (Eq,Ord,Show)++-- | Chern classes: @c1^i * c2^j@, monomial base of @Z[c1,c2]@+data Chern = Chern !Int !Int deriving (Eq,Ord,Show)++-- | Schur basis function: @S[i,j]@+data Schur = Schur !Int !Int deriving (Eq,Ord,Show) ++alpha, beta :: AB+alpha = AB 1 0 +beta = AB 0 1 ++--------------------------------------------------------------------------------++-- | @alpha * beta = c2@+alphaBeta :: AB+alphaBeta = AB 1 1 ++-- | @c1 = alpha + beta@+c1 :: Chern+c1 = Chern 1 0 ++-- | @c2 = alpha * beta@+c2 :: Chern+c2 = Chern 0 1 ++--------------------------------------------------------------------------------+-- * Unified interface++-- | A singleton for distinguishing the two cases +data Sing base where+ ChernRoot :: Sing AB+ ChernClass :: Sing Chern++deriving instance Eq (Sing base)+deriving instance Ord (Sing base)++-- | Common interface to work with Chern classes and Chern roots uniformly+class (Eq base, Ord base, Monoid base, Graded base, Pretty base) => ChernBase base where+ chernTag :: base -> Sing base+ chernTag1 :: f base -> Sing base+ chernTag2 :: f (g base) -> Sing base+ chernTag3 :: f (g (h base)) -> Sing base+ fromAB :: ZMod AB -> ZMod base + fromChern :: ZMod Chern -> ZMod base + fromSchur :: ZMod Schur -> ZMod base+ toAB :: ZMod base -> ZMod AB + toChern :: ZMod base -> ZMod Chern+ toSchur :: ZMod base -> ZMod Schur++instance ChernBase AB where+ chernTag _ = ChernRoot+ chernTag1 _ = ChernRoot+ chernTag2 _ = ChernRoot+ chernTag3 _ = ChernRoot+ fromAB = id+ fromChern = chernToAB+ fromSchur = schurToAB+ toAB = id+ toChern = abToChern+ toSchur = abToSchur++instance ChernBase Chern where+ chernTag _ = ChernClass+ chernTag1 _ = ChernClass+ chernTag2 _ = ChernClass+ chernTag3 _ = ChernClass+ fromAB = abToChern+ fromChern = id+ fromSchur = schurToChern+ toAB = chernToAB+ toChern = id+ toSchur = chernToSchur++--------------------------------------------------------------------------------+-- * Helper functions for constructing and specializing uniform things++-- | Constructing uniform things+select0 :: (AB, Chern) -> (ChernBase base => base)+select0 what = let final = select0' what (chernTag final) in final++select1 :: (f AB, f Chern) -> (ChernBase base => f base)+select1 what = let final = select1' what (chernTag1 final) in final++select2 :: (f (g AB), f (g Chern)) -> (ChernBase base => f (g base))+select2 what = let final = select2' what (chernTag2 final) in final++select3 :: (f (g (h AB)), f (g (h Chern))) -> (ChernBase base => f (g (h base)))+select3 what = let final = select3' what (chernTag3 final) in final++-- | Constructing unifom things using a tag+select0' :: (AB, Chern) -> (ChernBase base => Sing base -> base)+select0' (ab,ch) = \sing -> case sing of { ChernRoot -> ab ; ChernClass -> ch }++select1' :: (f AB, f Chern) -> (ChernBase base => Sing base -> f base)+select1' (ab,ch) = \sing -> case sing of { ChernRoot -> ab ; ChernClass -> ch }++select2' :: (f (g AB), f (g Chern)) -> (ChernBase base => Sing base -> f (g base))+select2' (ab,ch) = \sing -> case sing of { ChernRoot -> ab ; ChernClass -> ch }++select3' :: (f (g (h AB)), f (g (h Chern))) -> (ChernBase base => Sing base -> f (g (h base)))+select3' (ab,ch) = \sing -> case sing of { ChernRoot -> ab ; ChernClass -> ch }++-- | Specializing uniform things+spec0' :: ChernBase base => Sing base -> (forall b. ChernBase b => b) -> base+spec0' _ x = x++spec1' :: ChernBase base => Sing base -> (forall b. ChernBase b => f b) -> f base+spec1' _ x = x++spec2' :: ChernBase base => Sing base -> (forall b. ChernBase b => f (g b)) -> f (g base)+spec2' _ x = x++spec3' :: ChernBase base => Sing base -> (forall b. ChernBase b => f (g (h b))) -> f (g (h base))+spec3' _ x = x++{-+proxyOf :: a -> Proxy a+proxyOf _ = Proxy++proxyOf1 :: f a -> Proxy a+proxyOf1 _ = Proxy++proxyOf2 :: g (f a) -> Proxy a+proxyOf2 _ = Proxy+-}++--------------------------------------------------------------------------------++instance Monoid AB where+ mempty = AB 0 0 + (AB a1 b1) `mappend` (AB a2 b2) = AB (a1+a2) (b1+b2)++instance Monoid Chern where+ mempty = Chern 0 0 + (Chern e1 f1) `mappend` (Chern e2 f2) = Chern (e1+e2) (f1+f2)++instance Monoid Schur where+ mempty = Schur 0 0+ mappend = error "Schur/mappend: not a monoid"++--------------------------------------------------------------------------------++instance Pretty AB where+ pretty ab = case ab of+ AB 0 0 -> "" + AB e 0 -> showVarPower "a" e+ AB 0 f -> showVarPower "b" f+ AB e f -> showVarPower "a" e ++ "*" ++ showVarPower "b" f+ +instance Pretty Chern where+ pretty (Chern 0 0) = ""+ pretty (Chern e 0) = showVarPower "c1" e+ pretty (Chern 0 f) = showVarPower "c2" f+ pretty (Chern e f) = showVarPower "c1" e ++ "*" ++ showVarPower "c2" f++instance Pretty Schur where+ pretty (Schur a b) + | b == 0 = "s[" ++ show a ++ "]"+ | otherwise = "s[" ++ show a ++ "," ++ show b ++ "]"++--------------------------------------------------------------------------------+-- * Grading++class Graded a where+ grade :: a -> Int++instance Graded AB where grade (AB a b) = a + b+instance Graded Chern where grade (Chern e f) = e + 2*f+instance Graded Schur where grade (Schur i j) = i + j++filterGrade :: (Ord b, Graded b) => Int -> ZMod b -> ZMod b+filterGrade g = ZMod.onFreeMod filt where+ filt = Map.filterWithKey $ \x _ -> (grade x == g)++--------------------------------------------------------------------------------+-- * Conversions++chernToAB :: ZMod Chern -> ZMod AB +chernToAB = ZMod.flatMap expandToAlphaBeta_1 where++ -- | c1^k * c2^n = (alpha+beta)^k * (alpha*beta)^n+ expandToAlphaBeta_1 :: Chern -> ZMod AB + expandToAlphaBeta_1 (Chern k n) = ZMod.fromList [ (AB (n+i) (n+k-i) , binomial k i) | i<-[0..k] ]++--------------------------------------------------------------------------------++-- | Converts a symmetric polynomial in the AB base (Chern roots) +-- to the Chern base (elementary symmetric polynomials or Chern classes)+abToChern :: ZMod AB -> ZMod Chern+abToChern ab = case symmetricReduction ab of+ Right c -> c+ Left _ -> error "abToChern: input was not symmetric"++-- | @Left@ means there is a non-symmetric remainder; @Right@ means+-- that input was symmetric.+symmetricReduction :: ZMod AB -> Either (ZMod Chern, ZMod AB) (ZMod Chern)+symmetricReduction = go [] where++ go sofar zmod = case ZMod.findMaxTerm zmod of+ Nothing -> Right q+ Just (AB n m, k) -> if n < m+ then Left (q,zmod)+ else go ((ch,k):sofar) (zmod - this) where+ ch = Chern (n-m) m+ this = ZMod.scale k $ expandToAlphaBeta_1 ch+ where+ q = ZMod.fromList sofar++ -- | c1^k * c2^n = (alpha+beta)^k * (alpha*beta)^n+ expandToAlphaBeta_1 :: Chern -> ZMod AB + expandToAlphaBeta_1 (Chern k n) = ZMod.fromList [ (AB (n+i) (n+k-i) , binomial k i) | i<-[0..k] ]+ +--------------------------------------------------------------------------------++-- | Convert Schur to Chern roots+schurToAB :: ZMod Schur -> ZMod AB+schurToAB = ZMod.flatMap schurExpandAB_1 where++ schurExpandAB_1 :: Schur -> ZMod AB+ schurExpandAB_1 (Schur a b)+ | b > a = error "schurExpandAB"+ | b < 0 = error "schurExpandAB"+ | otherwise = ZMod.fromList [ ( AB (a-j) (b+j) , 1 ) | j <- [0..a-b] ]++ {-+ schurab[i_, j_] := + Expand[Factor[ Det[{{a^(i + 1), b^(i + 1)}, {a^j, b^j}}]] / + Det[{{a, b}, {1, 1}}] ]+ -}++--------------------------------------------------------------------------------++-- | Convert Schur to Chern classes (elementary symmetric polynomials)+schurToChern :: ZMod Schur -> ZMod Chern+schurToChern = ZMod.flatMap schurExpandChern_1 where++ schurExpandChern_1 :: Schur -> ZMod Chern+ schurExpandChern_1 (Schur a b) + | b > a = error "schurExpandChern_1"+ | b < 0 = error "schurExpandChern_1"+ | otherwise = ZMod.fromList [ ( Chern (a-b-2*j) (b+j) , paritySignValue j * binomial (a-b-j) j ) | j <- [0..(div (a-b) 2)] ]++ -- schurcd[i_, j_] := SymmetricReduction[schurab[i, j], {a, b}, {c1, c2}][[1]]++--------------------------------------------------------------------------------++chernToSchur :: ZMod Chern -> ZMod Schur+chernToSchur = ZMod.flatMap chernExpandSchur_1 where++ chernExpandSchur_1 :: Chern -> ZMod Schur+ chernExpandSchur_1 (Chern e f)+ | e < 0 || f < 0 = error "chernExpandSchur"+ | otherwise = ZMod.fromList [ ( Schur (e+f-i) (f+i) , catalanTriangle (e-i) i) | i<-[0..(div e 2)] ]++--------------------------------------------------------------------------------++abToSchur :: ZMod AB -> ZMod Schur+abToSchur = chernToSchur . abToChern++chernToSchurNaive :: ZMod Chern -> ZMod Schur+chernToSchurNaive = ZMod.fromList . go where++ go zmod = case ZMod.findMaxTerm zmod of + Nothing -> []+ Just (Chern a b, k) -> ( s , k ) : go (zmod - this) where+ this = ZMod.scale k $ schurExpandChern_1 s+ s = Schur (a+b) b++ schurExpandChern_1 :: Schur -> ZMod Chern+ schurExpandChern_1 (Schur a b) + | b > a = error "schurExpandChern_1"+ | b < 0 = error "schurExpandChern_1"+ | otherwise = ZMod.fromList [ ( Chern (a-b-2*j) (b+j) , paritySignValue j * binomial (a-b-j) j ) | j <- [0..(div (a-b) 2)] ]++--------------------------------------------------------------------------------+-- * random polynomials for testing++randomChernMonom :: IO Chern+randomChernMonom = do+ a <- randomRIO (0,30)+ b <- randomRIO (0,15)+ return (Chern a b)++randomSchurMonom :: IO Schur+randomSchurMonom = do+ a <- randomRIO (0,30)+ b <- randomRIO (0,30)+ return (Schur (a+b) b)++withRandomCoeff :: IO a -> IO (a,Integer)+withRandomCoeff rnd = do+ k <- randomRIO (-100,100)+ x <- rnd+ return (x,k)++randomChernPoly :: IO (ZMod Chern) +randomChernPoly = do+ n <- randomRIO (0,100)+ ZMod.fromList <$> replicateM n (withRandomCoeff randomChernMonom)++randomSchurPoly :: IO (ZMod Schur) +randomSchurPoly = do+ n <- randomRIO (0,100)+ ZMod.fromList <$> replicateM n (withRandomCoeff randomSchurMonom)++--------------------------------------------------------------------------------+
+ src/Math/RootLoci/CSM/Aluffi.hs view
@@ -0,0 +1,105 @@++-- | Aluffi's computation of the non-equivariant CSM in @P^n@+--+-- See: Paolo Aluffi: Characteristic classes of discriminants and enumerative geometry, Comm. in Algebra 26(10), 3165-3193 (1998).+--+{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}++module Math.RootLoci.CSM.Aluffi where++--------------------------------------------------------------------------------++import Data.List++import Control.Monad++import Math.Combinat.Classes+import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer+import Math.Combinat.Sets++import qualified Data.Map as Map ; import Data.Map (Map)+import qualified Data.Set as Set ; import Data.Set (Set)++import Data.Array (Array)+import Data.Array.IArray++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Classic+import Math.RootLoci.Misc++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++--------------------------------------------------------------------------------+-- * CSM computation++-- | Paolo Aluffi's explicit formula for the (non-equivariant) CSM of open coincident root loci+aluffiOpenCSM :: Partition -> ZMod G+aluffiOpenCSM part@(Partition ps) = ZMod.invScale (aut part) xsum where+ n = sum ps+ d = length ps+ xsum = ZMod.fromList [ ( G (n-d+k) , coeff k ) | k<-[0..d] ] + coeff k = negateIfOdd k + $ signedBinomial (d-3) k * factorial k * factorial (d-k) * symPolyNum (d-k) (map fromIntegral ps)++-- | Summing together the open loci CSMs, we got the CSMs of the closures of the strata+aluffiClosedCSM :: Partition -> ZMod G+aluffiClosedCSM part@(Partition ps) = ZMod.sum opens where+ opens = [ aluffiOpenCSM q | q <- Set.toList (closureSet part) ]++--------------------------------------------------------------------------------+-- * Euler characteristics++-- | Euler characteristic, computed form 'aluffiOpenCSM'+aluffiOpenEuler :: Partition -> Integer+aluffiOpenEuler p = ZMod.coeffOf (G n) (aluffiOpenCSM p) where+ n = partitionWeight p++-- | Euler characteristic, computed form 'aluffiClosedCSM'+aluffiClosedEuler :: Partition -> Integer+aluffiClosedEuler p = ZMod.coeffOf (G n) (aluffiClosedCSM p) where+ n = partitionWeight p++--------------------------------------------------------------------------------++-- | It is easy to see from Aluffi\'s formula that only dimensions 1 and 2 has nonzero Euler characteristic.+-- This function implements the resulting rather trivial formula:+--+-- > chi( X_{n} ) = 2+-- > chi( X_{p,q} ) = if p==q then 1 else 2+-- > chi( X_{...} ) = 0+--+openEulerChar :: Partition -> Integer+openEulerChar (Partition ps) = case ps of+ [n] -> 2+ [a,b] -> if a==b then 1 else 2+ _ -> 0++--------------------------------------------------------------------------------+-- * General linear sections++-- | Converts the CSM class of a (locally closed?) projective variety Z to the Euler characteristics+-- of general linear sections of Z (so the first number will be @chi(Z)@, the second will be+-- @chi(Z cap H1)@, the third @chi(Z cap H1 cap H2)@ with @H1@, @H2@... being generic hyperplanes.+-- Finally the codim-th number will be the degree.+--+-- See: Paolo Aluffi: EULER CHARACTERISTICS OF GENERAL LINEAR SECTIONS AND POLYNOMIAL CHERN CLASSES,+-- Proposition 2.6+-- +csmToEulerOfLinearSections + :: Int -- ^ the dimension of the ambient projective space @P^n@+ -> ZMod G -- ^ the CSM class+ -> [Integer] -- ^ the resulting sequence of Euler characteristics+csmToEulerOfLinearSections n csm = [ euler i | i<-[0..n] ] where+ csmArr = accumArray (flip const) 0 (0,n) [ (i,c) | (G i, c) <- ZMod.toList csm ] :: Array Int Integer+ euler k = foldl' (+) 0 [ signedBinomial (-k) i * csmArr ! (n-k-i) | i<-[0..n-k] ]++-- | We can compute the degree of the closures of the strata by intersection them+-- with @dim(X)@ generic hiperplanes.+aluffiDegree :: Partition -> Integer+aluffiDegree part = list !! dimension part where+ list = csmToEulerOfLinearSections (weight part) (aluffiClosedCSM part)++--------------------------------------------------------------------------------
+ src/Math/RootLoci/CSM/Equivariant/Direct.hs view
@@ -0,0 +1,65 @@++-- | We compute the open CSM classes directly, generalizing Aluffi's argument+-- to the equivariant case:+--+-- First we compute the CSM of set of the distinct /ordered/ points, then+-- push that forward first with @delta_*@ then with @pi_*@ to get the+-- CSM of the distinct unordered points with given multiplicities.+--+-- After that, we can get the closed CSM classes by summing over the+-- strata in the closure.+--+-- This is faster, especially since we have a (recursive) formula for the +-- CSM of the distinct ordered points.++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}+module Math.RootLoci.CSM.Equivariant.Direct + ( directOpenCSM+ , directClosedCSM+ )+ where++--------------------------------------------------------------------------------++import Math.Combinat.Partitions.Integer++import qualified Data.Set as Set++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.CSM.Equivariant.PushForward+import qualified Math.RootLoci.CSM.Equivariant.Ordered as Ordered++--------------------------------------------------------------------------------++-- | CSM class of the open strata.+-- +-- We just push-forward first with Delta then down with Pi the conjectured +-- (recursive) formula for the CSM of the set of distinct ordered points+-- +directOpenCSM :: ChernBase base => Partition -> ZMod (Gam base)+directOpenCSM = polyCache2 directCalcOpenCSM where++ directCalcOpenCSM :: ChernBase base => Partition -> ZMod (Gam base)+ directCalcOpenCSM part@(Partition xs) = result where+ m = partitionWeight part+ result = ZMod.invScale (aut part) $ pi_star m middle+ middle = delta_star_ part distinct+ distinct = Ordered.formulaDistinctCSM (length xs)++--------------------------------------------------------------------------------++-- | To compute the CSM of the closed loci, we just some over the open strata+-- in the closure.+directClosedCSM :: ChernBase base => Partition -> ZMod (Gam base)+directClosedCSM = polyCache2 calc where+ + calc :: ChernBase base => Partition -> ZMod (Gam base)+ calc part = ZMod.sum [ directOpenCSM q | q <- Set.toList (closureSet part) ] ++--------------------------------------------------------------------------------+
+ src/Math/RootLoci/CSM/Equivariant/Ordered.hs view
@@ -0,0 +1,412 @@++-- | CSM classes of the (open) strata in the set of /ordered/ @n@-tuples,+-- that is, @Q^n = P^1 x P^1 x ... x P^1@+--+-- Of special interest is the open stratum of distinct points, +-- since any other stratum can be computed from that stratum +-- by a simple push-forward.+-- +-- The open stratum of distinct points can be computed recursively, +-- since the full space @Q^n@ is the disjoint union of all stratums +-- (indexed by /set partitions/).+-- +-- But we also have a recursive formula, which makes the computation +-- significantly faster.+--++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances,+ ScopedTypeVariables, Rank2Types, GADTs+ #-}++module Math.RootLoci.CSM.Equivariant.Ordered + ( -- * The product of projective lines @P^1 x ... x P^1@+ tangentChernClass+ -- * Diagonal embedding+ , j_star + , smallDiagonal+ -- * Recursive computation of the CSM of the strata+ , computeOpenStratumCSM + , computeAnyStratumCSM+ , computeClosureOfAnyStratumCSM+ -- * The structure lemma+ , QPow(..)+ , umbralDistinctFormula+ , umbralSubstQPow+ , computeQPolys+ -- * The recursive formula for the @Q_k(a,b)@ polynomials+ , formulaQPoly + -- * Formula for the CSM class of the stratum of distinct points+ , formulaDistinctCSM+ , formulaAnyStratumCSM+ ) + where++--------------------------------------------------------------------------------++import Math.Combinat.Classes+import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer ( Partition(..) )+import Math.Combinat.Partitions.Set+import Math.Combinat.Sets++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Data.Set as Set ; import Data.Set (Set)++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.CSM.Equivariant.PushForward++--------------------------------------------------------------------------------+-- * The product of projective lines @P^1 x ... x P^1@++-- | Chern class of the tangent bundle of a product of projective lines.+--+-- The formula is:+--+-- > c(T(P^1 x P^1 ... x P^1)) = prod_i (1 + alpha + beta + 2*omega_i)+--+-- because+--+-- > c(T(PV)) = \prod_k (1 + w_i + omega) `mod` prod_k (w_i + omega) +--+-- and+-- +-- > (1+alpha+omega) * (1+beta+omega) = 1 + alpha + beta + 2*omega +--+-- since the quadratic term is c_2 of a line bundle which is zero+--+tangentChernClass+ :: ChernBase base + => Int -- ^ the number of projective lines+ -> ZMod (Omega base) -- ^ the tangent chern class of their product+tangentChernClass n = select2 + ( tangentChernClassAB n+ , tangentChernClassChern n+ )++tangentChernClassAB+ :: Int -- ^ The number of projective lines+ -> ZMod (Omega AB)+tangentChernClassAB d = ZMod.product [ entry i | i<-[1..d] ] where+ entry i = ZMod.fromList+ [ (Omega [] (AB 0 0) , 1)+ , (Omega [] (AB 1 0) , 1)+ , (Omega [] (AB 0 1) , 1)+ , (Omega [i] (AB 0 0) , 2) -- 2x !+ ]++tangentChernClassChern+ :: Int -- ^ The number of projective lines+ -> ZMod (Omega Chern)+tangentChernClassChern d = ZMod.product [ entry i | i<-[1..d] ] where+ entry i = ZMod.fromList+ [ (Omega [] (Chern 0 0) , 1)+ , (Omega [] (Chern 1 0) , 1)+ , (Omega [i] (Chern 0 0) , 2) -- 2x !+ ]++--------------------------------------------------------------------------------+-- * Diagonal embedding++-- | Diagonal embeddings of ordered products of P^1-s+j_star :: ChernBase base => [[Int]] -> ZMod (Omega base) -> ZMod (Omega base)+j_star indices = unsafeEtaToOmega . delta_star' indices where++-- | The CSM of the small diagonal in @P^1 x ... x P^1@+smallDiagonal :: forall base. ChernBase base => Int -> ZMod (Omega base)+smallDiagonal n = smallDiagonal' [1..n] where++ smallDiagonal' :: [Int] -> ZMod (Omega base)+ smallDiagonal' indices = j_star [indices] (tangentChernClass 1)++--------------------------------------------------------------------------------+-- * CSM of the strata++-- | Recursively compute the CSM of the Zariski-open set @U^n@ of distinct ordered points+-- in @Q^d = P^1 x ... x P^1@. We can compute this by we can subtract all the distinct +-- fat diagonals from the Chern class of @Q^d@, and the diagonals are just pushforwards +-- of the same thing for smaller @d@-s.+--+-- NOTE: We also have a more explicit formula for the result (which is /much/ faster to compute)+-- and we can compare the two.+--+-- Note: Forgetting the alpha\/beta part, this should equal to+--+-- > (1-h1-h2-...-hd)^(d-3)+--+-- But, remember that in this formula, @h_i^2 = 0@ for all i!+--+-- Including also @alpha@ and @beta@ we have instead the umbral formula+--+-- > (q-h1-h2-...-hd)^(d-3)+-- +-- where we also have to do the umbral substitution @q^k -> Q_k@, and the polynomials @Q_k(alpha,beta)@ +-- are defined recursively, and are defined for @k >= -3@.+--+computeOpenStratumCSM :: ChernBase base => Int -> ZMod (Omega base)+computeOpenStratumCSM = polyCache2 calcOpenStratumCSM where+ + calcOpenStratumCSM :: forall b. ChernBase b => Int -> ZMod (Omega b)+ calcOpenStratumCSM d+ | d == 0 = ZMod.one + | d == 1 = tangentChernClass 1+ | otherwise = (tangentChernClass d) `ZMod.sub` (ZMod.sum diagonals)+ where+ diagonals = + [ computeAnyStratumCSM setp+ | setp <- setPartitions d + , let k = numberOfParts setp+ , k < d+ ]+++-- | Simply the pushforward of the CSM of the open stratum along the+-- diagonal map corresponding to the given set partition +--+computeAnyStratumCSM :: ChernBase base => SetPartition -> ZMod (Omega base)+computeAnyStratumCSM (SetPartition pps) = (j_star pps $ computeOpenStratumCSM $ length pps)++-- | We sum over the closure+computeClosureOfAnyStratumCSM :: ChernBase base => SetPartition -> ZMod (Omega base)+computeClosureOfAnyStratumCSM setp = ZMod.sum+ [ computeAnyStratumCSM p | p <- Set.toList (closureSetOfSetPartition setp) ] ++--------------------------------------------------------------------------------+-- * The structure lemma++-- | A formal monomial @q^k@+newtype QPow = QPow Int deriving (Eq,Ord,Show)++instance Monoid QPow where+ mempty = QPow 0+ mappend (QPow e) (QPow f) = QPow (e+f)++instance Pretty QPow where+ pretty (QPow k) = showVarPower "q" k++--------------------------------------------------------------------------------++-- | The umbral formula for the open stratum of the CSM of distinct ordered point:+--+-- > (q - u1 - u2 - ... - un)^(n-3)+--+-- where @u_i^2 = 1@. This also works @n = 0,1,2,3@+-- For these we have the expansion:+--+-- > (q - u1 - u2 - u3)^0 = q^0+-- > (q - u1 - u2 )^-1 = 1/q + u1/q^2 + u2/q^2 + (2*u1*u2)/q^3+-- > (q - u1 )^-2 = 1/q^2 + (2*u1)/q^3+-- > (q )^-3 = 1/q^3+--+umbralDistinctFormula :: Int -> ZMod (Omega QPow)+umbralDistinctFormula n+ | n < 0 = error "umbralDistinct: n should be nonnegative"+ | n == 0 = ZMod.generator $ monom [] (-3)+ | n == 1 = ZMod.fromList + [ (monom [] (-2) , 1) + , (monom [1] (-3) , 2)+ ]+ | n == 2 = ZMod.fromList + [ (monom [] (-1) , 1)+ , (monom [1] (-2) , 1)+ , (monom [2] (-2) , 1)+ , (monom [1,2] (-3) , 2)+ ]+ | n >= 3 = ZMod.sum+ [ ZMod.scale coeff $ (ZMod.symPoly (n-3-k) us) * (ZMod.generator $ monom [] k)+ | k<-[0..n-3]+ , let coeff = negateIfOdd (n-3+k) (factorial (n-3) `div` factorial k)+ ]++ where+ monom xs k = Omega xs (QPow k)+ us = [ monom [i] 0 | i<-[1..n] ]++-- | Given a function specifying what to substitute in the place of @q^k@, we do the substitution.+umbralSubstQPow :: (ChernBase base) => (QPow -> ZMod base) -> ZMod (Omega QPow) -> ZMod (Omega base)+umbralSubstQPow subst1 input = ZMod.sum + [ ZMod.fromList + [ (Omega us ab , c*coeff) + | (ab,c) <- ZMod.toList (subst1 qpow) + ] + | (Omega us qpow , coeff) <- ZMod.toList input + ]++--------------------------------------------------------------------------------++-- | It is not hard to prove (by considering the pushforward along+-- the map forgetting one of the points), that the CSM of the locus+-- @U^n@ of the distinct points has the following form (for @n>=3@):+--+-- > csm(U^n) = sum_{k=0}^{n-3} \frac{(n-3)!}{k!} (-1)^{n-3-k} \sigma_{n-3-k}(u) Q_k(a,b)+-- +-- We can already compute all CSM-s recursively, and from that information we can+-- determine these polynomials.+--+-- Which then we can compare with the recursive formula for the+-- polynomials itself (which is /much/ faster to evaluate)+--+computeQPolys :: Int -> ZMod AB+computeQPolys = icache' ZMod.zero (-3) calcComputeQPolys where++ calcComputeQPolys :: Int -> ZMod AB+ calcComputeQPolys n + | n < -3 = error "computeQPolys: n >= -3 is required"+ | n == -3 = ZMod.one+ | otherwise = ZMod.mapBase project almost+ where++ almost = open - smaller+ open = computeOpenStratumCSM (n+3) -- we should use this as the basis of the computation, unfortunately it's rather slow+ + umbSmaller = umbralDistinctFormula (n+3) - umbHighest+ umbHighest = ZMod.generator (Omega [] (QPow n)) -- q^n+ smaller = umbralSubstQPow (\(QPow k) -> computeQPolys k) umbSmaller++{-+ smaller = ZMod.sum + [ ZMod.scale coeff $ + (ZMod.symPoly (n-k) us) * (embed $ computeQPolys k)+ | k<-[0..n-1]+ , let coeff = negateIfOdd (n+k) (factorial n `div` factorial k)+ ]+ us = [ Omega [i] (AB 0 0) | i<-[1..n+3] ]+ embed = ZMod.mapBase $ \ab -> Omega [] ab+-}++ project (Omega us ab) = case us of+ [] -> ab+ _ -> error $ "computeQPolys: cannot project u terms:\n " ++ pretty almost++--------------------------------------------------------------------------------+-- * The recursive formula for the @Q_k(a,b)@ polynomials++-- | The Fibonacci-type recursive formula for the @Q_k(a,b)@ polynomials+--+-- > Q_{-3} = 1+-- > Q_k = Q_{k-1} * (1 - (k+1)*(a+b)) - Q_{k-2} * a*b * (k-1)*(k+2)+-- > = Q_{k-1} * (1 - (k+1)* c_1 ) - Q_{k-2} * c_2 * (k-1)*(k+2)+--+-- We provide both the Chern root and the Chern class version in a uniform+-- way for convenience.+formulaQPoly :: ChernBase base => Int -> ZMod base+formulaQPoly n = select1 + ( formulaQPolyAB n + , formulaQPolyChern n+ )++formulaQPolyAB :: Int -> ZMod AB+formulaQPolyAB = icache' ZMod.zero (-3) calcQPoly where+ + calcQPoly :: Int -> ZMod AB+ calcQPoly n+ | n < -3 = ZMod.zero+ | n == -3 = ZMod.konst 1+ | otherwise = mult1 * prev1 + mult2 * prev2+ where+ prev1 = formulaQPolyAB (n-1)+ prev2 = formulaQPolyAB (n-2)++ Pair mult1 mult2 = qpolyRecursionCoeffs n++-- | Chern class version of the @Q_k@ formula (should be faster then the Chern root version, because the are less terms).+formulaQPolyChern :: Int -> ZMod Chern+formulaQPolyChern = icache' ZMod.zero (-3) calcQPoly where+ + calcQPoly :: Int -> ZMod Chern+ calcQPoly n+ | n < -3 = ZMod.zero+ | n == -3 = ZMod.konst 1+ | otherwise = mult1 * prev1 + mult2 * prev2+ where+ nn = fromIntegral n :: Integer++ prev1 = formulaQPolyChern (n-1)+ prev2 = formulaQPolyChern (n-2)++ Pair mult1 mult2 = qpolyRecursionCoeffs n++qpolyRecursionCoeffs :: ChernBase base => Int -> Pair (ZMod base)+qpolyRecursionCoeffs n = select2 + ( Pair mult1_AB mult2_AB + , Pair mult1_Chern mult2_Chern+ )+ where++ mult1_AB = ZMod.fromList + [ ( AB 0 0 , 1 )+ , ( AB 1 0 , -nn-1 )+ , ( AB 0 1 , -nn-1 )+ ]+ mult2_AB = ZMod.singleton (AB 1 1) (-(nn-1)*(nn+2)) + + mult1_Chern = ZMod.fromList + [ ( Chern 0 0 , 1 )+ , ( Chern 1 0 , -nn-1 )+ ]+ mult2_Chern = ZMod.singleton (Chern 0 1) (-(nn-1)*(nn+2))++ nn = fromIntegral n :: Integer++--------------------------------------------------------------------------------+-- small @Q_k@ polynomials++{-+polyZMod :: ZMod AB -> (forall base. ChernBase base => ZMod base)+polyZMod ab = select1 (ab, abToChern ab)++-- | @Q_0 = ( 1 - a + b) ( 1 + a - b) = 1 - a^2 - b^2 + 2ab = 1 - c_1^2 + 4c_2@+konstQ0 :: ChernBase base => ZMod base+konstQ0 = polyZMod q0 where + q0 = ZMod.fromList [ ( AB 0 0 , 1 ) , ( AB 2 0 , -1 ) , ( AB 0 2 , -1 ) , ( AB 1 1 , 2 ) ] ++-- | @Q_-1 = 1 + a + b + 2 a*b = 1 + c_1 + 2c_2@+konstQminus1 :: ChernBase base => ZMod base+konstQminus1 = polyZMod qminus1 where+ qminus1 = ZMod.fromList [ ( AB 0 0 , 1 ) , ( AB 1 0 , 1 ) , ( AB 0 1 , 1 ) , ( AB 1 1 , 2 ) ]++-- | @Q_-2 = 1 + a + b = 1 + c_1@+konstQminus2 :: ChernBase base => ZMod base+konstQminus2 = polyZMod qminus2 where+ qminus2 = ZMod.fromList [ ( AB 0 0 , 1 ) , ( AB 1 0 , 1 ) , ( AB 0 1 , 1 ) ]++-- | @Q_-3 = 1@+konstQminus3 :: ChernBase base => ZMod base+konstQminus3 = ZMod.konst 1+-}++--------------------------------------------------------------------------------+-- * Formula for the CSM class of the stratum of distinct points++-- | The formula for the CSM of the set of distinct ordered points+-- using the formula for the Q_k(a,b) polynomials above+--+formulaDistinctCSM :: ChernBase base => Int -> ZMod (Omega base)+formulaDistinctCSM n + | n < 0 = error "formulaDistinctCSM: dimension should be nonnegative"+ | otherwise = umbralSubstQPow fun + $ umbralDistinctFormula n+ where+ fun (QPow k) = formulaQPoly k+{-+ | n < 3 = computeOpenStratumCSM n+ | otherwise = ZMod.sum + [ ZMod.scale coeff poly+ | k <- [0..n-3] + , let coeff = paritySignValue (n-3-k) * div (factorial (n-3)) (factorial k)+ , let qk = formulaQPoly k+ , let sym = choose (n-3-k) [1..n]+ , let poly = ZMod.fromList [ (Omega xs ab, k) | xs <- sym, (ab,k) <- ZMod.toList qk ]+ ]+-}++-- | Just the pushforward of the previous along @Delta_mu@+formulaAnyStratumCSM :: ChernBase base => SetPartition -> ZMod (Omega base)+formulaAnyStratumCSM setp = unsafeEtaToOmega $ delta_star setp (formulaDistinctCSM k) where+ k = numberOfParts setp+ +--------------------------------------------------------------------------------
+ src/Math/RootLoci/CSM/Equivariant/PushForward.hs view
@@ -0,0 +1,305 @@++-- | Compute the pushforward maps @pi_*@ and @delta_*@ between the+-- @GL2@-equivariant cohomology rings+--+-- Recall that:+--+-- * @Delta_nu : Q^d -> Q^n@+--+-- * @pi : Q^n -> P^n@+--+-- and @Q^n = P^1 x P^1 x ... x P^1@.+-- ++{-# LANGUAGE + BangPatterns, TypeSynonymInstances, FlexibleInstances, FlexibleContexts,+ ScopedTypeVariables, TypeFamilies + #-}++module Math.RootLoci.CSM.Equivariant.PushForward + ( -- * The function tau+ tau , tauEta+ -- * pushforward along the diagonal map @Delta_{nu} : Q^d -> Q^n@+ , delta_star_ , delta_star , delta_star' + -- * pushforward along the order-forgetting map @pi : Q^n -> P^n@+ , pi_star_table+ , compute_pi_star+ , pi_star+ -- * Fibonacci-type recursion formula for @pi_*@+ , piStarTableAff + , piStarTableProj+ )+ where++--------------------------------------------------------------------------------++import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set+import Math.Combinat.Sets+import Math.Combinat.Tuples++import Data.Array (Array)+import Data.Array.IArray++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++--------------------------------------------------------------------------------+-- * The function tau++-- | @tau_k := ( a^(k+1) - b^(k+1) ) / ( a - b )@+tau :: ChernBase base => Int -> ZMod base+tau k = select1 ( tauAB k , tauChern k ) ++-- | In chern classes, the coefficients of tau are (signed) binomial coefficients; cf. A011973+tauChern :: Int -> ZMod Chern+tauChern k + | k < -1 = error "tau: negative index is not implemented"+ | k == -1 = ZMod.zero + | otherwise = ZMod.fromList [ ( Chern (k - 2*j) j , negateIfOdd j $ binomial (k-j) j ) | j<-[0..div k 2] ]++tauChernUnsafe :: Int -> ZMod Chern+tauChernUnsafe = icache $ \k -> abToChern (tauAB k)++tauAB :: Int -> ZMod AB+tauAB k + | k < -1 = error "tau: negative index is not implemented"+ | k == -1 = ZMod.zero+ | otherwise = ZMod.fromList [ (AB j (k-j) , 1) | j <- [0..k] ]++tauEta :: ChernBase base => Int -> ZMod (Eta base)+tauEta k = injectZMod (tau k)++--------------------------------------------------------------------------------+-- * @Delta_{\nu} : Q^d -> Q^n@++-- | Input: diagonal eta indices, and whether we are pushing forward 1 or the generator u/xi+delta_star_single :: ChernBase base => [Int] -> Bool -> ZMod (Eta base)+delta_star_single ks xi = + if xi+ then bbb + else aaa + where+ n = length ks++ aaa = ZMod.sum [ sigma (n-1-i) * (tauEta i) | i<-[0..n-1] ]+ bbb = full - rest++ ab = ZMod.generator $ Eta [] $ select0 (alphaBeta, c2)+ full = ZMod.generator (Eta ks mempty) -- == sigma_n(eta)+ rest = ZMod.sum [ sigma (n-i) * tauEta (i-2) * ab | i<-[2..n] ]++ sigma k = ZMod.symPoly k [ Eta [k] mempty | k<-ks ]+ +-- | a group generator on the left is a subset (=product) of U-s, which+-- we map to a linear combinaton of H-s+delta_star_1 :: ChernBase base => Partition -> Omega base -> ZMod (Eta base)+delta_star_1 part = delta_star_1' (linearIndices part)++-- | a group generator on the left is a subset (=product) of U-s, which+-- we map to a linear combinaton of H-s+delta_star_1' :: forall base. ChernBase base => [[Int]] -> Omega base -> ZMod (Eta base)+delta_star_1' idxtable (Omega us ab) = final where+ + final = mulInjMonom ab $ ZMod.product $ go 1 idxtable+ + go :: Int -> [[Int]] -> [ZMod (Eta base)]+ go _ [] = []+ go k (is:iss) = this : go (k+1) iss where+ this = delta_star_single is (k `elem` us)++delta_star_ :: ChernBase base => Partition -> ZMod (Omega base) -> ZMod (Eta base)+delta_star_ part = ZMod.flatMap (delta_star_1 part)++delta_star :: ChernBase base => SetPartition -> ZMod (Omega base) -> ZMod (Eta base)+delta_star setp = ZMod.flatMap (delta_star_1' (fromSetPartition setp))++-- | We can give an explicit indexing scheme (set partition), instead of the linear indexing+-- used above. This will be useful when computing the \"open\" part+delta_star' :: ChernBase base => [[Int]] -> ZMod (Omega base) -> ZMod (Eta base)+delta_star' indices = ZMod.flatMap (delta_star_1' indices)++--------------------------------------------------------------------------------+-- * @pi : Q^n -> P^n@++-- | This is upside the class where @[0:1]@ is a root with multiplicity @k@ and @[1:0]@ is a root with multiplicity l+up_root_xy :: Int -> (Int,Int) -> ZMod (Eta AB)+up_root_xy n (k,l) = as * bs where++ as = ZMod.product [ abh i 1 0 | i<-[1..k] ]+ bs = ZMod.product [ abh (n+1-j) 0 1 | j<-[1..l] ]++ -- (eta_i + na*alpha + nb*beta)+ abh i na nb = ZMod.fromList + [ (Eta [i] (AB 0 0) , 1 ) + , (Eta [] (AB 1 0) , na) + , (Eta [] (AB 0 1) , nb) + ]++-- | This is downside the class where @[0:1]@ is a root with multiplicity @k@ and @[1:0]@ is a root with multiplicity l.+-- It should be true that @pi_* up_root_xy = down_root_xy@+down_root_xy :: Int -> (Int,Int) -> ZMod (Gam AB)+down_root_xy n (k,l) = as * bs where++ as = ZMod.product [ abg (n-i) (i) | i<-[0..k-1] ]+ bs = ZMod.product [ abg (j) (n-j) | j<-[0..l-1] ]++ -- (na*alpha + nb*beta + gamma)+ abg na nb = ZMod.fromList + [ (Gam 1 (AB 0 0) , 1 ) + , (Gam 0 (AB 1 0) , fromIntegral na) + , (Gam 0 (AB 0 1) , fromIntegral nb) + ]++pi_star_0 :: Int -> Int -> ZMod (Gam AB)+pi_star_0 n k = ZMod.sum+ [ ZMod.scale + (negateIfOdd i $ binomial k i * factorial (n-k+i)) + (mulAB (AB i 0) $ down_root_xy n (k-i,0)) + | i<-[0..k] ]++-- | Table of @pi_*( eta_1*eta_2*...*eta_k )@, computed by breaking the symmetry.+pi_star_table :: Int -> Array Int (ZMod (Gam AB))+pi_star_table = monoCache calc where+ calc n = listArray (0,n) [ pi_star_0 n k | k<-[0..n] ]++-- | Slow implementation of @pi_star@, using @pi_star_table@+compute_pi_star + :: Int -- ^ the number of points @m@ (recall the pi : @Q^m -> P^m@)+ -> ZMod (Eta AB) + -> ZMod (Gam AB)+compute_pi_star m = ZMod.flatMap f where + table = pi_star_table m+ f (Eta hs ab) = mulAB ab (table ! length hs)++--------------------------------------------------------------------------------+-- * Fibonacci-type recursion formula for @pi_*@++-- | However it should faster to just use the recursion for the @P_j(m)@ polynomials,+-- which this function does.+pi_star + :: forall base. (ChernBase base) + => Int -- ^ the number of points @m@ (recall the pi : @Q^m -> P^m@)+ -> ZMod (Eta base) + -> ZMod (Gam base)+pi_star m = ZMod.flatMap f where + table = piStarTableProj m :: Array Int (ZMod (Gam base))+ f (Eta hs ab) = mulInjMonom ab (table ! length hs)++piStarTableAff :: ChernBase base => Int -> Array Int (ZMod base)+piStarTableAff = polyCache2 calc where+ calc n = select2 ( aff_fibPiStar_AB n , aff_fibPiStar_Chern n )++piStarTableProj :: ChernBase base => Int -> Array Int (ZMod (Gam base))+piStarTableProj = polyCache3 calc where+ calc n = select3 ( proj_fibPiStar_AB n , proj_fibPiStar_Chern n )++{-++class ChernBase (PiStarBase tgtmonom) => PiStar tgtmonom where+ type PiStarBase tgtmonom :: *+ piStarTable :: Int -> Array Int (ZMod tgtmonom)++instance PiStar (Gam Chern) where { piStarTable = proj_fibPiStar_Chern ; type PiStarBase (Gam Chern) = Chern }+instance PiStar (Gam AB ) where { piStarTable = proj_fibPiStar_AB ; type PiStarBase (Gam AB ) = AB }+instance PiStar Chern where { piStarTable = aff_fibPiStar_Chern ; type PiStarBase (Chern ) = Chern }+instance PiStar AB where { piStarTable = aff_fibPiStar_AB ; type PiStarBase (AB ) = AB }++-- instance PiStar (Gam Schur) where { piStarTable = proj_fibPiStar_Schur ; type PiStarBase = Gam Schur }+-- instance PiStar Schur where { piStarTable = aff_fibPiStar_Schur ; type PiStarBase = Schur }+-}++proj_fibPiStar_Chern :: Int -> Array Int (ZMod (Gam Chern))+proj_fibPiStar_Chern m = listArray (0,m) $ take (m+1) fib where++ fib :: [ZMod (Gam Chern)]+ fib = ZMod.konst (factorial m )+ : ZMod.singleton (Gam 1 mempty) (factorial (m-1))+ : zipWith3 g [1..] (tail fib) fib ++ g :: Integer -> ZMod (Gam Chern) -> ZMod (Gam Chern) -> ZMod (Gam Chern)+ g k prev1 prev2 + = ZMod.invScale (mm-k)+ $ mulGam prev1 + ZMod.scale k (mulInjMonom c1 prev1) + + ZMod.scale k (mulInjMonom c2 prev2) ++ mm = fromIntegral m :: Integer++-- c1 = Chern 1 0+-- c2 = Chern 0 1++----------------------------------------++aff_fibPiStar_Chern :: Int -> Array Int (ZMod Chern)+aff_fibPiStar_Chern m = listArray (0,m) $ take (m+1) fib where++ fib :: [ZMod Chern]+ fib = ZMod.konst (factorial m)+ : ZMod.zero+ : zipWith3 g [1..] (tail fib) fib ++ g :: Integer -> ZMod Chern -> ZMod Chern -> ZMod Chern+ g k prev1 prev2 + = ZMod.invScale (mm-k)+ $ ZMod.scale ( k)+ $ (ZMod.mulMonom c1 prev1 + ZMod.mulMonom c2 prev2) ++ mm = fromIntegral m :: Integer++-- c1 = Chern 1 0+-- c2 = Chern 0 1++----------------------------------------++proj_fibPiStar_AB :: Int -> Array Int (ZMod (Gam AB))+proj_fibPiStar_AB m = fmap (convertGam chernToAB) (proj_fibPiStar_Chern m)++proj_fibPiStar_Schur :: Int -> Array Int (ZMod (Gam Schur))+proj_fibPiStar_Schur m = fmap (convertGam chernToSchur) (proj_fibPiStar_Chern m)++aff_fibPiStar_AB :: Int -> Array Int (ZMod AB)+aff_fibPiStar_AB m = fmap chernToAB (aff_fibPiStar_Chern m)++aff_fibPiStar_Schur :: Int -> Array Int (ZMod Schur)+aff_fibPiStar_Schur m = fmap chernToSchur (aff_fibPiStar_Chern m)++--------------------------------------------------------------------------------+-- * helpers++-- | Multiplies by an injected monomial +mulInjMonom :: (Functor f, Monoid ab, Ord (f ab)) => ab -> ZMod (f ab) -> ZMod (f ab)+mulInjMonom monom = ZMod.mapBase f where+ f = fmap (mappend monom)++-- | Multiplies by @(alpha^i * beta^j)@+mulAB :: (Functor f, Ord (f AB)) => AB -> ZMod (f AB) -> ZMod (f AB)+mulAB = mulInjMonom++-- | Multiplies with @gamma@+mulGam :: Ord ab => ZMod (Gam ab) -> ZMod (Gam ab)+mulGam = ZMod.mapBase f where + f (Gam k x) = Gam (k+1) x++{-+-- | Multiplies by alpha^i beta^j+omegaMulAB :: AB -> ZMod (Omega AB) -> ZMod (Omega AB)+omegaMulAB (AB i j) = Map.mapKeys f where+ f (Omega us (AB a b)) = Omega us (AB (a+i) (b+j))++-- | Multiplies by alpha^i beta^j+etaMulAB :: AB -> ZMod (Eta AB)-> ZMod (Eta AB)+etaMulAB (AB i j) = Map.mapKeys f where+ f (Eta hs (AB a b)) = Eta hs (AB (a+i) (b+j))++-- | Multiplies by alpha^i beta^j+gamMulAB :: AB -> ZMod (Gam AB) -> ZMod (Gam AB)+gamMulAB (AB i j) = Map.mapKeys f where+ f (Gam g (AB a b)) = Gam g (AB (a+i) (b+j))+-}++--------------------------------------------------------------------------------
+ src/Math/RootLoci/CSM/Equivariant/Recursive.hs view
@@ -0,0 +1,97 @@++-- | We compute the @GL2@-equivariant open and closed CSM classes recursively,+-- starting from smallest strata. +--+-- The idea is that we have a smooth resolution of the /closure/ of the strata @X_mu@, +-- namely, the set of @n=length(mu)@ ordered points: @Q^n = P^1 x ... x P^1@+--+-- We can pushforward this to @Q^m@, and get a linear combination of the strata of+-- the CSM-s we want to compute. Since the smallest strata is actually closed,+-- we know that, and can work upward from that.+--+-- This is rather slow, however as it's a very different algorithm copmared to+-- the direct approach, it's useful for checking if the two agrees.+--++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}+module Math.RootLoci.CSM.Equivariant.Recursive where++--------------------------------------------------------------------------------++import qualified Data.Set as Set ; import Data.Set (Set)+import qualified Data.Map as Map ; import Data.Map (Map)++import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set++import qualified Math.RootLoci.CSM.Equivariant.Ordered as Ordered+import Math.RootLoci.CSM.Equivariant.PushForward++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++--------------------------------------------------------------------------------+-- * CSM calculation++-- | This is just the pushforward along @Delta_nu@ of the tangent Chern class.+--+-- As @Delta@ is injective, the resulting class is just the CSM class of the+-- closed /ordered/ strata corresponding to one of the set partitions which+-- matches the given partition +----+upperClass :: ChernBase base => SetPartition -> ZMod (Eta base)+upperClass = polyCache2 calcUpper where++ calcUpper :: ChernBase base => SetPartition -> ZMod (Eta base)+ calcUpper part@(SetPartition ps) = delta_star part (Ordered.tangentChernClass d) where+ d = length ps++-- | pushforward of `upperCSM` to the space of unordered points+lowerClass :: ChernBase base => Partition -> ZMod (Gam base)+lowerClass = polyCache2 calcLower where++ calcLower :: ChernBase base => Partition -> ZMod (Gam base)+ calcLower part = pi_star n (upperClass $ defaultSetPartition part) where+ n = partitionWeight part++--------------------------------------------------------------------------------++-- | We know from the pushforward property of CSM clsses that @(pi_* upperCSM) = sum (chi * openCSM)@.+-- we can use this to recursively compute the CSM classes of the open loci+--+openCSM :: ChernBase base => Partition -> ZMod (Gam base)+openCSM = polyCache2 calcOpenCSM where++ calcOpenCSM :: ChernBase base => Partition -> ZMod (Gam base)+ calcOpenCSM part = ZMod.invScale thisCoeff (pushdown `ZMod.sub` smaller) where+ n = partitionWeight part+ pushdown = lowerClass part+ smaller = ZMod.linComb [ (c , openCSM q) | (q,c) <- Map.assocs theClosure ]+ (thisCoeff,theClosure) = preimageView part -- closureView' part++-- | To compute the CSM of the closed loci, we just some over the open strata+-- in the closure. +closedCSM :: ChernBase base => Partition -> ZMod (Gam base)+closedCSM = polyCache2 calcClosedCSM where++ calcClosedCSM :: ChernBase base => Partition -> ZMod (Gam base)+ calcClosedCSM part =+ ZMod.sum [ openCSM q | q <- Set.toList (closureSet part) ] + +--------------------------------------------------------------------------------++{-+equivDualClass :: Partition -> ZMod Gam+equivDualClass part = filterGrade (codim part) (closedCSM part)++equivOpenEuler :: Partition -> ZMod Gam+equivOpenEuler part = filterGrade (partitionWeight part) (openCSM part)++equivClosedEuler :: Partition -> ZMod Gam+equivClosedEuler part = filterGrade (partitionWeight part) (closedCSM part)+-}++--------------------------------------------------------------------------------
+ src/Math/RootLoci/CSM/Equivariant/Umbral.hs view
@@ -0,0 +1,214 @@++-- | The umbral formula for the open CSM classes.+--+-- The formula is the following:+--+-- > A(mu) = 1 / aut(mu) * prod_i Theta(mu_i)+-- > Theta(p) = ( (1 + beta*s) (alpha+t)^p - (1 + alpha*s) (beta+t)^p ) / ( alpha - beta )+--+-- and the umbral subtitution resulting in the CSM class (at least for @length(mu)>=3@) is:+--+-- > t^j -> P_j(m)+-- > s^k -> (n-3)(n-3-1)(...n-3-k+1) * Q(n-3-k)+--+-- Note that Theta(p) is actually a (symmetric) polynomial in @alpha@ and @beta@; furthermore+-- it's linear in s and degree p in t. ++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances, ScopedTypeVariables #-}+module Math.RootLoci.CSM.Equivariant.Umbral where++--------------------------------------------------------------------------------++import Math.Combinat.Classes+import Math.Combinat.Numbers+import Math.Combinat.Partitions.Integer++import Data.Array.IArray++import qualified Data.Set as Set++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.CSM.Equivariant.PushForward ( tau , piStarTableAff , piStarTableProj )+import Math.RootLoci.CSM.Equivariant.Ordered ( formulaQPoly )++import qualified Math.RootLoci.CSM.Equivariant.Direct as Direct++--------------------------------------------------------------------------------+-- * The umbral variables++-- | A monomial @s^k * t^j@+data ST + = ST !Int !Int+ deriving (Eq,Ord,Show)++instance Monoid ST where+ mempty = ST 0 0 + (ST s1 t1) `mappend` (ST s2 t2) = ST (s1+s2) (t1+t2)++instance Pretty ST where+ pretty st = case st of+ ST 0 0 -> "" + ST e 0 -> showVarPower "s" e+ ST 0 f -> showVarPower "t" f+ ST e f -> showVarPower "s" e ++ "*" ++ showVarPower "t" f++prettyMixedST :: forall b c. (Pretty b, Num c, Eq c, IsSigned c, Show c) => FreeMod (FreeMod c b) ST -> String+prettyMixedST = prettyFreeMod'' prettyInner pretty where++ prettyInner :: FreeMod c b -> String+ prettyInner = paren . pretty++--------------------------------------------------------------------------------+-- * The umbral formula++-- | @Theta(p)@ is defined by the formula+--+-- > Theta(p) = ( (1 + beta*s) (alpha+t)^p - (1 + alpha*s) (beta+t)^p ) / ( alpha - beta )+--+-- This is actually a polynomial in @alpha@,@beta@,@s@,@t@, also symmetric in @alpha@ and @beta@+--+theta :: ChernBase base => Int -> FreeMod (ZMod base) ST+theta p + | p >= 1 = ZMod.fromList (term0 ++ term1) + | otherwise = error "theta: non-positive input"+ where+ + term0 = [ (ST 0 i , ZMod.scale (binomial p i) ( tau (p-i-1)) ) | i<-[0..p-1] ]+ term1 = [ (ST 1 i , ZMod.scale (binomial p i) (ZMod.mulMonom c2_monom $ tau (p-i-2)) ) | i<-[0..p-2] ] + ++ [ (ST 1 p , ZMod.konst (-1) ) ]++ c2_monom = select0 (alphaBeta,c2)++-- | Same as 'theta' but with rational coefficients+thetaQ :: ChernBase b => Int -> FreeMod (QMod b) ST+thetaQ p = ZMod.mapCoeff (ZMod.mapCoeff fromIntegral) (theta p)++-------------------------------------------------------------------------------- ++-- | This is just @prod_i Theta_{mu_i}@+integralUmbralFormula :: ChernBase base => Partition -> FreeMod (ZMod base) ST +integralUmbralFormula (Partition ps) = ZMod.product [ theta p | p <- ps ]++-- | This is @1/aut(mu) * prod_i Theta_{mu_i}@+umbralFormula :: ChernBase base => Partition -> FreeMod (QMod base) ST +umbralFormula mu@(Partition ps) = result where+ + result = ZMod.mapCoeff (ZMod.scale (1 / autmu))+ $ ZMod.product [ thetaQ p | p <- ps ]++ autmu :: Rational+ autmu = fromIntegral (aut mu)++--------------------------------------------------------------------------------+-- * The affine CSM++-- | The polynomial to be substituted in the place of @s^k*t^j@:+--+-- > s^k*t^j -> P_j(m) * Q_k(n-3-k) * (n-3)_k+--+-- where @n = length(mu)@ and @m = weight(mu)@.+--+umbralSubstPolyAff :: ChernBase base => Partition -> ST -> ZMod base+umbralSubstPolyAff part = fun where++ n = numberOfParts part+ m = weight part+ tablePPoly = piStarTableAff m++ fun (ST k j) + | k >= -3 && k <= n-3 && j >= 0 && j <= m = ZMod.scale falling (qpoly `ZMod.mul` ppoly)+ | otherwise = ZMod.zero+ where+ falling :: Integer+ falling = product [ fromIntegral (n-3-i) | i<-[0..k-1] ]++ qpoly = formulaQPoly (n-3-k)+ ppoly = tablePPoly ! j++-- | The (affine) umbral substitution+umbralSubstitutionAff :: (ChernBase base) => Partition -> FreeMod (ZMod base) ST -> ZMod base+umbralSubstitutionAff part input = output where++ output = ZMod.sum [ ab `ZMod.mul` (substfun st) | (st,ab) <- ZMod.toList input ]+ substfun = umbralSubstPolyAff part++-- | CSM of the open stratums from the umbral the formula+umbralAffOpenCSM :: ChernBase base => Partition -> ZMod base +umbralAffOpenCSM = polyCache1 calc where++ -- the current umbral formula only works for @n >= 3@ ??+ calc mu + | n < 3 = forgetGamma (Direct.directOpenCSM mu)+ | otherwise = ZMod.invScale (aut mu)+ $ umbralSubstitutionAff mu+ $ integralUmbralFormula mu+ where+ n = numberOfParts mu++-- | Sum over the strata in the closure+umbralAffClosedCSM :: ChernBase base => Partition -> ZMod base +umbralAffClosedCSM = polyCache1 calc where+ + calc :: ChernBase base => Partition -> ZMod base+ calc part = ZMod.sum [ umbralAffOpenCSM q | q <- Set.toList (closureSet part) ] ++--------------------------------------------------------------------------------+-- * The projective CSM++-- | The polynomial to be substituted in the place of @s^k*t^j@:+--+-- > s^k*t^j -> P_j(m) * Q_k(n-3-k) * (n-3)_k+--+-- where @n = length(mu)@ and @m = weight(mu)@.+--+umbralSubstPolyProj :: forall base. ChernBase base => Partition -> ST -> ZMod (Gam base)+umbralSubstPolyProj part = fun where++ n = numberOfParts part+ m = weight part+ tablePPoly = piStarTableProj m++ fun (ST k j) + | k >= -3 && k <= n-3 && j >= 0 && j <= m = ZMod.scale falling (qpoly `ZMod.mul` ppoly)+ | otherwise = ZMod.zero+ where+ falling :: Integer+ falling = product [ fromIntegral (n-3-i) | i<-[0..k-1] ]++ qpoly = injectZMod (formulaQPoly (n-3-k)) :: ZMod (Gam base)+ ppoly = tablePPoly ! j :: ZMod (Gam base)+++-- | The (projective) umbral substitution+umbralSubstitutionProj :: (ChernBase base) => Partition -> FreeMod (ZMod base) ST -> ZMod (Gam base)+umbralSubstitutionProj part input = output where++ output = ZMod.sum [ injectZMod ab `ZMod.mul` (substfun st) | (st,ab) <- ZMod.toList input ]+ substfun = umbralSubstPolyProj part++-- | CSM of the open stratums from the umbral the formula (for @length(mu) >= 3@)+umbralOpenCSM :: ChernBase base => Partition -> ZMod (Gam base)+umbralOpenCSM = polyCache2 calc where++ -- the current umbral formula only works for @n >= 3@ ??+ calc mu + | n < 3 = Direct.directOpenCSM mu + | otherwise = ZMod.invScale (aut mu)+ $ umbralSubstitutionProj mu+ $ integralUmbralFormula mu+ where+ n = numberOfParts mu++-- | Sum over the strata in the closure+umbralClosedCSM :: ChernBase base => Partition -> ZMod (Gam base)+umbralClosedCSM = polyCache2 calc where+ + calc :: ChernBase base => Partition -> ZMod (Gam base)+ calc part = ZMod.sum [ umbralOpenCSM q | q <- Set.toList (closureSet part) ] ++--------------------------------------------------------------------------------
+ src/Math/RootLoci/CSM/Projective.hs view
@@ -0,0 +1,218 @@++-- | Compute the non-equivariant CSM in @P^n@ recursively++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}+module Math.RootLoci.CSM.Projective + ( -- * Pushforwards+ delta_star+ , pi_star+ -- * Easy things+ , tangentChernClass+ , smallestOrbitCSM+ -- * CSM calculation+ , upperCSM , lowerCSM+ , openCSM , closedCSM+ -- * extracting coefficients+ , highestCoeff_ , lowestCoeff_+ , highestCoeff , lowestCoeff + ) + where++--------------------------------------------------------------------------------++import Data.List+import Data.Maybe++import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set+import Math.Combinat.Sets++import qualified Data.Map as Map ; import Data.Map (Map)+import qualified Data.Set as Set ; import Data.Set (Set)++import Data.Array.IArray+import Data.Array (Array)++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.Algebra.FreeMod as ZMod+ +--------------------------------------------------------------------------------++{-+ +we have maps+* Delta_nu : Q^d -> Q^n+* pi : Q^n -> P^n+ +-}++--------------------------------------------------------------------------------+-- * The order-forgetting map @pi : Q^n -> P^n@++pi_star_1 :: Int -> HS -> (G,Integer)+pi_star_1 n (HS hs) = (gk,c) where+ c = factorial (n - length hs) + gk = G (length hs)++-- | The pushforward map @pi_*@ along @pi@.+--+-- A (cohomology) group generator above is a subset (=product) of H-s, which we map to+-- a group generator below. This defines the map on the cohomology ring by additive extension.+--+pi_star + :: Int -- ^ the number of points @m@ (with multiplicity)+ -> ZMod HS -- ^ the cohomoly class \"up\"+ -> ZMod G+pi_star n = ZMod.flatMap (sing . pi_star_1 n) where + sing (b,c) = ZMod.singleton b c++--------------------------------------------------------------------------------+-- * The diagonal maps @Delta_{\nu} : Q^d -> Q^n@+ +delta_star_1 :: Partition -> US -> ZMod HS+delta_star_1 part@(Partition ps) (US us) = ZMod.histogram almost where++ n = sum ps+ d = length ps+ + idxtable = linearIndices part+ + -- inner lists = monoms+ -- outer lists = linear combination of monoms+ -- now we want to multiply those together+ stuff :: [[[H]]]+ stuff = (map . map . map) H (go 1 idxtable)+ + almost :: [HS]+ almost = map (HS . concat) $ listTensor stuff -- this does the multiplication of terms+ + uis = [ i | U i <- us ]+ + go :: Int -> [[Int]] -> [[[Int]]]+ go _ [] = []+ go k (is:iss) = this : go (k+1) iss where+ this = if k `elem` uis+ then [is] -- "sigma_k"+ else chooseN1 is -- "sigma_(k-1)"+ +-- | A group generator on the left is a subset (=product) of U-s, which+-- we map to a linear combinaton of H-s. This is then extended additively+-- to the cohomology ring.+--+delta_star :: Partition -> ZMod US -> ZMod HS+delta_star part = ZMod.flatMap (delta_star_1 part)++--------------------------------------------------------------------------------+-- * Easy things++-- | The total Chern class of the tangent bundle of @Q^d = P^1 x P^1 x ... x P^1@+--+-- This is just the product of @(1+2u_i)@-s for @i=[1..d]@+--+tangentChernClass :: Int -> ZMod US+tangentChernClass d = ZMod.fromList $ concatMap worker [0..d] where+ worker k = map (\xs -> (US (map U xs) , 2^k)) (choose_ k d)++-- | The CSM of the smallest orbit: 1 point with multiplicity @n@,+-- which is just the rational normal curve in @P^n@.+--+smallestOrbitCSM :: Int -> ZMod G+smallestOrbitCSM n = ZMod.fromList + [ (G (n-1) , fromIntegral n) + , (G n , 2 * fromIntegral n) + ] ++--------------------------------------------------------------------------------+-- * CSM calculation++-- | We know that:+-- +-- > csm(im(Delta) = Delta_* c(TQ^d)+-- > c(TQ^d) = (1+2*u1) (1+2*u2) ... (1+2*ud)+--+-- From these, we can compute @csm(im(Delta_nu))@ recursively+--+upperCSM :: Partition -> ZMod HS+upperCSM = pcache calc where++ calc part@(Partition ps) = (delta_star part) (tangentChernClass d) where+ d = length ps++-- | A formula for @pi_*(csm(im(delta)))@. This should satisfy+--+-- > lowerCSM part = pi_star n (upperCSM part)+--+lowerCSM :: Partition -> ZMod G+lowerCSM = pcache calc where++ calc part@(Partition ps) = zmod where+ d = length ps+ n = sum ps+ zmod = ZMod.fromList+ [ ( G (n-d+r) , coeff )+ | r<-[0..d]+ , let coeff = factorial (d-r) * 2^r * symPolyNum (d-r) (map fi ps)+ ]+ + fi :: Int -> Integer+ fi = fromIntegral++check_lower_upper :: Int -> Bool+check_lower_upper n = and [ pi_star n (upperCSM p) == lowerCSM p | p <- partitions n ]++-- | Cached CSM computation of the open strata+openCSM :: Partition -> ZMod G+openCSM = pcache calcOpenCSM where++ -- | we know that (pi_* upperCSM) = sum (chi * openCSM)+ calcOpenCSM :: Partition -> ZMod G+ calcOpenCSM part = ZMod.invScale thisCoeff (pushdown - smaller) where+ n = partitionWeight part+ pushdown = lowerCSM part -- pi_star n (upperCSM part) + smaller = ZMod.linComb [ (c , openCSM q) | (q,c) <- Map.assocs theClosure ]+ (thisCoeff,theClosure) = preimageView part++-- | To get the CSM of the closed strata, we just sum over the open strata contained+-- in the closure.++closedCSM :: Partition -> ZMod G +closedCSM = pcache calcClosedCSM where ++ calcClosedCSM :: Partition -> ZMod G+ calcClosedCSM part = ZMod.sum [ openCSM q | q <- Set.toList (closureSet part) ]++--------------------------------------------------------------------------------++lowestCoeff_ :: ZMod G -> Integer+lowestCoeff_ = snd . lowestCoeff++highestCoeff_ :: ZMod G -> Integer+highestCoeff_ = snd . highestCoeff++lowestCoeff :: ZMod G -> (G,Integer)+lowestCoeff = fromJust . ZMod.findMinTerm +-- lowestCoeff = head . ZMod.toList ++highestCoeff :: ZMod G -> (G,Integer)+highestCoeff = fromJust . ZMod.findMaxTerm+-- highestCoeff = last . ZMod.toList ++--------------------------------------------------------------------------------++{-+check_degree :: Partition -> Bool+check_degree p = hilbert p == lowestCoeff_ (closedCSM p)++check_euler_degree :: Partition -> Bool+check_euler_degree p@(Partition ps) = hilbert p == ((csmToEuler n $ closedCSM p) !! d) where+ d = length ps+ n = sum ps+-}++--------------------------------------------------------------------------------+
+ src/Math/RootLoci/Classic.hs view
@@ -0,0 +1,91 @@++-- | Classical results: +--+-- * Hilbert's degree formula+--+-- * some enumarative geometry computations by Schubert+--++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}++module Math.RootLoci.Classic where++--------------------------------------------------------------------------------++import Data.List++import Control.Monad++import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer+import Math.Combinat.Sets++--------------------------------------------------------------------------------++-- | Codimension of a strata. This is simply @(sum mu_i) - length(mu)@.+codim :: Partition -> Int+codim (Partition ps) = sum ps - length ps++-- | Dimension of the strata. @dim = length(mu)@.+dimension :: Partition -> Int+dimension (Partition ps) = length ps++--------------------------------------------------------------------------------+-- * Hilbert formula++-- | Hilbert's formula for the degree of a stratum+hilbert :: Partition -> Integer+hilbert part@(Partition ps) = div numer denom where++ n = sum ps+ d = length ps++ numer = factorial d * product (map fi ps) -- d! * prod (nu_i)+ denom = product (map (factorial . snd) ies) -- prod (e_r!)+ + ies = toExponentialForm part -- (r,e_r) pairs+ + fi :: Int -> Integer+ fi = fromIntegral++-- | Hilbert's degree formula, another version (as a sanity test).+hilbert2 :: Partition -> Integer+hilbert2 part@(Partition ps) = div numer denom where++ -- this is from FNR, opposite notation (d and n are swapped!)+ -- just to be really sure about the formula :)++ n = sum es+ d = sum [ i*ei | (i,ei) <- toExponentialForm part ]+ es = [ ei | (i,ei) <- toExponentialForm part ]++ numer = factorial n * product [ (fi i)^ei | (i,ei) <- toExponentialForm part ]+ denom = product [ factorial ei | (i,ei) <- toExponentialForm part ]++ fi :: Int -> Integer+ fi = fromIntegral+ +-- check_hilbert2 :: Bool +-- check_hilbert2 = and [ hilbert p == hilbert2 p | n<-[0..20] , p<-partitions n ]++--------------------------------------------------------------------------------+-- * Schubert++-- | Number of 4-tangent lines to a generic degree @d@ surface +quadTangentLines :: Int -> Integer+quadTangentLines d0+ | d < 8 = 0+ | otherwise = d * (d - 4) * (d - 5) * (d - 6) * (d - 7) * (d^3 + 6*d^2 + 7*d - 30)+ where+ d = fromIntegral d0 :: Integer++-- | Number of lines meeting a generic degree @d@ surface at point with 5x multiplicity+quintFlexLines :: Int -> Integer+quintFlexLines d0+ | d < 5 = 0+ | otherwise = error "quintFlexLines"+ where+ d = fromIntegral d0 :: Integer++--------------------------------------------------------------------------------
+ src/Math/RootLoci/Dual/Localization.hs view
@@ -0,0 +1,115 @@++-- | Localization formula for the dual class from:+--+-- L. M. Feher, A. Nemethi, R. Rimanyi: Coincident root loci of binary forms;+-- Michigan Math. J. Volume 54, Issue 2 (2006), 375--392.+--+-- Note: This formula is in the form of /rational function/ (as opposed to +-- a polynomial). Since we don't have polynomial factorization implemented here,+-- instead we /evaluate/ it substituting different rational numbers+-- into @alpha@ and @beta@, and then use Lagrange interpolation to figure+-- out the result (we know a priori that it is a homogenenous polynomial+-- in @alpha@ and @beta@).++module Math.RootLoci.Dual.Localization where++--------------------------------------------------------------------------------++import Control.Monad++import Data.List+import Data.Ratio++import Math.Combinat.Numbers+import Math.Combinat.Sets+import Math.Combinat.Sign+import Math.Combinat.Partitions++import qualified Data.Map as Map++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Algebra+import Math.RootLoci.Classic++--------------------------------------------------------------------------------++-- | The localization formula as a string which Mathematica can parse+localizeMathematica :: Partition -> String+localizeMathematica (Partition xs) = formula where+ n = sum xs+ d = length xs+ ies = [ (head ys, length ys) | ys <- group (sort xs) ]+ es = map snd ies++ paren str = '(' : str ++ ")"+ wt j = paren $ show j ++ "a+" ++ show (n-j) ++ "b"++ sumOver = listTensor [ [0..e] | e<-es ] + formula = global ++ " * " ++ paren (intercalate " + " (map term sumOver)) ++ global = intercalate "*" [ wt j | j<-[0..n] ] ++ " / (b-a)^" ++ show d++ rkonst ss = product [ factorial s * factorial (e-s) | (s,e) <- zip ss es ]+ konst ss = show (paritySignValue (sum ss)) + ++ "/" ++ show (rkonst ss) + denom ss = show n ++ "*a - " ++ show (sum [ i*s | ((i,e),s) <- zip ies ss ]) ++ "*(a-b)"+ term ss = konst ss ++ " / " ++ paren (denom ss)++--------------------------------------------------------------------------------++-- | The localization formula evaluated at given values of @a@ and @b@+localizeEval :: Fractional q => Partition -> q -> q -> q+localizeEval (Partition xs) a b = formula where+ n = sum xs+ d = length xs+ ies = [ (head ys, length ys) | ys <- group (sort xs) ]+ es = map snd ies++ wt j = fromIntegral j * a + fromIntegral (n-j) * b++ sumOver = listTensor [ [0..e] | e<-es ] + formula = global * sum (map term sumOver)++ global = product [ wt j | j<-[0..n] ] / (b-a)^d++ rkonst ss = product [ factorial s * factorial (e-s) | (s,e) <- zip ss es ]+ konst ss = fromIntegral (paritySignValue (sum ss)) + / fromIntegral (rkonst ss) + denom ss = fromIntegral n * a - fromIntegral (sum [ i*s | ((i,e),s) <- zip ies ss ]) * (a-b)+ term ss = konst ss / denom ss++--------------------------------------------------------------------------------++-- | The dual class, recovered via from the localization formula via Lagrange+-- interpolation+localizeDual :: Partition -> ZMod AB+localizeDual part = ZMod.mapBase worker $ localizeInterpolatedZ part where+ c = codim part+ worker (X i) = AB (c-i) i ++-- | We can use Lagrange interpolation to express the dual class from the+-- localization formula (since we know a priori that the result is a homogeneous+-- polynomial in @a@ and @b@)+--+localizeInterpolatedQ :: Partition -> QMod X+localizeInterpolatedQ part@(Partition xs) = final where+ codim = sum xs - length xs+ bs = map fromIntegral [ 2..codim+2 ] :: [Rational]+ qs = [ localizeEval part 1 b | b<-bs ] :: [Rational]+ final = lagrangeInterp' (zip bs qs)++localizeInterpolatedZ :: Partition -> ZMod X+localizeInterpolatedZ = (ZMod.mapCoeff f . localizeInterpolatedQ) where+ f :: Rational -> Integer+ f q = case denominator q of+ 1 -> numerator q+ _ -> error "non-integral coefficient in the result"++--------------------------------------------------------------------------------++{-+main = do+ forM_ (partitions 9) $ \part@(Partition xs) -> do+ putStrLn $ "X" ++ concatMap show xs ++ " = Factor[ " ++ tp_local_mathematica part ++ " ]"+-}
+ src/Math/RootLoci/Dual/Restriction.hs view
@@ -0,0 +1,223 @@+++-- | Formula for the dual cohomology class of the /cones/ over the strata (sometimes called Thom polynomial) +-- in terms of the Chern classes @c1@ and @c2@, from the author's MSc thesis.+--+-- Note that the dual class agress with the lowest degree part of the CSM class.+--+-- See: Balazs Komuves: Thom Polynomials via Restriction Equations; MSc thesis, ELTE, 2003+--++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances, ScopedTypeVariables #-}+module Math.RootLoci.Dual.Restriction where++--------------------------------------------------------------------------------++import Data.List+import Data.Ratio++import Control.Monad++import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set+import Math.Combinat.Sets+import Math.Combinat.Tuples++import qualified Data.Set as Set ; import Data.Set (Set)++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Algebra+import Math.RootLoci.Classic+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++--------------------------------------------------------------------------------+-- * The dual class++-- | The affine Thom polynomial formula from my MSc thesis+affineDualMSc :: Partition -> ZMod Chern+affineDualMSc part@(Partition ps) = ++ case ps of+ [] -> error "affine_tp_msc: empty partition"+ [n] -> ZMod.fromList [ ( Chern (n-d-2*j) j , rat2int $ single j ) | j<-[ 0 .. div (n-d) 2] ] + [a,b] | a==b -> ZMod.fromList [ ( Chern (n-d-2*j) j , rat2int $ double j ) | j<-[ 0 .. div (n-d) 2] ] + otherwise -> ZMod.fromList [ ( Chern (n-d-2*j) j , rat2int $ lambda j ) | j<-[ 0 .. div (n-d) 2] ] ++ where++ n = sum ps+ d = length ps++ p = div n 2+ q = div (n-1) 2++ rat2int r = case denominator r of+ 1 -> numerator r+ _ -> error "lambda_j: not integer"++ lambda j = (fi n / 2)^(n-2*q) * fi (doubleFactorial (n-2))^2 * s where+ s = sum+ [ negateIfOdd (n + p + j + lpsi) $ bigTheta j nphi * (fi (2*nphi-n) / fi n)^(d-2) / (fi $ aut phi * aut psi)+ | (phi,psi) <- Set.toList (divideIntoTwoNonEmpty part)+ , let nphi = sum $ fromPartition phi+ , let npsi = sum $ fromPartition psi+ , let lphi = length $ fromPartition phi+ , let lpsi = length $ fromPartition psi+ ] ++ gamma :: Int -> Rational+ gamma k + | 2*k == n = 0 + | otherwise = fi (k*(k-n)) / fi ((2*k-n)*(2*k-n))++ bigTheta :: Int -> Int -> Rational+ bigTheta j k + | 2*k == n = 0 + | otherwise = gamma k * smallTheta j k++ smallTheta :: Int -> Int -> Rational+ smallTheta j k = sympoly (q-1-j) [ gamma i | i<-[1..q] , i/=k, i/=n-k ]+ + fi :: Integral a => a -> Rational+ fi = fromIntegral++ sqj :: Int -> Rational+ sqj j = sympoly (q-j) [ gamma i | i<-[1..q] ]++ sympoly :: Int -> [Rational] -> Rational+ sympoly k xs = sum [ product ys | ys <- choose k xs ]++ -- S(n)+ single j = fi (factorial n) / (product [ gamma i | i<-[1..q] ])+ * negateIfOdd j (sqj j) ++ -- S(p,p)+ double j = fi (doubleFactorial n)^2 / 4 + * negateIfOdd (q+j) (sqj j) +++--------------------------------------------------------------------------------+-- * Degree++-- | Compute the projective degree from the affine equivariant dual +-- (which can be checked against Hilbert's formula)+-- +-- This is just a simple substition:+--+-- > alpha -> 1/n+-- > beta -> 1/n+--+-- or in terms of Chern classes:+--+-- > c1 -> 2/n+-- > c2 -> 1/n^2+--+projDegreeFromDual+ :: Int -- ^ number of points = dimension of the projective space @P^n@+ -> ZMod Chern -- ^ dual class+ -> Integer -- ^ degree+projDegreeFromDual n zm = fromRat s where ++ s :: Rational+ s = sum [ fromIntegral c * c1^e * c2^f | (Chern e f, c) <- ZMod.toList zm ]++ c1 = 2 / fromIntegral n :: Rational+ c2 = 1 / fromIntegral (n*n) :: Rational++-- | Compute the degree of the strata via the formula for the dual class+degreeMSc :: Partition -> Integer+degreeMSc part = projDegreeFromDual (partitionWeight part) (affineDualMSc part)++{-++check_msc_degree :: Bool+check_msc_degree = and+ [ msc_degree part == hilbert part | n<-[1..12] , part <- partitions n ]+-}++--------------------------------------------------------------------------------+-- * extract the dual class from the CSM class ++-- | The dual class of the closure agress with the lowest degree part of the CSM class.+dualClassFromProjCSM :: forall base. ChernBase base => ZMod (Gam base) -> ZMod base+dualClassFromProjCSM csm = dualClassFromAffCSM (ZMod.filterBase nogamma csm) where+ nogamma :: Gam base -> Maybe base+ nogamma (Gam k ab) = if k==0 then Just ab else Nothing++dualClassFromAffCSM :: ChernBase base => ZMod base -> ZMod base+dualClassFromAffCSM csm = filterGrade min_degree csm where+ min_degree = minimum $ map grade $ map fst $ ZMod.toList csm++--------------------------------------------------------------------------------+-- * Lemma 9.1.3++{-+test_lemma_913 = and+ [ lemma913 p h + | n<-[1..10] + , p@(Partition ps)<-partitions n+ , let d=length ps+ , h<-[0..d]+ ]++test_lemma_913' = + [ (lemma913' p h,(p,h),(d,n))+ | n<-[1..10] + , p@(Partition ps)<-partitions n+ , let d=length ps+ , h<-[0..d]+ ]+-}++-- | Checks if Lemma 9.1.3 from the thesis is true for the given inputs+lemma913 :: Partition -> Int -> Bool+lemma913 part h = (a==b) where + (a,b) = lemma913' part h ++ lemma913' :: Partition -> Int -> (Rational, Rational)+ lemma913' part@(Partition ps) h = ( lhs , rhs ) where++ n = sum ps+ d = length ps++ rhs | h == d = tr (factorial d) * product (map fi ps)+ | h < d = 0+ | h > d = -666++ lhs = sum+ [ negateIfOdd (length rs) $ (fi (2 * sum qs - n) / 2)^h * (tr $ aut part) / (tr $ aut phi * aut psi)+ | ( phi@(Partition qs) , psi@(Partition rs) ) <- Set.toList (divideIntoTwo part)+ ]++ fi :: Int -> Rational+ fi = fromIntegral++ tr :: Integer -> Rational+ tr = fromIntegral +++--------------------------------------------------------------------------------+-- * helper functions++-- | Different ways to divide a partition into two +divideIntoTwo :: Partition -> Set (Partition,Partition)+divideIntoTwo (Partition ps) = Set.fromList $ map f (binaryTuples d) where++ d = length ps+ f ts = ( g ts , g (map not ts) )+ g ts = Partition [ k | (b,k) <- zip ts ps , b ]++ -- nonempty (p,q) = not (isEmptyPartition p) && not (isEmptyPartition q)++-- | Different ways to divide a partition into two /nonempty/ partitions+divideIntoTwoNonEmpty :: Partition -> Set (Partition,Partition)+divideIntoTwoNonEmpty p = Set.delete x $ Set.delete y $ divideIntoTwo p where+ x = (emptyPartition,p)+ y = (p,emptyPartition)++--------------------------------------------------------------------------------+
+ src/Math/RootLoci/Geometry.hs view
@@ -0,0 +1,13 @@++-- | Re-exporting the Geometry.* modules++module Math.RootLoci.Geometry+ ( module Math.RootLoci.Geometry.Cohomology+ , module Math.RootLoci.Geometry.Forget+ , module Math.RootLoci.Geometry.Mobius+ )+ where++import Math.RootLoci.Geometry.Cohomology+import Math.RootLoci.Geometry.Forget+import Math.RootLoci.Geometry.Mobius
+ src/Math/RootLoci/Geometry/Cohomology.hs view
@@ -0,0 +1,279 @@++-- | Bases in the cohomology of the spaces appearing in the computations.+--+-- We have three different spaces: +--+-- * @Q^n = P^1 x P^1 x ... x P^1@ (@n@ times; @m = length lambda@)+--+-- * @Q^m = P^1 x P^1 x ... x P^1 x P^1@ (@m@ times, @m = sum lambda >= n@)+-- +-- * @P^m = P(Sym^m C^2)@+--+-- Furthermore, we have @GL2@ acting naturally on these spaces.+--++{-# LANGUAGE + BangPatterns, TypeSynonymInstances, FlexibleInstances, DeriveFunctor, + ScopedTypeVariables, Rank2Types + #-}+module Math.RootLoci.Geometry.Cohomology where++--------------------------------------------------------------------------------++import Data.List+import Data.Monoid++import Math.Combinat.Numbers++import qualified Data.Map as Map+import qualified Data.Set as Set++import qualified Math.RootLoci.Algebra.FreeMod as ZMod+import Math.RootLoci.Algebra.FreeMod ( ZMod , FreeMod(..) , unFreeMod )++import Math.RootLoci.Algebra.SymmPoly +import Math.RootLoci.Misc.Pretty++--------------------------------------------------------------------------------+-- * The non-equivariant case++-- | a (ring) generator of @H^*(Q^n)@ (note that @u_i^2 = 0@)+newtype U = U Int deriving (Eq,Ord,Show)++-- | (a ring) generator of @H^*(Q^m)@ (note that @h_i^2 = 0@)+newtype H = H Int deriving (Eq,Ord,Show)++-- | the generator of @H^*(P^n)@ (with @g^(n+1) = 0@)+newtype G = G Int deriving (Eq,Ord,Show)++-- | A monomial in @u_i@ (encoded as a subset of @[1..n]@, as @u_i^2=0@)+newtype US = US [U] deriving (Eq,Ord,Show)++-- | A monomial in @h_i@ (encoded as a subset of @[1..m]@, as @h_i^2=0@)+newtype HS = HS [H] deriving (Eq,Ord,Show)++--------------------------------------------------------------------------------++instance Monoid US where+ mempty = US []+ (US us1) `mappend` (US us2) = + if nub us3 == us3+ then US us3+ else error "[U]/monoid: duplicate indices"+ where+ us3 = sort (us1 ++ us2)++instance Monoid HS where+ mempty = HS []+ (HS hs1) `mappend` (HS hs2) = + if nub hs3 == hs3+ then HS hs3+ else error "[H]/monoid: duplicate indices"+ where+ hs3 = sort (hs1 ++ hs2)++instance Monoid G where+ mempty = G 0+ (G e) `mappend` (G f) = G (e+f)+ +--------------------------------------------------------------------------------++instance Pretty G where+ pretty (G e) = "g^" ++ show e++instance Pretty H where+ pretty (H i) = "h" ++ show i++instance Pretty U where+ pretty (U i) = "u" ++ show i++instance Pretty HS where+ pretty (HS []) = ""+ pretty (HS hs) = intercalate "*" (map pretty hs)++instance Pretty US where+ pretty (US []) = ""+ pretty (US us) = intercalate "*" (map pretty us)++--------------------------------------------------------------------------------++instance Graded U where grade _ = 1+instance Graded H where grade _ = 1+instance Graded G where grade (G g) = g+instance Graded HS where grade (HS js) = length js+instance Graded US where grade (US js) = length js++instance Graded ab => Graded (Omega ab) where grade (Omega us ab) = length us + grade ab+instance Graded ab => Graded (Eta ab) where grade (Eta hs ab) = length hs + grade ab+instance Graded ab => Graded (Gam ab) where grade (Gam g ab) = g + grade ab++--------------------------------------------------------------------------------+-- * The equivariant case++-- | A monomial generator of @Z[alpha,beta;u1,u2,...,u_nd]/(...)@, +-- the cohomology ring of @Q^n@. +--+-- The encoding is that the list is the list of indices of @u@ which appear.+data Omega ab = Omega ![Int] !ab deriving (Eq,Ord,Show,Functor)++-- | A monomial generator of @Z[alpha,beta;eta1,eta2...eta_m]/(...)@,+-- he cohomology ring of @Q^m@. +--+-- The encoding is that the list is the list of indices of @eta@ which appear.+data Eta ab = Eta ![Int] !ab deriving (Eq,Ord,Show,Functor)++-- | A monomial generator of @Z[alpha,beta;gamma]/(...)@,+-- the cohomology ring of @P^m@. +data Gam ab = Gam !Int !ab deriving (Eq,Ord,Show,Functor)++--------------------------------------------------------------------------------++-- | Class of monomial bases which form modules over the @H^*(BGL2)@+class Functor f => Equivariant f where + injectMonom :: x -> f x+ projectMonom :: f x -> x++instance Equivariant Omega where + injectMonom = Omega [] + projectMonom (Omega _ ab) = ab++instance Equivariant Eta where + injectMonom = Eta [] + projectMonom (Eta _ ab) = ab++instance Equivariant Gam where + injectMonom = Gam 0 + projectMonom (Gam _ ab) = ab++injectZMod :: (Equivariant f, ChernBase base, Ord (f base)) => ZMod base -> ZMod (f base)+injectZMod = ZMod.mapBase injectMonom++forgetGamma :: Ord base => ZMod (Gam base) -> ZMod base +forgetGamma = ZMod.filterBase f where+ f (Gam k ab) = case k of+ 0 -> Just ab+ _ -> Nothing++forgetEquiv :: ChernBase base => ZMod (Gam base) -> ZMod G+forgetEquiv = ZMod.filterBase f where+ f (Gam k ab) = if (ab == mempty) + then Just (G k)+ else Nothing++--------------------------------------------------------------------------------+-- * Conversion between different bases++convertOmega + :: (Ord ab, Ord cd)+ => (ZMod ab -> ZMod cd) + -> ZMod (Omega ab) -> ZMod (Omega cd)+convertOmega = convertEach f g Omega where+ f (Omega xs _ ) = xs+ g (Omega _ ab) = ab++convertEta+ :: (Ord ab, Ord cd)+ => (ZMod ab -> ZMod cd) + -> ZMod (Eta ab) -> ZMod (Eta cd)+convertEta = convertEach f g Eta where+ f (Eta xs _ ) = xs+ g (Eta _ ab) = ab++convertGam+ :: (Ord ab, Ord cd)+ => (ZMod ab -> ZMod cd) + -> ZMod (Gam ab) -> ZMod (Gam cd)+convertGam = convertEach f g Gam where+ f (Gam k _ ) = k+ g (Gam _ ab) = ab++-- | A generic function which can convert the @GL2@ representations+convertEach + :: forall f x y ab cd. (Functor f, Ord ab, Ord cd, Ord (f ab), Ord (f cd), Ord x) + => (forall y. f y -> x)+ -> (forall y. f y -> y)+ -> (forall y. x -> y -> f y)+ -> (ZMod ab -> ZMod cd )+ -> ZMod (f ab) -> ZMod (f cd)+convertEach selx sely build convert src = tgt where+ tgt = ZMod.sum [ worker layer | layer <- layers ]+ layers = Set.toList $ Set.map selx $ Map.keysSet $ unFreeMod src :: [x]+ worker layer + = FreeMod+ $ Map.mapKeys (build layer)+ $ unFreeMod+ $ convert+ $ FreeMod+ $ Map.mapKeys sely + $ Map.filterWithKey (\k _ -> selx k == layer) + $ unFreeMod src++--------------------------------------------------------------------------------++-- | This is a hack to reuse the same pushforward code+unsafeEtaToOmega :: Ord ab => FreeMod coeff (Eta ab) -> FreeMod coeff (Omega ab)+unsafeEtaToOmega = ZMod.mapBase f where+ f (Eta js ab) = Omega js ab++unsafeOmegaToEta :: Ord ab => FreeMod coeff (Omega ab) -> FreeMod coeff (Eta ab)+unsafeOmegaToEta = ZMod.mapBase f where+ f (Omega js ab) = Eta js ab++--------------------------------------------------------------------------------++instance Monoid ab => Monoid (Omega ab) where+ mempty = Omega [] mempty+ (Omega as ab1) `mappend` (Omega bs ab2) = + if nub cs == cs+ then Omega cs (ab1 <> ab2)+ else error "Omega/monoid: duplicate indices"+ where+ cs = sort (as ++ bs)++instance Monoid ab => Monoid (Eta ab) where+ mempty = Eta [] mempty+ (Eta fs ab1) `mappend` (Eta gs ab2) = + if nub hs == hs+ then Eta hs (ab1 <> ab2)+ else error "Eta/monoid: duplicate indices"+ where+ hs = sort (fs ++ gs)++instance Monoid ab => Monoid (Gam ab) where+ mempty = Gam 0 mempty+ (Gam e ab1) `mappend` (Gam f ab2) = Gam (e+f) (ab1 <> ab2)++--------------------------------------------------------------------------------++instance (Pretty ab, Monoid ab, Eq ab) => Pretty (Gam ab) where+ pretty (Gam 0 ab) = pretty ab+ pretty (Gam g ab)+ | ab == mempty = "g^" ++ show g+ | otherwise = "g^" ++ show g ++ "*" ++ pretty ab++instance (Pretty ab, Monoid ab, Eq ab) => Pretty (Eta ab) where+ pretty eta = + case eta of+ (Eta [] ab) -> pretty ab + (Eta is ab) + | ab == mempty -> hs is+ | otherwise -> hs is ++ "*" ++ pretty ab + where+ hs is = case is of+ [] -> ""+ _ -> intercalate "*" [ "h" ++ show i | i<-is ]++instance (Pretty ab, Monoid ab, Eq ab) => Pretty (Omega ab) where+ pretty omega = + case omega of+ (Omega [] ab) -> pretty ab + (Omega is ab) + | ab == mempty -> us is+ | otherwise -> us is ++ "*" ++ pretty ab + where+ us is = case is of+ [] -> ""+ _ -> intercalate "*" [ "u" ++ show i | i<-is ]++--------------------------------------------------------------------------------+
+ src/Math/RootLoci/Geometry/Forget.hs view
@@ -0,0 +1,111 @@++-- | Geometry of the degree @n!@ finite map @pi@, which just forgets the order points:+--+-- > pi : Q^n = P^1 x P^1 x ... x P^1 -> P^n = P(Sym^n C^2)+--+-- It's clear that the degree of @pi@ restricted to an open stratum corresponding to+-- a partition @mu@ is the multinomial coefficient corresponding to @n `choose` mu@.+--+-- It is also not hard to see that the degree of @pi@ restricted to the intersection+-- of the open stratum corresponding to @mu@ with the image of the diagonal map +-- corresponding to @nu@ equals the number of \"automorphisms\" @aut(mu) = prod (e_i!)@+-- where @mu = (1^e1 2^e2 ... k^ek)@ and the number of ways @nu@ is refinement of @mu@.+--+-- Note that for @nu=(1,1...1)@ the multinomial agrees with the number of refinements.+--+-- This module contains functions to compute these numbers.+--++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}+module Math.RootLoci.Geometry.Forget where++--------------------------------------------------------------------------------++import Data.List++import Control.Monad++import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set+import Math.Combinat.Sets++import qualified Data.Map.Strict as Map+import Data.Map.Strict (Map)++import qualified Data.Map.Lazy as LMap++import qualified Data.Set as Set+import Data.Set (Set)++import Data.Array.IArray+import Data.Array.Unboxed+import Data.Array (Array)++import Math.RootLoci.Misc.Common+import Math.RootLoci.Misc.PTable+-- import Math.RootLoci.Geometry.Mobius++--------------------------------------------------------------------------------++-- | Given a partition, we list all coarser partitions together+-- with the number of ways the input is a refinement of the+-- coarser partition.+--+-- TODO: at the moment this is just a synonym for 'countCoarseningsNaive' ...+--+countCoarsenings :: Partition -> Map Partition Integer+countCoarsenings = countCoarseningsNaive++-- | Count coarsenings (with multiplicities) which are shorter by just 1.+countDirectCoarsenings :: Partition -> Map Partition Integer+countDirectCoarsenings part = Map.fromListWith (+) list where+ list = + [ ( fromExponentialFrom ((i1+i2,1):(i1,e1-1):(i2,e2-1):rest) , fromIntegral (e1*e2) )+ | ( (i1,e1):(i2,e2):[] , rest ) <- choose' 2 ies+ ] +++ [ ( fromExponentialFrom ((2*i,1):(i,e-2):rest) , binomial e 2 )+ | ( (i,e):[] , rest ) <- choose' 1 ies+ , e >= 2+ ]+ ies = toExponentialForm part + +--------------------------------------------------------------------------------++-- | Naive (very slow) implementation of 'countCoarsenings'.+countCoarseningsNaive :: Partition -> Map Partition Integer+countCoarseningsNaive = pcache count where++ count (Partition ps) = histogram (map f setps) where+ d = length ps+ setps = map fromSetPartition $ setPartitions d :: [[[Int]]]+ arr = listArray (1,d) ps :: UArray Int Int+ f iss = mkPartition [ sum [ arr ! k | k <- is ] | is <- iss ]++-- | Given a partition @nu@, we stratify the image of the +-- corresponding diagonal @Delta_nu@ as usual, and list+-- the degree of @pi@ restricted to these strata+--+-- This is just counting the coarsenings, multiplied by+-- the number of \"automorphisms\" of the partition.+--+countPreimage :: Partition -> Map Partition Integer+countPreimage = pcache compute where+ compute part = Map.mapWithKey f (countCoarsenings part) + f q c = c * aut q++-- | The preimage counts, but the partition itself is separated out.+preimageView :: Partition -> (Integer, Map Partition Integer)+preimageView part = unsafeDeleteLookup part (countPreimage part) ++--------------------------------------------------------------------------------++-- | The preimage @pi^-1(x)@ of a point under the map +-- @pi : Q^n -> P^n@ is just a multinomial coefficient+countFullPreimage :: Partition -> Integer+countFullPreimage part@(Partition ps) = multinomial ps + +--------------------------------------------------------------------------------++
+ src/Math/RootLoci/Geometry/Mobius.hs view
@@ -0,0 +1,224 @@++-- | Mobius inversion for the coarsening poset of partitions++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}+module Math.RootLoci.Geometry.Mobius + ( Partition(..) + -- * The refinement poset of partitions+ , coarserThan , finerThan+ , (.==.) , (./=.) , (.<=.) , (.>=.) , (.<.) , (.>.) + -- * closures+ , fastClosure , fastAntiClosure+ , closureSet , closureSet'+ -- * Mobius function+ , zetaOf , mobiusOf+ -- * helpers+ , firstLevelDown , firstLevelUp + -- * set partitions+ , closureSetOfSetPartition+ , firstLevelDownSetP+ )+ where++--------------------------------------------------------------------------------++import Data.List++import qualified Data.Map.Strict as Map ; import Data.Map.Strict (Map)+import qualified Data.Set as Set ; import Data.Set (Set)++import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set+import Math.Combinat.Sets++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Algebra+import Math.RootLoci.Misc++--------------------------------------------------------------------------------++{-+indicator :: Bool -> Integer+indicator b = if b then 1 else 0++kronecker' :: Partition -> ZMod Partition+kronecker' p = ZMod.singleton p 1++kronecker :: Partition -> Partition -> Integer+kronecker p q = indicator (p .==. q)++zeta :: Partition -> Partition -> Integer+zeta p q = indicator (p .<=. q)+-}++--------------------------------------------------------------------------------+-- * Mobius function++-- | Zeta function of the refinement poset+zetaOf :: Partition -> ZMod Partition+zetaOf = pcache calc where+ calc p = ZMod.fromList $ map (\p -> (p,1)) $ Set.toList $ closureSet p++-- | Mobius function of the refinement poset+mobiusOf :: Partition -> ZMod Partition+mobiusOf = pcache calc where+ calc p = ZMod.sub (ZMod.singleton p 1) (smaller p)+ smaller p = ZMod.sum [ mobiusOf q | q <- Set.toList (closureSet' p) ]++--------------------------------------------------------------------------------+-- * The refinement poset of partitions++coarserThan :: Partition -> Partition -> Bool+coarserThan p q = Set.member p (closureSet q)++finerThan :: Partition -> Partition -> Bool+finerThan q p = coarserThan p q++(.<=.) :: Partition -> Partition -> Bool+(.<=.) = coarserThan++(.>=.) :: Partition -> Partition -> Bool+(.>=.) = finerThan++(.==.) :: Partition -> Partition -> Bool+(.==.) = (==)++(./=.) :: Partition -> Partition -> Bool+(./=.) = (/=)++(.<.) :: Partition -> Partition -> Bool+(.<.) p q = (p .<=. q) && (p /= q) ++(.>.) :: Partition -> Partition -> Bool+(.>.) p q = (p .>=. q) && (p /= q) ++--------------------------------------------------------------------------------+-- | Efficient first level merge/split++insertRevSorted :: Int -> [Int] -> [Int]+insertRevSorted x = go where+ go yys@(y:ys) = if x >= y then x : yys else y : go ys+ go [] = [x]++insertRevSorted2 :: Int -> Int -> [Int] -> [Int]+insertRevSorted2 x y = insertRevSorted x . insertRevSorted y++-- | Example: +-- +-- > insertGroup [3,3] [[5,5,5],[4],[1,1,1,1]] == [5,5,5,4,3,3,1,1,1,1]+--+insertGroup_ :: [Int] -> [[Int]] -> [Int]+insertGroup_ zs@(z:_) = go where+ go (xs@(x:_):rest) = if z >= x then zs ++ xs ++ concat rest + else xs ++ go rest+ go ([] :rest) = go rest+ go [] = zs+insertGroup_ [] = concat++-- | These satisfy:+--+-- > concat . insertGroup what == insertGroup_ what+--+insertGroup :: [Int] -> [[Int]] -> [[Int]]+insertGroup zs@(z:_) = go where+ go (xs@(x:_):rest) = if z >= x then zs : xs : rest + else xs : go rest+ go ([] :rest) = go rest+ go [] = [zs]+insertGroup [] = id++insertGroup2_ :: [Int] -> [Int] -> [[Int]] -> [Int]+insertGroup2_ xs ys = insertGroup_ xs . insertGroup ys++insertGroup2 :: [Int] -> [Int] -> [[Int]] -> [[Int]]+insertGroup2 xs ys = insertGroup xs . insertGroup ys++choose1 :: [a] -> [(a,[a])]+choose1 (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- choose1 xs ]+choose1 [] = []++choose2 :: [a] -> [(a,a,[a])]+choose2 (x:xs) = [ (x,y,ys ) | (y,ys) <- choose1 xs ]+ ++ [ (y,z,x:zs) | (y,z,zs) <- choose2 xs ]+choose2 [] = []++-- | Merging two parts+firstLevelDown :: Partition -> [Partition]+firstLevelDown (Partition ps) = (one ++ two) where+ gs = group ps+ one = [ Partition $ insertRevSorted (x+y) (insertGroup_ zs rest) | ((x:y:zs) ,rest) <- choose1 gs ]+ two = [ Partition $ insertRevSorted (x+y) (insertGroup2_ xs ys rest) | ((x:xs),(y:ys),rest) <- choose2 gs ]++-- | Splitting one part into two+firstLevelUp :: Partition -> [Partition]+firstLevelUp (Partition ps) = one where+ gs = group ps+ one = [ Partition $ insertRevSorted2 x (z-x) (insertGroup_ zs rest) | ((z:zs),rest) <- choose1 gs , x<-[1..div z 2] ]++-- | Sanity check+firstLevelDownNaive :: Partition -> [Partition]+firstLevelDownNaive (Partition ps) = unique [ mkPartition ( x+y : zs ) | ([x,y],zs) <- choose' 2 ps ]++firstLevelUpNaive :: Partition -> [Partition]+firstLevelUpNaive (Partition ps) = unique [ mkPartition ( x : z-x : zs ) | ([z],zs) <- choose' 1 ps , x<-[1..z-1] ]++checkDown :: Partition -> Bool+checkDown p = (sort (firstLevelDown p) == firstLevelDownNaive p)++checkUp :: Partition -> Bool+checkUp p = (sort (firstLevelUp p) == firstLevelUpNaive p)++--------------------------------------------------------------------------------++-- | Fast computation of a single closure+fastClosure :: Partition -> Set Partition+fastClosure p = go Set.empty [p] where+ go !acc (p:ps) = case Set.member p acc of+ True -> go acc ps+ False -> go (Set.insert p acc) (firstLevelDown p ++ ps)+ go !acc [] = acc++-- | Fast computation of a single \"anticlosure\" (opposite poset)+fastAntiClosure :: Partition -> Set Partition+fastAntiClosure p = go Set.empty [p] where+ go !acc (p:ps) = case Set.member p acc of+ True -> go acc ps+ False -> go (Set.insert p acc) (firstLevelUp p ++ ps)+ go !acc [] = acc++--------------------------------------------------------------------------------++-- | Caches and reuses all closures (lazily), this is the fastest version+closureSet :: Partition -> Set Partition +closureSet = cached where+ cached = monoCache calc + calc p = go (Set.singleton p) (firstLevelDown p) where+ go !acc (p:ps) = case Set.member p acc of+ True -> go acc ps+ False -> go (Set.union acc (cached p)) ps+ go !acc [] = acc++-- | The closure without the stratum itself+closureSet' :: Partition -> Set Partition+closureSet' p = Set.delete p (closureSet p)++--------------------------------------------------------------------------------+-- * set partitions++firstLevelDownSetP :: SetPartition -> [SetPartition]+firstLevelDownSetP (SetPartition ps) =+ [ toSetPartition ( (x++y) : zs ) | ([x,y],zs) <- choose' 2 ps ]+ +closureSetOfSetPartition :: SetPartition -> Set SetPartition +closureSetOfSetPartition = cached where+ cached = monoCache calc+ calc p = go (Set.singleton p) (firstLevelDownSetP p) where+ go !acc (p:ps) = case Set.member p acc of+ True -> go acc ps+ False -> go (Set.union acc (cached p)) ps+ go !acc [] = acc+ +--------------------------------------------------------------------------------+ +
+ src/Math/RootLoci/Misc.hs view
@@ -0,0 +1,13 @@++-- | Re-exporting the Misc.* modules++module Math.RootLoci.Misc + ( module Math.RootLoci.Misc.Common + , module Math.RootLoci.Misc.PTable+ , module Math.RootLoci.Misc.Pretty + )+ where++import Math.RootLoci.Misc.Common +import Math.RootLoci.Misc.PTable+import Math.RootLoci.Misc.Pretty
+ src/Math/RootLoci/Misc/Common.hs view
@@ -0,0 +1,132 @@++-- | Some auxilary functions++{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances, DeriveFunctor #-}+module Math.RootLoci.Misc.Common where++--------------------------------------------------------------------------------++import Data.List+import Data.Monoid+import Data.Ratio++import Control.Monad++import Math.Combinat.Numbers+import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer +import Math.Combinat.Partitions.Set+import Math.Combinat.Sets++import qualified Data.Map.Strict as Map+import Data.Map (Map)++-- import qualified Math.RootLoci.Algebra.FreeMod as ZMod+-- import Math.RootLoci.Algebra.SymmPoly+-- import Math.RootLoci.Geometry.Cohomology++--------------------------------------------------------------------------------+-- * Pairs++data Pair a + = Pair a a + deriving (Eq,Ord,Show,Functor)++--------------------------------------------------------------------------------+-- * Lists++{-# SPECIALIZE unique :: [Partition] -> [Partition] #-}+unique :: Ord a => [a] -> [a]+unique = map head . group . sort++-- | Synonym for histogram+count :: Ord b => [b] -> Map b Integer+count = histogram++{-# SPECIALIZE histogram :: [Partition] -> Map Partition Integer #-}+histogram :: Ord b => [b] -> Map b Integer+histogram xs = foldl' f Map.empty xs where+ f old x = Map.insertWith (+) x 1 old++--------------------------------------------------------------------------------+-- * Maps+ +deleteLookup :: Ord a => a -> Map a b -> (Maybe b, Map a b)+deleteLookup k table = (Map.lookup k table, Map.delete k table) ++unsafeDeleteLookup :: Ord a => a -> Map a b -> (b, Map a b)+unsafeDeleteLookup k table = (fromJust (Map.lookup k table), Map.delete k table) where+ fromJust mb = case mb of+ Just y -> y+ Nothing -> error "unsafeDeleteLookup: key not found"++--------------------------------------------------------------------------------+-- * Partitions++-- | @aut(mu)@ is the number of symmetries of the partition mu:+--+-- > aut(mu) = prod_r (e_r)!+--+-- where @mu = (1^e1 2^e2 .. k^ek)@+aut :: Partition -> Integer+aut part = product $ map factorial es where+ es = map snd $ toExponentialForm part ++--------------------------------------------------------------------------------+-- * Set partitions+ +-- | Makes set partition from a partition (simply filling up from left to right)+-- with the shape giving back the input partition+defaultSetPartition :: Partition -> SetPartition+defaultSetPartition = SetPartition . linearIndices++-- | Produce linear indices from a partition @nu@ (to encode the diagonal map @Delta_nu@).+linearIndices :: Partition -> [[Int]]+linearIndices (Partition ps) = go 0 ps where+ go _ [] = []+ go !k (a:as) = [k+1..k+a] : go (k+a) as++--------------------------------------------------------------------------------+-- * Signs++class IsSigned a where+ signOf :: a -> Maybe Sign++signOfNum :: (Ord a, Num a) => a -> Maybe Sign +signOfNum x = case compare x 0 of+ LT -> Just Minus+ GT -> Just Plus+ EQ -> Nothing++instance IsSigned Int where signOf = signOfNum+instance IsSigned Integer where signOf = signOfNum+instance IsSigned Rational where signOf = signOfNum++--------------------------------------------------------------------------------+-- * Numbers++fromRat :: Rational -> Integer+fromRat r = case denominator r of+ 1 -> numerator r+ _ -> error "fromRat: not an integer" ++safeDiv :: Integer -> Integer -> Integer+safeDiv a b = case divMod a b of+ (q,0) -> q+ (q,r) -> error $ "saveDiv: " ++ show a ++ " = " ++ show b ++ " * " ++ show q ++ " + " ++ show r++--------------------------------------------------------------------------------+-- * Combinatorics++-- | Chooses (n-1) elements out of n+chooseN1 :: [a] -> [[a]]+chooseN1 = go where+ go (x:xs) = xs : map (x:) (go xs)+ go [] = []+ +symPolyNum :: Num a => Int -> [a] -> a+symPolyNum k xs = sum' (map prod' $ choose k xs) where+ sum' = foldl' (+) 0+ prod' = foldl' (*) 1++--------------------------------------------------------------------------------
+ src/Math/RootLoci/Misc/PTable.hs view
@@ -0,0 +1,130 @@++-- | Infinite lazy partition tables (used for caching).+--+-- We cache almost all computations (which would be otherwise typically +-- executed many times); this really helps performance.+--++{-# LANGUAGE Rank2Types #-} +module Math.RootLoci.Misc.PTable where++--------------------------------------------------------------------------------++import Data.List++import Math.Combinat.Classes+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set++import qualified Data.Map.Lazy as LMap++import Math.RootLoci.Algebra.SymmPoly++--------------------------------------------------------------------------------+-- * Finite lazy partition tables++newtype PTable a = PTable (LMap.Map Partition a)++createPTable :: (Partition -> a) -> Int -> PTable a+createPTable f n = PTable $ LMap.fromList [ (p, f p) | p <- partitions n ]++lookupPTable :: Partition -> PTable a -> a+lookupPTable p (PTable lmap) = case LMap.lookup p lmap of+ Just y -> y+ Nothing -> error "lookupPTable"++--------------------------------------------------------------------------------+-- * Infinite lazy partition tables++newtype PSeries a = PSeries [PTable a]+ +createPSeries :: (Partition -> a) -> PSeries a+createPSeries f = PSeries [ createPTable f n | n<-[0..] ]++lookupPSeries :: Partition -> PSeries a -> a+lookupPSeries part (PSeries series) = lookupPTable part (series !! partitionWeight part)++--------------------------------------------------------------------------------+-- * Finite lazy set-partition tables++newtype SetPTable a = SetPTable (LMap.Map SetPartition a)++createSetPTable :: (SetPartition -> a) -> Int -> SetPTable a+createSetPTable f n = SetPTable $ LMap.fromList [ (p, f p) | p <- setPartitions n ]++lookupSetPTable :: SetPartition -> SetPTable a -> a+lookupSetPTable p (SetPTable lmap) = case LMap.lookup p lmap of+ Just y -> y+ Nothing -> error "lookupSetPTable"++--------------------------------------------------------------------------------+-- * Infinite lazy set-partition tables++newtype SetPSeries a = SetPSeries [SetPTable a]+ +createSetPSeries :: (SetPartition -> a) -> SetPSeries a+createSetPSeries f = SetPSeries [ createSetPTable f n | n<-[0..] ]++lookupSetPSeries :: SetPartition -> SetPSeries a -> a+lookupSetPSeries setp (SetPSeries series) = lookupSetPTable setp (series !! setpWeight setp) where+ setpWeight (SetPartition ps) = foldl' (+) 0 (map length ps)++--------------------------------------------------------------------------------+-- * polymorphic caching ++polyCache1 + :: (CacheKey key) + => (forall base. ChernBase base => key -> f base) -- ^ polymorphic function to be cached+ -> (forall base. ChernBase base => key -> f base)+polyCache1 calc = \key -> select1 (cacheAB key, cacheChern key) where+ cacheAB = monoCache $ \k -> spec1' ChernRoot (calc k)+ cacheChern = monoCache $ \k -> spec1' ChernClass (calc k)++polyCache2 + :: (CacheKey key) + => (forall base. ChernBase base => key -> f (g base)) -- ^ polymorphic function to be cached+ -> (forall base. ChernBase base => key -> f (g base))+polyCache2 calc = \key -> select2 (cacheAB key, cacheChern key) where+ cacheAB = monoCache $ \k -> spec2' ChernRoot (calc k)+ cacheChern = monoCache $ \k -> spec2' ChernClass (calc k)++polyCache3 + :: (CacheKey key) + => (forall base. ChernBase base => key -> f (g (h base))) -- ^ polymorphic function to be cached+ -> (forall base. ChernBase base => key -> f (g (h base)))+polyCache3 calc = \key -> select3 (cacheAB key, cacheChern key) where+ cacheAB = monoCache $ \k -> spec3' ChernRoot (calc k)+ cacheChern = monoCache $ \k -> spec3' ChernClass (calc k)++--------------------------------------------------------------------------------+-- * monomorphic caching ++class CacheKey key where+ monoCache :: (key -> a) -> (key -> a)++instance CacheKey Int where monoCache = icache+instance CacheKey Partition where monoCache = pcache+instance CacheKey SetPartition where monoCache = setpcache++--------------------------------------------------------------------------------+-- * individual caching functions++pcache :: (Partition -> a) -> (Partition -> a)+pcache calc = lkp where+ lkp p = lookupPSeries p table + table = createPSeries calc++setpcache :: (SetPartition -> a) -> (SetPartition -> a)+setpcache calc = lkp where+ lkp setp = lookupSetPSeries setp table + table = createSetPSeries calc++icache :: (Int -> a) -> (Int -> a)+icache calc = \n -> (table !! n) where+ table = [ calc i | i <- [0..] ]++icache' :: a -> Int -> (Int -> a) -> (Int -> a)+icache' dflt fstidx calc = \n -> if n < fstidx then dflt else (table !! (n-fstidx)) where+ table = [ calc i | i <- [fstidx..] ]++--------------------------------------------------------------------------------
+ src/Math/RootLoci/Misc/Pretty.hs view
@@ -0,0 +1,137 @@++{-# LANGUAGE FlexibleInstances #-}++-- | Pretty-printing+ +module Math.RootLoci.Misc.Pretty where++--------------------------------------------------------------------------------++import Data.List++import Math.Combinat.Sign+import Math.Combinat.Partitions.Integer++import qualified Data.Map.Strict as Map+import Data.Map.Strict (Map)++import Math.RootLoci.Algebra.FreeMod ( FreeMod, ZMod, QMod )+import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Misc.Common++--------------------------------------------------------------------------------++class Pretty a where+ pretty :: a -> String++-- instance Pretty a => Pretty (ZMod a) where+-- pretty = prettyZMod pretty++instance (Num c, Eq c, Show c, IsSigned c, Pretty b) => Pretty (FreeMod c b) where+ pretty = prettyFreeMod' True pretty++--------------------------------------------------------------------------------+-- * Pretty printing elements of free modules++-- | Example: @showVarPower "x" 5 == "x^5"@+showVarPower :: String -> Int -> String+showVarPower name expo = case expo of+ 0 -> "1"+ 1 -> name+ _ -> name ++ "^" ++ show expo++--------------------------------------------------------------------------------++-- | no multiplication sign (ok for mathematica and humans)+prettyZMod_ :: (b -> String) -> ZMod b -> String+prettyZMod_ = prettyFreeMod' False+ +-- | multiplication sign (ok for maple etc)+prettyZMod :: (b -> String) -> ZMod b -> String+prettyZMod = prettyFreeMod' True++--------------------------------------------------------------------------------++prettyFreeMod' + :: (Num c, Eq c, Show c, IsSigned c) + => Bool -- ^ use star for multiplication (@False@ means just concatenation)+ -> (b -> String) -- ^ show base+ -> FreeMod c b + -> String+prettyFreeMod' star showBase what = final where+ final = if take 3 stuff == " + " then drop 3 stuff else drop 1 stuff+ stuff = concatMap f (ZMod.toList what) + f (g, 1) = plus ++ showBase' g+ f (g, -1) = minus ++ showBase' g+ f (g, c) = sgn c ++ {- extendStringR 3 -} (show $ abs c) ++ starStr ++ showBase' g+ -- cond (_,c) = (c/=0)+ starStr = if star then "*" else " "+ showBase' g = case showBase g of+ "" -> "1" -- "(1)"+ s -> s+ sgn c = case signOf c of+ Just Minus -> minus+ _ -> plus+ plus = " + "+ minus = " - "++prettyFreeMod'' + :: (c -> String) -- ^ show coefficient+ -> (b -> String) -- ^ show base+ -> FreeMod c b + -> String+prettyFreeMod'' showCoeff showBase what = result where+ result = intercalate " + " (map f $ ZMod.toList what) + f (g, c) = showCoeff c ++ starStr ++ showBase' g+ starStr = "*" -- if star then "*" else " "+ showBase' g = case showBase g of+ "" -> "1" -- "(1)"+ s -> s++--------------------------------------------------------------------------------+-- * Utility++-- | Put into parentheses+paren :: String -> String+paren s = '(' : s ++ ")"++--------------------------------------------------------------------------------++-- | Exponential form of a partition+expFormString :: Partition -> String+expFormString p = "(" ++ intercalate "," (map f ies) ++ ")" where+ ies = toExponentialForm p+ f (i,e) = show i ++ "^" ++ show e++extendStringL :: Int -> String -> String+extendStringL k s = s ++ replicate (k - length s) ' '++extendStringR :: Int -> String -> String+extendStringR k s = replicate (k - length s) ' ' ++ s++--------------------------------------------------------------------------------+-- * Mathematica-formatted output++class Mathematica a where+ mathematica :: a -> String++instance Mathematica Int where+ mathematica = show++instance Mathematica Integer where+ mathematica = show++instance Mathematica String where+ mathematica = show++instance Mathematica Partition where+ mathematica (Partition ps) = "{" ++ intercalate "," (map show ps) ++ "}"++data Indexed a = Indexed String a++instance Mathematica a => Mathematica (Indexed a) where+ mathematica (Indexed x sub) = "Subscript[" ++ x ++ "," ++ mathematica sub ++ "]"++--------------------------------------------------------------------------------+
+ test/Tests/CSM/Equivariant.hs view
@@ -0,0 +1,91 @@++-- | Tests for the equivariant CSM class+++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.CSM.Equivariant where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Classes+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.CSM.Equivariant.Ordered as Ordered+import qualified Math.RootLoci.CSM.Equivariant.Recursive as Recur+import qualified Math.RootLoci.CSM.Equivariant.Direct as Direct+import qualified Math.RootLoci.CSM.Equivariant.Umbral as Umbral++import Math.RootLoci.Classic+import Math.RootLoci.CSM.Aluffi++import Tests.Common++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "equivariant (projective) CSM classes"+ [ testGroup "ordered"+ [ testCase "structure lemma" (forList [-3..4] "failed" prop_structure_lemma )+ , testCase "rec. ord. distinct = U(n) formula /AB" (forAllInt 7 "failed" $ prop_Un_equals_recursive ChernRoot )+ , testCase "rec. ord. distinct = U(n) formula /Chern" (forAllInt 7 "failed" $ prop_Un_equals_recursive ChernClass )+ , testCase "recur. upper = sum of direct opens /AB" (forAllSetp 6 "failed" $ prop_ord_rec_upper_vs_sum_direct ChernRoot )+ , testCase "recur. upper = sum of direct opens /Chern" (forAllSetp 6 "failed" $ prop_ord_rec_upper_vs_sum_direct ChernClass )+ , testCase "tangent class = sum of all strata" (forAllInt 7 "failed" $ prop_tangent_class_equals_sum ChernClass)+ ]+ , testGroup "unordered"+ [ testGroup "direct"+ [ testCase "recursive CSM = direct CSM (open) /AB" (forAllPart 8 "failed" $ prop_recur_direct_open ChernRoot ) + , testCase "recursive CSM = direct CSM (open) /Chern" (forAllPart 8 "failed" $ prop_recur_direct_open ChernClass ) + , testCase "recursive CSM = direct CSM (closed) /AB" (forAllPart 8 "failed" $ prop_recur_direct_closed ChernRoot ) + , testCase "recursive CSM = direct CSM (closed) /Chern" (forAllPart 8 "failed" $ prop_recur_direct_closed ChernClass ) + ]+ , testGroup "umbral"+ [ testCase "umbral CSM = direct CSM (open) /AB" (forAllPart 10 "failed" $ prop_umbral_vs_direct_open ChernRoot ) + , testCase "umbral CSM = direct CSM (open) /Chern" (forAllPart 10 "failed" $ prop_umbral_vs_direct_open ChernClass ) + , testCase "umbral CSM = direct CSM (closed) /AB" (forAllPart 10 "failed" $ prop_umbral_vs_direct_closed ChernRoot ) + , testCase "umbral CSM = direct CSM (closed) /Chern" (forAllPart 10 "failed" $ prop_umbral_vs_direct_closed ChernClass ) + ]+ ]+ ]++--------------------------------------------------------------------------------++prop_umbral_vs_direct_open sing part + = ( spec2' sing (Direct.directOpenCSM part) == spec2' sing (Umbral.umbralOpenCSM part) )++prop_umbral_vs_direct_closed sing part + = ( spec2' sing (Direct.directClosedCSM part) == spec2' sing (Umbral.umbralClosedCSM part) )++prop_recur_direct_open sing part = (spec2' sing (Direct.directOpenCSM part) == spec2' sing (Recur.openCSM part))+prop_recur_direct_closed sing part = (spec2' sing (Direct.directClosedCSM part) == spec2' sing (Recur.closedCSM part))++--------------------------------------------------------------------------------++-- very slow for n>=5 !! (because we have +3, so 5 -> 8)+prop_structure_lemma n = (Ordered.computeQPolys n == Ordered.formulaQPoly n)++prop_Un_equals_recursive sing n = + (spec2' sing $ Ordered.computeOpenStratumCSM n) == + (spec2' sing $ Ordered.formulaDistinctCSM n)++prop_ord_rec_upper_vs_sum_direct sing setp =+ (spec2' sing $ unsafeEtaToOmega (Recur.upperClass setp)) ==+ (spec2' sing $ Ordered.computeClosureOfAnyStratumCSM setp ) ++prop_tangent_class_equals_sum sing n = + (spec2' sing $ Ordered.tangentChernClass n) == + (spec2' sing $ ZMod.sum [ Ordered.formulaAnyStratumCSM setp | setp <- setPartitions n ]) + +--------------------------------------------------------------------------------+
+ test/Tests/CSM/Projective.hs view
@@ -0,0 +1,54 @@++-- | Tests for the non-equivarant CSM classes++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.CSM.Projective where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Classes+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.CSM.Equivariant.Ordered as Ordered+import qualified Math.RootLoci.CSM.Equivariant.Direct as Direct++import Math.RootLoci.Classic++import qualified Math.RootLoci.CSM.Aluffi as Aluffi+import qualified Math.RootLoci.CSM.Projective as Proj++import Tests.Common++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "non-equivariant CSM classes"+ [ testGroup "unordered"+ [ testCase "aluffi == recursive (open)" (forAllPart 10 "failed" prop_aluffi_vs_recursive_open )+ , testCase "aluffi == recursive (closed)" (forAllPart 10 "failed" prop_aluffi_vs_recursive_closed )+ , testCase "aluffi == from equiv (open)" (forAllPart 10 "failed" prop_aluffi_vs_equiv_open )+ , testCase "aluffi == from equiv. (closed)" (forAllPart 10 "failed" prop_aluffi_vs_equiv_closed )+ , testCase "degree == lowest coeff of CSM" (forAllPart 10 "failed" prop_csm_degree )+ ]+ ]++prop_aluffi_vs_recursive_open part = (Proj.openCSM part == Aluffi.aluffiOpenCSM part)+prop_aluffi_vs_recursive_closed part = (Proj.closedCSM part == Aluffi.aluffiClosedCSM part)++prop_aluffi_vs_equiv_open part = (Aluffi.aluffiOpenCSM part == forgetEquiv (spec2' ChernClass $ Direct.directOpenCSM part))+prop_aluffi_vs_equiv_closed part = (Aluffi.aluffiClosedCSM part == forgetEquiv (spec2' ChernClass $ Direct.directClosedCSM part))++prop_csm_degree part = (hilbert part == Proj.lowestCoeff_ (Proj.closedCSM part))++--------------------------------------------------------------------------------
+ test/Tests/Common.hs view
@@ -0,0 +1,35 @@++-- | Shared utilities for testing++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.Common where++--------------------------------------------------------------------------------++import Math.Combinat.Classes+import Math.Combinat.Partitions.Integer+import Math.Combinat.Partitions.Set++import Math.RootLoci.Algebra+import Math.RootLoci.Misc++import Test.Tasty.HUnit++--------------------------------------------------------------------------------++forList :: [a] -> String -> (a -> Bool) -> Assertion+forList xs msg check = assertBool msg $ and [ check x | x <- xs ]++forAllInt :: Int -> String -> (Int -> Bool) -> Assertion+forAllInt maxn msg check = assertBool msg $ and [ check i | i<-[0..maxn] ]++forAllPart :: Int -> String -> (Partition -> Bool) -> Assertion+forAllPart maxn msg check = assertBool msg $ and [ check p | p <- allPartitions maxn ]++forAllPartPos :: Int -> String -> (Partition -> Bool) -> Assertion+forAllPartPos maxn msg check = assertBool msg $ and [ check p | p <- allPartitions maxn , not (isEmpty p) ]++forAllSetp :: Int -> String -> (SetPartition -> Bool) -> Assertion+forAllSetp maxn msg check = assertBool msg $ and [ check p | k<-[0..maxn] , p <- setPartitions k ]++--------------------------------------------------------------------------------
+ test/Tests/Dual.hs view
@@ -0,0 +1,54 @@++-- | Tests involving the cohomological dual+++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.Dual where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Classes+import Math.Combinat.Partitions++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import qualified Math.RootLoci.Dual.Restriction as MSc+import qualified Math.RootLoci.Dual.Localization as FNR++import qualified Math.RootLoci.CSM.Equivariant.Direct as Direct++import Math.RootLoci.Classic+import Math.RootLoci.CSM.Aluffi++import Tests.Common++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "dual classes"+ [ testCase "lemma 9.1.3" (forAllPartPos 15 "failed" prop_lemma913 ) + , testCase "proj degree matches Hilbert" (forAllPartPos 15 "failed" prop_degree_Hilbert )+ , testCase "proj degree matches Aluffi" (forAllPartPos 14 "failed" prop_degree_Aluffi )+ , testCase "dual class agrees with localization" (forAllPartPos 14 "failed" prop_msc_equals_local)+ + , testCase "dual class = lowest deg part of open CSM" (forAllPartPos 10 "failed" prop_msc_equals_lowest_csm_open )+ , testCase "dual class = lowest deg part of closed CSM" (forAllPartPos 10 "failed" prop_msc_equals_lowest_csm_closed)+ ]++prop_lemma913 part = and [ MSc.lemma913 part k | k<-[0..m] ] where m = numberOfParts part+ +prop_degree_Hilbert part = (MSc.degreeMSc part == hilbert part)+prop_degree_Aluffi part = (MSc.degreeMSc part == aluffiDegree part)++prop_msc_equals_local part = FNR.localizeDual part == chernToAB (MSc.affineDualMSc part)++prop_msc_equals_lowest_csm_open part = MSc.dualClassFromProjCSM (Direct.directOpenCSM part) == MSc.affineDualMSc part+prop_msc_equals_lowest_csm_closed part = MSc.dualClassFromProjCSM (Direct.directClosedCSM part) == MSc.affineDualMSc part++--------------------------------------------------------------------------------
+ test/Tests/Pushforward.hs view
@@ -0,0 +1,49 @@++-- | Tests for the push-forward+++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.Pushforward where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Classes+import Math.Combinat.Partitions++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import Math.RootLoci.CSM.Equivariant.PushForward ++import Math.RootLoci.Classic++import Tests.Common++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "pushforward"+ [ testCase "tau definition" (forList [-1..20] "failed" prop_tau_defin ) + , testCase "symm breaking pi_* == recursive formula for P_j" (forAllInt 20 "failed" prop_symmbreaking_vs_ppolys ) + , testCase "affine pi_* == proj pi_* [ gamma -> 0 ] /AB" (forAllInt 20 "failed" (prop_ppoly_aff_vs_proj ChernRoot ))+ , testCase "affine pi_* == proj pi_* [ gamma -> 0 ] /Chern" (forAllInt 20 "failed" (prop_ppoly_aff_vs_proj ChernClass))+ ]++prop_symmbreaking_vs_ppolys n = spec3' ChernRoot (piStarTableProj n) == pi_star_table n++prop_ppoly_aff_vs_proj sing n = spec2' sing (piStarTableAff n) == fmap forgetGamma (spec3' sing (piStarTableProj n))++prop_tau_defin n = (tau n * (a - b)) == (apow - bpow) where+ a = ZMod.generator $ AB 1 0 + b = ZMod.generator $ AB 0 1 + apow = ZMod.generator $ AB (n+1) 0 + bpow = ZMod.generator $ AB 0 (n+1)++--------------------------------------------------------------------------------
+ test/Tests/RootVsClass/Check.hs view
@@ -0,0 +1,93 @@++-- | Checking polymorphic functions++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies, ScopedTypeVariables #-}+module Tests.RootVsClass.Check where++--------------------------------------------------------------------------------++-- import Data.Proxy+-- import Math.Combinat.Partitions++import Data.Array++import Math.RootLoci.Algebra+import Math.RootLoci.Misc+import Math.RootLoci.Geometry.Cohomology ++import qualified Math.RootLoci.Algebra.FreeMod as ZMod++import Math.RootLoci.CSM.Equivariant.Umbral ( ST )++--------------------------------------------------------------------------------++checkZMod :: (forall b. ChernBase b => ZMod b) -> Bool+checkZMod polymorph+ = ( abToChern (spec1' ChernRoot polymorph) == spec1' ChernClass polymorph )+ && ( spec1' ChernRoot polymorph == chernToAB (spec1' ChernClass polymorph) ) ++{-+checkZModExt :: forall f. Equivariant f => (forall b. ChernBase b => ZMod (f b)) -> Bool+checkZModExt polymorph+ = ( convertEquiv abToChern (spec2' ChernRoot polymorph) == spec2' ChernClass polymorph )+ && ( spec2' ChernRoot polymorph == convertEquiv chernToAB (spec2' ChernClass polymorph) ) +-}++--------------------------------------------------------------------------------++{-+checkGam :: (forall b. ChernBase b => ZMod (Gam b)) -> Bool+checkOmega :: (forall b. ChernBase b => ZMod (Omega b)) -> Bool+checkEta :: (forall b. ChernBase b => ZMod (Eta b)) -> Bool++checkGam = checkZModExt+checkOmega = checkZModExt+checkEta = checkZModExt+-}++checkOmega :: (forall b. ChernBase b => ZMod (Omega b)) -> Bool+checkOmega polymorph+ = ( convertOmega abToChern (spec2' ChernRoot polymorph) == spec2' ChernClass polymorph )+ && ( spec2' ChernRoot polymorph == convertOmega chernToAB (spec2' ChernClass polymorph) ) ++checkEta :: (forall b. ChernBase b => ZMod (Eta b)) -> Bool+checkEta polymorph+ = ( convertEta abToChern (spec2' ChernRoot polymorph) == spec2' ChernClass polymorph )+ && ( spec2' ChernRoot polymorph == convertEta chernToAB (spec2' ChernClass polymorph) ) ++checkGam :: (forall b. ChernBase b => ZMod (Gam b)) -> Bool+checkGam polymorph+ = ( convertGam abToChern (spec2' ChernRoot polymorph) == spec2' ChernClass polymorph )+ && ( spec2' ChernRoot polymorph == convertGam chernToAB (spec2' ChernClass polymorph) ) ++--------------------------------------------------------------------------------++checkArrZMod :: (forall b. ChernBase b => Array Int (ZMod b)) -> Bool+checkArrZMod polymorph+ = ( fmap abToChern (spec2' ChernRoot polymorph) == spec2' ChernClass polymorph )+ && ( spec2' ChernRoot polymorph == fmap chernToAB (spec2' ChernClass polymorph) ) ++checkArrGam :: (forall b. ChernBase b => Array Int (ZMod (Gam b))) -> Bool+checkArrGam polymorph+ = ( fmap fwd (spec3' ChernRoot polymorph) == spec3' ChernClass polymorph )+ && ( spec3' ChernRoot polymorph == fmap bwd (spec3' ChernClass polymorph) ) + where+ fwd = convertGam abToChern+ bwd = convertGam chernToAB+ +--------------------------------------------------------------------------------++{-+checkMixedST :: forall c. (Eq c, Num c) => (forall b. ChernBase b => FreeMod (FreeMod c b) ST) -> Bool+checkMixedST polymorph+ = ( fwd (spec2' ChernRoot polymorph) == spec2' ChernClass polymorph )+ && ( spec2' ChernRoot polymorph == bwd (spec2' ChernClass polymorph) ) + where+ fwd :: FreeMod (FreeMod c AB ) ST -> FreeMod (FreeMod c Chern) ST + bwd :: FreeMod (FreeMod c Chern) ST -> FreeMod (FreeMod c AB ) ST + fwd = ZMod.mapCoeff abToChern+ bwd = ZMod.mapCoeff chernToAB+-}++--------------------------------------------------------------------------------+
+ test/Tests/RootVsClass/Direct.hs view
@@ -0,0 +1,36 @@++-- | Comparing the Chern root vs. the Chern class versions for stuff in+-- "Math.RootLoci.CSM.Equivariant.Direct"++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.RootVsClass.Direct where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Partitions++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import Math.RootLoci.CSM.Equivariant.Direct ++import Tests.Common+import Tests.RootVsClass.Check++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "direct"+ [ testCase "open CSM" (forAllPart 9 "failed" prop_directOpenCSM ) + , testCase "closed CSM" (forAllPart 9 "failed" prop_directClosedCSM) + ]+ +prop_directOpenCSM part = checkGam (directOpenCSM part)+prop_directClosedCSM part = checkGam (directClosedCSM part)++--------------------------------------------------------------------------------
+ test/Tests/RootVsClass/Ordered.hs view
@@ -0,0 +1,46 @@++-- | Comparing the Chern root vs. the Chern class versions for stuff in+-- "Math.RootLoci.CSM.Equivariant.Ordered"++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.RootVsClass.Ordered where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Partitions++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import Math.RootLoci.CSM.Equivariant.Ordered ++import Tests.Common+import Tests.RootVsClass.Check++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "ordered"+ [ testCase "tangent Chern class" (forAllInt 9 "failed" prop_tangentChernClass )+ , testCase "small diagonals" (forAllInt 9 "failed" prop_smallDiagonal )+ , testCase "open stratum" (forAllInt 7 "failed" prop_openStratumCSM )+ , testCase "any stratum" (forAllSetp 6 "failed" prop_anyStratumCSM )+ , testCase "formula for Q-poly" (forList [-3.. 20] "failed" prop_formulaQPoly )+ , testCase "formula U(n)" (forAllInt 10 "failed" prop_formulaDistinctCSM )+ ]+ +--------------------------------------------------------------------------------++prop_tangentChernClass n = checkOmega (tangentChernClass n)+prop_smallDiagonal n = checkOmega (smallDiagonal n)+prop_openStratumCSM n = checkOmega (computeOpenStratumCSM n)+prop_anyStratumCSM setp = checkOmega (computeAnyStratumCSM setp)+prop_formulaDistinctCSM n = checkOmega (formulaDistinctCSM n)+prop_formulaQPoly n = checkZMod (formulaQPoly n)++--------------------------------------------------------------------------------
+ test/Tests/RootVsClass/PushForward.hs view
@@ -0,0 +1,41 @@++-- | Comparing the Chern root vs. the Chern class versions for stuff in+-- "Math.RootLoci.CSM.Equivariant.PushForward"++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.RootVsClass.PushForward where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Partitions++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import Math.RootLoci.CSM.Equivariant.PushForward++import Tests.Common+import Tests.RootVsClass.Check++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "pushforward"+ [ testCase "tau" (forAllInt 20 "failed" prop_tau ) + , testCase "tauEta" (forAllInt 20 "failed" prop_tauEta ) + , testCase "piStarTableAff" (forAllInt 15 "failed" prop_piStarTableAff ) + , testCase "piStarTableProj" (forAllInt 15 "failed" prop_piStarTableProj ) + ]+ +prop_tau n = checkZMod (tau n)+prop_tauEta n = checkEta (tauEta n)++prop_piStarTableAff n = checkArrZMod (piStarTableAff n)+prop_piStarTableProj n = checkArrGam (piStarTableProj n)++--------------------------------------------------------------------------------
+ test/Tests/RootVsClass/Recursive.hs view
@@ -0,0 +1,44 @@++-- | Comparing the Chern root vs. the Chern class versions for stuff in+-- "Math.RootLoci.CSM.Equivariant.Recursive"++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.RootVsClass.Recursive where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Partitions++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import Math.RootLoci.CSM.Equivariant.Recursive ++import Tests.Common+import Tests.RootVsClass.Check++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "recursive"+ [ testCase "upper classes /setp" (forAllSetp 6 "failed" prop_upper_setp )+ , testCase "upper classes /part" (forAllPart 7 "failed" prop_upper_part )+ , testCase "lower classes" (forAllPart 7 "failed" prop_lower )+ , testCase "open CSM" (forAllPart 8 "failed" prop_openCSM ) + , testCase "closed CSM" (forAllPart 8 "failed" prop_closedCSM) + ]+ +prop_openCSM part = checkGam (openCSM part)+prop_closedCSM part = checkGam (closedCSM part)++prop_upper_setp setp = checkEta (upperClass $ setp)+prop_upper_part part = checkEta (upperClass $ defaultSetPartition part)++prop_lower part = checkGam (lowerClass part)++--------------------------------------------------------------------------------
+ test/Tests/RootVsClass/Umbral.hs view
@@ -0,0 +1,42 @@++-- | Comparing the Chern root vs. the Chern class versions for stuff in+-- "Math.RootLoci.CSM.Equivariant.Umbral"++{-# LANGUAGE Rank2Types, GADTs, TypeFamilies #-}+module Tests.RootVsClass.Umbral where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Combinat.Partitions++import Math.RootLoci.Algebra+import Math.RootLoci.Geometry+import Math.RootLoci.Misc++import Math.RootLoci.CSM.Equivariant.Umbral++import Tests.Common+import Tests.RootVsClass.Check++import Test.Tasty+import Test.Tasty.HUnit++--------------------------------------------------------------------------------++all_tests = testGroup "umbral"+ [ + testCase "open affine CSM" (forAllPart 11 "failed" prop_umbralAffOpenCSM ) + , testCase "closed affine CSM" (forAllPart 11 "failed" prop_umbralAffClosedCSM) + -- , testCase "theta" (forAllPosInt 15 "failed" prop_theta ) + -- , testCase "thetaQ" (forAllPosInt 15 "failed" prop_thetaQ) + ]+ +-- prop_theta n = checkMixedST (theta n)+-- prop_thetaQ n = checkMixedST (thetaQ n)++prop_umbralAffOpenCSM part = checkZMod (umbralAffOpenCSM part)+prop_umbralAffClosedCSM part = checkZMod (umbralAffClosedCSM part)++--------------------------------------------------------------------------------
+ test/testSuite.hs view
@@ -0,0 +1,49 @@++-- | The test-suite++module Main where++--------------------------------------------------------------------------------++import Test.Tasty++-- import Test.Tasty.HUnit+-- import Test.Tasty.SmallCheck as SC+-- import Test.Tasty.QuickCheck as QC++import qualified Tests.RootVsClass.Ordered +import qualified Tests.RootVsClass.Recursive+import qualified Tests.RootVsClass.Direct+import qualified Tests.RootVsClass.PushForward+import qualified Tests.RootVsClass.Umbral++import qualified Tests.Dual+import qualified Tests.Pushforward++import qualified Tests.CSM.Equivariant+import qualified Tests.CSM.Projective++--------------------------------------------------------------------------------++main = defaultMain tests++tests :: TestTree+tests = testGroup "Tests" + [ Tests.Pushforward.all_tests+ , Tests.CSM.Projective.all_tests+ , Tests.CSM.Equivariant.all_tests+ , rootVsClass+ , Tests.Dual.all_tests+ ]++rootVsClass :: TestTree +rootVsClass = testGroup "chern root vs. chern class tests"+ [ Tests.RootVsClass.Ordered.all_tests+ , Tests.RootVsClass.Recursive.all_tests+ , Tests.RootVsClass.Direct.all_tests+ , Tests.RootVsClass.PushForward.all_tests+ , Tests.RootVsClass.Umbral.all_tests+ ]++--------------------------------------------------------------------------------+