polynom-0.1.0.0: Data/Polynom/Impl.hs
module Data.Polynom.Impl where
import Control.Applicative
import Control.Category.Unicode
import Data.Bool
import Data.Foldable (Foldable (foldr), all)
import Data.Function (($), on)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe
import Data.Monoid
import Data.Ord
import Data.Traversable
import Numeric.Algebra
import Numeric.Decidable.Zero
import Numeric.Domain.Euclidean hiding (degree)
import Numeric.Partial.Group
import Numeric.Semiring.Integral
import Util
-- | Polynomial in monomial exponents @α@ over coefficients @a@
newtype Polynom α a = Polynom (Map α a)
instance (Ord α, Monoidal a) => Additive (Polynom α a) where
Polynom as + Polynom bs = Polynom (Map.unionWith (+) as bs)
instance (Ord α, Monoidal a, Abelian a) => Abelian (Polynom α a)
instance (Ord α, Monoidal a, Idempotent a) => Idempotent (Polynom α a)
instance {-# INCOHERENT #-} (Ord α, Monoidal a, Semiring a) => LeftModule a (Polynom α a) where
n .* Polynom cs = Polynom ((n *) <$> cs)
instance {-# INCOHERENT #-} (Ord α, Monoidal a, Semiring a) => RightModule a (Polynom α a) where
Polynom cs *. n = Polynom ((n *) <$> cs)
instance {-# INCOHERENT #-} (Ord α, Monoidal a, LeftModule b a) => LeftModule b (Polynom α a) where
n .* Polynom cs = Polynom ((n .*) <$> cs)
instance {-# INCOHERENT #-} (Ord α, Monoidal a, RightModule b a) => RightModule b (Polynom α a) where
Polynom cs *. n = Polynom ((*. n) <$> cs)
instance (Ord α, Monoidal a) => Monoidal (Polynom α a) where
zero = Polynom Map.empty
instance (Ord α, Group a) => Group (Polynom α a) where
negate (Polynom cs) = Polynom (negate <$> cs)
instance (Ord α, Semigroup α, Monoidal a, Semiring a) => Multiplicative (Polynom α a) where
Polynom as * Polynom bs = fromList $
(liftA2 (\ (α, a) (β, b) -> (α<>β, a*b)) `on` Map.assocs) as bs
instance (Ord α, Semigroup α, Abelian α, Monoidal a, Commutative a, Semiring a) => Commutative (Polynom α a)
instance (Ord α, Monoid α, Monoidal a, Unital a, Semiring a) => Unital (Polynom α a) where
one = Polynom (Map.singleton mempty one)
instance (Ord α, DecidableZero a) => DecidableZero (Polynom α a) where
isZero (Polynom cs) = all isZero cs
instance (Ord α, Semigroup α, Monoidal a, Semiring a) => Semiring (Polynom α a)
instance (Ord α, Semigroup α, Monoidal a, IntegralSemiring a) => IntegralSemiring (Polynom α a)
-- | Compute the /degree/ of a polynomial, the maximum total exponent of any monomial.
degree :: (Foldable p, Ord α, Monoidal α, DecidableZero a) => Polynom (p α) a -> Maybe α
degree (Polynom cs) = foldr (max ∘ Just ∘ sum) Nothing ((Map.keys ∘ Map.filter (not ∘ isZero)) cs)
-- | Compute the content of a polynomial over a unique factorization domain @a@.
-- The /content/ of such a polynomial is defined as the unit normal GCD of its coefficients.
content :: (Euclidean a) => Polynom α a -> a
content (Polynom cs) = gcd' (foldr (:) [] cs)
-- | Compute the primitive part of a polynomial over a unique factorization domain @a@.
-- A polynomial over a unique factorization domain is called /primitive/ if its coefficients
-- are all unit normal and pairwise coprime. The /primitive part/ of a polynomial @p@ is @q@
-- where @p = content p * q@.
primPart :: (Euclidean a) => Polynom α a -> Polynom α a
primPart p@(Polynom cs) = Polynom ((`quot` content p) <$> cs)
-- | Differentiate a polynomial. Each component of the given monomial exponent is how many times
-- to differentiate the polynomial by that variable.
formalDiff :: (Ord (p Natural), Applicative p, Traversable p, Abelian a, LeftModule Natural a) =>
p Natural -> Polynom (p Natural) a -> Polynom (p Natural) a
formalDiff α (Polynom cs) = fromList [(γ, foldr (.*) b (liftA2 facQuot β γ))
| (β, b) <- Map.assocs cs,
Just γ <- [traverse2 pminus β α]]
where facQuot n m = product [m+1..n]
fromList :: (Ord α, Abelian a) => [(α, a)] -> Polynom α a
fromList = Polynom ∘ Map.fromListWith (+)
type Semigroup = Monoid