{-# LANGUAGE CPP, BangPatterns, GeneralizedNewtypeDeriving #-}
module Math.Combinat.Numbers.Series where
import Data.List
import Math.Combinat.Sign
import Math.Combinat.Numbers
import Math.Combinat.Partitions.Integer
import Math.Combinat.Helper
{-# SPECIALIZE unitSeries :: [Integer] #-}
unitSeries :: Num a => [a]
unitSeries = 1 : repeat 0
zeroSeries :: Num a => [a]
zeroSeries = repeat 0
constSeries :: Num a => a -> [a]
constSeries x = x : repeat 0
idSeries :: Num a => [a]
idSeries = 0 : 1 : repeat 0
powerTerm :: Num a => Int -> [a]
powerTerm n = replicate n 0 ++ (1 : repeat 0)
addSeries :: Num a => [a] -> [a] -> [a]
addSeries xs ys = longZipWith 0 0 (+) xs ys
sumSeries :: Num a => [[a]] -> [a]
sumSeries [] = [0]
sumSeries xs = foldl1' addSeries xs
subSeries :: Num a => [a] -> [a] -> [a]
subSeries xs ys = longZipWith 0 0 (-) xs ys
negateSeries :: Num a => [a] -> [a]
negateSeries = map negate
scaleSeries :: Num a => a -> [a] -> [a]
scaleSeries s = map (*s)
mulSeries :: Num a => [a] -> [a] -> [a]
mulSeries xs ys = go (xs ++ repeat 0) (ys ++ repeat 0) where
go (f:fs) ggs@(g:gs) = f*g : (scaleSeries f gs) `addSeries` go fs ggs
mulSeriesNaive :: Num a => [a] -> [a] -> [a]
mulSeriesNaive = convolve
productOfSeries :: Num a => [[a]] -> [a]
productOfSeries = convolveMany
convolve :: Num a => [a] -> [a] -> [a]
convolve xs1 ys1 = res where
res = [ foldl' (+) 0 (zipWith (*) xs (reverse (take n ys)))
| n<-[1..]
]
xs = xs1 ++ repeat 0
ys = ys1 ++ repeat 0
convolveMany :: Num a => [[a]] -> [a]
convolveMany [] = 1 : repeat 0
convolveMany xss = foldl1 convolve xss
divSeries :: (Eq a, Fractional a) => [a] -> [a] -> [a]
divSeries xs ys = go (xs ++ repeat 0) (ys ++ repeat 0) where
go (0:fs) (0:gs) = go fs gs
go (f:fs) ggs@(g:gs) = let q = f/g in q : go (fs `subSeries` scaleSeries q gs) ggs
reciprocalSeries :: (Eq a, Fractional a) => [a] -> [a]
reciprocalSeries series = case series of
[] -> error "reciprocalSeries: empty input series (const 0 function does not have an inverse)"
(a:as) -> case a of
0 -> error "reciprocalSeries: input series has constant term 0"
_ -> map (/a) $ integralReciprocalSeries $ map (/a) series
{-# SPECIALIZE integralReciprocalSeries :: [Int] -> [Int] #-}
{-# SPECIALIZE integralReciprocalSeries :: [Integer] -> [Integer] #-}
integralReciprocalSeries :: (Eq a, Num a) => [a] -> [a]
integralReciprocalSeries series = case series of
[] -> error "integralReciprocalSeries: empty input series (const 0 function does not have an inverse)"
(a:as) -> case a of
1 -> 1 : worker [1]
_ -> error "integralReciprocalSeries: input series must start with 1"
where
worker bs = let b' = - sum (zipWith (*) (tail series) bs)
in b' : worker (b':bs)
composeSeries :: (Eq a, Num a) => [a] -> [a] -> [a]
composeSeries xs ys = go (xs ++ repeat 0) (ys ++ repeat 0) where
go (f:fs) (0:gs) = f : mulSeries gs (go fs (0:gs))
go (f:fs) (_:gs) = error "PowerSeries/composeSeries: we expect the the constant term of the inner series to be zero"
substitute :: (Eq a, Num a) => [a] -> [a] -> [a]
substitute f g = composeSeries g f
composeSeriesNaive :: (Eq a, Num a) => [a] -> [a] -> [a]
composeSeriesNaive g f = substituteNaive f g
substituteNaive :: (Eq a, Num a) => [a] -> [a] -> [a]
substituteNaive as_ bs_ =
case head as of
0 -> [ f n | n<-[0..] ]
_ -> error "PowerSeries/substituteNaive: we expect the the constant term of the inner series to be zero"
where
as = as_ ++ repeat 0
bs = bs_ ++ repeat 0
a i = as !! i
b j = bs !! j
f n = sum
[ b m * product [ (a i)^j | (i,j)<-es ] * fromInteger (multinomial (map snd es))
| p <- partitions n
, let es = toExponentialForm p
, let m = partitionWidth p
]
lagrangeInversion :: (Eq a, Fractional a) => [a] -> [a]
lagrangeInversion xs = go (xs ++ repeat 0) where
go (0:fs) = rs where rs = 0 : divSeries unitSeries (composeSeries fs rs)
go (_:fs) = error "lagrangeInversion: the series should start with (0 + a1*x + a2*x^2 + ...) where a1 is non-zero"
lagrangeCoeff :: Partition -> Integer
lagrangeCoeff p = div numer denom where
numer = (-1)^m * product (map fromIntegral [n+1..n+m])
denom = fromIntegral (n+1) * product (map (factorial . snd) es)
m = partitionWidth p
n = partitionWeight p
es = toExponentialForm p
integralLagrangeInversionNaive :: (Eq a, Num a) => [a] -> [a]
integralLagrangeInversionNaive series_ =
case series of
(0:1:rest) -> 0 : 1 : [ f n | n<-[1..] ]
_ -> error "integralLagrangeInversionNaive: the series should start with (0 + x + a2*x^2 + ...)"
where
series = series_ ++ repeat 0
as = tail series
a i = as !! i
f n = sum [ fromInteger (lagrangeCoeff p) * product [ (a i)^j | (i,j) <- toExponentialForm p ]
| p <- partitions n
]
lagrangeInversionNaive :: (Eq a, Fractional a) => [a] -> [a]
lagrangeInversionNaive series_ =
case series of
(0:a1:rest) -> if a1 ==0
then err
else 0 : (1/a1) : [ f n / a1^(n+1) | n<-[1..] ]
_ -> err
where
err = error "lagrangeInversionNaive: the series should start with (0 + a1*x + a2*x^2 + ...) where a1 is non-zero"
series = series_ ++ repeat 0
a1 = series !! 1
as = map (/a1) (tail series)
a i = as !! i
f n = sum [ fromInteger (lagrangeCoeff p) * product [ (a i)^j | (i,j) <- toExponentialForm p ]
| p <- partitions n
]
differentiateSeries :: Num a => [a] -> [a]
differentiateSeries (y:ys) = go (1::Int) ys where
go !n (x:xs) = fromIntegral n * x : go (n+1) xs
go _ [] = []
integrateSeries :: Fractional a => [a] -> [a]
integrateSeries ys = 0 : go (1::Int) ys where
go !n (x:xs) = x / (fromIntegral n) : go (n+1) xs
go _ [] = []
expSeries :: Fractional a => [a]
expSeries = go 0 1 where
go i e = e : go (i+1) (e / (i+1))
cosSeries :: Fractional a => [a]
cosSeries = go 0 1 where
go i e = e : 0 : go (i+2) (-e / ((i+1)*(i+2)))
sinSeries :: Fractional a => [a]
sinSeries = go 1 1 where
go i e = 0 : e : go (i+2) (-e / ((i+1)*(i+2)))
cosSeries2, sinSeries2 :: Fractional a => [a]
cosSeries2 = unitSeries `subSeries` integrateSeries sinSeries2
sinSeries2 = integrateSeries cosSeries2
coshSeries :: Fractional a => [a]
coshSeries = go 0 1 where
go i e = e : 0 : go (i+2) (e / ((i+1)*(i+2)))
sinhSeries :: Fractional a => [a]
sinhSeries = go 1 1 where
go i e = 0 : e : go (i+2) (e / ((i+1)*(i+2)))
log1Series :: Fractional a => [a]
log1Series = 0 : go 1 1 where
go i e = (e/i) : go (i+1) (-e)
dyckSeries :: Num a => [a]
dyckSeries = [ fromInteger (catalan i) | i<-[(0::Int)..] ]
coinSeries :: [Int] -> [Integer]
coinSeries [] = 1 : repeat 0
coinSeries (k:ks) = xs where
xs = zipWith (+) (coinSeries ks) (replicate k 0 ++ xs)
coinSeries' :: Num a => [(a,Int)] -> [a]
coinSeries' [] = 1 : repeat 0
coinSeries' ((a,k):aks) = xs where
xs = zipWith (+) (coinSeries' aks) (replicate k 0 ++ map (*a) xs)
convolveWithCoinSeries :: [Int] -> [Integer] -> [Integer]
convolveWithCoinSeries ks series1 = worker ks where
series = series1 ++ repeat 0
worker [] = series
worker (k:ks) = xs where
xs = zipWith (+) (worker ks) (replicate k 0 ++ xs)
convolveWithCoinSeries' :: Num a => [(a,Int)] -> [a] -> [a]
convolveWithCoinSeries' ks series1 = worker ks where
series = series1 ++ repeat 0
worker [] = series
worker ((a,k):aks) = xs where
xs = zipWith (+) (worker aks) (replicate k 0 ++ map (*a) xs)
productPSeries :: [[Int]] -> [Integer]
productPSeries = foldl (flip convolveWithPSeries) unitSeries
productPSeries' :: Num a => [[(a,Int)]] -> [a]
productPSeries' = foldl (flip convolveWithPSeries') unitSeries
convolveWithProductPSeries :: [[Int]] -> [Integer] -> [Integer]
convolveWithProductPSeries kss ser = foldl (flip convolveWithPSeries) ser kss
convolveWithProductPSeries' :: Num a => [[(a,Int)]] -> [a] -> [a]
convolveWithProductPSeries' akss ser = foldl (flip convolveWithPSeries') ser akss
pseries :: [Int] -> [Integer]
pseries ks = convolveWithPSeries ks unitSeries
convolveWithPSeries :: [Int] -> [Integer] -> [Integer]
convolveWithPSeries ks series1 = ys where
series = series1 ++ repeat 0
ys = worker ks ys
worker [] _ = series
worker (k:ks) ys = xs where
xs = zipWith (+) (replicate k 0 ++ ys) (worker ks ys)
pseries' :: Num a => [(a,Int)] -> [a]
pseries' aks = convolveWithPSeries' aks unitSeries
convolveWithPSeries' :: Num a => [(a,Int)] -> [a] -> [a]
convolveWithPSeries' aks series1 = ys where
series = series1 ++ repeat 0
ys = worker aks ys
worker [] _ = series
worker ((a,k):aks) ys = xs where
xs = zipWith (+) (replicate k 0 ++ map (*a) ys) (worker aks ys)
signedPSeries :: [(Sign,Int)] -> [Integer]
signedPSeries aks = convolveWithSignedPSeries aks unitSeries
convolveWithSignedPSeries :: [(Sign,Int)] -> [Integer] -> [Integer]
convolveWithSignedPSeries aks series1 = ys where
series = series1 ++ repeat 0
ys = worker aks ys
worker [] _ = series
worker ((a,k):aks) ys = xs where
xs = case a of
Minus -> zipWith (+) one two
Plus -> zipWith (-) one two
one = worker aks ys
two = replicate k 0 ++ ys