-- | High-level bindings to singular-factory {-# LANGUAGE BangPatterns, PatternSynonyms, KindSignatures, DataKinds, FlexibleInstances, TypeSynonymInstances, ScopedTypeVariables, EmptyDataDecls #-} module Math.Singular.Factory.Polynomial where -------------------------------------------------------------------------------- import GHC.TypeLits import Data.Proxy import Data.Text.Lazy ( Text , pack ) import System.IO.Unsafe as Unsafe import Math.Singular.Factory.Internal.CanonicalForm import Math.Singular.Factory.Internal.Factory import Math.Singular.Factory.Variables import Math.Singular.Factory.Domains import Math.Singular.Factory.Expr import Math.Singular.Factory.Parser -------------------------------------------------------------------------------- -- * Polynomials -- | A multivariate polynomial over a base domain. -- -- Typically, you want to fix your variable set (see the module "Math.Singular.Factory.Variables"), -- make a type synonym, and use that; for example: -- -- > type Poly domain = Polynomial (VarN "x") domain -- newtype Polynomial varset domain = Poly { unPoly :: CF } instance Eq (Polynomial vars domain) where (==) (Poly cf1) (Poly cf2) = safeEqCF cf1 cf2 instance forall vars domain. VariableSet vars => Show (Polynomial vars domain) where show (Poly cf) = showCF_with (varIdxName (Proxy :: Proxy vars)) cf polyIsZero :: Polynomial vars domain -> Bool polyIsZero (Poly cf) = isZeroCF cf polyIsOne :: Polynomial vars domain -> Bool polyIsOne (Poly cf) = isOneCF cf -- | Returns true if the polynomial is a constant inBaseDomain :: Polynomial vars domain -> Bool inBaseDomain (Poly cf) = isInBaseDomainCF cf -- | If it is a constant, returns the value mbConstant :: BaseDomain domain => Polynomial vars domain -> Maybe domain mbConstant (Poly cf) = if isInBaseDomainCF cf then Just (unsafeCfToBase cf) else Nothing -- | A constant polynomial konst :: BaseDomain domain => domain -> Polynomial vars domain konst = Poly . baseToCF -- | A variable as a polynomial var :: VarIdx -> Polynomial vars domain var idx = Poly $ varCF (theNthVar idx) -- | A power of a variable varPow :: VarIdx -> Int -> Polynomial vars domain varPow idx expo = Poly $ varPowCF (theNthVar idx) expo -------------------------------------------------------------------------------- -- * Operations on polynomials mapIntoDomain :: forall domain1 domain2 vars. (BaseDomain domain1, BaseDomain domain2) => Polynomial vars domain1 -> Polynomial vars domain2 mapIntoDomain (Poly cf) = result where result = Poly (mapIntoCF (factoryChar pxy) cf) pxy = Proxy :: Proxy domain2 instance forall vars domain. BaseDomain domain => Num (Polynomial vars domain) where fromInteger = Poly . (baseToCF :: domain -> CF) . fromInteger negate (Poly cf) = Poly (negate cf) (Poly cf1) + (Poly cf2) = Poly (cf1 + cf2) (Poly cf1) - (Poly cf2) = Poly (cf1 - cf2) (Poly cf1) * (Poly cf2) = Poly (cf1 * cf2) abs = id signum = const 1 pow :: BaseDomain domain => Polynomial vars domain -> Int -> Polynomial vars domain pow (Poly cf) expo = Poly $ powCF cf expo -- | Polynomial GCD polyGCD :: BaseDomain domain => Polynomial vars domain -> Polynomial vars domain -> Polynomial vars domain polyGCD (Poly cf1) (Poly cf2) = Poly $ gcdPolyCF cf1 cf2 -- | Polynomial reduction polyReduce :: BaseDomain domain => Polynomial vars domain -> Polynomial vars domain -> Polynomial vars domain polyReduce (Poly cf1) (Poly cf2) = Poly $ reduceCF cf1 cf2 -- | Polynomial factorization factorize :: BaseDomain domain => Polynomial vars domain -> [(Polynomial vars domain, Int)] factorize (Poly cf) = map f (factorizeCF cf) where f (p, expo) = (Poly p, expo) {- -- | Polynomial factorization (the new algorithms by Martin Lee) factorizeNew :: forall vars domain. BaseDomain domain => Polynomial vars domain -> [(Polynomial vars domain, Int)] factorizeNew (Poly cf) = case factoryChar (Proxy :: Proxy domain) of CharZero -> map f (ratFactorizeCF cf alphaOne True) CharFp p -> map f (fpFactorizeCF cf True) CharGF p n -> map f (gfFactorizeCF cf True) where f (p, expo) = (Poly p, expo) alphaOne = theNthVar 1 -- const Variable& v= Variable (1) -- | Polynomial factorization (old way) factorizeOld :: BaseDomain domain => Polynomial vars domain -> [(Polynomial vars domain, Int)] factorizeOld (Poly cf) = map f (oldFactorizeCF cf) where f (p, expo) = (Poly p, expo) -} -- | Substitution substitute1 :: BaseDomain domain => VarIdx -> Polynomial vars domain -> Polynomial vars domain -> Polynomial vars domain substitute1 idx (Poly what) (Poly cf) = Poly (substituteCF (theNthVar idx) what cf) -- | Evaluate a polynomial at the given point evaluate :: BaseDomain domain => (VarIdx -> domain) -> Polynomial vars domain -> domain evaluate fun (Poly cf0) = unsafeCfToBase (go 1 cf0) where go :: Int -> CF -> CF go !idx !cf = if isInBaseDomainCF cf then cf else go (idx+1) (substituteCF (theNthVar idx) (baseToCF $ fun idx) cf) -------------------------------------------------------------------------------- -- * Parsing -- | Parse a polynomial in expanded form parsePolynomial :: forall vars. VariableSet vars => Text -> Maybe (Polynomial vars Integer) parsePolynomial text = evalGenPoly konst var <$> parseGenPoly (Proxy :: Proxy vars) text -- | Parse a polynomial expression (for example the product of two polynomials) parsePolyExpr :: forall vars. VariableSet vars => Text -> Maybe (Polynomial vars Integer) parsePolyExpr text = evalExpr {- konst -} var <$> parseExpr (Proxy :: Proxy vars) text parsePolynomialStr :: forall vars. VariableSet vars => String -> Maybe (Polynomial vars Integer) parsePolynomialStr = parsePolynomial . pack parsePolyExprStr :: forall vars. VariableSet vars => String -> Maybe (Polynomial vars Integer) parsePolyExprStr = parsePolyExpr . pack --------------------------------------------------------------------------------