coincident-root-loci-0.3: src/Math/RootLoci/Motivic/Abstract.hs
-- | The abstract motivic algorithm
--
-- See: B. Komuves: Motivic characteristic classes of discriminant strata
--
-- TODO: caching of results (otherwise it is very slow)
{-# LANGUAGE CPP, BangPatterns, FlexibleInstances, TypeSynonymInstances,
MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving,
TypeFamilies
#-}
module Math.RootLoci.Motivic.Abstract where
--------------------------------------------------------------------------------
import Data.Char
import Data.List
import Data.Ord
import Data.Maybe
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import qualified Math.Algebra.Polynomial.FreeModule as ZMod
import Math.Algebra.Polynomial.FreeModule (ZMod,QMod,FreeMod)
import Math.Algebra.Polynomial.Pretty
import Math.Combinat.Classes hiding (empty)
import Math.Combinat.Tuples
import Math.Combinat.Partitions
import Math.Combinat.Permutations hiding (permute)
-- import Debug.Trace
-- debug s x y = trace (">>> " ++ s ++ " -> " ++ show x) y
import Math.RootLoci.Motivic.Classes
import Math.RootLoci.Misc.Common
--------------------------------------------------------------------------------
-- * The abstract algorithm
-- | The (abstract) class of @Sym^n(X)@
symn :: Num c => Dim -> FreeMod c SingleLam
symn dim = ZMod.generator $ SingleLam (Bindings [dim]) (Single [(DeBruijn 0, 1)])
-- | The open stratum X(1,1,...,1)
open :: Dim -> ZMod SingleLam
open d@(Dim n) = symn d `ZMod.sub` rest where
rest = ZMod.sum [ xlam p | p <- partitions n , width p < n ]
zeros :: Int -> ZMod MultiLam
zeros k = ZMod.generator
$ MultiLam (Bindings []) (Multi $ replicate k (Single []))
-- | The open stratum X(lambda)
xlam :: Partition -> ZMod SingleLam
xlam p =
if height p == 1
then open (Dim $ weight p)
else normalize $ psi $ omega123 $ dvec $ dimVector p
-- | The open stratum D(n1,n2,...)
dvec :: [Dim] -> ZMod MultiLam
dvec dims0 = permute invperm sorted where
invperm = inversePermutation perm
perm = sortingPermutationDesc dims0
dims1 = permuteList perm dims0
(dims2,dzeros) = span (>0) dims1 -- separate zero dimensions
sorted = cross (dvecSorted dims2) (zeros $ length dzeros)
-- | The open stratum D(n1,n2,...), assuming @n1 >= n2 >= n3 >= ...@
dvecSorted :: [Dim] -> ZMod MultiLam
dvecSorted [] = error "dvec: empty dimension vector shouldn't appear in the algorithm"
dvecSorted [n] = singleToMulti (open n)
dvecSorted (p:ns) = normalize (ZMod.sub big rest) where
big = cross (singleToMulti $ open p) (dvecSorted ns)
rest = ZMod.sum
[ theta (dvec (k : interleave ds es))
| ds <- dimTuples ns
, let es = zipWith (-) ns ds
, let l = sum es
, l > 0
, let k = p - l
, k >= 0
]
--------------------------------------------------------------------------------
-- * Data types and instances
-- | A variable, implemented as a /de Bruijn level/ (indexing starts from 0)
newtype Var
= DeBruijn Int
deriving (Eq,Ord,Show)
--------------------------------------------------------------------------------
-- | We use de Bruijn levels to index the bound variables, and ecah bound variables has a dimension
newtype Bindings
= Bindings [Dim]
deriving (Eq,Ord,Show)
numberOfBoundVariables :: Bindings -> Int
numberOfBoundVariables (Bindings ds) = length ds
dimensionTable :: Bindings -> Map Var Dim
dimensionTable (Bindings dims) = Map.fromList $ zip (map DeBruijn [0..]) dims
--------------------------------------------------------------------------------
-- | An expression living on @Sym^n(X)@, with free variables
newtype Single
= Single [(Var,Int)]
deriving (Eq,Ord,Show)
unSingle :: Single -> [(Var,Int)]
unSingle (Single ves) = ves
-- | An expression living on @Sym^{n_1}(X) x ... x Sym^{n_r}(X)@, with free variables
newtype Multi
= Multi [Single]
deriving (Eq,Ord,Show)
-- | A lambda expression living on @Sym^n(X)@, with variables bound to @Sym^d(X)@ with different dimensions
data SingleLam
= SingleLam !Bindings !Single
deriving (Eq,Ord,Show)
-- | A lambda expression living on @Sym^{n_1}(X) x ... x Sym^{n_r}(X)@, with variables bound to @Sym^d(X)@ with different dimensions
data MultiLam
= MultiLam !Bindings !Multi
deriving (Eq,Ord,Show)
--------------------------------------------------------------------------------
instance Pretty Bindings where
pretty (Bindings dims) = "\\" ++ concat (zipWith f vars dims) where
vars = map DeBruijn [0..]
f v d = "(" ++ pretty v ++ ":S" ++ show d ++ ")"
instance Pretty Var where
pretty (DeBruijn i) = chr (97 + i) : []
instance Pretty (Var,Int) where
pretty (v,0) = "1"
pretty (v,1) = pretty v
pretty (v,e) = pretty v ++ "^" ++ show e
instance Pretty Single where
pretty (Single ves) = intercalate "*" $ map pretty ves
instance Pretty Multi where
pretty (Multi ts) = "[" ++ (intercalate "," $ map pretty ts) ++ "]"
instance Pretty SingleLam where
pretty (SingleLam binds body) = "{" ++ pretty binds ++ "->" ++ pretty body ++ "}"
instance Pretty MultiLam where
pretty (MultiLam binds body) = "{" ++ pretty binds ++ "->" ++ pretty body ++ "}"
--------------------------------------------------------------------------------
instance Degree SingleLam where
type MultiDegree SingleLam = Int
multiDegree (SingleLam binds (Single ves)) = sum [ (unDim $ (Map.!) dimTable v) * e | (v,e) <- ves ] where
dimTable = dimensionTable binds
totalDegree = multiDegree
instance Degree MultiLam where
type MultiDegree MultiLam = [Int]
multiDegree (MultiLam binds (Multi bodies)) = map totalDegree [ (SingleLam binds b) | b <- bodies ]
totalDegree = sum . multiDegree
--------------------------------------------------------------------------------
instance Empty Bindings where
empty = Bindings []
instance Empty Single where
empty = Single []
instance Empty Multi where
empty = Multi []
instance Empty SingleLam where
empty = SingleLam empty empty
instance Empty MultiLam where
empty = MultiLam empty empty
--------------------------------------------------------------------------------
-- | Shift de Bruijn levels
class Shift a where
shift :: Int -> a -> a
instance Shift Var where
shift k (DeBruijn l) = DeBruijn (k+l)
instance Shift Single where
shift k (Single ves) = Single [ (shift k v, e) | (v,e) <- ves ]
instance Shift Multi where
shift k (Multi terms) = Multi $ map (shift k) terms
--------------------------------------------------------------------------------
-- | Rename variables
class Rename a where
rename :: (Var -> Var) -> a -> a
instance Rename Var where
rename f v = f v
instance Rename (Var,Int) where
rename f (v,e) = (f v, e)
instance Rename Single where
rename f (Single ves) = Single $ map (rename f) ves
instance Rename Multi where
rename f (Multi ts) = Multi $ map (rename f) ts
--------------------------------------------------------------------------------
-- | Extract the exponent of a given variable
exponentOf :: Var -> Single -> Int
exponentOf u (Single ves) = sum [ e | (v,e) <- ves , v==u ]
-- | Extract the exponent vector of a given variable
exponentVectorOf :: Var -> Multi -> [Int]
exponentVectorOf v (Multi ts) = map (exponentOf v) ts
--------------------------------------------------------------------------------
instance Normalize Single where
normalize (Single ves) = Single $ Map.toList $ Map.fromListWith (+) ves
instance Normalize Multi where
normalize (Multi terms) = Multi (map normalize terms)
normalizeWithExpo :: (Rename term, Normalize term, Ord expo) => (expo -> Bool) -> (Var -> term -> expo) -> (Bindings,term) -> (Bindings,term)
normalizeWithExpo cond expo (binds,body) = (binds',body') where
Bindings dims = binds
vars = map DeBruijn [0..]
vby = [ (v,(d,es)) | (v,d) <- zip vars dims , let es = expo v body , cond es ]
sorted = sortOn snd vby
dims' = map (fst . snd) sorted
binds' = Bindings dims'
f v = DeBruijn $ fromJust $ findIndex (\pair -> fst pair == v) sorted
body' = normalize $ rename f $ body
instance Normalize SingleLam where
normalize (SingleLam binds body) = SingleLam binds' body' where
(binds',body') = normalizeWithExpo (>0) exponentOf (binds,body)
instance Normalize MultiLam where
normalize (MultiLam binds body) = MultiLam binds' body' where
cond ds = any (>0) ds
(binds',body') = normalizeWithExpo cond f (binds,body)
f v = {- reverse . -} exponentVectorOf v
instance (Eq c, Num c) => Normalize (FreeMod c SingleLam) where
normalize = ZMod.mapBase normalize
instance (Eq c, Num c) => Normalize (FreeMod c MultiLam) where
normalize = ZMod.mapBase normalize
--------------------------------------------------------------------------------
instance SuperNormalize Multi where
superNormalize (Multi ts) = Multi $ reverse $ dropWhile isempty $ reverse $ map normalize $ ts where
isempty (Single xs) = null xs
instance SuperNormalize MultiLam where
superNormalize mlam = MultiLam binds (superNormalize body) where
(MultiLam binds body) = normalize mlam
instance (Eq c, Num c) => SuperNormalize (FreeMod c MultiLam) where
superNormalize = ZMod.mapBase superNormalize
--------------------------------------------------------------------------------
instance Cross Bindings where
cross (Bindings ds) (Bindings es) = Bindings (ds++es)
crossInterleave = error "Bindings/crossInterleave: undefined"
instance Cross Multi where
cross (Multi xs) (Multi ys) = Multi (xs++ys)
crossInterleave (Multi xs) (Multi ys) = Multi (interleave xs ys)
instance Cross MultiLam where
cross (MultiLam binds1 bodies1) (MultiLam binds2 bodies2) = normalize $ MultiLam binds3 bodies3 where
n1 = numberOfBoundVariables binds1
binds3 = binds1 `cross` binds2
bodies3 = bodies1 `cross` (shift n1 bodies2)
crossInterleave (MultiLam binds1 bodies1) (MultiLam binds2 bodies2) = normalize $ MultiLam binds3 bodies3 where
n1 = numberOfBoundVariables binds1
binds3 = binds1 `cross` binds2
bodies3 = bodies1 `crossInterleave` (shift n1 bodies2)
instance (Eq c, Num c) => Cross (FreeMod c MultiLam) where
cross x y = normalize $ ZMod.mulWith cross x y
crossInterleave x y = normalize $ ZMod.mulWith crossInterleave x y
--------------------------------------------------------------------------------
instance SingleToMulti Single Multi where
singleToMulti = Multi . (:[])
instance SingleToMulti SingleLam MultiLam where
singleToMulti (SingleLam binds single) = MultiLam binds (Multi [single])
instance (Eq c, Num c) => SingleToMulti (FreeMod c SingleLam) (FreeMod c MultiLam) where
singleToMulti = ZMod.mapBase singleToMulti
--------------------------------------------------------------------------------
instance Omega (Var,Int) where
omega 0 _ = omegaZeroError
omega k (v,d) = (v,d*k)
instance Omega Single where
omega 0 _ = Single [] -- omegaZeroError
omega k (Single ves) = Single $ map (omega k) ves
instance Omega Multi where
omega 0 _ = omegaZeroError
omega k (Multi ts) = Multi $ map (omega k) ts
instance Omega SingleLam where
omega 0 _ = omegaZeroError
omega k (SingleLam binds body) = SingleLam binds (omega k body)
instance Omega MultiLam where
omega 0 _ = omegaZeroError
omega k (MultiLam binds body) = MultiLam binds (omega k body)
instance (Eq c, Num c) => Omega (FreeMod c SingleLam) where
omega 0 = omegaZeroError
omega k = ZMod.mapBase (omega k)
instance (Eq c, Num c) => Omega (FreeMod c MultiLam) where
omega 0 = omegaZeroError
omega k = normalize . ZMod.mapBase (omega k)
--------------------------------------------------------------------------------
instance Omega123 Multi where
omega123 (Multi ts) = Multi $ zipWith omega [1..] ts
instance Omega123 MultiLam where
omega123 (MultiLam binds body) = MultiLam binds (omega123 body)
instance (Eq c, Num c) => Omega123 (FreeMod c MultiLam) where
omega123 = normalize . ZMod.mapBase omega123
--------------------------------------------------------------------------------
instance Psi Multi Single where
psi (Multi ts) = normalize $ Single $ concat $ map unSingle ts
instance Psi MultiLam SingleLam where
psi (MultiLam binds body) = SingleLam binds (psi body)
instance (Eq c, Num c) => Psi (FreeMod c MultiLam) (FreeMod c SingleLam) where
psi = normalize . ZMod.mapBase psi
instance (Eq c, Num c) => Psi [FreeMod c SingleLam] (FreeMod c SingleLam) where
psi = normalize . psi . crossMany . map singleToMulti
--------------------------------------------------------------------------------
instance PsiEvenOdd Multi where
psiEvenOdd (Multi ts) = normalize $ Multi $ zipWith f (evens ts) (odds ts) where
f (Single xs) (Single ys) = Single (xs++ys)
instance PsiEvenOdd MultiLam where
psiEvenOdd (MultiLam binds body) = MultiLam binds (psiEvenOdd body)
instance PsiEvenOdd (ZMod MultiLam) where
psiEvenOdd = normalize . ZMod.mapBase psiEvenOdd
--------------------------------------------------------------------------------
instance Pontrjagin SingleLam where
pontrjaginOne = empty
pontrjaginMul a b = psi $ cross (singleToMulti a) (singleToMulti b)
instance Pontrjagin MultiLam where
pontrjaginOne = empty
pontrjaginMul a b = psiEvenOdd $ crossInterleave a' b' where
(a',b') = extendToCommonSize (a,b)
--------------------------------------------------------------------------------
instance ExtendToCommonSize Multi where
extendToCommonSize (Multi xs, Multi ys) = (Multi xs', Multi ys') where
(xs',ys') = extendToCommonSize (xs,ys)
instance ExtendToCommonSize MultiLam where
extendToCommonSize (MultiLam as xs, MultiLam bs ys) = (MultiLam as xs', MultiLam bs ys') where
(xs',ys') = extendToCommonSize (xs,ys)
--------------------------------------------------------------------------------
instance Permute Multi where
permute p (Multi ts) = Multi (permuteList p ts)
instance Permute MultiLam where
permute p (MultiLam binds multi) = MultiLam binds (permute p multi)
instance Permute (ZMod MultiLam) where
permute p = ZMod.mapBase (permute p)
--------------------------------------------------------------------------------
instance Theta Multi where
theta (Multi (u:us)) = Multi (a:bs) where
a = psi $ Multi (u : odds us)
bs = zipWith f (evens us) (odds us)
f (Single u) (Single v) = normalize $ Single (u ++ v)
instance Theta MultiLam where
theta (MultiLam binds body) = MultiLam binds (theta body)
instance Theta (ZMod MultiLam) where
theta = normalize . ZMod.mapBase theta
--------------------------------------------------------------------------------