{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module MathObj.PowerSum where
import qualified MathObj.Polynomial as Poly
import qualified MathObj.Polynomial.Core as PolyCore
import qualified MathObj.PowerSeries.Core as PS
import qualified Algebra.VectorSpace as VectorSpace
import qualified Algebra.Module as Module
import qualified Algebra.Algebraic as Algebraic
import qualified Algebra.Field as Field
import qualified Algebra.IntegralDomain as Integral
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import qualified Algebra.ZeroTestable as ZeroTestable
import Control.Monad(liftM2)
import qualified Data.List as List
import Data.List.HT (shearTranspose, sieve)
import NumericPrelude.Base as P hiding (const)
import NumericPrelude.Numeric as NP
newtype T a = Cons {sums :: [a]}
lift0 :: [a] -> T a
lift0 = Cons
lift1 :: ([a] -> [a]) -> (T a -> T a)
lift1 f (Cons x0) = Cons (f x0)
lift2 :: ([a] -> [a] -> [a]) -> (T a -> T a -> T a)
lift2 f (Cons x0) (Cons x1) = Cons (f x0 x1)
const :: (Ring.C a) => a -> T a
const x = Cons [1,x]
fromElemSym :: (Eq a, Ring.C a) => [a] -> [a]
fromElemSym s =
fromIntegral (length s - 1) :
PolyCore.alternate (divOneFlip s (PolyCore.differentiate s))
divOneFlip :: (Eq a, Ring.C a) => [a] -> [a] -> [a]
divOneFlip (1:xs) =
let aux (y:ys) = y : aux (ys - PolyCore.scale y xs)
aux [] = []
in aux
divOneFlip _ =
error "divOneFlip: first element must be one"
fromElemSymDenormalized :: (Field.C a, ZeroTestable.C a) => [a] -> [a]
fromElemSymDenormalized s =
fromIntegral (length s - 1) :
PolyCore.alternate (PS.derivedLog s)
toElemSym :: (Field.C a, ZeroTestable.C a) => [a] -> [a]
toElemSym p =
let s' = PolyCore.mul (PolyCore.alternate (tail p)) s
s = PolyCore.integrate 1 s'
in s
toElemSymInt :: (Integral.C a, ZeroTestable.C a) => [a] -> [a]
toElemSymInt p =
let s' = PolyCore.mul (PolyCore.alternate (tail p)) s
s = PolyCore.integrateInt 1 s'
in s
fromPolynomial :: (Field.C a, ZeroTestable.C a) => Poly.T a -> [a]
fromPolynomial =
let aux s =
fromIntegral (length s - 1) :
PolyCore.negate (PS.derivedLog s)
in aux . reverse . Poly.coeffs
elemSymFromPolynomial :: Additive.C a => Poly.T a -> [a]
elemSymFromPolynomial = PolyCore.alternate . reverse . Poly.coeffs
binomials :: Ring.C a => [[a]]
binomials = [1] : binomials + map (0:) binomials
appPrec :: Int
appPrec = 10
instance (Show a) => Show (T a) where
showsPrec p (Cons xs) =
showParen (p >= appPrec)
(showString "PowerSum.Cons " . shows xs)
add :: (Ring.C a) => [a] -> [a] -> [a]
add xs ys =
let powers = shearTranspose (PolyCore.tensorProduct xs ys)
in zipWith Ring.scalarProduct binomials powers
instance (Ring.C a) => Additive.C (T a) where
zero = const zero
(+) = lift2 add
negate = lift1 PolyCore.alternate
mul :: (Ring.C a) => [a] -> [a] -> [a]
mul xs ys = zipWith (*) xs ys
pow :: Integer -> [a] -> [a]
pow n =
if n<0
then error "PowerSum.pow: negative exponent"
else sieve (fromInteger n)
instance (Ring.C a) => Ring.C (T a) where
one = const one
fromInteger n = const (fromInteger n)
(*) = lift2 mul
x^n = lift1 (pow n) x
instance (Module.C a v, Ring.C v) => Module.C a (T v) where
x *> y = lift1 (zipWith (*>) (iterate (x*) one)) y
instance (VectorSpace.C a v, Ring.C v) => VectorSpace.C a (T v)
instance (Field.C a, ZeroTestable.C a) => Field.C (T a) where
recip = lift1 (fromElemSymDenormalized . reverse . toElemSym)
root :: (Ring.C a) => Integer -> [a] -> [a]
root n xs =
let upsample m ys =
concat (List.intersperse
(List.genericReplicate (m - 1) zero)
(map (:[]) ys))
in case compare n 0 of
LT -> upsample (-n) (reverse xs)
GT -> upsample n xs
EQ -> [1]
instance (Field.C a, ZeroTestable.C a) => Algebraic.C (T a) where
root n = lift1 (fromElemSymDenormalized . root n . toElemSym)
approxSeries :: Module.C a b => [b] -> [a] -> [b]
approxSeries y x =
scanl (+) zero (zipWith (*>) x y)
propOp :: (Eq a, Field.C a, ZeroTestable.C a) =>
([a] -> [a] -> [a]) -> (a -> a -> a) -> [a] -> [a] -> [Bool]
propOp powerOp op xs ys =
let zs = liftM2 op xs ys
xp = fromPolynomial (Poly.fromRoots xs)
yp = fromPolynomial (Poly.fromRoots ys)
ze = elemSymFromPolynomial (Poly.fromRoots zs)
in zipWith (==) (toElemSym (powerOp xp yp)) ze