{-# LANGUAGE CPP #-} {- 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 <http://www.gnu.org/licenses/>. -} {- | [@AUTHOR@] Dr. Alistair Ward [@DESCRIPTION@] * Describes a <https://en.wikipedia.org/wiki/Monomial> 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 (<=>), (</>), (<*>), -- CAVEAT: this clashes with the Prelude from 'base-4.8'. (=~), -- ** Predicates isMonomial ) where import qualified Control.Arrow #if MIN_VERSION_base(4,8,0) import Prelude hiding ((<*>)) -- The "Prelude" from 'base-4.8' exports this symbol. #endif 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