numbers 2007.9.25 → 2008.4.20
raw patch · 4 files changed
+183/−181 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/Number/Dif.hs +179/−179
- Data/Number/Natural.hs +1/−1
- Data/Number/Symbolic.hs +1/−0
- numbers.cabal +2/−1
Data/Number/Dif.hs view
@@ -1,179 +1,179 @@--- | The 'Data.Number.Dif' module contains a data type, 'Dif', that allows for --- automatic forward differentiation. --- --- All the ideas are from Jerzy Karczmarczuk\'s work, --- see <http://users.info.unicaen.fr/~karczma/arpap/diffalg.pdf>. --- --- A simple example, if we define --- --- > foo x = x*x --- --- then the function --- --- > foo' = deriv foo --- --- will behave as if its body was 2*x. --- -module Data.Number.Dif(Dif, val, df, mkDif, dCon, dVar, deriv, unDif) where - --- |The 'Dif' type is the type of differentiable numbers. --- It's an instance of all the usual numeric classes. --- The computed derivative of a function is is correct --- except where the function is discontinuous, at these points --- the derivative should be a Dirac pulse, but it isn\'t. --- --- The 'Dif' numbers are printed with a trailing ~~ to --- indicate that there is a \"tail\" of derivatives. -data Dif a = D !a (Dif a) | C !a - --- |The 'dCon' function turns a normal number into a 'Dif' --- number with the same value. Not that numeric literals --- do not need an explicit conversion due to the normal --- Haskell overloading of literals. -dCon :: (Num a) => a -> Dif a -dCon x = C x - --- |The 'dVar' function turns a number into a variable --- number. This is the number with with respect to which --- the derivaticve is computed. -dVar :: (Num a) => a -> Dif a -dVar x = D x 1 - --- |The 'df' takes a 'Dif' number and returns its first --- derivative. The function can be iterated to to get --- higher derivaties. -df :: (Num a) => Dif a -> Dif a -df (D _ x') = x' -df (C _ ) = 0 - --- |The 'val' function takes a 'Dif' number back to a normal --- number, thus forgetting about all the derivatives. -val :: Dif a -> a -val (D x _) = x -val (C x ) = x - --- |The 'mkDif' takes a value and 'Dif' value and makes --- a 'Dif' number that has the given value as its normal --- value, and the 'Dif' number as its derivatives. -mkDif :: a -> Dif a -> Dif a -mkDif = D - --- |The 'deriv' function is a simple utility to take the --- derivative of a (single argument) function. --- It is simply defined as --- --- > deriv f = val . df . f . dVar --- -deriv :: (Num a, Num b) => (Dif a -> Dif b) -> (a -> b) -deriv f = val . df . f . dVar - --- |Convert a 'Dif' function to an ordinary function. -unDif :: (Num a) => (Dif a -> Dif b) -> (a -> b) -unDif f = val . f . dVar - -instance (Show a) => Show (Dif a) where - show x = show (val x) ++ "~~" - -instance (Read a) => Read (Dif a) where - readsPrec p s = [(C x, s') | (x, s') <- readsPrec p s] - -instance (Eq a) => Eq (Dif a) where - x == y = val x == val y - -instance (Ord a) => Ord (Dif a) where - x `compare` y = val x `compare` val y - -instance (Num a) => Num (Dif a) where - (C x) + (C y) = C (x + y) - (C x) + (D y y') = D (x + y) y' - (D x x') + (C y) = D (x + y) x' - (D x x') + (D y y') = D (x + y) (x' + y') - - (C x) - (C y) = C (x - y) - (C x) - (D y y') = D (x - y) y' - (D x x') - (C y) = D (x - y) x' - (D x x') - (D y y') = D (x - y) (x' - y') - - (C 0) * _ = C 0 - _ * (C 0) = C 0 - (C x) * (C y) = C (x * y) - p@(C x) * (D y y') = D (x * y) (p * y') - (D x x') * q@(C y) = D (x * y) (x' * q) - p@(D x x') * q@(D y y') = D (x * y) (x' * q + p * y') - - negate (C x) = C (negate x) - negate (D x x') = D (negate x) (negate x') - - fromInteger i = C (fromInteger i) - - abs (C x) = C (abs x) - abs p@(D x x') = D (abs x) (signum p * x') - - -- The derivative of the signum function is (2*) the Dirac impulse, - -- but there's not really any good way to encode this. - -- We could do it by +Infinity (1/0) at 0. - signum (C x) = C (signum x) - signum (D x _) = C (signum x) - -instance (Fractional a) => Fractional (Dif a) where - recip (C x) = C (recip x) - recip (D x x') = ip - where ip = D (recip x) (-x' * ip * ip) - fromRational r = C (fromRational r) - -lift :: (Num a) => [a -> a] -> Dif a -> Dif a -lift (f : _) (C x) = C (f x) -lift (f : f') p@(D x x') = D (f x) (x' * lift f' p) -lift _ _ = error "lift" - -instance (Floating a) => Floating (Dif a) where - pi = C pi - - exp (C x) = C (exp x) - exp (D x x') = r where r = D (exp x) (x' * r) - - log (C x) = C (log x) - log p@(D x x') = D (log x) (x' / p) - - sqrt (C x) = C (sqrt x) - sqrt (D x x') = r where r = D (sqrt x) (x' / (2 * r)) - - sin = lift (cycle [sin, cos, negate . sin, negate . cos]) - cos = lift (cycle [cos, negate . sin, negate . cos, sin]) - - acos (C x) = C (acos x) - acos p@(D x x') = D (acos x) (-x' / sqrt(1 - p*p)) - asin (C x) = C (asin x) - asin p@(D x x') = D (asin x) ( x' / sqrt(1 - p*p)) - atan (C x) = C (atan x) - atan p@(D x x') = D (atan x) ( x' / (p*p - 1)) - - sinh x = (exp x - exp (-x)) / 2 - cosh x = (exp x + exp (-x)) / 2 - asinh x = log (x + sqrt (x*x + 1)) - acosh x = log (x + sqrt (x*x - 1)) - atanh x = (log (1 + x) - log (1 - x)) / 2 - -instance (Real a) => Real (Dif a) where - toRational = toRational . val - -instance (RealFrac a) => RealFrac (Dif a) where - -- Second component should have an impulse derivative. - properFraction x = (i, x - fromIntegral i) where (i, _) = properFraction (val x) - truncate = truncate . val - round = round . val - ceiling = ceiling . val - floor = floor . val - --- Partial definition on purpose, more could be defined. -instance (RealFloat a) => RealFloat (Dif a) where - floatRadix = floatRadix . val - floatDigits = floatDigits . val - floatRange = floatRange . val - exponent _ = 0 - scaleFloat 0 x = x - isNaN = isNaN . val - isInfinite = isInfinite . val - isDenormalized = isDenormalized . val - isNegativeZero = isNegativeZero . val - isIEEE = isIEEE . val +-- | The 'Data.Number.Dif' module contains a data type, 'Dif', that allows for+-- automatic forward differentiation.+--+-- All the ideas are from Jerzy Karczmarczuk\'s work,+-- see <http://users.info.unicaen.fr/~karczma/arpap/diffalg.pdf>.+--+-- A simple example, if we define+--+-- > foo x = x*x+--+-- then the function+--+-- > foo' = deriv foo+--+-- will behave as if its body was 2*x.+--+module Data.Number.Dif(Dif, val, df, mkDif, dCon, dVar, deriv, unDif) where++-- |The 'Dif' type is the type of differentiable numbers.+-- It's an instance of all the usual numeric classes.+-- The computed derivative of a function is is correct+-- except where the function is discontinuous, at these points+-- the derivative should be a Dirac pulse, but it isn\'t.+--+-- The 'Dif' numbers are printed with a trailing ~~ to+-- indicate that there is a \"tail\" of derivatives.+data Dif a = D !a (Dif a) | C !a++-- |The 'dCon' function turns a normal number into a 'Dif'+-- number with the same value. Not that numeric literals+-- do not need an explicit conversion due to the normal+-- Haskell overloading of literals.+dCon :: (Num a) => a -> Dif a+dCon x = C x++-- |The 'dVar' function turns a number into a variable+-- number. This is the number with with respect to which+-- the derivaticve is computed.+dVar :: (Num a) => a -> Dif a+dVar x = D x 1++-- |The 'df' takes a 'Dif' number and returns its first+-- derivative. The function can be iterated to to get+-- higher derivaties.+df :: (Num a) => Dif a -> Dif a+df (D _ x') = x'+df (C _ ) = 0++-- |The 'val' function takes a 'Dif' number back to a normal+-- number, thus forgetting about all the derivatives.+val :: Dif a -> a+val (D x _) = x+val (C x ) = x++-- |The 'mkDif' takes a value and 'Dif' value and makes+-- a 'Dif' number that has the given value as its normal+-- value, and the 'Dif' number as its derivatives.+mkDif :: a -> Dif a -> Dif a+mkDif = D++-- |The 'deriv' function is a simple utility to take the+-- derivative of a (single argument) function.+-- It is simply defined as+-- +-- > deriv f = val . df . f . dVar+-- +deriv :: (Num a, Num b) => (Dif a -> Dif b) -> (a -> b)+deriv f = val . df . f . dVar++-- |Convert a 'Dif' function to an ordinary function.+unDif :: (Num a) => (Dif a -> Dif b) -> (a -> b)+unDif f = val . f . dVar++instance (Show a) => Show (Dif a) where+ show x = show (val x) ++ "~~"++instance (Read a) => Read (Dif a) where+ readsPrec p s = [(C x, s') | (x, s') <- readsPrec p s]++instance (Eq a) => Eq (Dif a) where+ x == y = val x == val y++instance (Ord a) => Ord (Dif a) where+ x `compare` y = val x `compare` val y++instance (Num a) => Num (Dif a) where+ (C x) + (C y) = C (x + y)+ (C x) + (D y y') = D (x + y) y'+ (D x x') + (C y) = D (x + y) x'+ (D x x') + (D y y') = D (x + y) (x' + y')++ (C x) - (C y) = C (x - y)+ (C x) - (D y y') = D (x - y) (-y')+ (D x x') - (C y) = D (x - y) x'+ (D x x') - (D y y') = D (x - y) (x' - y')++ (C 0) * _ = C 0+ _ * (C 0) = C 0+ (C x) * (C y) = C (x * y)+ p@(C x) * (D y y') = D (x * y) (p * y')+ (D x x') * q@(C y) = D (x * y) (x' * q)+ p@(D x x') * q@(D y y') = D (x * y) (x' * q + p * y')++ negate (C x) = C (negate x)+ negate (D x x') = D (negate x) (negate x')++ fromInteger i = C (fromInteger i)++ abs (C x) = C (abs x)+ abs p@(D x x') = D (abs x) (signum p * x')++ -- The derivative of the signum function is (2*) the Dirac impulse,+ -- but there's not really any good way to encode this.+ -- We could do it by +Infinity (1/0) at 0.+ signum (C x) = C (signum x)+ signum (D x _) = C (signum x)++instance (Fractional a) => Fractional (Dif a) where+ recip (C x) = C (recip x)+ recip (D x x') = ip+ where ip = D (recip x) (-x' * ip * ip)+ fromRational r = C (fromRational r)++lift :: (Num a) => [a -> a] -> Dif a -> Dif a+lift (f : _) (C x) = C (f x)+lift (f : f') p@(D x x') = D (f x) (x' * lift f' p)+lift _ _ = error "lift"++instance (Floating a) => Floating (Dif a) where+ pi = C pi++ exp (C x) = C (exp x)+ exp (D x x') = r where r = D (exp x) (x' * r)++ log (C x) = C (log x)+ log p@(D x x') = D (log x) (x' / p)++ sqrt (C x) = C (sqrt x)+ sqrt (D x x') = r where r = D (sqrt x) (x' / (2 * r))++ sin = lift (cycle [sin, cos, negate . sin, negate . cos])+ cos = lift (cycle [cos, negate . sin, negate . cos, sin])++ acos (C x) = C (acos x)+ acos p@(D x x') = D (acos x) (-x' / sqrt(1 - p*p))+ asin (C x) = C (asin x)+ asin p@(D x x') = D (asin x) ( x' / sqrt(1 - p*p))+ atan (C x) = C (atan x)+ atan p@(D x x') = D (atan x) ( x' / (p*p - 1))++ sinh x = (exp x - exp (-x)) / 2+ cosh x = (exp x + exp (-x)) / 2+ asinh x = log (x + sqrt (x*x + 1))+ acosh x = log (x + sqrt (x*x - 1))+ atanh x = (log (1 + x) - log (1 - x)) / 2++instance (Real a) => Real (Dif a) where+ toRational = toRational . val++instance (RealFrac a) => RealFrac (Dif a) where+ -- Second component should have an impulse derivative.+ properFraction x = (i, x - fromIntegral i) where (i, _) = properFraction (val x)+ truncate = truncate . val+ round = round . val+ ceiling = ceiling . val+ floor = floor . val++-- Partial definition on purpose, more could be defined.+instance (RealFloat a) => RealFloat (Dif a) where+ floatRadix = floatRadix . val+ floatDigits = floatDigits . val+ floatRange = floatRange . val+ exponent _ = 0+ scaleFloat 0 x = x+ isNaN = isNaN . val+ isInfinite = isInfinite . val+ isDenormalized = isDenormalized . val+ isNegativeZero = isNegativeZero . val+ isIEEE = isIEEE . val
Data/Number/Natural.hs view
@@ -2,7 +2,7 @@ -- Addition and multiplication recurses over the first argument, i.e., -- @1 + n@ is the way to write the constant time successor function. ----- Not that (+) and (*) are not commutative for lazy natural numbers+-- Note that (+) and (*) are not commutative for lazy natural numbers -- when considering bottom. module Data.Number.Natural(Natural, infinity) where
Data/Number/Symbolic.hs view
@@ -126,6 +126,7 @@ instance (Integral a) => Integral (Sym a) where quot x y = binOp quot x "quot" y rem x y = binOp rem x "rem" y+ quotRem x y = (quot x y, rem x y) div x y = binOp div x "div" y mod x y = binOp mod x "mod" y toInteger (Con c) = toInteger c
numbers.cabal view
@@ -1,5 +1,5 @@ Name: numbers-Version: 2007.9.25+Version: 2008.4.20 License: BSD3 Author: Lennart Augustsson Maintainer: Lennart Augustsson@@ -11,6 +11,7 @@ arbitrary precision floating point numbers, differentiable numbers, symbolic numbers, natural numbers, interval arithmetic.+Build-type: Simple Build-Depends: base Exposed-modules: Data.Number.Symbolic Data.Number.Dif Data.Number.CReal Data.Number.Fixed