ad 0.21 → 0.22
raw patch · 6 files changed
+150/−94 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Numeric.AD.Internal.Composition: O :: f (AD g a) -> :. f g a
- Numeric.AD.Internal.Composition: compose :: AD f (AD g a) -> AD (f :. g) a
- Numeric.AD.Internal.Composition: decompose :: AD (f :. g) a -> AD f (AD g a)
- Numeric.AD.Internal.Composition: instance (Mode f, Mode g) => Lifted (f :. g)
- Numeric.AD.Internal.Composition: instance (Mode f, Mode g) => Mode (f :. g)
- Numeric.AD.Internal.Composition: instance (Primal f, Mode g, Primal g) => Primal (f :. g)
- Numeric.AD.Internal.Composition: newtype (:.) f g a
- Numeric.AD.Internal.Composition: runO :: :. f g a -> f (AD g a)
- Numeric.AD.Internal.Composition: type On f g = g :. f
+ Numeric.AD: hessian :: (Traversable f, Num a) => (forall s. (Mode s) => f (AD s a) -> AD s a) -> f a -> f (f a)
+ Numeric.AD: hessianTensor :: (Traversable f, Traversable g, Num a) => (forall s. (Mode s) => f (AD s a) -> g (AD s a)) -> f a -> g (f (f a))
+ Numeric.AD.Internal.Composition: ComposeFunctor :: f (g a) -> ComposeFunctor f g a
+ Numeric.AD.Internal.Composition: ComposeMode :: f (AD g a) -> ComposeMode f g a
+ Numeric.AD.Internal.Composition: composeMode :: AD f (AD g a) -> AD (ComposeMode f g) a
+ Numeric.AD.Internal.Composition: decomposeFunctor :: ComposeFunctor f g a -> f (g a)
+ Numeric.AD.Internal.Composition: decomposeMode :: AD (ComposeMode f g) a -> AD f (AD g a)
+ Numeric.AD.Internal.Composition: instance (Foldable f, Foldable g) => Foldable (ComposeFunctor f g)
+ Numeric.AD.Internal.Composition: instance (Functor f, Functor g) => Functor (ComposeFunctor f g)
+ Numeric.AD.Internal.Composition: instance (Mode f, Mode g) => Lifted (ComposeMode f g)
+ Numeric.AD.Internal.Composition: instance (Mode f, Mode g) => Mode (ComposeMode f g)
+ Numeric.AD.Internal.Composition: instance (Primal f, Mode g, Primal g) => Primal (ComposeMode f g)
+ Numeric.AD.Internal.Composition: instance (Traversable f, Traversable g) => Traversable (ComposeFunctor f g)
+ Numeric.AD.Internal.Composition: newtype ComposeFunctor f g a
+ Numeric.AD.Internal.Composition: newtype ComposeMode f g a
+ Numeric.AD.Internal.Composition: runComposeMode :: ComposeMode f g a -> f (AD g a)
+ Numeric.AD.Reverse: hessian :: (Traversable f, Num a) => (forall s. (Mode s) => f (AD s a) -> AD s a) -> f a -> f (f a)
+ Numeric.AD.Reverse: hessianM :: (Traversable f, Monad m, Num a) => (forall s. (Mode s) => f (AD s a) -> m (AD s a)) -> f a -> m (f (f a))
+ Numeric.AD.Reverse: hessianTensor :: (Traversable f, Functor g, Num a) => (forall s. (Mode s) => f (AD s a) -> g (AD s a)) -> f a -> g (f (f a))
Files
- Numeric/AD.hs +29/−9
- Numeric/AD/Forward.hs +2/−2
- Numeric/AD/Internal/Composition.hs +93/−80
- Numeric/AD/Newton.hs +2/−2
- Numeric/AD/Reverse.hs +23/−0
- ad.cabal +1/−1
Numeric/AD.hs view
@@ -16,12 +16,16 @@ module Numeric.AD ( -- * Gradients (Reverse Mode)- grad, grad'- , gradWith, gradWith'+ grad+ , grad'+ , gradWith+ , gradWith' -- * Jacobians (Mixed Mode)- , jacobian, jacobian'- , jacobianWith, jacobianWith'+ , jacobian+ , jacobian'+ , jacobianWith+ , jacobianWith' -- * Jacobians (Reverse Mode) , gradF@@ -30,9 +34,16 @@ , gradWithF' -- * Jacobians (Forward Mode)- , jacobianT, jacobianWithT+ , jacobianT+ , jacobianWithT - -- * Hessians (Forward-On-Reverse Mode)+ -- * Hessian (Forward-On-Reverse)+ , hessian++ -- * Hessian Tensors (Forward-On-Mixed)+ , hessianTensor++ -- * Hessian Vector Products (Forward-On-Reverse) , hessianProduct , hessianProduct' @@ -87,7 +98,7 @@ import Numeric.AD.Forward (diff, diff', diffF, diffF', du, du', duF, duF', diffM, diffM', jacobianT, jacobianWithT) import Numeric.AD.Tower (diffsF, diffs0F , diffs, diffs0, taylor, taylor0, maclaurin, maclaurin0) import Numeric.AD.Reverse (grad, grad', gradWith, gradWith', gradM, gradM', gradWithM, gradWithM', gradF, gradF', gradWithF, gradWithF')-import Numeric.AD.Internal.Composition (compose, decompose)+import Numeric.AD.Internal.Composition import qualified Numeric.AD.Forward as Forward import qualified Numeric.AD.Reverse as Reverse@@ -147,7 +158,7 @@ -- -- Or in other words, we take the directional derivative of the gradient. hessianProduct :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> f a-hessianProduct f = duF (grad (decompose . f . fmap compose))+hessianProduct f = duF (grad (decomposeMode . f . fmap composeMode)) -- | @'hessianProduct'' f wv@ computes both the gradient of a non-scalar-to-scalar @f@ at @w = 'fst' <$> wv@ and the product of the hessian @H@ at @w@ with a vector @v = snd <$> wv@ using \"Pearlmutter\'s method\". The outputs are returned wrapped in the same functor. --@@ -156,5 +167,14 @@ -- Or in other words, we take the directional derivative of the gradient. -- hessianProduct' :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> f (a, a)-hessianProduct' f = duF' (grad (decompose . f . fmap compose))+hessianProduct' f = duF' (grad (decomposeMode . f . fmap composeMode)) +-- hessianProductWith' :: (Traversable f, Num a) => (a -> a -> a -> a -> b) -> (forall s. Mode s. f (AD s a) -> AD s a) -> f (a, a) -> f b++-- | Compute the hessian via the jacobian of the gradient. gradient is computed in reverse mode and then the jacobian is computed in forward mode.+hessian :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f (f a)+hessian f = Forward.jacobian (grad (decomposeMode . f . fmap composeMode))++-- | Compute the order 3 Hessian tensor on a non-scalar-to-non-scalar function via the forward-mode Jacobian of the mixed-mode Jacobian of the function.+hessianTensor :: (Traversable f, Traversable g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f (f a))+hessianTensor f = decomposeFunctor . Forward.jacobian (ComposeFunctor . jacobian (fmap decomposeMode . f . fmap composeMode))
Numeric/AD/Forward.hs view
@@ -166,8 +166,8 @@ -- | Compute the product of a vector with the Hessian using forward-on-forward-mode AD. hessianProduct :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> f a-hessianProduct f = duF (grad (decompose . f . fmap compose))+hessianProduct f = duF (grad (decomposeMode . f . fmap composeMode)) -- | Compute the gradient and hessian product using forward-on-forward-mode AD. hessianProduct' :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> f (a, a)-hessianProduct' f = duF' (grad (decompose . f . fmap compose))+hessianProduct' f = duF' (grad (decomposeMode . f . fmap composeMode))
Numeric/AD/Internal/Composition.hs view
@@ -12,98 +12,111 @@ ----------------------------------------------------------------------------- module Numeric.AD.Internal.Composition- ( (:.)(..)- , On- , compose- , decompose+ ( ComposeFunctor(..)+ , ComposeMode(..)+ , composeMode+ , decomposeMode ) where +import Data.Traversable+import Control.Applicative+import Data.Foldable import Numeric.AD.Classes import Numeric.AD.Internal -newtype (f :. g) a = O { runO :: f (AD g a) }+-- * Functor composition +newtype ComposeFunctor f g a = ComposeFunctor { decomposeFunctor :: f (g a) } -type On f g = g :. f+instance (Functor f, Functor g) => Functor (ComposeFunctor f g) where+ fmap f (ComposeFunctor a) = ComposeFunctor (fmap (fmap f) a)+ +instance (Foldable f, Foldable g) => Foldable (ComposeFunctor f g) where+ foldMap f (ComposeFunctor a) = foldMap (foldMap f) a+ +instance (Traversable f, Traversable g) => Traversable (ComposeFunctor f g) where+ traverse f (ComposeFunctor a) = ComposeFunctor <$> traverse (traverse f) a -compose :: AD f (AD g a) -> AD (f :. g) a-compose (AD a) = AD (O a)+newtype ComposeMode f g a = ComposeMode { runComposeMode :: f (AD g a) } -decompose :: AD (f :. g) a -> AD f (AD g a)-decompose (AD (O a)) = AD a+composeMode :: AD f (AD g a) -> AD (ComposeMode f g) a+composeMode (AD a) = AD (ComposeMode a) -instance (Primal f, Mode g, Primal g) => Primal (f :. g) where- primal = primal . primal . runO+decomposeMode :: AD (ComposeMode f g) a -> AD f (AD g a)+decomposeMode (AD (ComposeMode a)) = AD a -instance (Mode f, Mode g) => Mode (f :. g) where- lift = O . lift . lift- O a <+> O b = O (a <+> b) - a *^ O b = O (lift a *^ b) - O a ^* b = O (a ^* lift b)- O a ^/ b = O (a ^/ lift b)+instance (Primal f, Mode g, Primal g) => Primal (ComposeMode f g) where+ primal = primal . primal . runComposeMode -instance (Mode f, Mode g) => Lifted (f :. g) where- showsPrec1 n (O a) = showsPrec1 n a- O a ==! O b = a ==! b- compare1 (O a) (O b) = compare1 a b- fromInteger1 = O . lift . fromInteger1- O a +! O b = O (a +! b)- O a -! O b = O (a -! b)- O a *! O b = O (a *! b)- negate1 (O a) = O (negate1 a)- abs1 (O a) = O (abs1 a)- signum1 (O a) = O (signum1 a)- O a /! O b = O (a /! b) - recip1 (O a) = O (recip1 a)- fromRational1 = O . lift . fromRational1- toRational1 (O a) = toRational1 a- pi1 = O pi1- exp1 (O a) = O (exp1 a)- log1 (O a) = O (log1 a) - sqrt1 (O a) = O (sqrt1 a)- O a **! O b = O (a **! b)- logBase1 (O a) (O b) = O (logBase1 a b)- sin1 (O a) = O (sin1 a)- cos1 (O a) = O (cos1 a)- tan1 (O a) = O (tan1 a)- asin1 (O a) = O (asin1 a)- acos1 (O a) = O (acos1 a)- atan1 (O a) = O (atan1 a)- sinh1 (O a) = O (sinh1 a)- cosh1 (O a) = O (cosh1 a)- tanh1 (O a) = O (tanh1 a)- asinh1 (O a) = O (asinh1 a)- acosh1 (O a) = O (acosh1 a)- atanh1 (O a) = O (atanh1 a)- properFraction1 (O a) = (b, O c) where+instance (Mode f, Mode g) => Mode (ComposeMode f g) where+ lift = ComposeMode . lift . lift+ ComposeMode a <+> ComposeMode b = ComposeMode (a <+> b) + a *^ ComposeMode b = ComposeMode (lift a *^ b) + ComposeMode a ^* b = ComposeMode (a ^* lift b)+ ComposeMode a ^/ b = ComposeMode (a ^/ lift b)++instance (Mode f, Mode g) => Lifted (ComposeMode f g) where+ showsPrec1 n (ComposeMode a) = showsPrec1 n a+ ComposeMode a ==! ComposeMode b = a ==! b+ compare1 (ComposeMode a) (ComposeMode b) = compare1 a b+ fromInteger1 = ComposeMode . lift . fromInteger1+ ComposeMode a +! ComposeMode b = ComposeMode (a +! b)+ ComposeMode a -! ComposeMode b = ComposeMode (a -! b)+ ComposeMode a *! ComposeMode b = ComposeMode (a *! b)+ negate1 (ComposeMode a) = ComposeMode (negate1 a)+ abs1 (ComposeMode a) = ComposeMode (abs1 a)+ signum1 (ComposeMode a) = ComposeMode (signum1 a)+ ComposeMode a /! ComposeMode b = ComposeMode (a /! b) + recip1 (ComposeMode a) = ComposeMode (recip1 a)+ fromRational1 = ComposeMode . lift . fromRational1+ toRational1 (ComposeMode a) = toRational1 a+ pi1 = ComposeMode pi1+ exp1 (ComposeMode a) = ComposeMode (exp1 a)+ log1 (ComposeMode a) = ComposeMode (log1 a) + sqrt1 (ComposeMode a) = ComposeMode (sqrt1 a)+ ComposeMode a **! ComposeMode b = ComposeMode (a **! b)+ logBase1 (ComposeMode a) (ComposeMode b) = ComposeMode (logBase1 a b)+ sin1 (ComposeMode a) = ComposeMode (sin1 a)+ cos1 (ComposeMode a) = ComposeMode (cos1 a)+ tan1 (ComposeMode a) = ComposeMode (tan1 a)+ asin1 (ComposeMode a) = ComposeMode (asin1 a)+ acos1 (ComposeMode a) = ComposeMode (acos1 a)+ atan1 (ComposeMode a) = ComposeMode (atan1 a)+ sinh1 (ComposeMode a) = ComposeMode (sinh1 a)+ cosh1 (ComposeMode a) = ComposeMode (cosh1 a)+ tanh1 (ComposeMode a) = ComposeMode (tanh1 a)+ asinh1 (ComposeMode a) = ComposeMode (asinh1 a)+ acosh1 (ComposeMode a) = ComposeMode (acosh1 a)+ atanh1 (ComposeMode a) = ComposeMode (atanh1 a)+ properFraction1 (ComposeMode a) = (b, ComposeMode c) where (b, c) = properFraction1 a- truncate1 (O a) = truncate1 a- round1 (O a) = round1 a- ceiling1 (O a) = ceiling1 a- floor1 (O a) = floor1 a- floatRadix1 (O a) = floatRadix1 a- floatDigits1 (O a) = floatDigits1 a- floatRange1 (O a) = floatRange1 a- decodeFloat1 (O a) = decodeFloat1 a- encodeFloat1 m e = O (encodeFloat1 m e)- exponent1 (O a) = exponent1 a- significand1 (O a) = O (significand1 a)- scaleFloat1 n (O a) = O (scaleFloat1 n a)- isNaN1 (O a) = isNaN1 a - isInfinite1 (O a) = isInfinite1 a- isDenormalized1 (O a) = isDenormalized1 a- isNegativeZero1 (O a) = isNegativeZero1 a- isIEEE1 (O a) = isIEEE1 a- atan21 (O a) (O b) = O (atan21 a b)- succ1 (O a) = O (succ1 a)- pred1 (O a) = O (pred1 a)- toEnum1 n = O (toEnum1 n)- fromEnum1 (O a) = fromEnum1 a- enumFrom1 (O a) = map O $ enumFrom1 a- enumFromThen1 (O a) (O b) = map O $ enumFromThen1 a b- enumFromTo1 (O a) (O b) = map O $ enumFromTo1 a b- enumFromThenTo1 (O a) (O b) (O c) = map O $ enumFromThenTo1 a b c- minBound1 = O minBound1- maxBound1 = O maxBound1+ truncate1 (ComposeMode a) = truncate1 a+ round1 (ComposeMode a) = round1 a+ ceiling1 (ComposeMode a) = ceiling1 a+ floor1 (ComposeMode a) = floor1 a+ floatRadix1 (ComposeMode a) = floatRadix1 a+ floatDigits1 (ComposeMode a) = floatDigits1 a+ floatRange1 (ComposeMode a) = floatRange1 a+ decodeFloat1 (ComposeMode a) = decodeFloat1 a+ encodeFloat1 m e = ComposeMode (encodeFloat1 m e)+ exponent1 (ComposeMode a) = exponent1 a+ significand1 (ComposeMode a) = ComposeMode (significand1 a)+ scaleFloat1 n (ComposeMode a) = ComposeMode (scaleFloat1 n a)+ isNaN1 (ComposeMode a) = isNaN1 a + isInfinite1 (ComposeMode a) = isInfinite1 a+ isDenormalized1 (ComposeMode a) = isDenormalized1 a+ isNegativeZero1 (ComposeMode a) = isNegativeZero1 a+ isIEEE1 (ComposeMode a) = isIEEE1 a+ atan21 (ComposeMode a) (ComposeMode b) = ComposeMode (atan21 a b)+ succ1 (ComposeMode a) = ComposeMode (succ1 a)+ pred1 (ComposeMode a) = ComposeMode (pred1 a)+ toEnum1 n = ComposeMode (toEnum1 n)+ fromEnum1 (ComposeMode a) = fromEnum1 a+ enumFrom1 (ComposeMode a) = map ComposeMode $ enumFrom1 a+ enumFromThen1 (ComposeMode a) (ComposeMode b) = map ComposeMode $ enumFromThen1 a b+ enumFromTo1 (ComposeMode a) (ComposeMode b) = map ComposeMode $ enumFromTo1 a b+ enumFromThenTo1 (ComposeMode a) (ComposeMode b) (ComposeMode c) = map ComposeMode $ enumFromThenTo1 a b c+ minBound1 = ComposeMode minBound1+ maxBound1 = ComposeMode maxBound1 -- deriveNumeric (conT `appT` varT (mkName "f") `appT` varT (mkName "g"))
Numeric/AD/Newton.hs view
@@ -106,11 +106,11 @@ -- -- > take 10 $ extremum cos 1 -- convert to 0 extremum :: Fractional a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]-extremum f = findZero (diff (decompose . f . compose))+extremum f = findZero (diff (decomposeMode . f . composeMode)) {-# INLINE extremum #-} extremumM :: (Monad m, Fractional a) => (forall s. Mode s => AD s a -> m (AD s a)) -> a -> MList m a-extremumM f = findZeroM (diffM (liftM decompose . f . compose))+extremumM f = findZeroM (diffM (liftM decomposeMode . f . composeMode)) {-# INLINE extremumM #-} -- | The 'gradientDescent' function performs a multivariate
Numeric/AD/Reverse.hs view
@@ -29,6 +29,11 @@ , jacobian' , jacobianWith , jacobianWith'+ -- * Hessian+ , hessian+ , hessianM+ , hessianTensor+ -- * Derivatives , diff , diff'@@ -57,6 +62,7 @@ import Numeric.AD.Classes import Numeric.AD.Internal+import Numeric.AD.Internal.Composition import Numeric.AD.Internal.Reverse -- | The 'grad' function calculates the gradient of a non-scalar-to-scalar function with 'Reverse' AD in a single pass.@@ -193,3 +199,20 @@ gradWithM' :: (Traversable f, Monad m, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> m (AD s a)) -> f a -> m (a, f b) gradWithM' g f = unwrapMonad . jacobianWith' g (WrapMonad . f) +-- | Compute the hessian via the jacobian of the gradient. gradient is computed in reverse mode and then the jacobian is computed in reverse mode.+--+-- However, since the @'grad f :: f a -> f a'@ is square this is not as fast as using the forward-mode Jacobian of a reverse mode gradient provided by 'Numeric.AD.hessian' in "Numeric.AD".+hessian :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f (f a)+hessian f = jacobian (grad (decomposeMode . f . fmap composeMode))++-- | Compute the order 3 Hessian tensor on a non-scalar-to-non-scalar function via the forward-mode Jacobian of the mixed-mode Jacobian of the function.+--+-- While this is less efficient than 'Numeric.AD.hessianTensor' from "Numeric.AD" or 'Numeric.AD.Forward.hessianTensor' from "Numeric.AD.Forward", the type signature is more permissive with regards to the output non-scalar, and it may be more efficient if only a few coefficients of the result are consumed.+hessianTensor :: (Traversable f, Functor g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f (f a))+hessianTensor f = decomposeFunctor . jacobian (ComposeFunctor . jacobian (fmap decomposeMode . f . fmap composeMode))++-- | Compute the hessian via the reverse-mode jacobian of the reverse-mode gradient of a non-scalar-to-scalar monadic action. +--+-- While this is less efficient than 'Numeric.AD.hessianTensor' from "Numeric.AD" or 'Numeric.AD.Forward.hessianTensor' from "Numeric.AD.Forward", the type signature is more permissive with regards to the output non-scalar, and it may be more efficient if only a few coefficients of the result are consumed.+hessianM :: (Traversable f, Monad m, Num a) => (forall s. Mode s => f (AD s a) -> m (AD s a)) -> f a -> m (f (f a))+hessianM f = unwrapMonad . hessianTensor (WrapMonad . f)
ad.cabal view
@@ -1,5 +1,5 @@ Name: ad-Version: 0.21+Version: 0.22 License: BSD3 License-File: LICENSE Copyright: Edward Kmett 2010