-- | Multivariate polynomials where the variable set is the countably infinite -- set @{x_1, x_2, x_3, ...}@ {-# LANGUAGE BangPatterns, TypeFamilies, DataKinds, KindSignatures, ScopedTypeVariables, FlexibleContexts #-} module Math.Algebra.Polynomial.Multivariate.Infinite ( Poly(..) , unPoly , polyVar , renamePolyVar , ZPoly , QPoly , fromZPoly, fromQPoly , truncate , XInf(..) ) where -------------------------------------------------------------------------------- import Prelude hiding ( truncate ) import Data.Maybe import Data.List import Data.Array.Unboxed import Data.Typeable import GHC.TypeLits import Data.Proxy import Unsafe.Coerce as Unsafe import Data.Foldable as F import qualified Math.Algebra.Polynomial.FreeModule as ZMod import Math.Algebra.Polynomial.FreeModule ( FreeMod , FreeModule(..) ) -- , ZMod , QMod ) import Math.Algebra.Polynomial.Monomial.Infinite import Math.Algebra.Polynomial.Class import Math.Algebra.Polynomial.Pretty import Math.Algebra.Polynomial.Misc import qualified Math.Algebra.Polynomial.Monomial.Indexed as Fin import qualified Math.Algebra.Polynomial.Multivariate.Indexed as Fin -------------------------------------------------------------------------------- -- * Polynomials -- | A multivariate polynomial in with a given coefficient ring. -- -- It is also indexed by the (shared) /name/ of the variables and the /number of/ -- variable. For example @Polyn Rational "x" 3@ the type of polynomials in the -- variables @x1, x2, x3@ with rational coefficients. newtype Poly (coeff :: *) (var :: Symbol) = Poly (FreeMod coeff (XInf var)) deriving (Eq,Ord,Show,Typeable) unPoly :: Poly c v -> FreeMod c (XInf v) unPoly (Poly p) = p -- | Name of the variables polyVar :: KnownSymbol var => Poly c var -> String polyVar = symbolVal . varProxy where varProxy :: Poly c var -> Proxy var varProxy _ = Proxy instance FreeModule (Poly c v) where type BaseF (Poly c v) = XInf v type CoeffF (Poly c v) = c toFreeModule = unPoly fromFreeModule = Poly renamePolyVar :: Poly c var1 -> Poly c var2 renamePolyVar = Unsafe.unsafeCoerce -------------------------------------------------------------------------------- type ZPoly = Poly Integer type QPoly = Poly Rational -- | Change the coefficient ring (from integers) fromZPoly :: (Ring c, KnownSymbol v) => Poly Integer v -> Poly c v fromZPoly= Poly . ZMod.fromZMod . unPoly -- | Change the coefficient field (from rationals) fromQPoly :: (Field c, KnownSymbol v) => Poly Rational v -> Poly c v fromQPoly = Poly . ZMod.fromQMod . unPoly -------------------------------------------------------------------------------- instance (Ring c, KnownSymbol v) => AlmostPolynomial (Poly c v) where type CoeffP (Poly c v) = c type MonomP (Poly c v) = XInf v type VarP (Poly c v) = Index zeroP = Poly ZMod.zero isZeroP = ZMod.isZero . unPoly oneP = Poly (ZMod.generator emptyM) fromListP = Poly . ZMod.fromList toListP = ZMod.toList . unPoly variableP = Poly . ZMod.generator . variableXInf singletonP = \v e -> Poly (ZMod.generator (singletonXInf v e)) monomP = \m -> Poly $ ZMod.generator m monomP' = \m c -> Poly $ ZMod.singleton m c scalarP = \s -> Poly $ ZMod.singleton emptyXInf s addP = \p1 p2 -> Poly $ ZMod.add (unPoly p1) (unPoly p2) subP = \p1 p2 -> Poly $ ZMod.sub (unPoly p1) (unPoly p2) negP = Poly . ZMod.neg . unPoly mulP = \p1 p2 -> Poly $ ZMod.mulWith mulXInf (unPoly p1) (unPoly p2) coeffOfP = \m p -> ZMod.coeffOf m (unPoly p) productP = \ps -> Poly $ ZMod.productWith emptyXInf mulXInf $ map unPoly ps mulByMonomP = \m p -> Poly $ ZMod.mulByMonom m (unPoly p) scaleP = \s p -> Poly $ ZMod.scale s (unPoly p) instance (Ring c, KnownSymbol v) => Polynomial (Poly c v) where evalP = \g f p -> let { !z = evalM f ; h (!m,!c) = g c * z m } in sum' $ map h $ ZMod.toList $ unPoly p varSubsP = \f p -> Poly $ ZMod.mapBase (varSubsM f) (unPoly p) coeffSubsP = \f p -> Poly $ ZMod.fromList $ map (termSubsM f) $ ZMod.toList $ unPoly p subsP = \f p -> Poly $ ZMod.flatMap (evalM (unPoly . f)) (unPoly p) instance (Ring c, KnownSymbol v) => Num (Poly c v) where fromInteger = scalarP . fromInteger (+) = addP (-) = subP negate = negP (*) = mulP abs = id signum = \_ -> scalarP 1 instance (Ring c, KnownSymbol v, Pretty (XInf v)) => Pretty (Poly c v) where pretty poly@(Poly fm) = if isSignedR (proxyCoeffP poly) then prettyFreeMod' True pretty fm else prettyFreeMod'' pretty pretty fm -- hackety hack hack... instance IsSigned (Poly c v) where signOf = const (Just Plus) -- So that we can use it again as a coefficient ring instance (Ring c, KnownSymbol v) => Ring (Poly c v) where isZeroR = ZMod.isZero . unPoly isAtomicR = const False isSignedR = const False absR = id signumR = const (Just Plus) -------------------------------------------------------------------------------- -- | We can always truncate to a given number of variables, simply -- by substituting zero to the rest truncate :: (Eq c, Num c, KnownNat n) => Poly c v -> Fin.Poly c v n truncate input@(Poly inpoly) = output where n = Fin.nOfPoly output output = Fin.Poly $ ZMod.mapMaybeBase f inpoly f (XInf es) = let (fs,rest) = splitAt n es in if all (==0) rest then Just (Fin.xsFromExponents fs) else Nothing --------------------------------------------------------------------------------