uncertain 0.3.1.0 → 0.4.0.0
raw patch · 10 files changed
+821/−757 lines, 10 filessetup-changedPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Numeric.Uncertain: pattern (:+/-) :: Floating a => a -> a -> Uncert a
- Numeric.Uncertain.MonteCarlo: liftU4 :: PrimMonad m => (Double -> Double -> Double -> Double -> Double) -> Uncert Double -> Uncert Double -> Uncert Double -> Uncert Double -> Gen (PrimState m) -> m (Uncert Double)
+ Numeric.Uncertain.MonteCarlo: liftU4 :: (PrimMonad m, Applicative m) => (Double -> Double -> Double -> Double -> Double) -> Uncert Double -> Uncert Double -> Uncert Double -> Uncert Double -> Gen (PrimState m) -> m (Uncert Double)
Files
- CHANGELOG.md +16/−3
- README.md +10/−8
- Setup.hs +1/−0
- src/Data/Hople.hs +21/−18
- src/Numeric/Uncertain.hs +318/−280
- src/Numeric/Uncertain/Correlated.hs +30/−22
- src/Numeric/Uncertain/Correlated/Interactive.hs +38/−26
- src/Numeric/Uncertain/Correlated/Internal.hs +196/−177
- src/Numeric/Uncertain/MonteCarlo.hs +138/−183
- uncertain.cabal +53/−40
CHANGELOG.md view
@@ -1,5 +1,18 @@+Changelog+=========++Version 0.4.0.0+---------------++*August 22, 2024*++<https://github.com/mstksg/uncertain/releases/tag/v0.4.0.0>++* Dropped support for GHC < 8.10+* Fixed support for GHC 9.0+ Version 0.3.1.0-===============+--------------- <https://github.com/mstksg/uncertain/releases/tag/v0.3.1.0> @@ -13,7 +26,7 @@ module's `liftUX` functions. Version 0.3.0.0-===============+--------------- <https://github.com/mstksg/uncertain/releases/tag/v0.3.0.0> @@ -22,7 +35,7 @@ convention of other similar libraries. Version 0.2.0.0-===============+--------------- <https://github.com/mstksg/uncertain/releases/tag/v0.2.0.0>
README.md view
@@ -1,14 +1,15 @@ Uncertain ========= +[](https://hackage.haskell.org/package/uncertain)+[](http://stackage.org/lts/package/uncertain)+[](http://stackage.org/nightly/package/uncertain) [](https://travis-ci.org/mstksg/uncertain) Provides tools to manipulate numbers with inherent experimental/measurement uncertainty, and propagates them through functions based on principles from statistics. -Documentation maintained at <https://mstksg.github.io/uncertain>.- ## Usage ```haskell@@ -94,7 +95,8 @@ ## Monte Carlo-based propagation of uncertainty Provides a module for propagating uncertainty using [Monte Carlo-simulations][]+simulations][], which could potentially be more accurate if third-order and+higher taylor series expansion terms are non-negligible. [Monte Carlo simulations]: https://en.wikipedia.org/wiki/Monte_Carlo_method @@ -122,11 +124,11 @@ ## Comparisons Note that this is very different from other libraries with similar data types-(like from [intervals][] and [rounding][]); these do not attempt to maintain intervals or-simply digit precisions; they instead are intended to model actual-experimental and measurement data with their uncertainties, and apply-functions to the data with the uncertainties and properly propagating the-errors with sound statistical principles.+(like from [intervals][] and [rounding][]); these do not attempt to maintain+intervals or simply digit precisions; they instead are intended to model actual+experimental and measurement data with their uncertainties, and apply functions+to the data with the uncertainties and properly propagating the errors with+sound statistical principles. [intervals]: https://hackage.haskell.org/package/intervals [rounding]: https://hackage.haskell.org/package/rounding
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
src/Data/Hople.hs view
@@ -1,9 +1,7 @@-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE NoImplicitPrelude #-}-{-# OPTIONS_HADDOCK hide #-}-{-# OPTIONS_HADDOCK prune #-}+{-# OPTIONS_HADDOCK hide #-}+{-# OPTIONS_HADDOCK prune #-} -- | -- Module : Data.Hople@@ -15,22 +13,28 @@ -- Portability : non-portable -- -- Homogeneous strict tuples used for implementing 'liftU2', etc.--module Data.Hople- ( H1(..)- , H2(..)- , H3(..)- , H4(..)- , H5(..)- , curryH1, curryH2, curryH3, curryH4, curryH5- , uncurryH1, uncurryH2, uncurryH3, uncurryH4, uncurryH5- )- where+module Data.Hople (+ H1 (..),+ H2 (..),+ H3 (..),+ H4 (..),+ H5 (..),+ curryH1,+ curryH2,+ curryH3,+ curryH4,+ curryH5,+ uncurryH1,+ uncurryH2,+ uncurryH3,+ uncurryH4,+ uncurryH5,+)+where import Prelude.Compat --data H1 a = H1 !a+newtype H1 a = H1 a deriving (Functor, Foldable, Traversable, Show) data H2 a = H2 !a !a@@ -84,4 +88,3 @@ uncurryH5 :: (a -> a -> a -> a -> a -> a) -> H5 a -> a uncurryH5 f (H5 x y z a b) = f x y z a b {-# INLINE uncurryH5 #-}-
src/Numeric/Uncertain.hs view
@@ -1,12 +1,12 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE NoImplicitPrelude #-} #if __GLASGOW_HASKELL__ >= 708 {-# LANGUAGE PatternSynonyms #-}@@ -20,42 +20,52 @@ -- Maintainer : justin@jle.im -- Stability : experimental -- Portability : non-portable---+module Numeric.Uncertain (+ -- * 'Uncert'+ Uncert ((:+/-)), -module Numeric.Uncertain- ( -- * 'Uncert'-#if __GLASGOW_HASKELL__ >= 810- Uncert((:+/-))-#else- Uncert-#if __GLASGOW_HASKELL__ >= 708- , pattern (:+/-)-#endif-#endif- -- ** Creating 'Uncert' values- , (+/-), exact, withPrecision, withPrecisionAtBase, withVar, fromSamples- -- ** Inspecting properties- , uMean, uVar, uStd, uMeanVar, uMeanStd, uRange- -- * Applying arbitrary functions- , liftU- , liftU2, liftU3, liftU4, liftU5, liftUF- -- * Utility functions- , uNormalize, uNormalizeAtBase- , uShow, uShowsPrec- )- where+ -- ** Creating 'Uncert' values+ (+/-),+ exact,+ withPrecision,+ withPrecisionAtBase,+ withVar,+ fromSamples, -import Data.Data-import Data.Foldable (toList, foldl')-import Data.Function-import Data.Hople-import Data.Ord-import GHC.Generics-import Numeric.AD.Mode.Sparse-import Prelude.Compat-import qualified Numeric.AD.Mode.Tower as T+ -- ** Inspecting properties+ uMean,+ uVar,+ uStd,+ uMeanVar,+ uMeanStd,+ uRange, + -- * Applying arbitrary functions+ liftU,+ liftU2,+ liftU3,+ liftU4,+ liftU5,+ liftUF, + -- * Utility functions+ uNormalize,+ uNormalizeAtBase,+ uShow,+ uShowsPrec,+)+where++import Data.Data+import Data.Foldable (toList)+import Data.Function+import Data.Hople+import Data.Ord+import GHC.Generics+import Numeric.AD.Mode.Sparse+import qualified Numeric.AD.Mode.Tower as T+import Prelude.Compat+ -- | Represents an independent experimental value centered around a mean -- value with "inherent" and independent uncertainty. --@@ -129,10 +139,11 @@ -- 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.----data Uncert a = Un { _uMean :: !a- , _uVar :: !a -- ^ maintained to be positive!- }+data Uncert a = Un+ { _uMean :: !a+ , _uVar :: !a+ -- ^ maintained to be positive!+ } deriving (Data, Typeable, Generic, Generic1) -- | Get the mean (central) value of an 'Uncert'.@@ -159,10 +170,11 @@ {-# INLINE uStd #-} -- | Create an 'Uncert' with an exact value and 0 uncertainty.-exact- :: Num a- => a -- ^ The exact value- -> Uncert a+exact ::+ Num a =>+ -- | The exact value+ a ->+ Uncert a exact x = Un x 0 {-# INLINE exact #-} @@ -178,12 +190,14 @@ -- a bit nicer. -- -- See 'uStd' for more details.-(+/-)- :: Num a- => a -- ^ The mean or central value- -> a -- ^ The standard deviation of the underlying uncertainty- -> Uncert a-x +/- dx = Un x (dx*dx)+(+/-) ::+ Num a =>+ -- | The mean or central value+ a ->+ -- | The standard deviation of the underlying uncertainty+ a ->+ Uncert a+x +/- dx = Un x (dx * dx) {-# INLINE (+/-) #-} -- | Create an 'Uncert' around a central value, specifying its uncertainty@@ -191,11 +205,13 @@ -- the square of the range of uncertainty. See 'uStd' for more details. -- -- "Negative variances" are treated as positive.-withVar- :: Num a- => a -- ^ The mean or central value- -> a -- ^ The variance of the underlying uncertainty- -> Uncert a+withVar ::+ Num a =>+ -- | The mean or central value+ a ->+ -- | The variance of the underlying uncertainty+ a ->+ Uncert a withVar x vx = Un x (abs vx) {-# INLINE withVar #-} @@ -228,12 +244,12 @@ where makeUn (H3 x0 x1 x2) = Un μ v where- μ = x1/x0- v = x2/x0 - μ*μ -- maybe use pop var?+ μ = x1 / x0+ v = x2 / x0 - μ * μ -- maybe use pop var? foldStats = flip foldl' (H3 0 0 0) $- \(H3 s0 s1 s2) x ->- H3 (s0 + 1) (s1 + x) (s2 + x*x)-{-# INLINABLE fromSamples #-}+ \(H3 s0 s1 s2) x ->+ H3 (s0 + 1) (s1 + x) (s2 + x * x)+{-# INLINEABLE fromSamples #-} -- | Retrieve both the mean (central) value and the underlying variance of -- an 'Uncert' together.@@ -258,65 +274,71 @@ -- -- @uRange (x +/- dx) ≡ (x - dx, x + dx)@ uRange :: Floating a => Uncert a -> (a, a)-uRange (uMeanStd->(x, dx)) = (x - dx, x + dx)-{-# INLINABLE uRange #-}+uRange (uMeanStd -> (x, dx)) = (x - dx, x + dx)+{-# INLINEABLE uRange #-} -- | 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@-withPrecisionAtBase- :: (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+withPrecisionAtBase ::+ (Floating a, RealFrac a) =>+ -- | The base to determine precision with respect to+ Int ->+ -- | The approximate value of the 'Uncert'+ a ->+ -- | The number of "digits" of precision to take+ Int ->+ Uncert a withPrecisionAtBase b x p = x' +/- dx' where leading :: Int leading = negate . floor . logBase (fromIntegral b) $ x- uncert :: Int- uncert = leading - 1 + fromIntegral p+ uncert :: Int+ uncert = leading - 1 + fromIntegral p rounder = fromIntegral b ** fromIntegral uncert- x' = (/ rounder) . fromIntegral . round' . (* rounder) $ x- dx' = 1 / rounder- round' :: RealFrac a => a -> Integer- round' = round-{-# INLINABLE withPrecisionAtBase #-}+ x' = (/ rounder) . fromIntegral . round' . (* rounder) $ x+ dx' = 1 / rounder+ round' :: RealFrac a => a -> Integer+ round' = round+{-# INLINEABLE withPrecisionAtBase #-} -- | 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@-withPrecision- :: (Floating a, RealFrac a)- => a -- ^ The approximate value of the 'Uncert'- -> Int -- ^ The number of "digits" of precision to take- -> Uncert a+withPrecision ::+ (Floating a, RealFrac a) =>+ -- | The approximate value of the 'Uncert'+ a ->+ -- | The number of "digits" of precision to take+ Int ->+ Uncert a withPrecision = withPrecisionAtBase 10-{-# INLINABLE withPrecision #-}+{-# INLINEABLE withPrecision #-} -- | Like 'uNormalize', but takes a numerical base to round with respect -- to. -- -- @'uNormalize' ≡ uNormalizeAtBase 10@-uNormalizeAtBase- :: (Floating a, RealFrac a)- => Int -- ^ The base to normalize with respect to- -> Uncert a- -> Uncert a-uNormalizeAtBase b (uMeanStd->(x, dx)) = x' +/- dx'+uNormalizeAtBase ::+ (Floating a, RealFrac a) =>+ -- | The base to normalize with respect to+ Int ->+ Uncert a ->+ Uncert a+uNormalizeAtBase b (uMeanStd -> (x, dx)) = x' +/- dx' where- uncert :: Int- uncert = negate . floor . logBase (fromIntegral b) $ dx- rounder = fromIntegral b ** fromIntegral uncert- roundTo = (/ rounder) . fromIntegral . round' . (* rounder)- x' = roundTo x- dx' = roundTo dx- round' :: RealFrac a => a -> Integer- round' = round-{-# INLINABLE uNormalizeAtBase #-}+ uncert :: Int+ uncert = negate . floor . logBase (fromIntegral b) $ dx+ rounder = fromIntegral b ** fromIntegral uncert+ roundTo = (/ rounder) . fromIntegral . round' . (* rounder)+ x' = roundTo x+ dx' = roundTo dx+ round' :: RealFrac a => a -> Integer+ round' = round+{-# INLINEABLE uNormalizeAtBase #-} -- | Attempts to "normalize" an 'Uncert'. Rounds the uncertainty (the -- standard deviation) to one digit of precision, and rounds the central@@ -329,25 +351,26 @@ -- -- Note that the 'Show' instance for 'Uncert' normalizes values before -- showing them.-uNormalize- :: (Floating a, RealFrac a)- => Uncert a- -> Uncert a+uNormalize ::+ (Floating a, RealFrac a) =>+ Uncert a ->+ Uncert a uNormalize = uNormalizeAtBase 10-{-# INLINABLE uNormalize #-}+{-# INLINEABLE uNormalize #-} instance (Show a, Floating a, RealFrac a) => Show (Uncert a) where- showsPrec d = uShowsPrec d . uNormalize+ showsPrec d = uShowsPrec d . uNormalize -- | 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. uShowsPrec :: (Show a, Floating a) => Int -> Uncert a -> ShowS-uShowsPrec d (uMeanStd->(x, dx)) = showParen (d > 5) $- showsPrec 6 x- . showString " +/- "- . showsPrec 6 dx-{-# INLINABLE uShowsPrec #-}+uShowsPrec d (uMeanStd -> (x, dx)) =+ showParen (d > 5) $+ showsPrec 6 x+ . showString " +/- "+ . showsPrec 6 dx+{-# INLINEABLE uShowsPrec #-} -- | Like 'show' for 'Uncert', but does not normalize the value (see -- 'uNormalize') before showing.@@ -355,7 +378,7 @@ -- @'show' ≡ uShow . 'uNormalize'@ uShow :: (Show a, Floating a) => Uncert a -> String uShow u = uShowsPrec 0 u ""-{-# INLINABLE uShow #-}+{-# INLINEABLE uShow #-} -- | Lifts a multivariate numeric function on a container (given as an @f -- a -> a@) to work on a container of 'Uncert's. Correctly propagates the@@ -371,35 +394,38 @@ -- ghci> liftUF (\\[x,y,z] -> x*y+z) [12.2 +/- 0.5, 56 +/- 2, 0.12 +/- 0.08] -- 680 +/- 40 -- @----liftUF- :: (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 'Uncert's to apply the function to- -> Uncert a+liftUF ::+ (Traversable f, Fractional a) =>+ -- | Function on container of values to lift+ (forall s. f (AD s (Sparse a)) -> AD s (Sparse a)) ->+ -- | Container of 'Uncert's to apply the function to+ f (Uncert a) ->+ Uncert a liftUF f us = Un y vy where- xs = uMean <$> us- vxs = uVar <$> us- vxsL = toList vxs+ xs = uMean <$> us+ vxs = uVar <$> us+ vxsL = toList vxs (fx, dfxsh) = hessian' f xs- dfxs = fst <$> dfxsh- hess = snd <$> dfxsh- y = fx + hessQuad / 2+ dfxs = fst <$> dfxsh+ hess = snd <$> dfxsh+ y = fx + hessQuad / 2 where- hessQuad = dot vxsL- . diag- . toList- $ fmap toList hess- vy = dot vxsL ((^ (2::Int)) <$> dfxs)+ hessQuad =+ dot vxsL+ . diag+ . toList+ $ fmap toList hess+ vy = dot vxsL ((^ (2 :: Int)) <$> dfxs) dot x = sum . zipWith (*) x . toList- diag = \case [] -> []- [] :yss -> diag (drop1 <$> yss)- (x:_):yss -> x : diag (drop1 <$> yss)+ diag = \case+ [] -> []+ [] : yss -> diag (drop1 <$> yss)+ (x : _) : yss -> x : diag (drop1 <$> yss) where- drop1 [] = []- drop1 (_:zs) = zs-{-# INLINABLE liftUF #-}+ drop1 [] = []+ drop1 (_ : zs) = zs+{-# INLINEABLE liftUF #-} -- | Lifts a numeric function over an 'Uncert'. Correctly propagates the -- uncertainty according to the second-order taylor expansion expansion of@@ -414,17 +440,21 @@ -- ghci> liftU (\\x -> log x ^ 2) (12.2 +/- 0.5) -- 6.3 +/- 0.2 -- @-liftU- :: Fractional a- => (forall s. AD s (T.Tower a) -> AD s (T.Tower a)) -- ^ Function on values to lift- -> Uncert a -- ^ 'Uncert' to apply the function to- -> Uncert a+liftU ::+ Fractional a =>+ -- | Function on values to lift+ (forall s. AD s (T.Tower a) -> AD s (T.Tower a)) ->+ -- | 'Uncert' to apply the function to+ Uncert a ->+ Uncert a liftU f (Un x vx) = Un y vy where- fx:dfx:ddfx:_ = T.diffs0 f x- y = fx + ddfx * vx / 2- vy = dfx*dfx * vx-{-# INLINABLE liftU #-}+ (fx, dfx, ddfx) = case T.diffs0 f x of+ a : b : c : _ -> (a, b, c)+ _ -> error "diffs0 should return an infinite list"+ y = fx + ddfx * vx / 2+ vy = dfx * dfx * vx+{-# INLINEABLE liftU #-} -- | Lifts a two-argument (curried) function over two 'Uncert's. Correctly -- propagates the uncertainty according to the second-order (multivariate)@@ -439,168 +469,176 @@ -- ghci> liftU2 (\\x y -> x**y) (13.5 +/- 0.1) (1.64 +/- 0.08) -- 70 +/- 10 -- @-liftU2- :: Fractional a- => (forall s. AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a))- -> Uncert a- -> Uncert a- -> Uncert a+liftU2 ::+ Fractional a =>+ (forall s. AD s (Sparse a) -> AD s (Sparse a) -> AD s (Sparse a)) ->+ Uncert a ->+ Uncert a ->+ Uncert a liftU2 f = curryH2 $ liftUF (uncurryH2 f)-{-# INLINABLE liftU2 #-}+{-# INLINEABLE liftU2 #-} -- | Lifts a three-argument (curried) function over three 'Uncert's. See -- 'liftU2' and 'liftUF' for more details.-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+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 liftU3 f = curryH3 $ liftUF (uncurryH3 f)-{-# INLINABLE liftU3 #-}+{-# INLINEABLE liftU3 #-} -- | Lifts a four-argument (curried) function over four 'Uncert's. 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+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 liftU4 f = curryH4 $ liftUF (uncurryH4 f)-{-# INLINABLE liftU4 #-}+{-# INLINEABLE liftU4 #-} -- | Lifts a five-argument (curried) function over five 'Uncert's. 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+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 liftU5 f = curryH5 $ liftUF (uncurryH5 f)-{-# INLINABLE liftU5 #-}+{-# INLINEABLE liftU5 #-} instance Fractional a => Num (Uncert a) where- (+) = liftU2 (+)- {-# INLINE (+) #-}- (*) = liftU2 (*)- {-# INLINE (*) #-}- (-) = liftU2 (-)- {-# INLINE (-) #-}- negate = liftU negate- {-# INLINE negate #-}- abs = liftU abs- {-# INLINE abs #-}- signum = liftU signum- {-# INLINE signum #-}- fromInteger = exact . fromInteger- {-# INLINE fromInteger #-}+ (+) = liftU2 (+)+ {-# INLINE (+) #-}+ (*) = liftU2 (*)+ {-# INLINE (*) #-}+ (-) = liftU2 (-)+ {-# INLINE (-) #-}+ negate = liftU negate+ {-# INLINE negate #-}+ abs = liftU abs+ {-# INLINE abs #-}+ signum = liftU signum+ {-# INLINE signum #-}+ fromInteger = exact . fromInteger+ {-# INLINE fromInteger #-} instance Fractional a => Fractional (Uncert a) where- recip = liftU recip- {-# INLINE recip #-}- (/) = liftU2 (/)- {-# INLINE (/) #-}- fromRational = exact . fromRational- {-# INLINE fromRational #-}+ recip = liftU recip+ {-# INLINE recip #-}+ (/) = liftU2 (/)+ {-# INLINE (/) #-}+ fromRational = exact . fromRational+ {-# INLINE fromRational #-} instance Floating a => Floating (Uncert a) where- pi = exact pi- {-# INLINE pi #-}- exp = liftU exp- {-# INLINE exp #-}- log = liftU log- {-# INLINE log #-}- sqrt = liftU sqrt- {-# INLINE sqrt #-}- (**) = liftU2 (**)- {-# INLINE (**) #-}- logBase = liftU2 logBase- {-# INLINE logBase #-}- sin = liftU sin- {-# INLINE sin #-}- cos = liftU cos- {-# INLINE cos #-}- asin = liftU asin- {-# INLINE asin #-}- acos = liftU acos- {-# INLINE acos #-}- atan = liftU atan- {-# INLINE atan #-}- sinh = liftU sinh- {-# INLINE sinh #-}- cosh = liftU cosh- {-# INLINE cosh #-}- asinh = liftU asinh- {-# INLINE asinh #-}- acosh = liftU acosh- {-# INLINE acosh #-}- atanh = liftU atanh- {-# INLINE atanh #-}+ pi = exact pi+ {-# INLINE pi #-}+ exp = liftU exp+ {-# INLINE exp #-}+ log = liftU log+ {-# INLINE log #-}+ sqrt = liftU sqrt+ {-# INLINE sqrt #-}+ (**) = liftU2 (**)+ {-# INLINE (**) #-}+ logBase = liftU2 logBase+ {-# INLINE logBase #-}+ sin = liftU sin+ {-# INLINE sin #-}+ cos = liftU cos+ {-# INLINE cos #-}+ asin = liftU asin+ {-# INLINE asin #-}+ acos = liftU acos+ {-# INLINE acos #-}+ atan = liftU atan+ {-# INLINE atan #-}+ sinh = liftU sinh+ {-# INLINE sinh #-}+ cosh = liftU cosh+ {-# INLINE cosh #-}+ asinh = liftU asinh+ {-# INLINE asinh #-}+ acosh = liftU acosh+ {-# INLINE acosh #-}+ atanh = liftU atanh+ {-# INLINE atanh #-} instance Eq a => Eq (Uncert a) where- (==) = (==) `on` uMean- {-# INLINE (==) #-}- (/=) = (/=) `on` uMean- {-# INLINE (/=) #-}+ (==) = (==) `on` uMean+ {-# INLINE (==) #-}+ (/=) = (/=) `on` uMean+ {-# INLINE (/=) #-} instance Ord a => Ord (Uncert a) where- compare = comparing uMean- {-# INLINE compare #-}+ compare = comparing uMean+ {-# INLINE compare #-} instance (Fractional a, Real a) => Real (Uncert a) where- toRational = toRational . uMean- {-# INLINE toRational #-}+ toRational = toRational . uMean+ {-# INLINE toRational #-} instance RealFrac a => RealFrac (Uncert a) where- properFraction x = (n, d)- where- d = liftU (snd' . properFraction) x- n = fst . properFraction $ uMean x- snd' :: (Int, b) -> b- snd' = snd- {-# INLINABLE properFraction #-}- truncate = truncate . uMean- {-# INLINE truncate #-}- round = round . uMean- {-# INLINE round #-}- ceiling = ceiling . uMean- {-# INLINE ceiling #-}- floor = floor . uMean- {-# INLINE floor #-}+ properFraction x = (n, d)+ where+ d = liftU (snd' . properFraction) x+ n = fst . properFraction $ uMean x+ snd' :: (Int, b) -> b+ snd' = snd+ {-# INLINEABLE properFraction #-}+ truncate = truncate . uMean+ {-# INLINE truncate #-}+ round = round . uMean+ {-# INLINE round #-}+ ceiling = ceiling . uMean+ {-# INLINE ceiling #-}+ floor = floor . uMean+ {-# INLINE floor #-} instance RealFloat a => RealFloat (Uncert a) where- floatRadix = floatRadix . uMean- {-# INLINE floatRadix #-}- floatDigits = floatDigits . uMean- {-# INLINE floatDigits #-}- floatRange = floatRange . uMean- {-# INLINE floatRange #-}- decodeFloat = decodeFloat . uMean- {-# INLINE decodeFloat #-}- exponent = exponent . uMean- {-# INLINE exponent #-}- isNaN = isNaN . uMean- {-# INLINE isNaN #-}- isInfinite = isInfinite . uMean- {-# INLINE isInfinite #-}- isDenormalized = isDenormalized . uMean- {-# INLINE isDenormalized #-}- isNegativeZero = isNegativeZero . uMean- {-# INLINE isNegativeZero #-}- isIEEE = isIEEE . uMean- {-# INLINE isIEEE #-}- encodeFloat a b = exact (encodeFloat a b)- {-# INLINE encodeFloat #-}- significand = liftU significand- {-# INLINE significand #-}- atan2 = liftU2 atan2- {-# INLINE atan2 #-}-+ floatRadix = floatRadix . uMean+ {-# INLINE floatRadix #-}+ floatDigits = floatDigits . uMean+ {-# INLINE floatDigits #-}+ floatRange = floatRange . uMean+ {-# INLINE floatRange #-}+ decodeFloat = decodeFloat . uMean+ {-# INLINE decodeFloat #-}+ exponent = exponent . uMean+ {-# INLINE exponent #-}+ isNaN = isNaN . uMean+ {-# INLINE isNaN #-}+ isInfinite = isInfinite . uMean+ {-# INLINE isInfinite #-}+ isDenormalized = isDenormalized . uMean+ {-# INLINE isDenormalized #-}+ isNegativeZero = isNegativeZero . uMean+ {-# INLINE isNegativeZero #-}+ isIEEE = isIEEE . uMean+ {-# INLINE isIEEE #-}+ encodeFloat a b = exact (encodeFloat a b)+ {-# INLINE encodeFloat #-}+ significand = liftU significand+ {-# INLINE significand #-}+ atan2 = liftU2 atan2+ {-# INLINE atan2 #-}
@@ -15,28 +15,38 @@ -- -- See the "Numeric.Uncertain.Correlated.Interactive" module for an -- "interactive" and exploratory interface for this module's functionality.---+module Numeric.Uncertain.Correlated (+ -- * 'Corr'+ Corr,+ evalCorr, -module Numeric.Uncertain.Correlated- ( -- * 'Corr'- Corr, evalCorr- -- * Uncertain and Correlated Values- , CVar- -- ** Sampling- , sampleUncert, sampleExact, constC- -- ** Resolving- , resolveUncert- -- * Applying arbitrary functions- , liftC, liftC2, liftC3, liftC4, liftC5, liftCF- )- where+ -- * Uncertain and Correlated Values+ CVar, -import Control.Monad.Free-import Control.Monad.Trans.State-import Numeric.Uncertain-import Numeric.Uncertain.Correlated.Internal-import qualified Data.IntMap.Strict as M+ -- ** Sampling+ sampleUncert,+ sampleExact,+ constC, + -- ** Resolving+ resolveUncert,++ -- * Applying arbitrary functions+ liftC,+ liftC2,+ liftC3,+ liftC4,+ liftC5,+ liftCF,+)+where++import Control.Monad.Free+import Control.Monad.Trans.State+import qualified Data.IntMap.Strict as M+import Numeric.Uncertain+import Numeric.Uncertain.Correlated.Internal+ -- | Evaluates the value described by a 'Corr' monad, taking into account -- inter-correlations between samples. --@@ -46,7 +56,7 @@ -- allowed to ever use 'evalCorr' to evaluate a 'CVar'. evalCorr :: Fractional a => (forall s. Corr s a b) -> b evalCorr c = evalState (corrToState c) (0, M.empty)-{-# INLINABLE evalCorr #-}+{-# INLINEABLE evalCorr #-} -- | Generate a sample in 'Corr' from an 'Uncert' value, independently from -- all other samples.@@ -72,7 +82,6 @@ -- -- Note that you can exactly sample an @a@ within a @'Corr' s a@, meaning -- that all other "sampled" values are also @a@s.--- sampleExact :: a -> Corr s a (CVar s a) sampleExact = return . constC {-# INLINE sampleExact #-}@@ -87,4 +96,3 @@ resolveUncert :: CVar s a -> Corr s a (Uncert a) resolveUncert v = liftF $ Rei v id {-# INLINE resolveUncert #-}-
@@ -48,29 +48,39 @@ -- -- Be aware that this module is not robustly tested in heavily concurrent -- situations/applications.----module Numeric.Uncertain.Correlated.Interactive- ( -- * Uncertain and Correlated Values- CVar, CVarIO- -- ** Sampling- , sampleUncert, sampleExact, constC- -- ** Resolving- , resolveUncert- -- * Applying arbitrary functions- , liftC, liftC2, liftC3, liftC4, liftC5, liftCF- )- where+module Numeric.Uncertain.Correlated.Interactive (+ -- * Uncertain and Correlated Values+ CVar,+ CVarIO, -import Control.Monad.ST-import Control.Monad.Trans.State-import Data.IORef-import Data.Tuple-import Numeric.Uncertain-import Numeric.Uncertain.Correlated.Internal-import System.IO.Unsafe (unsafePerformIO)-import qualified Data.IntMap.Strict as M-import qualified Numeric.Uncertain.Correlated as C+ -- ** Sampling+ sampleUncert,+ sampleExact,+ constC, + -- ** Resolving+ resolveUncert,++ -- * Applying arbitrary functions+ liftC,+ liftC2,+ liftC3,+ liftC4,+ liftC5,+ liftCF,+)+where++import Control.Monad.ST+import Control.Monad.Trans.State+import Data.IORef+import qualified Data.IntMap.Strict as M+import Data.Tuple+import Numeric.Uncertain+import qualified Numeric.Uncertain.Correlated as C+import Numeric.Uncertain.Correlated.Internal+import System.IO.Unsafe (unsafePerformIO)+ -- | A 'CVar' specialized to work in an "interactive" context, in /ghci/ or -- 'IO'. type CVarIO = CVar RealWorld Double@@ -81,15 +91,17 @@ globalCorrMap = unsafePerformIO $ newIORef (0, M.empty) runCorrIO :: Corr RealWorld Double a -> IO a-runCorrIO c = atomicModifyIORef' globalCorrMap- (swap . runState (corrToState c))+runCorrIO c =+ atomicModifyIORef'+ globalCorrMap+ (swap . runState (corrToState c)) {-# INLINE runCorrIO #-} -- | Generate a sample in 'IO' from an @'Uncert' 'Double'@ value, -- independently from all other samples. sampleUncert :: Uncert Double -> IO CVarIO sampleUncert u = runCorrIO $ C.sampleUncert u-{-# INLINABLE sampleUncert #-}+{-# INLINEABLE sampleUncert #-} -- | Generate an exact sample in 'IO' with zero uncertainty, -- independently from all other samples.@@ -105,7 +117,7 @@ -- But is provided for completeness alongside 'sampleUncert'. sampleExact :: Double -> IO CVarIO sampleExact d = runCorrIO $ C.sampleExact d-{-# INLINABLE sampleExact #-}+{-# INLINEABLE sampleExact #-} -- | "Resolve" an 'Uncert' from a 'CVarIO' using its potential multiple -- samples and sample sources, taking into account inter-correlations@@ -116,4 +128,4 @@ -- only be used as the "final value" of your computation or exploration. resolveUncert :: CVarIO -> IO (Uncert Double) resolveUncert v = runCorrIO $ C.resolveUncert v-{-# INLINABLE resolveUncert #-}+{-# INLINEABLE resolveUncert #-}
@@ -1,15 +1,15 @@-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE GADTs #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# OPTIONS_HADDOCK hide #-}-{-# OPTIONS_HADDOCK prune #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# OPTIONS_HADDOCK hide #-}+{-# OPTIONS_HADDOCK prune #-} -- | -- Module : Numeric.Uncertain.Correlated.Internal@@ -23,26 +23,31 @@ -- Internal utility functions for functionality shared by -- "Numeric.Uncertain.Correlated" and -- "Numeric.Uncertain.Correlated.Interactive".-----module Numeric.Uncertain.Correlated.Internal- ( CVar, dephantom- , CorrF(..), Corr- , liftCF- , constC, liftC, liftC2, liftC3, liftC4, liftC5- , corrToState- )- where--import Control.Arrow ((***))-import Control.Monad.Free-import Control.Monad.Trans.State-import Prelude.Compat-import Data.Hople-import Numeric.Uncertain-import Numeric.AD.Mode.Sparse-import qualified Data.IntMap.Strict as M+module Numeric.Uncertain.Correlated.Internal (+ CVar,+ dephantom,+ CorrF (..),+ Corr,+ liftCF,+ constC,+ liftC,+ liftC2,+ liftC3,+ liftC4,+ liftC5,+ corrToState,+)+where +import Control.Arrow ((***))+import Control.Monad.Free+import Control.Monad.Trans.State+import Data.Hople+import qualified Data.IntMap.Strict as M+import Data.Kind+import Numeric.AD.Mode.Sparse+import Numeric.Uncertain+import Prelude.Compat -- | Represents a single sample (or a value calculated from samples) within -- the 'Corr' monad. These can be created with 'sampleUncert',@@ -63,36 +68,40 @@ -- s a@, meaning that the all samples within that 'Corr' are of the same -- type. data CVar s a where- CK :: a -> CVar s a- CV :: M.Key -> CVar s a- CF :: Functor f- => (forall t. f (AD t (Sparse a)) -> AD t (Sparse a))- -> f (CVar s a)- -> CVar s a+ CK :: a -> CVar s a+ CV :: M.Key -> CVar s a+ CF ::+ Functor f =>+ (forall t. f (AD t (Sparse a)) -> AD t (Sparse a)) ->+ f (CVar s a) ->+ CVar s a -- | Unsafe function to bypass the universal qualification guard for -- returning 'CVar's from 'Corr's. dephantom :: CVar s a -> CVar t a-dephantom = \case CK x -> CK x- CV k -> CV k- CF f xs -> CF f (dephantom <$> xs)+dephantom = \case+ CK x -> CK x+ CV k -> CV k+ CF f xs -> CF f (dephantom <$> xs) -data CorrF :: * -> * -> * -> * where- Gen :: Uncert a -> (CVar s a -> b) -> CorrF s a b- Fun :: Functor f- => (forall t. f (AD t (Sparse a)) -> AD t (Sparse a))- -> f (CVar s a)- -> (CVar s a -> b)- -> CorrF s a b- Rei :: CVar s a- -> (Uncert a -> b)- -> CorrF s a b+data CorrF :: Type -> Type -> Type -> Type where+ Gen :: Uncert a -> (CVar s a -> b) -> CorrF s a b+ Fun ::+ Functor f =>+ (forall t. f (AD t (Sparse a)) -> AD t (Sparse a)) ->+ f (CVar s a) ->+ (CVar s a -> b) ->+ CorrF s a b+ Rei ::+ CVar s a ->+ (Uncert a -> b) ->+ CorrF s a b instance Functor (CorrF s a) where- fmap f = \case Gen u next -> Gen u (f . next)- Fun g us next -> Fun g us (f . next)- Rei v next -> Rei v (f . next)-+ fmap f = \case+ Gen u next -> Gen u (f . next)+ Fun g us next -> Fun g us (f . next)+ Rei v next -> Rei v (f . next) -- | The 'Corr' monad allows us to keep track of correlated and -- non-independent samples. It fixes a basic "failure" of the 'Uncert'@@ -150,42 +159,42 @@ -- 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.-newtype Corr s a b = Corr { corrFree :: Free (CorrF s a) b- }- deriving (Functor, Applicative, Monad)+newtype Corr s a b = Corr+ { corrFree :: Free (CorrF s a) b+ }+ deriving (Functor, Applicative, Monad) deriving instance MonadFree (CorrF s a) (Corr s a) -corrToState- :: (Monad m, Fractional a)- => Corr s a b- -> StateT (M.Key, M.IntMap (Uncert a)) m b+corrToState ::+ (Monad m, Fractional a) =>+ Corr s a b ->+ StateT (M.Key, M.IntMap (Uncert a)) m b corrToState = iterM go . corrFree where go = \case- Gen u next -> do- i <- gets fst- modify $ succ *** M.insert i u- next (CV i)- Fun f us next ->- next $ CF f us- Rei v next -> do- u <- gets (getCVar v . snd)- next u- getCVar- :: forall a s. Fractional a- => CVar s a- -> M.IntMap (Uncert a)- -> Uncert a+ Gen u next -> do+ i <- gets fst+ modify $ succ *** M.insert i u+ next (CV i)+ Fun f us next ->+ next $ CF f us+ Rei v next -> do+ u <- gets (getCVar v . snd)+ next u+ getCVar ::+ forall a s.+ Fractional a =>+ CVar s a ->+ M.IntMap (Uncert a) ->+ Uncert a getCVar cv = liftUF (cVarToF cv) where- cVarToF- :: CVar s a- -> (forall t. M.IntMap (AD t (Sparse a)) -> AD t (Sparse a))- cVarToF (CK x) _ = auto x- cVarToF (CV k) us = us M.! k- cVarToF (CF f cs) us = f (flip cVarToF us <$> cs)-{-# INLINABLE corrToState #-}+ cVarToF :: CVar s a -> M.IntMap (AD t (Sparse a)) -> AD t (Sparse a)+ cVarToF (CK x) _ = auto x+ cVarToF (CV k) us = us M.! k+ cVarToF (CF f cs) us = f ((`cVarToF` us) <$> cs)+{-# INLINEABLE corrToState #-} -- | Lifts a multivariate numeric function on a container (given as an @f -- a -> a@) to work on a container of 'CVar's. Correctly propagates the@@ -206,13 +215,14 @@ -- 'resolveUncert' $ liftCF (\\[a,b,c] -> (a+c) * logBase c (b**a)) x y z -- 1200 +/- 200 -- @----liftCF- :: 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-liftCF f cs = CF f cs+liftCF ::+ Functor f =>+ -- | Function on container of values to lift+ (forall t. f (AD t (Sparse a)) -> AD t (Sparse a)) ->+ -- | Container of 'CVar' samples to apply the function to+ f (CVar s a) ->+ CVar s a+liftCF = CF {-# INLINE liftCF #-} -- | Creates a 'CVar' representing a completely independent sample from all@@ -237,13 +247,14 @@ -- 'resolveUncert' $ liftC (\\z -> log z ^ 2) (x + y) -- 11.2 +/- 0.2 -- @----liftC- :: (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+liftC ::+ -- | Function on values to lift+ (forall t. AD t (Sparse a) -> AD t (Sparse a)) ->+ -- | 'CVar' sample to apply the function to+ CVar s a ->+ CVar s a liftC f = curryH1 $ liftCF (uncurryH1 f)-{-# INLINABLE liftC #-}+{-# INLINEABLE liftC #-} -- | Lifts a two-argument (curried) function over the samples represented -- by two 'CVar's. Correctly propagates the uncertainty according to the@@ -263,105 +274,113 @@ -- 'resolveUncert' $ liftC2 (\\a b -> log (a + b) ^ 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+liftC2 ::+ (forall t. AD t (Sparse a) -> AD t (Sparse a) -> AD t (Sparse a)) ->+ CVar s a ->+ CVar s a ->+ CVar s a liftC2 f = curryH2 $ liftCF (uncurryH2 f)-{-# INLINABLE liftC2 #-}+{-# INLINEABLE liftC2 #-} -- | Lifts a three-argument (curried) function over the samples represented -- by three 'CVar's. See 'liftC2' and 'liftCF' for more details.-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+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 liftC3 f = curryH3 $ liftCF (uncurryH3 f)-{-# INLINABLE liftC3 #-}+{-# INLINEABLE liftC3 #-} -- | Lifts a four-argument (curried) function over the samples represented -- by four 'CVar's. 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+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 liftC4 f = curryH4 $ liftCF (uncurryH4 f)-{-# INLINABLE liftC4 #-}+{-# INLINEABLE liftC4 #-} -- | Lifts a five-argument (curried) function over the samples represented -- by five 'CVar's. 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+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 liftC5 f = curryH5 $ liftCF (uncurryH5 f)-{-# INLINABLE liftC5 #-}+{-# INLINEABLE liftC5 #-} instance Fractional a => Num (CVar s a) where- (+) = liftC2 (+)- {-# INLINE (+) #-}- (*) = liftC2 (*)- {-# INLINE (*) #-}- (-) = liftC2 (-)- {-# INLINE (-) #-}- negate = liftC negate- {-# INLINE negate #-}- abs = liftC abs- {-# INLINE abs #-}- signum = liftC signum- {-# INLINE signum #-}- fromInteger = constC . fromInteger- {-# INLINE fromInteger #-}+ (+) = liftC2 (+)+ {-# INLINE (+) #-}+ (*) = liftC2 (*)+ {-# INLINE (*) #-}+ (-) = liftC2 (-)+ {-# INLINE (-) #-}+ negate = liftC negate+ {-# INLINE negate #-}+ abs = liftC abs+ {-# INLINE abs #-}+ signum = liftC signum+ {-# INLINE signum #-}+ fromInteger = constC . fromInteger+ {-# INLINE fromInteger #-} instance Fractional a => Fractional (CVar s a) where- recip = liftC recip- {-# INLINE recip #-}- (/) = liftC2 (/)- {-# INLINE (/) #-}- fromRational = constC . fromRational- {-# INLINE fromRational #-}+ recip = liftC recip+ {-# INLINE recip #-}+ (/) = liftC2 (/)+ {-# INLINE (/) #-}+ fromRational = constC . fromRational+ {-# INLINE fromRational #-} instance Floating a => Floating (CVar s a) where- pi = constC pi- {-# INLINE pi #-}- exp = liftC exp- {-# INLINE exp #-}- log = liftC log- {-# INLINE log #-}- sqrt = liftC sqrt- {-# INLINE sqrt #-}- (**) = liftC2 (**)- {-# INLINE (**) #-}- logBase = liftC2 logBase- {-# INLINE logBase #-}- sin = liftC sin- {-# INLINE sin #-}- cos = liftC cos- {-# INLINE cos #-}- asin = liftC asin- {-# INLINE asin #-}- acos = liftC acos- {-# INLINE acos #-}- atan = liftC atan- {-# INLINE atan #-}- sinh = liftC sinh- {-# INLINE sinh #-}- cosh = liftC cosh- {-# INLINE cosh #-}- asinh = liftC asinh- {-# INLINE asinh #-}- acosh = liftC acosh- {-# INLINE acosh #-}- atanh = liftC atanh- {-# INLINE atanh #-}+ pi = constC pi+ {-# INLINE pi #-}+ exp = liftC exp+ {-# INLINE exp #-}+ log = liftC log+ {-# INLINE log #-}+ sqrt = liftC sqrt+ {-# INLINE sqrt #-}+ (**) = liftC2 (**)+ {-# INLINE (**) #-}+ logBase = liftC2 logBase+ {-# INLINE logBase #-}+ sin = liftC sin+ {-# INLINE sin #-}+ cos = liftC cos+ {-# INLINE cos #-}+ asin = liftC asin+ {-# INLINE asin #-}+ acos = liftC acos+ {-# INLINE acos #-}+ atan = liftC atan+ {-# INLINE atan #-}+ sinh = liftC sinh+ {-# INLINE sinh #-}+ cosh = liftC cosh+ {-# INLINE cosh #-}+ asinh = liftC asinh+ {-# INLINE asinh #-}+ acosh = liftC acosh+ {-# INLINE acosh #-}+ atanh = liftC atanh+ {-# INLINE atanh #-}
src/Numeric/Uncertain/MonteCarlo.hs view
@@ -1,7 +1,6 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE ViewPatterns #-} -- | -- Module : Numeric.Uncertain.MonteCarlo@@ -14,6 +13,8 @@ -- -- Provides an interface for computing and propagating uncertainty by using -- <https://en.wikipedia.org/wiki/Monte_Carlo_method Monte Carlo simulations>.+-- These may be more accurate than the normal propagators if the third-order+-- taylor series expansion terms are non-negligible. -- -- Basically simulates sampling from the distribution represented by the given -- 'Uncert's, applying the function of interest, and aggregating the mean@@ -54,44 +55,49 @@ -- ghci> MC.liftU2 (\\a b -> pi + 3 * logBase a b) x y g -- 51 +/- 5 -- @---+module Numeric.Uncertain.MonteCarlo (+ -- * Sampling from an 'Uncert'+ sampleUncert, -module Numeric.Uncertain.MonteCarlo- ( -- * Sampling from an 'Uncert'- sampleUncert- -- * Lifting functions via Monte Carlo simulation- -- ** Fixed iterations- , liftU, liftU2, liftU3, liftU4, liftU5, liftUF- -- ** Variable iterations- , liftU', liftU2', liftU3', liftU4', liftU5', liftUF'- )- where+ -- * Lifting functions via Monte Carlo simulation + -- ** Fixed iterations+ liftU,+ liftU2,+ liftU3,+ liftU4,+ liftU5,+ liftUF,++ -- ** Variable iterations+ liftU',+ liftU2',+ liftU3',+ liftU4',+ liftU5',+ liftUF',+)+where+ import Control.Monad import Control.Monad.Primitive import Data.Hople-import Numeric.Uncertain (Uncert, fromSamples, uMeanStd)+import Numeric.Uncertain (Uncert, fromSamples, uMeanStd) import Prelude.Compat import System.Random.MWC import System.Random.MWC.Distributions - -- | Sample a random 'Double' from the distribution specified by an -- @'Uncert' 'Double'@. @x '+/-' dx@ is treated as a random variable whose -- probability density is the normal distribution with mean @x@ and -- standard deviation @dx@.----sampleUncert-#if __GLASGOW_HASKELL__ < 710- :: (PrimMonad m, Functor m)-#else- :: PrimMonad m-#endif- => Uncert Double- -> Gen (PrimState m)- -> m Double-sampleUncert (uMeanStd->(x, dx)) g = normal x dx g-{-# INLINABLE sampleUncert #-}+sampleUncert ::+ PrimMonad m =>+ Uncert Double ->+ Gen (PrimState m) ->+ m Double+sampleUncert (uMeanStd -> (x, dx)) = normal x dx+{-# INLINEABLE sampleUncert #-} -- | Lifts a numeric function over an 'Uncert' using a Monte Carlo -- simulation with 1000 samples.@@ -101,17 +107,12 @@ -- ghci> MC.liftU (\\x -> log x ^ 2) (12.2 +/- 0.5) g -- 6.3 +/- 0.2 -- @----liftU-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Functor m)-#endif- => (Double -> Double)- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU ::+ PrimMonad m =>+ (Double -> Double) ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU = liftU' 1000 {-# INLINE liftU #-} @@ -124,17 +125,12 @@ -- ghci> M.liftUF (\\[x,y,z] -> x*y+z) [12.2 +/- 0.5, 56 +/- 2, 0.12 +/- 0.08] g -- 680 +/- 40 -- @----liftUF-#if __GLASGOW_HASKELL__ >= 710- :: (Traversable f, PrimMonad m)-#else- :: (Traversable f, PrimMonad m, Applicative m)-#endif- => (f Double -> Double)- -> f (Uncert Double)- -> Gen (PrimState m)- -> m (Uncert Double)+liftUF ::+ (Traversable f, PrimMonad m) =>+ (f Double -> Double) ->+ f (Uncert Double) ->+ Gen (PrimState m) ->+ m (Uncert Double) liftUF = liftUF' 1000 {-# INLINE liftUF #-} @@ -146,181 +142,140 @@ -- ghci> MC.liftU2 (\\x y -> x**y) (13.5 +/- 0.1) (1.64 +/- 0.08) -- 70 +/- 20 -- @----liftU2-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => (Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU2 ::+ PrimMonad m =>+ (Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU2 = liftU2' 1000 {-# INLINE liftU2 #-} -- | Lifts a three-argument (curried) function over three 'Uncert's. See -- 'liftU2' and 'liftUF' for more details.-liftU3-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => (Double -> Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU3 ::+ PrimMonad m =>+ (Double -> Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU3 = liftU3' 1000 {-# INLINE liftU3 #-} -- | Lifts a four-argument (curried) function over four 'Uncert's. See -- 'liftU2' and 'liftUF' for more details.-liftU4-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => (Double -> Double -> Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU4 ::+ (PrimMonad m, Applicative m) =>+ (Double -> Double -> Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU4 = liftU4' 1000 {-# INLINE liftU4 #-} -- | Lifts a five-argument (curried) function over five 'Uncert's. See -- 'liftU2' and 'liftUF' for more details.-liftU5-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => (Double -> Double -> Double -> Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU5 ::+ PrimMonad m =>+ (Double -> Double -> Double -> Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU5 = liftU5' 1000 {-# INLINE liftU5 #-} -- | Like 'liftU', but allows you to specify the number of samples to run -- the Monte Carlo simulation with.-liftU'-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Functor m)-#endif- => Int- -> (Double -> Double)- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU' ::+ PrimMonad m =>+ Int ->+ (Double -> Double) ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU' n f u g = fromSamples <$> replicateM n samp where samp = f <$> sampleUncert u g-{-# INLINABLE liftU' #-}+{-# INLINEABLE liftU' #-} -- | Like 'liftUF', but allows you to specify the number of samples to run -- the Monte Carlo simulation with.-liftUF'-#if __GLASGOW_HASKELL__ >= 710- :: (Traversable f, PrimMonad m)-#else- :: (Traversable f, PrimMonad m, Applicative m)-#endif- => Int- -> (f Double -> Double)- -> f (Uncert Double)- -> Gen (PrimState m)- -> m (Uncert Double)+liftUF' ::+ (Traversable f, PrimMonad m) =>+ Int ->+ (f Double -> Double) ->+ f (Uncert Double) ->+ Gen (PrimState m) ->+ m (Uncert Double) liftUF' n f us g = fromSamples <$> replicateM n samp where- samp = f <$> traverse (flip sampleUncert g) us-{-# INLINABLE liftUF' #-}+ samp = f <$> traverse (`sampleUncert` g) us+{-# INLINEABLE liftUF' #-} -- | Like 'liftU2', but allows you to specify the number of samples to run -- the Monte Carlo simulation with.-liftU2'-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => Int- -> (Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU2' ::+ PrimMonad m =>+ Int ->+ (Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU2' n f x y = liftUF' n (uncurryH2 f) (H2 x y)-{-# INLINABLE liftU2' #-}+{-# INLINEABLE liftU2' #-} -- | Like 'liftU3', but allows you to specify the number of samples to run -- the Monte Carlo simulation with.-liftU3'-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => Int- -> (Double -> Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU3' ::+ PrimMonad m =>+ Int ->+ (Double -> Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU3' n f x y z = liftUF' n (uncurryH3 f) (H3 x y z)-{-# INLINABLE liftU3' #-}+{-# INLINEABLE liftU3' #-} -- | Like 'liftU4', but allows you to specify the number of samples to run -- the Monte Carlo simulation with.-liftU4'-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => Int- -> (Double -> Double -> Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU4' ::+ PrimMonad m =>+ Int ->+ (Double -> Double -> Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU4' n f x y z a = liftUF' n (uncurryH4 f) (H4 x y z a)-{-# INLINABLE liftU4' #-}+{-# INLINEABLE liftU4' #-} -- | Like 'liftU5', but allows you to specify the number of samples to run -- the Monte Carlo simulation with.-liftU5'-#if __GLASGOW_HASKELL__ >= 710- :: PrimMonad m-#else- :: (PrimMonad m, Applicative m)-#endif- => Int- -> (Double -> Double -> Double -> Double -> Double -> Double)- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Uncert Double- -> Gen (PrimState m)- -> m (Uncert Double)+liftU5' ::+ PrimMonad m =>+ Int ->+ (Double -> Double -> Double -> Double -> Double -> Double) ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Uncert Double ->+ Gen (PrimState m) ->+ m (Uncert Double) liftU5' n f x y z a b = liftUF' n (uncurryH5 f) (H5 x y z a b) {-# INLINEABLE liftU5' #-}
uncertain.cabal view
@@ -1,45 +1,58 @@--- Initial uncertain.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/+cabal-version: 1.12 -name: uncertain-version: 0.3.1.0-synopsis: Manipulating numbers with inherent experimental/measurement uncertainty-description: See <https://github.com/mstksg/uncertain/blob/master/README.md README.md>.- .- Documentation maintained at <https://mstksg.github.io/uncertain>-homepage: https://github.com/mstksg/uncertain-bug-reports: https://github.com/mstksg/uncertain/issues-license: BSD3-license-file: LICENSE-author: Justin Le-maintainer: justin@jle.im-copyright: (c) Justin Le 2016-category: Math-build-type: Simple-extra-source-files: README.md- CHANGELOG.md-cabal-version: >=1.10+-- This file has been generated from package.yaml by hpack version 0.36.0.+--+-- see: https://github.com/sol/hpack +name: uncertain+version: 0.4.0.0+synopsis:+ Manipulating numbers with inherent experimental/measurement uncertainty++description:+ Provides tools to manipulate numbers with inherent experimental/measurement+ uncertainty, and propagates them through functions based on principles from+ statistics.++category: Math+homepage: https://github.com/mstksg/uncertain#readme+bug-reports: https://github.com/mstksg/uncertain/issues+author: Justin Le+maintainer: justin@jle.im+copyright: (c) Justin Le 2024+license: BSD3+license-file: LICENSE+build-type: Simple+tested-with: GHC >=8.10+extra-source-files:+ CHANGELOG.md+ README.md+ source-repository head- type: git- location: git://github.com/mstksg/uncertain.git+ type: git+ location: https://github.com/mstksg/uncertain library- exposed-modules: Numeric.Uncertain- Numeric.Uncertain.Correlated- Numeric.Uncertain.Correlated.Interactive- Numeric.Uncertain.MonteCarlo- other-modules: Data.Hople- Numeric.Uncertain.Correlated.Internal- -- other-extensions: - build-depends: base >= 4.6 && < 5- , ad >= 4- , containers >= 0.5- , free >= 4- , mwc-random >= 0.10- , primitive >= 0.1- , transformers >= 0.2- , base-compat- hs-source-dirs: src- default-language: Haskell2010- ghc-options: -Wall+ exposed-modules:+ Numeric.Uncertain+ Numeric.Uncertain.Correlated+ Numeric.Uncertain.Correlated.Interactive+ Numeric.Uncertain.MonteCarlo++ other-modules:+ Data.Hople+ Numeric.Uncertain.Correlated.Internal++ hs-source-dirs: src+ ghc-options: -Wall+ build-depends:+ ad >=4+ , base >=4.6 && <5+ , base-compat+ , containers >=0.5+ , free >=4+ , mwc-random >=0.10+ , primitive >=0.1+ , transformers >=0.2++ default-language: Haskell2010