packages feed

coincident-root-loci-0.3: src/Math/RootLoci/Motivic/Homology.hs

-- | Motivic classes in homology

{-# LANGUAGE 
      DataKinds, KindSignatures, TypeOperators, ScopedTypeVariables, MultiParamTypeClasses,
      TypeFamilies, FlexibleContexts, TypeSynonymInstances, FlexibleInstances
  #-}
module Math.RootLoci.Motivic.Homology where

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

import Data.Array

import Data.Proxy
import GHC.TypeLits

import Unsafe.Coerce as Unsafe

import Math.Combinat.Classes
import Math.Combinat.Numbers
import Math.Combinat.Partitions

import qualified Math.Algebra.Polynomial.FreeModule as ZMod

import qualified Math.Algebra.Polynomial.Monomial.Infinite as XInf
import qualified Math.Algebra.Polynomial.Monomial.Indexed  as XS

import Math.Algebra.Polynomial.Multivariate.Infinite as XInf
import Math.Algebra.Polynomial.Multivariate.Indexed  as XS

import Math.Algebra.Polynomial.Class
import Math.Algebra.Polynomial.Univariate
import Math.Algebra.Polynomial.Pretty

import Math.RootLoci.Geometry.Cohomology ( G(..) )

import Math.RootLoci.Misc.Common
import Math.RootLoci.Motivic.Abstract as Abstract
import Math.RootLoci.Motivic.Classes

import Math.RootLoci.CSM.Aluffi

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

interpretSingleLam :: (Dim -> KRing Integer) -> SingleLam -> KRing Integer
interpretSingleLam symFun (SingleLam (Bindings bindings) (Single body)) = result where
  syms   = map symFun bindings
  result = psiAny $ crossKs $ map f body 
  f (DeBruijn i, e) = omegaH e (syms!!i)  

csmPn :: Dim -> KRing Integer
csmPn (Dim d) = Uni $ ZMod.fromList [ (U k , binomial (d+1) (k+1)) | k<-[0..d] ]

-- | CSM class in homology
csm_xlam_P1 :: Partition -> KRing Integer
csm_xlam_P1 part = Uni $ ZMod.flatMap f (Abstract.xlam part) where
  f x = unUni (interpretSingleLam csmPn x)

-- | CSM class in cohomology (via Poincare duality)
csm_xlam_P1_cohom :: Partition -> ZMod.ZMod G 
csm_xlam_P1_cohom part = ZMod.mapBase f $ unUni $ csm_xlam_P1 part  where
  n   = weight part
  f (U k) = G (n-k)

-- | Compares Aluffi's CSM formula to the motivic algorithm (up to partitions of size @n@)
test_motivic_csm_vs_aluffi :: Int -> Bool
test_motivic_csm_vs_aluffi n = and
  [ csm_xlam_P1_cohom part == aluffiOpenCSM part
  | k<-[1..n] , part <- partitions k 
  ]

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

instance SingleToMulti (KRing c) (GRing c) where
  singleToMulti = embedInf

instance Ring c => Psi (GRing c) (KRing c) where
  psi = psiAny

instance Ring c => Omega (KRing c) where
  omega = omegaH

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

type KRing c   = Univariate c "u"     -- ^ @lim_n H_*(Sym^n(P1))@
type GRing c   = XInf.Poly  c "u"     -- ^ @lim_{n1,n2,...} H_*(Sym^n1(P1) x Sym^n2(P1) x ... )@

-- fuck Haskell's type level naturals, they are completely unusable
-- type NRing c k = XS.Poly    c "u" k   -- ^ @lim_{n1,...,nk} H_*(Sym^n1(P1) x ... x Sym^nk(P1) )@

embedInf :: KRing c -> GRing c
embedInf = XInf.Poly . ZMod.unsafeMapBase f . unUni where
  f (U k) = if k > 0 then XInf [k] else XInf []

project1 :: GRing c -> KRing c
project1 = Uni . ZMod.unsafeMapBase f . XInf.unPoly where
  f (XInf ns) = U $ head ns

delta2 :: Ring c => KRing c -> GRing c
delta2 = XInf.Poly . ZMod.flatMap f . unUni where
  f (U k) = ZMod.sum [ ZMod.generator (XInf [i,k-i]) | i<-[0..k] ] 

deltaN :: Ring c => Int -> KRing c -> GRing c
deltaN n input 
  | n <= 0    = error "deltaN: n <= 0"
  | n == 1    = embedInf input
  | n == 2    = delta2   input
  | otherwise = unify1st2nd
              $ mapCoeffP delta2 
              $ separate1st (deltaN (n-1) input)
  where
    mapCoeffP f = XInf.Poly . ZMod.mapCoeff f . XInf.unPoly

psi2 :: Ring c => GRing c -> KRing c
psi2 = Uni . ZMod.mapMaybeBaseCoeff f . XInf.unPoly where
  f (XInf xs) = let [i,j] = take 2 (xs ++ [0,0])
                in  Just ( U (i+j) , fromInteger (binomial (i+j) i) )

psiNaive :: (Ring c) => Int -> GRing c -> KRing c
psiNaive n input 
  | n <= 0    = error "psiN: n <= 0"
  | n == 1    = project1 input
  | n == 2    = psi2     input
  | otherwise = psi2 $ kkToG2 $ psiNaive (n-1) $ separate1st input

psiAny :: Ring c => GRing c -> KRing c
psiAny = Uni . ZMod.mapMaybeBaseCoeff f . XInf.unPoly where
  f (XInf is) = Just (U (sum is) , fromInteger (multinomial is))

omegaNaive :: Ring c => Int -> KRing c -> KRing c
omegaNaive n = psiAny . deltaN n

omegaH :: Ring c => Int -> KRing c -> KRing c
omegaH d = Uni . ZMod.mapMaybeBaseCoeff f . unUni where
  f (U k) = Just (U k, fromIntegral d ^ k)

separate1st :: forall c n. (Ring c) => GRing c -> GRing (KRing c) 
separate1st = XInf.Poly . ZMod.mapMaybeBaseCoeff g . ZMod.mapCoeff f . XInf.unPoly where
  f c  = scalarP c :: KRing c
  g (XInf (k:ns)) = Just (XInf ns, c) where
    c = monomP (U k)

unify1st :: forall c n. (Ring c) => GRing (KRing c) -> GRing c 
unify1st = XInf.Poly . ZMod.fromList . concatMap f . ZMod.toList . XInf.unPoly where
  f (XInf xs , Uni poly) = [ (XInf (k:xs) , c)  | (U k, c) <- ZMod.toList poly ]

unify1st2nd :: forall c n. (Ring c) => GRing (GRing c) -> GRing c 
unify1st2nd = XInf.Poly . ZMod.fromList . concatMap f . ZMod.toList . XInf.unPoly where
  f (XInf xs , XInf.Poly poly) = [ (XInf (kl++xs) , c)  | (XInf kl0, c) <- ZMod.toList poly , let kl = take 2 (kl0++[0,0]) ]

crossKs :: Ring c => [KRing c] -> GRing c
crossKs = XInf.Poly . ZMod.productWith empty cross . map (ZMod.mapBase sing) . map unUni where
  sing (U k) = XInf [k]
  cross (XInf as) (XInf bs) = XInf (as++bs)
  empty = XInf []

kkToG2 :: Ring c => KRing (KRing c) -> GRing c 
kkToG2 = XInf.Poly . ZMod.fromList . concatMap f . ZMod.toList . unUni where
  f (U k , Uni poly) = [ (XInf [k,l] , c)  | (U l, c) <- ZMod.toList poly ]

unifyKK :: Ring c => KRing (KRing c) -> KRing c 
unifyKK = Uni . ZMod.fromList . concatMap f . ZMod.toList . unUni where
  f (U k , Uni poly) = [ (U (k+l) , c)  | (U l, c) <- ZMod.toList poly ]

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

{-
deltaN :: Num c => Int -> KRing c -> GRing c
deltaN 0 = error "deltaN: 0"
deltaN 1 = embed
deltaN 2 = delta2
deltaN 
-}