{-# LANGUAGE Rank2Types #-} {-# LANGUAGE BangPatterns #-} ----------------------------------------------------------------------------- -- | -- Copyright : (c) Edward Kmett 2010-2021 -- License : BSD3 -- Maintainer : ekmett@gmail.com -- Stability : experimental -- Portability : GHC only -- -- Higher order derivatives via a \"dual number tower\". -- ----------------------------------------------------------------------------- module Numeric.AD.Rank1.Tower.Double ( TowerDouble , auto -- * Taylor Series , taylor , taylor0 -- * Maclaurin Series , maclaurin , maclaurin0 -- * Derivatives , diff -- first derivative of (a -> a) , diff' -- answer and first derivative of (a -> a) , diffs -- answer and all derivatives of (a -> a) , diffs0 -- zero padded derivatives of (a -> a) , diffsF -- answer and all derivatives of (a -> f a) , diffs0F -- zero padded derivatives of (a -> f a) -- * Directional Derivatives , du -- directional derivative of (f a -> a) , du' -- answer and directional derivative of (f a -> a) , dus -- answer and all directional derivatives of (f a -> a) , dus0 -- answer and all zero padded directional derivatives of (f a -> a) , duF -- directional derivative of (f a -> g a) , duF' -- answer and directional derivative of (f a -> g a) , dusF -- answer and all directional derivatives of (f a -> g a) , dus0F -- answer and all zero padded directional derivatives of (f a -> g a) ) where import Numeric.AD.Internal.Tower.Double import Numeric.AD.Mode -- | Compute the answer and all derivatives of a function @(a -> a)@ diffs :: (TowerDouble -> TowerDouble) -> Double -> [Double] diffs f a = getADTower $ apply f a {-# INLINE diffs #-} -- | Compute the zero-padded derivatives of a function @(a -> a)@ diffs0 :: (TowerDouble -> TowerDouble) -> Double -> [Double] diffs0 f a = zeroPad (diffs f a) {-# INLINE diffs0 #-} -- | Compute the answer and all derivatives of a function @(a -> f a)@ diffsF :: Functor f => (TowerDouble -> f TowerDouble) -> Double -> f [Double] diffsF f a = getADTower <$> apply f a {-# INLINE diffsF #-} -- | Compute the zero-padded derivatives of a function @(a -> f a)@ diffs0F :: Functor f => (TowerDouble -> f TowerDouble) -> Double -> f [Double] diffs0F f a = zeroPad . getADTower <$> apply f a {-# INLINE diffs0F #-} -- | @taylor f x@ compute the Taylor series of @f@ around @x@. taylor :: (TowerDouble -> TowerDouble) -> Double -> Double -> [Double] taylor f x dx = go 1 1 (diffs f x) where go !n !acc (a:as) = a * acc : go (n + 1) (acc * dx / n) as go _ _ [] = [] -- | @taylor0 f x@ compute the Taylor series of @f@ around @x@, zero-padded. taylor0 :: (TowerDouble -> TowerDouble) -> Double -> Double -> [Double] taylor0 f x dx = zeroPad (taylor f x dx) {-# INLINE taylor0 #-} -- | @maclaurin f@ compute the Maclaurin series of @f@ maclaurin :: (TowerDouble -> TowerDouble) -> Double -> [Double] maclaurin f = taylor f 0 {-# INLINE maclaurin #-} -- | @maclaurin f@ compute the Maclaurin series of @f@, zero-padded maclaurin0 :: (TowerDouble -> TowerDouble) -> Double -> [Double] maclaurin0 f = taylor0 f 0 {-# INLINE maclaurin0 #-} -- | Compute the first derivative of a function @(a -> a)@ diff :: (TowerDouble -> TowerDouble) -> Double -> Double diff f = d . diffs f {-# INLINE diff #-} -- | Compute the answer and first derivative of a function @(a -> a)@ diff' :: (TowerDouble -> TowerDouble) -> Double -> (Double, Double) diff' f = d' . diffs f {-# INLINE diff' #-} -- | Compute a directional derivative of a function @(f a -> a)@ du :: Functor f => (f TowerDouble -> TowerDouble) -> f (Double, Double) -> Double du f = d . getADTower . f . fmap withD {-# INLINE du #-} -- | Compute the answer and a directional derivative of a function @(f a -> a)@ du' :: Functor f => (f TowerDouble -> TowerDouble) -> f (Double, Double) -> (Double, Double) du' f = d' . getADTower . f . fmap withD {-# INLINE du' #-} -- | Compute a directional derivative of a function @(f a -> g a)@ duF :: (Functor f, Functor g) => (f TowerDouble -> g TowerDouble) -> f (Double, Double) -> g Double duF f = fmap (d . getADTower) . f . fmap withD {-# INLINE duF #-} -- | Compute the answer and a directional derivative of a function @(f a -> g a)@ duF' :: (Functor f, Functor g) => (f TowerDouble -> g TowerDouble) -> f (Double, Double) -> g (Double, Double) duF' f = fmap (d' . getADTower) . f . fmap withD {-# INLINE duF' #-} -- | Given a function @(f a -> a)@, and a tower of derivatives, compute the corresponding directional derivatives. dus :: Functor f => (f TowerDouble -> TowerDouble) -> f [Double] -> [Double] dus f = getADTower . f . fmap tower {-# INLINE dus #-} -- | Given a function @(f a -> a)@, and a tower of derivatives, compute the corresponding directional derivatives, zero-padded dus0 :: Functor f => (f TowerDouble -> TowerDouble) -> f [Double] -> [Double] dus0 f = zeroPad . getADTower . f . fmap tower {-# INLINE dus0 #-} -- | Given a function @(f a -> g a)@, and a tower of derivatives, compute the corresponding directional derivatives dusF :: (Functor f, Functor g) => (f TowerDouble -> g TowerDouble) -> f [Double] -> g [Double] dusF f = fmap getADTower . f . fmap tower {-# INLINE dusF #-} -- | Given a function @(f a -> g a)@, and a tower of derivatives, compute the corresponding directional derivatives, zero-padded dus0F :: (Functor f, Functor g) => (f TowerDouble -> g TowerDouble) -> f [Double] -> g [Double] dus0F f = fmap getADTower . f . fmap tower {-# INLINE dus0F #-}