{-
Copyright (C) 2011-2015 Dr. Alistair Ward
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
-}
{- |
[@AUTHOR@] Dr. Alistair Ward
[@DESCRIPTION@]
* Describes a and operations on it.
* A /monomial/ is merely a /polynomial/ with a single non-zero term; cf. /Binomial/.
-}
module Factory.Data.Monomial(
-- * Types
-- ** Type-synonyms
Monomial,
-- * Functions
double,
mod',
negateCoefficient,
realCoefficientToFrac,
shiftCoefficient,
shiftExponent,
square,
-- ** Accessors
getExponent,
getCoefficient,
-- ** Operators
(<=>),
(>),
(<*>),
(=~),
-- ** Predicates
isMonomial
) where
import Prelude hiding ((<*>)) -- The "Prelude" from 'base-4.8' exports this symbol.
import qualified Control.Arrow
infix 4 <=> -- Same as (==).
infix 4 =~ -- Same as (==).
infixl 7 > -- Same as (/).
infixl 7 <*> -- Same as (*).
{- |
* The type of an arbitrary monomial.
* CAVEAT: though a /monomial/ has an integral power, this contraint is only imposed at the function-level.
-}
type Monomial coefficient exponent = (coefficient, exponent)
-- | Accessor.
{-# INLINE getCoefficient #-}
getCoefficient :: Monomial c e -> c
getCoefficient = fst
-- | Accessor.
{-# INLINE getExponent #-}
getExponent :: Monomial c e -> e
getExponent = snd
{- |
* 'True' if the /exponent/ is both integral and non-/negative/.
* CAVEAT: one can't even call this function unless the /exponent/ is integral.
-}
isMonomial :: Integral e => Monomial c e -> Bool
isMonomial = (>= 0) . getExponent
-- | Compares the /exponents/ of the specified 'Monomial's.
{-# INLINE (<=>) #-}
(<=>) :: Ord e => Monomial c e -> Monomial c e -> Ordering
(_, l) <=> (_, r) = l `compare` r
-- | True if the /exponents/ are equal.
(=~) :: Eq e => Monomial c e -> Monomial c e -> Bool
(_, l) =~ (_, r) = l == r
-- | Multiply the two specified 'Monomial's.
{-# INLINE (<*>) #-}
(<*>) :: (Num c, Num e) => Monomial c e -> Monomial c e -> Monomial c e
(cL, eL) <*> (cR, eR) = (cL * cR, eL + eR)
-- | Divide the two specified 'Monomial's.
(>) :: (Eq c, Fractional c, Num e)
=> Monomial c e -- ^ Numerator.
-> Monomial c e -- ^ Denominator.
-> Monomial c e
(cN, eN) > (1, eD) = (cN, eN - eD)
(cN, eN) > (cD, eD) = (cN / cD, eN - eD)
-- | Square the specified 'Monomial'.
square :: (Num c, Num e) => Monomial c e -> Monomial c e
square (c, e) = (c ^ (2 :: Int), 2 * e)
-- | Double the specified 'Monomial'.
{-# INLINE double #-}
double :: Num c => Monomial c e -> Monomial c e
double (c, e) = (2 * c, e)
-- | Shift the /coefficient/, by the specified amount.
{-# INLINE shiftCoefficient #-}
shiftCoefficient :: Num c
=> Monomial c e
-> c -- ^ The magnitude of the shift.
-> Monomial c e
-- m `shiftCoefficient` i = Control.Arrow.first (+ i) m -- CAVEAT: Too slow.
(c, e) `shiftCoefficient` i = (c + i, e)
-- | Shift the /exponent/, by the specified amount.
{-# INLINE shiftExponent #-}
shiftExponent :: Num e
=> Monomial c e
-> e -- ^ The magnitude of the shift.
-> Monomial c e
-- m `shiftExponent` i = Control.Arrow.second (+ i) m -- CAVEAT: Too slow.
(c, e) `shiftExponent` i = (c, e + i)
-- | Negate the coefficient.
negateCoefficient :: Num c => Monomial c e -> Monomial c e
negateCoefficient = Control.Arrow.first negate
-- | Reduce the coefficient using /modular/ arithmetic.
{-# INLINE mod' #-}
mod' :: Integral c
=> Monomial c e
-> c -- ^ Modulus.
-> Monomial c e
monomial `mod'` modulus = Control.Arrow.first (`mod` modulus) monomial
-- | Convert the type of the /coefficient/.
realCoefficientToFrac :: (Real r, Fractional f) => Monomial r e -> Monomial f e
realCoefficientToFrac = Control.Arrow.first realToFrac