-- | Univariate polynomials {-# LANGUAGE BangPatterns, DataKinds, KindSignatures, GeneralizedNewtypeDeriving, TypeFamilies #-} module Math.Algebra.Polynomial.Univariate ( -- * Univariate polynomials Univariate(..) , U(..) , unUni , uniVar , renameUniVar , ZUni , QUni , fromZUni , fromQUni , differentiateUni , integrateUni , integrateUni' ) where -------------------------------------------------------------------------------- import Data.Array ( Array , (!) , listArray , assocs ) import Data.List import GHC.TypeLits import Data.Proxy import Unsafe.Coerce as Unsafe import Math.Algebra.Polynomial.Class import Math.Algebra.Polynomial.Misc import Math.Algebra.Polynomial.Pretty import qualified Math.Algebra.Polynomial.FreeModule as ZMod import Math.Algebra.Polynomial.FreeModule ( FreeMod , FreeModule(..) , ZMod , QMod ) import Math.Algebra.Polynomial.Monomial.Univariate -------------------------------------------------------------------------------- -- * Univariate polynomials -- | A univariate polynomial with the given coefficient ring. Note: this -- is also indexed by the /name/ of the variable. newtype Univariate (coeff :: *) (var :: Symbol) = Uni (FreeMod coeff (U var)) deriving (Eq,Ord,Show) unUni :: Univariate c v -> FreeMod c (U v) unUni (Uni a) = a instance FreeModule (Univariate c v) where type BaseF (Univariate c v) = U v type CoeffF (Univariate c v) = c toFreeModule = unUni fromFreeModule = Uni -- | Name of the variable uniVar :: KnownSymbol var => Univariate c var -> String uniVar = symbolVal . varProxy where varProxy :: Univariate c var -> Proxy var varProxy _ = Proxy -- | Rename the variable (zero cost) renameUniVar :: Univariate c var1 -> Univariate c var2 renameUniVar = Unsafe.unsafeCoerce -------------------------------------------------------------------------------- -- | An univariate polynomial integer coefficients type ZUni var = Univariate Integer var -- | An univariate polynomial with rational coefficients type QUni var = Univariate Rational var -- | Change the coefficient ring fromZUni :: (Ring c, KnownSymbol v) => Univariate Integer v -> Univariate c v fromZUni = Uni . ZMod.fromZMod . unUni -- | Change the coefficient ring fromQUni :: (Field c, KnownSymbol v) => Univariate Rational v -> Univariate c v fromQUni = Uni . ZMod.fromQMod . unUni -------------------------------------------------------------------------------- -- | Differentiation differentiateUni :: (Ring c, KnownSymbol var) => Univariate c var -> Univariate c var differentiateUni = Uni . ZMod.mapMaybeBaseCoeff f . unUni where f (U k) = case k of 0 -> Nothing _ -> Just ( U (k-1) , fromIntegral k ) -- | Integration integrateUni :: (Field c, KnownSymbol var) => Univariate c var -> Univariate c var integrateUni = Uni . ZMod.mapMaybeBaseCoeff f . unUni where f (U k) = Just ( U (k+1) , 1 / fromIntegral (k+1) ) integrateUni' :: (Field c, KnownSymbol var) => c -> Univariate c var -> Univariate c var integrateUni' c0 p = integrateUni p + scalarP c0 -------------------------------------------------------------------------------- instance (Ring coeff, KnownSymbol var) => AlmostPolynomial (Univariate coeff var) where type CoeffP (Univariate coeff var) = coeff type MonomP (Univariate coeff var) = U var type VarP (Univariate coeff var) = () fromListP = Uni . ZMod.fromList toListP = ZMod.toList . unUni zeroP = Uni ZMod.zero isZeroP = ZMod.isZero . unUni oneP = Uni (ZMod.generator emptyM) variableP = Uni . ZMod.generator . variableM singletonP = \v e -> Uni (ZMod.generator (singletonM v e)) monomP = \m -> Uni $ ZMod.generator m monomP' = \m c -> Uni $ ZMod.singleton m c scalarP = \s -> Uni $ ZMod.singleton emptyM s addP = \p1 p2 -> Uni $ ZMod.add (unUni p1) (unUni p2) subP = \p1 p2 -> Uni $ ZMod.sub (unUni p1) (unUni p2) negP = Uni . ZMod.neg . unUni mulP = \p1 p2 -> Uni $ ZMod.mulWith mulM (unUni p1) (unUni p2) productP = \ps -> Uni $ ZMod.productWith emptyM mulM $ map unUni ps coeffOfP = \m p -> ZMod.coeffOf m (unUni p) mulByMonomP = \m p -> Uni $ ZMod.mulByMonom m (unUni p) scaleP = \s p -> Uni $ ZMod.scale s (unUni p) instance (Ring coeff, KnownSymbol var) => Polynomial (Univariate coeff var) where evalP = \g f p -> let { !z = evalM f ; h (!m,!c) = g c * z m } in sum' $ map h $ ZMod.toList $ unUni p varSubsP = \f p -> Uni $ ZMod.mapBase (varSubsM f) (unUni p) coeffSubsP = \f p -> Uni $ ZMod.fromList $ map (termSubsM f) $ ZMod.toList $ unUni p subsP = \f p -> Uni $ ZMod.flatMap (evalM (unUni . f)) (unUni p) instance (Ring c, KnownSymbol v) => Num (Univariate c v) where fromInteger = scalarP . fromInteger (+) = addP (-) = subP negate = negP (*) = mulP abs = id signum = \_ -> scalarP 1 instance (Ring c, KnownSymbol v) => Pretty (Univariate c v) where pretty poly@(Uni fm) = if isSignedR (proxyCoeffP poly) then prettyFreeMod' True pretty fm else prettyFreeMod'' pretty pretty fm -- hackety hack hack... instance IsSigned (Univariate c v) where signOf = const (Just Plus) -- So that we can use it again as a coefficient ring instance (Ring c, KnownSymbol v) => Ring (Univariate c v) where isZeroR = ZMod.isZero . unUni isAtomicR = const False isSignedR = const False absR = id signumR = const (Just Plus) --------------------------------------------------------------------------------