{-# OPTIONS_HADDOCK show-extensions #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-| Module : Data.Utils.Analytic Description : "analytic" values Copyright : (c) Lars Brünjes, 2016 License : MIT Maintainer : brunjlar@gmail.com Stability : experimental Portability : portable This module defines the numeric type 'Analytic', which has "built in differentiation". -} module Data.Utils.Analytic ( Analytic , fromDouble , fromAnalytic , gradient ) where import qualified Numeric.AD.Rank1.Kahn as K import qualified Numeric.AD.Internal.Kahn as K -- | The numeric type 'Analytic' is a wrapper around Edward Kmett's @'K.Kahn' Double@ type. -- Using functions from Analytics to Analytics, we automatically get numerically exact gradients. -- An number of type 'Analytic' is conceptionally a 'Double' together with an infinitesimal component. -- newtype Analytic = Analytic { toKahn :: K.Kahn Double } deriving (Show, Num, Eq, Floating, Fractional, Ord, Real, RealFloat, RealFrac) -- | Converts a 'Double' to an 'Analytic' without infinitesimal component. -- fromDouble :: Double -> Analytic fromDouble = Analytic . K.auto -- | Tries to convert an 'Analytic' to a 'Double'. -- This conversion will work if the 'Analytic' has no infinitesimal component. -- fromAnalytic :: Analytic -> Maybe Double fromAnalytic x = case toKahn x of K.Kahn (K.Lift y) -> Just y _ -> Nothing -- | Computes the gradient of an analytic function and combines it with the argument. -- -- >>> gradient (\_ d -> d) (\[x, y] -> x * x + 3 * y + 7) [2, 1] -- (14.0,[4.0,3.0]) -- gradient :: Traversable t => (Double -> Double -> a) -- ^ how to combine argument and gradient -> (t Analytic -> Analytic) -- ^ analytic function -> t Double -- ^ function argument -> (Double, t a) -- ^ function value and combination of argument and gradient gradient c f = K.gradWith' c f' where f' = toKahn . f . fmap Analytic