packages feed

coincident-root-loci-0.3: src/Math/RootLoci/Dual/Localization.hs

-- | 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@).

{-# LANGUAGE DataKinds #-}
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.Algebra.Polynomial.FreeModule as ZMod

import Math.Algebra.Polynomial.Univariate
import Math.Algebra.Polynomial.Univariate.Lagrange

import Math.RootLoci.Algebra
import Math.RootLoci.Classic

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

type X = U "x"

mkX :: Int -> X
mkX = U

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

-- | 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 (U 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 = unUni $ 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 ++ " ]"
-}