uncertain-0.3.1.0: Manipulating numbers with inherent experimental/measurement uncertainty

Copyright (c) Justin Le 2016 BSD3 justin@jle.im experimental non-portable None Haskell2010

Numeric.Uncertain

Description

Synopsis

# Uncert

data Uncert a Source #

Represents an independent experimental value centered around a mean value with "inherent" and independent uncertainty.

Mostly useful due to its instances of numeric typeclasses like Num, Fractional, etc., which allows you to add and multiply and apply arbitrary numerical functions to them and have the uncertainty propagate appropriately. You can also lift arbitrary (sufficiently polymorphic) functions with liftU, liftUF, liftU2 and family.

ghci> let x = 1.52 +/- 0.07
ghci> let y = 781.4 +/- 0.3
ghci> let z = 1.53e-1 withPrecision' 3
ghci> cosh x
2.4 +/- 0.2
ghci> exp x / z * sin (y ** z)
10.9 +/- 0.9
ghci> pi + 3 * logBase x y
52 +/- 5


Uncertaintly is properly propagated according to the second-degree taylor series approximations of the applied functions. However, if the higher-degree terms are large with respect to to the means and variances of the uncertain values, these approximations may be inaccurate.

Can be created with exact to represent an "exact" measurement with no uncertainty, +/- and :+/- to specify a standard deviation as a range, withPrecision to specify through decimal precision, and withVar to specify with a variance. Can also be inferred from a list of samples with fromSamples

7.13 +/- 0.05
91800 +/- 100
12.5 withVar' 0.36
exact 7.9512
81.42 withPrecision' 4
7    :: Uncertain Double
9.18 :: Uncertain Double
fromSamples [12.5, 12.7, 12.6, 12.6, 12.5]


Can be deconstructed with :+/-, the pattern synonym/pseudo-constructor which matches on the mean and a standard deviation (supported on GHC 7.8+, with bidirectional constructor functionality supported on GHC 7.10+). You can also access properties with uMean, uStd, uVar, uMeanStd, uMeanVar, uRange, etc.

It's important to remember that each "occurrence" represents a unique independent sample, so:

ghci> let x = 15 +/- 2 in x + x
30 +/- 3

ghci> let x = 15 +/- 2 in x*2
30 +/- 4


x + x does not represent adding the same sample to itself twice, it represents independently sampling two values within the range 15 +/- 2 and adding them together. In general, errors and deviations will cancel each-other out, leading to a smaller uncertainty.

However, x*2 represents taking one sample and multiplying it by two. This yields a greater uncertainty, because errors and deviations are amplified.

Also be aware that the Show instance "normalizes" the result, and won't show any mean/central point to a decimal precision smaller than the uncertainty, rounding off the excess.

Instances

 Source # Associated Typestype Rep1 (Uncert :: * -> *) :: * -> * # Methodsfrom1 :: Uncert a -> Rep1 Uncert a #to1 :: Rep1 Uncert a -> Uncert a # Eq a => Eq (Uncert a) Source # Methods(==) :: Uncert a -> Uncert a -> Bool #(/=) :: Uncert a -> Uncert a -> Bool # Floating a => Floating (Uncert a) Source # Methodspi :: Uncert a #exp :: Uncert a -> Uncert a #log :: Uncert a -> Uncert a #sqrt :: Uncert a -> Uncert a #(**) :: Uncert a -> Uncert a -> Uncert a #logBase :: Uncert a -> Uncert a -> Uncert a #sin :: Uncert a -> Uncert a #cos :: Uncert a -> Uncert a #tan :: Uncert a -> Uncert a #asin :: Uncert a -> Uncert a #acos :: Uncert a -> Uncert a #atan :: Uncert a -> Uncert a #sinh :: Uncert a -> Uncert a #cosh :: Uncert a -> Uncert a #tanh :: Uncert a -> Uncert a #asinh :: Uncert a -> Uncert a #acosh :: Uncert a -> Uncert a #atanh :: Uncert a -> Uncert a #log1p :: Uncert a -> Uncert a #expm1 :: Uncert a -> Uncert a #log1pexp :: Uncert a -> Uncert a #log1mexp :: Uncert a -> Uncert a # Fractional a => Fractional (Uncert a) Source # Methods(/) :: Uncert a -> Uncert a -> Uncert a #recip :: Uncert a -> Uncert a # Data a => Data (Uncert a) Source # Methodsgfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Uncert a -> c (Uncert a) #gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Uncert a) #toConstr :: Uncert a -> Constr #dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c (Uncert a)) #dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Uncert a)) #gmapT :: (forall b. Data b => b -> b) -> Uncert a -> Uncert a #gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Uncert a -> r #gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Uncert a -> r #gmapQ :: (forall d. Data d => d -> u) -> Uncert a -> [u] #gmapQi :: Int -> (forall d. Data d => d -> u) -> Uncert a -> u #gmapM :: Monad m => (forall d. Data d => d -> m d) -> Uncert a -> m (Uncert a) #gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Uncert a -> m (Uncert a) #gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Uncert a -> m (Uncert a) # Fractional a => Num (Uncert a) Source # Methods(+) :: Uncert a -> Uncert a -> Uncert a #(-) :: Uncert a -> Uncert a -> Uncert a #(*) :: Uncert a -> Uncert a -> Uncert a #negate :: Uncert a -> Uncert a #abs :: Uncert a -> Uncert a #signum :: Uncert a -> Uncert a # Ord a => Ord (Uncert a) Source # Methodscompare :: Uncert a -> Uncert a -> Ordering #(<) :: Uncert a -> Uncert a -> Bool #(<=) :: Uncert a -> Uncert a -> Bool #(>) :: Uncert a -> Uncert a -> Bool #(>=) :: Uncert a -> Uncert a -> Bool #max :: Uncert a -> Uncert a -> Uncert a #min :: Uncert a -> Uncert a -> Uncert a # (Fractional a, Real a) => Real (Uncert a) Source # Methods RealFloat a => RealFloat (Uncert a) Source # MethodsfloatRadix :: Uncert a -> Integer #floatDigits :: Uncert a -> Int #floatRange :: Uncert a -> (Int, Int) #decodeFloat :: Uncert a -> (Integer, Int) #encodeFloat :: Integer -> Int -> Uncert a #exponent :: Uncert a -> Int #significand :: Uncert a -> Uncert a #scaleFloat :: Int -> Uncert a -> Uncert a #isNaN :: Uncert a -> Bool #isInfinite :: Uncert a -> Bool #isIEEE :: Uncert a -> Bool #atan2 :: Uncert a -> Uncert a -> Uncert a # RealFrac a => RealFrac (Uncert a) Source # MethodsproperFraction :: Integral b => Uncert a -> (b, Uncert a) #truncate :: Integral b => Uncert a -> b #round :: Integral b => Uncert a -> b #ceiling :: Integral b => Uncert a -> b #floor :: Integral b => Uncert a -> b # (Show a, Floating a, RealFrac a) => Show (Uncert a) Source # MethodsshowsPrec :: Int -> Uncert a -> ShowS #show :: Uncert a -> String #showList :: [Uncert a] -> ShowS # Source # Associated Typestype Rep (Uncert a) :: * -> * # Methodsfrom :: Uncert a -> Rep (Uncert a) x #to :: Rep (Uncert a) x -> Uncert a # type Rep1 Uncert Source # type Rep1 Uncert = D1 (MetaData "Uncert" "Numeric.Uncertain" "uncertain-0.3.1.0-5vRDQJTyrP4K46da66vNGj" False) (C1 (MetaCons "Un" PrefixI True) ((:*:) (S1 (MetaSel (Just Symbol "_uMean") NoSourceUnpackedness SourceStrict DecidedStrict) Par1) (S1 (MetaSel (Just Symbol "_uVar") NoSourceUnpackedness SourceStrict DecidedStrict) Par1))) type Rep (Uncert a) Source # type Rep (Uncert a) = D1 (MetaData "Uncert" "Numeric.Uncertain" "uncertain-0.3.1.0-5vRDQJTyrP4K46da66vNGj" False) (C1 (MetaCons "Un" PrefixI True) ((:*:) (S1 (MetaSel (Just Symbol "_uMean") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 a)) (S1 (MetaSel (Just Symbol "_uVar") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 a))))

pattern (:+/-) :: forall a. Floating a => a -> a -> Uncert a infixl 6 Source #

Pattern match on an Uncert with its central value and its standard deviation (see uStd for clarification).

Can also be used to construct an Uncert, identically as +/-.

Note: Only supported on GHC 7.8 and above. Bidirectional functionality (to allow use as a constructor) only supported on GHC 7.10 and above.

## Creating Uncert values

(+/-) infixl 6 Source #

Arguments

 :: Num a => a The mean or central value -> a The standard deviation of the underlying uncertainty -> Uncert a

Create an Uncert around a central value and a given "range" of uncertainty. The range is interpreted as the standard deviation of the underlying random variable. Might be preferrable over :+/- because it is more general (doesn't require a Floating constraint) and looks a bit nicer.

See uStd for more details.

Arguments

 :: Num a => a The exact value -> Uncert a

Create an Uncert with an exact value and 0 uncertainty.

Arguments

 :: (Floating a, RealFrac a) => a The approximate value of the Uncert -> Int The number of "digits" of precision to take -> Uncert a

Create an Uncert about a given approximate central value, with the given number of digits of precision (in decimal notation).

5.21 withPrecision 3 ≡ 5.21 +/- 0.01

Arguments

 :: (Floating a, RealFrac a) => Int The base to determine precision with respect to -> a The approximate value of the Uncert -> Int The number of "digits" of precision to take -> Uncert a

Like withPrecision, except takes a number of "digits" of precision in the desired numeric base. For example, in base 2, takes the number of bits of precision.

withPrecision ≡ withPrecisionAtBase 10

Arguments

 :: Num a => a The mean or central value -> a The variance of the underlying uncertainty -> Uncert a

Create an Uncert around a central value, specifying its uncertainty with a given variance. The variance is taken to be proportional to the square of the range of uncertainty. See uStd for more details.

"Negative variances" are treated as positive.

fromSamples :: Fractional a => [a] -> Uncert a Source #

Infer an Uncert from a given list of independent samples of an underlying uncertain or random distribution.

## Inspecting properties

uMean :: Uncert a -> a Source #

Get the mean (central) value of an Uncert.

uVar :: Uncert a -> a Source #

Get the variance of the uncertainty of an Uncert, proportional to the square of "how uncertain" a value is. Is the square of uStd.

uStd :: Floating a => Uncert a -> a Source #

Get the standard deviation of the uncertainty of an Uncert, proportional to "how uncertain" a value is.

Very informally, it can be thought of as the interval above and below the mean that about 68% of sampled values will fall under after repeated sampling, or as the range that one is 68% sure the true value is within.

Is the square root of uVar.

uMeanVar :: Uncert a -> (a, a) Source #

Retrieve both the mean (central) value and the underlying variance of an Uncert together.

uMeanVar ≡ uMean &&& uVar

uMeanStd :: Floating a => Uncert a -> (a, a) Source #

Retreve both the mean (central) value and the underlying standard deviation of an Uncert together. (See uStd for more details)

uMeanStd ≡ uMean &&& uStd

uRange :: Floating a => Uncert a -> (a, a) Source #

Retrieve the "range" of the underlying distribution of an Uncert, derived from the standard deviation, where which approximly 68% of sampled values are expected to occur (or within which you are 68% certain the true value is).

uRange (x +/- dx) ≡ (x - dx, x + dx)

# Applying arbitrary functions

Arguments

 :: Fractional a => (forall s. AD s (Tower a) -> AD s (Tower a)) Function on values to lift -> Uncert a Uncert to apply the function to -> Uncert a

Lifts a numeric function over an Uncert. Correctly propagates the uncertainty according to the second-order taylor expansion expansion of the function. Note that if the higher-degree taylor series terms are large with respect to the mean and variance, this approximation may be inaccurate.

Should take any function sufficiently polymorphic over numeric types, so you can use things like sqrt, sin, negate, etc.

ghci> liftU (\x -> log x ^ 2) (12.2 +/- 0.5)
6.3 +/- 0.2


liftU2 :: Fractional a => (forall s. AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a)) -> Uncert a -> Uncert a -> Uncert a Source #

Lifts a two-argument (curried) function over two Uncerts. Correctly propagates the uncertainty according to the second-order (multivariate) taylor expansion expansion of the function. Note that if the higher-degree taylor series terms are large with respect to the mean and variance, this approximation may be inaccurate.

Should take any function sufficiently polymorphic over numeric types, so you can use things like *, atan2, **, etc.

ghci> liftU2 (\x y -> x**y) (13.5 +- 0.1) (1.64 +- 0.08)
70 +/- 10


liftU3 :: Fractional a => (forall s. AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a)) -> Uncert a -> Uncert a -> Uncert a -> Uncert a Source #

Lifts a three-argument (curried) function over three Uncerts. See liftU2 and liftUF for more details.

liftU4 :: Fractional a => (forall s. AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a)) -> Uncert a -> Uncert a -> Uncert a -> Uncert a -> Uncert a Source #

Lifts a four-argument (curried) function over four Uncerts. See liftU2 and liftUF for more details.

liftU5 :: Fractional a => (forall s. AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a)) -> Uncert a -> Uncert a -> Uncert a -> Uncert a -> Uncert a -> Uncert a Source #

Lifts a five-argument (curried) function over five Uncerts. See liftU2 and liftUF for more details.

Arguments

 :: (Traversable f, Fractional a) => (forall s. f (AD s (Sparse a)) -> AD s (Sparse a)) Function on container of values to lift -> f (Uncert a) Container of Uncerts to apply the function to -> Uncert a

Lifts a multivariate numeric function on a container (given as an f a -> a) to work on a container of Uncerts. Correctly propagates the uncertainty according to the second-order (multivariate) taylor expansion of the function. Note that if the higher-degree taylor series terms are large with respect to the means and variances, this approximation may be inaccurate.

Should take any function sufficiently polymorphic over numeric types, so you can use things like *, sqrt, atan2, etc.

ghci> liftUF (\[x,y,z] -> x*y+z) [12.2 +- 0.5, 56 +- 2, 0.12 +/- 0.08]
680 +/- 40


# Utility functions

uNormalize :: (Floating a, RealFrac a) => Uncert a -> Uncert a Source #

Attempts to "normalize" an Uncert. Rounds the uncertainty (the standard deviation) to one digit of precision, and rounds the central moment up to the implied precision.

For example, it makes no real sense to have 542.185433 +/- 83.584, because the extra digits of 542.185433 past the tens place has no meaning because of the overpowering uncertainty. Normalizing this results in 540 +/- 80.

Note that the Show instance for Uncert normalizes values before showing them.

Arguments

 :: (Floating a, RealFrac a) => Int The base to normalize with respect to -> Uncert a -> Uncert a

Like uNormalize, but takes a numerical base to round with respect to.

uNormalize ≡ uNormalizeAtBase 10

uShow :: (Show a, Floating a) => Uncert a -> String Source #

Like show for Uncert, but does not normalize the value (see uNormalize) before showing.

show ≡ uShow . uNormalize

uShowsPrec :: (Show a, Floating a) => Int -> Uncert a -> ShowS Source #

Like showsPrec for Uncert, but does not normalize the value (see uNormalize) before showing. See documentation for showsPrec` for more information on how this is meant to be used.