{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module MathObj.LaurentPolynomial where
import qualified MathObj.Polynomial as Poly
import qualified MathObj.PowerSeries as PS
import qualified MathObj.PowerSeries.Core as PSCore
import qualified Algebra.VectorSpace as VectorSpace
import qualified Algebra.Module as Module
import qualified Algebra.Vector as Vector
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import qualified Algebra.ZeroTestable as ZeroTestable
import qualified Number.Complex as Complex
import qualified NumericPrelude.Numeric as NP
import NumericPrelude.Base hiding (const, reverse, )
import NumericPrelude.Numeric hiding (div, negate, )
import qualified Data.List as List
import Data.List.HT (mapAdjacent)
data T a = Cons {expon :: Int, coeffs :: [a]}
const :: a -> T a
const x = fromCoeffs [x]
(!) :: Additive.C a => T a -> Int -> a
(!) (Cons xt x) n =
if n<xt
then zero
else head (drop (n-xt) x ++ [zero])
fromCoeffs :: [a] -> T a
fromCoeffs = fromShiftCoeffs 0
fromShiftCoeffs :: Int -> [a] -> T a
fromShiftCoeffs = Cons
fromPolynomial :: Poly.T a -> T a
fromPolynomial = fromCoeffs . Poly.coeffs
fromPowerSeries :: PS.T a -> T a
fromPowerSeries = fromCoeffs . PS.coeffs
bounds :: T a -> (Int, Int)
bounds (Cons xt x) = (xt, xt + length x - 1)
shift :: Int -> T a -> T a
shift t (Cons xt x) = Cons (xt+t) x
{-# DEPRECATED translate "In order to avoid confusion with Polynomial.translate, use 'shift' instead" #-}
translate :: Int -> T a -> T a
translate = shift
instance Functor T where
fmap f (Cons xt xs) = Cons xt (map f xs)
appPrec :: Int
appPrec = 10
instance (Show a) => Show (T a) where
showsPrec p (Cons xt xs) =
showParen (p >= appPrec)
(showString "LaurentPolynomial.Cons " . shows xt .
showString " " . shows xs)
add :: Additive.C a => T a -> T a -> T a
add (Cons _ []) y = y
add x (Cons _ []) = x
add (Cons xt x) (Cons yt y) =
if xt < yt
then Cons xt (addShifted (yt-xt) x y)
else Cons yt (addShifted (xt-yt) y x)
series :: (Additive.C a) => [T a] -> T a
series [] = fromCoeffs []
series ps =
let es = map expon ps
xs = map coeffs ps
ds = mapAdjacent subtract es
in Cons (head es) (addShiftedMany ds xs)
addShiftedMany :: (Additive.C a) => [Int] -> [[a]] -> [a]
addShiftedMany ds xss =
foldr (uncurry addShifted) [] (zip (ds++[0]) xss)
addShifted :: Additive.C a => Int -> [a] -> [a] -> [a]
addShifted del px py =
let recurse 0 x = PSCore.add x py
recurse d [] = replicate d zero ++ py
recurse d (x:xs) = x : recurse (d-1) xs
in if del >= 0
then recurse del px
else error "LaurentPolynomial.addShifted: negative shift"
negate :: Additive.C a => T a -> T a
negate (Cons xt x) = Cons xt (map NP.negate x)
sub :: Additive.C a => T a -> T a -> T a
sub x y = add x (negate y)
instance Additive.C a => Additive.C (T a) where
zero = fromCoeffs []
(+) = add
(-) = sub
negate = negate
instance Vector.C T where
zero = zero
(<+>) = (+)
(*>) = Vector.functorScale
instance (Module.C a b) => Module.C a (T b) where
x *> Cons yt ys = Cons yt (x *> ys)
instance (Field.C a, Module.C a b) => VectorSpace.C a (T b)
mul :: Ring.C a => T a -> T a -> T a
mul (Cons xt x) (Cons yt y) = Cons (xt+yt) (PSCore.mul x y)
instance (Ring.C a) => Ring.C (T a) where
one = const one
fromInteger n = const (fromInteger n)
(*) = mul
div :: (Field.C a, ZeroTestable.C a) => T a -> T a -> T a
div (Cons xt xs) (Cons yt ys) =
let (xzero,x) = span isZero xs
(yzero,y) = span isZero ys
in Cons (xt - yt + length xzero - length yzero)
(PSCore.divide x y)
instance (Field.C a, ZeroTestable.C a) => Field.C (T a) where
(/) = div
divExample :: T NP.Rational
divExample = div (Cons 1 [0,0,1,2,1]) (Cons 1 [0,0,0,1,1])
equivalent :: (Eq a, ZeroTestable.C a) => T a -> T a -> Bool
equivalent xs ys =
let (Cons xt x, Cons yt y) =
if expon xs <= expon ys
then (xs,ys)
else (ys,xs)
(xPref, xSuf) = splitAt (yt-xt) x
aux (a:as) (b:bs) = a == b && aux as bs
aux [] bs = all isZero bs
aux as [] = all isZero as
in all isZero xPref && aux xSuf y
instance (Eq a, ZeroTestable.C a) => Eq (T a) where
(==) = equivalent
identical :: (Eq a) => T a -> T a -> Bool
identical (Cons xt xs) (Cons yt ys) =
xt==yt && xs == ys
isAbsolute :: (ZeroTestable.C a) => T a -> Bool
isAbsolute (Cons xt x) =
and (zipWith (\i xi -> isZero xi || i==0) [xt..] x)
alternate :: Additive.C a => T a -> T a
alternate (Cons xt x) =
Cons xt (zipWith id (drop (mod xt 2) (cycle [id,NP.negate])) x)
reverse :: T a -> T a
reverse (Cons xt x) =
Cons (1 - xt - length x) (List.reverse x)
adjoint :: Additive.C a => T (Complex.T a) -> T (Complex.T a)
adjoint x =
let (Cons yt y) = reverse x
in (Cons yt (map Complex.conjugate y))