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

Copyright(c) Justin Le 2016
LicenseBSD3
Maintainerjustin@jle.im
Stabilityexperimental
Portabilitynon-portable
Safe HaskellNone
LanguageHaskell2010

Numeric.Uncertain.Correlated

Contents

Description

Provides the Corr monad, which allows one to describe complex relationships between random variables and evaluate their propagated uncertainties respecting their inter-correlations.

See the Numeric.Uncertain.Correlated.Interactive module for an "interactive" and exploratory interface for this module's functionality.

Synopsis

Corr

data Corr s a b Source #

The Corr monad allows us to keep track of correlated and non-independent samples. It fixes a basic "failure" of the Uncert type, which can't describe correlated samples.

For example, consider the difference between:

ghci> sum $ replicate 10 (12.5 +/- 0.8)
125 +/- 3
ghci> 10 * (12.5 +/- 0.8)
125 +/- 8

The first one represents the addition of ten independent samples, whose errors will in general cancel eachother out. The second one represents sampling once and multiplying it by ten, which will amplify any error by a full factor of 10.

See how the Corr monad expresses the above computations:

ghci> evalCorr $ do
        x  <- sampleUncert $ 12.5 +/- 0.8
        y1 <- resolveUncert $ sum (replicate 10 x)
        y2 <- resolveUncert $ 10 * x
        return (y1, y2)
(125 +/- 8, 125 +/- 8)

ghci> evalCorr $ do
        xs <- replicateM 10 (sampleUncert (12.5 +/- 0.8))
        resolveUncert $ sum xs
125 +/- 3

The first example samples once and describes operations on the single sample; the second example samples 10 times with replicateM and sums all of the results.

Things are more interesting when you sample multiple variables:

ghci> evalCorr $ do
        x <- sampleUncert $ 12.5 +/- 0.8
        y <- sampleUncert $ 15.9 +/- 0.5
        z <- sampleUncert $ 1.52 +/- 0.07
        let k = y ** x
        resolveUncert $ (x+z) * logBase z k
1200 +/- 200

The first parameter is a dummy phantom parameter used to prevent CVars from leaking out of the computation (see evalCorr). The second parameter is the numeric type of all samples within the description (for example, if you ever sample an Uncert Double, the second parameter wil be Double). The third parameter is the result type of the computation -- the value the Corr is describing.

Instances

Monad (Corr s a) Source # 

Methods

(>>=) :: Corr s a a -> (a -> Corr s a b) -> Corr s a b #

(>>) :: Corr s a a -> Corr s a b -> Corr s a b #

return :: a -> Corr s a a #

fail :: String -> Corr s a a #

Functor (Corr s a) Source # 

Methods

fmap :: (a -> b) -> Corr s a a -> Corr s a b #

(<$) :: a -> Corr s a b -> Corr s a a #

Applicative (Corr s a) Source # 

Methods

pure :: a -> Corr s a a #

(<*>) :: Corr s a (a -> b) -> Corr s a a -> Corr s a b #

liftA2 :: (a -> b -> c) -> Corr s a a -> Corr s a b -> Corr s a c #

(*>) :: Corr s a a -> Corr s a b -> Corr s a b #

(<*) :: Corr s a a -> Corr s a b -> Corr s a a #

evalCorr :: Fractional a => (forall s. Corr s a b) -> b Source #

Evaluates the value described by a Corr monad, taking into account inter-correlations between samples.

Takes a universally qualified Corr, which should not affect usage. See the examples in the documentation for Corr. The univeral qualification is mostly a type system trick to ensure that you aren't allowed to ever use evalCorr to evaluate a CVar.

Uncertain and Correlated Values

data CVar s a Source #

Represents a single sample (or a value calculated from samples) within the Corr monad. These can be created with sampleUncert, sampleExact, and constC, or made by combinining others with its numeric typeclass instances (like Num) or its functions lifting arbitrary numeric functions (like liftC2). These keep track of inter-correlations between sources, and if you add together two CVars that are correlated, their results will reflect this.

Can be "resolved" into the uncertain value they represent using resolveUncert.

Note that these are parameterized by a dummy phantom parameter s so that they can't be "evaluated" out of the Corr they live in with evalCorr.

Note that a CVar s a can only ever meaningfully "exist" in a Corr s a, meaning that the all samples within that Corr are of the same type.

Instances

Floating a => Floating (CVar s a) Source # 

Methods

pi :: CVar s a #

exp :: CVar s a -> CVar s a #

log :: CVar s a -> CVar s a #

sqrt :: CVar s a -> CVar s a #

(**) :: CVar s a -> CVar s a -> CVar s a #

logBase :: CVar s a -> CVar s a -> CVar s a #

sin :: CVar s a -> CVar s a #

cos :: CVar s a -> CVar s a #

tan :: CVar s a -> CVar s a #

asin :: CVar s a -> CVar s a #

acos :: CVar s a -> CVar s a #

atan :: CVar s a -> CVar s a #

sinh :: CVar s a -> CVar s a #

cosh :: CVar s a -> CVar s a #

tanh :: CVar s a -> CVar s a #

asinh :: CVar s a -> CVar s a #

acosh :: CVar s a -> CVar s a #

atanh :: CVar s a -> CVar s a #

log1p :: CVar s a -> CVar s a #

expm1 :: CVar s a -> CVar s a #

log1pexp :: CVar s a -> CVar s a #

log1mexp :: CVar s a -> CVar s a #

Fractional a => Fractional (CVar s a) Source # 

Methods

(/) :: CVar s a -> CVar s a -> CVar s a #

recip :: CVar s a -> CVar s a #

fromRational :: Rational -> CVar s a #

Fractional a => Num (CVar s a) Source # 

Methods

(+) :: CVar s a -> CVar s a -> CVar s a #

(-) :: CVar s a -> CVar s a -> CVar s a #

(*) :: CVar s a -> CVar s a -> CVar s a #

negate :: CVar s a -> CVar s a #

abs :: CVar s a -> CVar s a #

signum :: CVar s a -> CVar s a #

fromInteger :: Integer -> CVar s a #

Sampling

sampleUncert :: Uncert a -> Corr s a (CVar s a) Source #

Generate a sample in Corr from an Uncert value, independently from all other samples.

Note that you can only sample Uncert as within a Corr s a, meaning that all other "sampled" values are also as.

sampleExact :: a -> Corr s a (CVar s a) Source #

Generate an exact sample in Corr with zero uncertainty, independently from all other samples.

Not super useful, since you can do something equivalent with constC or the numeric instances:

sampleExact x  ≡ return (constC x)
sampleExact 10 ≡ return 10

But is provided for completeness alongside sampleUncert.

Note that you can exactly sample an a within a Corr s a, meaning that all other "sampled" values are also as.

constC :: a -> CVar s a Source #

Creates a CVar representing a completely independent sample from all other CVars containing the exact value given.

Resolving

resolveUncert :: CVar s a -> Corr s a (Uncert a) Source #

Resolve an Uncert from a CVar using its potential multiple samples and sample sources, taking into account inter-correlations between CVars and samples.

Note that if you use sampleUncert on the result, the new sample will be treated as something completely independent. Usually this should only be used as the "exit point" of a Corr description.

Applying arbitrary functions

liftC Source #

Arguments

:: (forall t. AD t (Sparse a) -> AD t (Sparse a))

Function on values to lift

-> CVar s a

CVar sample to apply the function to

-> CVar s a 

Lifts a numeric function over the sample represented by a CVar. 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> evalCorr $ do
        x <- sampleUncert $ 12.5 +/- 0.8
        y <- sampleUncert $ 15.9 +/- 0.5
        resolveUncert $ liftC (\z -> log z ^ 2) (x + y)
11.2 +/- 0.2

liftC2 :: (forall t. AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a)) -> CVar s a -> CVar s a -> CVar s a Source #

Lifts a two-argument (curried) function over the samples represented by two CVars. Correctly propagates the uncertainty according to the second-order (multivariate) taylor expansion expansion of the function, and properly takes into account and keeps track of all inter-correlations between the CVar samples. 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> evalCorr $ do
        x <- sampleUncert $ 12.5 +/- 0.8
        y <- sampleUncert $ 15.9 +/- 0.5
        resolveUncert $ liftC2 (\a b -> log (a + b) ^ 2) x y
11.2 +/- 0.2

liftC3 :: (forall t. AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a)) -> CVar s a -> CVar s a -> CVar s a -> CVar s a Source #

Lifts a three-argument (curried) function over the samples represented by three CVars. See liftC2 and liftCF for more details.

liftC4 :: (forall t. AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a)) -> CVar s a -> CVar s a -> CVar s a -> CVar s a -> CVar s a Source #

Lifts a four-argument (curried) function over the samples represented by four CVars. See liftC2 and liftCF for more details.

liftC5 :: (forall t. AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a)) -> CVar s a -> CVar s a -> CVar s a -> CVar s a -> CVar s a -> CVar s a Source #

Lifts a five-argument (curried) function over the samples represented by five CVars. See liftC2 and liftCF for more details.

liftCF Source #

Arguments

:: Functor f 
=> (forall t. f (AD t (Sparse a)) -> AD t (Sparse a))

Function on container of values to lift

-> f (CVar s a)

Container of CVar samples to apply the function to

-> CVar s a 

Lifts a multivariate numeric function on a container (given as an f a -> a) to work on a container of CVars. Correctly propagates the uncertainty according to the second-order (multivariate) taylor expansion of the function, and properly takes into account and keeps track of all inter-correlations between the CVar samples. 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> evalCorr $ do
        x <- sampleUncert $ 12.5 +/- 0.8
        y <- sampleUncert $ 15.9 +/- 0.5
        z <- sampleUncert $ 1.52 +/- 0.07
        resolveUncert $ liftCF (\[a,b,c] -> (a+c) * logBase c (b**a)) x y z
1200 +/- 200