{-# 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 :: (TowerDouble -> TowerDouble) -> Double -> [Double]
diffs TowerDouble -> TowerDouble
f Double
a = TowerDouble -> [Double]
getADTower (TowerDouble -> [Double]) -> TowerDouble -> [Double]
forall a b. (a -> b) -> a -> b
$ (TowerDouble -> TowerDouble) -> Double -> TowerDouble
forall b. (TowerDouble -> b) -> Double -> b
apply TowerDouble -> TowerDouble
f Double
a
{-# INLINE diffs #-}

-- | Compute the zero-padded derivatives of a function @(a -> a)@
diffs0
  :: (TowerDouble -> TowerDouble)
  -> Double
  -> [Double]
diffs0 :: (TowerDouble -> TowerDouble) -> Double -> [Double]
diffs0 TowerDouble -> TowerDouble
f Double
a = [Double] -> [Double]
forall a. Num a => [a] -> [a]
zeroPad ((TowerDouble -> TowerDouble) -> Double -> [Double]
diffs TowerDouble -> TowerDouble
f Double
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 :: forall (f :: * -> *).
Functor f =>
(TowerDouble -> f TowerDouble) -> Double -> f [Double]
diffsF TowerDouble -> f TowerDouble
f Double
a = TowerDouble -> [Double]
getADTower (TowerDouble -> [Double]) -> f TowerDouble -> f [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (TowerDouble -> f TowerDouble) -> Double -> f TowerDouble
forall b. (TowerDouble -> b) -> Double -> b
apply TowerDouble -> f TowerDouble
f Double
a
{-# INLINE diffsF #-}

-- | Compute the zero-padded derivatives of a function @(a -> f a)@
diffs0F
  :: Functor f
  => (TowerDouble -> f TowerDouble)
  -> Double
  -> f [Double]
diffs0F :: forall (f :: * -> *).
Functor f =>
(TowerDouble -> f TowerDouble) -> Double -> f [Double]
diffs0F TowerDouble -> f TowerDouble
f Double
a = [Double] -> [Double]
forall a. Num a => [a] -> [a]
zeroPad ([Double] -> [Double])
-> (TowerDouble -> [Double]) -> TowerDouble -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TowerDouble -> [Double]
getADTower (TowerDouble -> [Double]) -> f TowerDouble -> f [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (TowerDouble -> f TowerDouble) -> Double -> f TowerDouble
forall b. (TowerDouble -> b) -> Double -> b
apply TowerDouble -> f TowerDouble
f Double
a
{-# INLINE diffs0F #-}

-- | @taylor f x@ compute the Taylor series of @f@ around @x@.
taylor
  :: (TowerDouble -> TowerDouble)
  -> Double
  -> Double
  -> [Double]
taylor :: (TowerDouble -> TowerDouble) -> Double -> Double -> [Double]
taylor TowerDouble -> TowerDouble
f Double
x Double
dx = Double -> Double -> [Double] -> [Double]
go Double
1 Double
1 ((TowerDouble -> TowerDouble) -> Double -> [Double]
diffs TowerDouble -> TowerDouble
f Double
x) where
  go :: Double -> Double -> [Double] -> [Double]
go !Double
n !Double
acc (Double
a:[Double]
as) = Double
a Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
acc Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: Double -> Double -> [Double] -> [Double]
go (Double
n Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
1) (Double
acc Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
dx Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
n) [Double]
as
  go Double
_ Double
_ [] = []

-- | @taylor0 f x@ compute the Taylor series of @f@ around @x@, zero-padded.
taylor0
  :: (TowerDouble -> TowerDouble)
  -> Double
  -> Double
  -> [Double]
taylor0 :: (TowerDouble -> TowerDouble) -> Double -> Double -> [Double]
taylor0 TowerDouble -> TowerDouble
f Double
x Double
dx = [Double] -> [Double]
forall a. Num a => [a] -> [a]
zeroPad ((TowerDouble -> TowerDouble) -> Double -> Double -> [Double]
taylor TowerDouble -> TowerDouble
f Double
x Double
dx)
{-# INLINE taylor0 #-}

-- | @maclaurin f@ compute the Maclaurin series of @f@
maclaurin
  :: (TowerDouble -> TowerDouble)
  -> Double
  -> [Double]
maclaurin :: (TowerDouble -> TowerDouble) -> Double -> [Double]
maclaurin TowerDouble -> TowerDouble
f = (TowerDouble -> TowerDouble) -> Double -> Double -> [Double]
taylor TowerDouble -> TowerDouble
f Double
0
{-# INLINE maclaurin #-}

-- | @maclaurin f@ compute the Maclaurin series of @f@, zero-padded
maclaurin0
  :: (TowerDouble -> TowerDouble)
  -> Double
  -> [Double]
maclaurin0 :: (TowerDouble -> TowerDouble) -> Double -> [Double]
maclaurin0 TowerDouble -> TowerDouble
f = (TowerDouble -> TowerDouble) -> Double -> Double -> [Double]
taylor0 TowerDouble -> TowerDouble
f Double
0
{-# INLINE maclaurin0 #-}

-- | Compute the first derivative of a function @(a -> a)@
diff
  :: (TowerDouble -> TowerDouble)
  -> Double
  -> Double
diff :: (TowerDouble -> TowerDouble) -> Double -> Double
diff TowerDouble -> TowerDouble
f = [Double] -> Double
forall a. Num a => [a] -> a
d ([Double] -> Double) -> (Double -> [Double]) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TowerDouble -> TowerDouble) -> Double -> [Double]
diffs TowerDouble -> TowerDouble
f
{-# INLINE diff #-}

-- | Compute the answer and first derivative of a function @(a -> a)@
diff'
  :: (TowerDouble -> TowerDouble)
  -> Double
  -> (Double, Double)
diff' :: (TowerDouble -> TowerDouble) -> Double -> (Double, Double)
diff' TowerDouble -> TowerDouble
f = [Double] -> (Double, Double)
forall a. Num a => [a] -> (a, a)
d' ([Double] -> (Double, Double))
-> (Double -> [Double]) -> Double -> (Double, Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TowerDouble -> TowerDouble) -> Double -> [Double]
diffs TowerDouble -> TowerDouble
f
{-# INLINE diff' #-}

-- | Compute a directional derivative of a function @(f a -> a)@
du
  :: Functor f
  => (f TowerDouble -> TowerDouble)
  -> f (Double, Double) -> Double
du :: forall (f :: * -> *).
Functor f =>
(f TowerDouble -> TowerDouble) -> f (Double, Double) -> Double
du f TowerDouble -> TowerDouble
f = [Double] -> Double
forall a. Num a => [a] -> a
d ([Double] -> Double)
-> (f (Double, Double) -> [Double]) -> f (Double, Double) -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TowerDouble -> [Double]
getADTower (TowerDouble -> [Double])
-> (f (Double, Double) -> TowerDouble)
-> f (Double, Double)
-> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> TowerDouble
f (f TowerDouble -> TowerDouble)
-> (f (Double, Double) -> f TowerDouble)
-> f (Double, Double)
-> TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Double, Double) -> TowerDouble)
-> f (Double, Double) -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Double, Double) -> TowerDouble
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' :: forall (f :: * -> *).
Functor f =>
(f TowerDouble -> TowerDouble)
-> f (Double, Double) -> (Double, Double)
du' f TowerDouble -> TowerDouble
f = [Double] -> (Double, Double)
forall a. Num a => [a] -> (a, a)
d' ([Double] -> (Double, Double))
-> (f (Double, Double) -> [Double])
-> f (Double, Double)
-> (Double, Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TowerDouble -> [Double]
getADTower (TowerDouble -> [Double])
-> (f (Double, Double) -> TowerDouble)
-> f (Double, Double)
-> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> TowerDouble
f (f TowerDouble -> TowerDouble)
-> (f (Double, Double) -> f TowerDouble)
-> f (Double, Double)
-> TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Double, Double) -> TowerDouble)
-> f (Double, Double) -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Double, Double) -> TowerDouble
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 :: forall (f :: * -> *) (g :: * -> *).
(Functor f, Functor g) =>
(f TowerDouble -> g TowerDouble) -> f (Double, Double) -> g Double
duF f TowerDouble -> g TowerDouble
f = (TowerDouble -> Double) -> g TowerDouble -> g Double
forall a b. (a -> b) -> g a -> g b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Double] -> Double
forall a. Num a => [a] -> a
d ([Double] -> Double)
-> (TowerDouble -> [Double]) -> TowerDouble -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TowerDouble -> [Double]
getADTower) (g TowerDouble -> g Double)
-> (f (Double, Double) -> g TowerDouble)
-> f (Double, Double)
-> g Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> g TowerDouble
f (f TowerDouble -> g TowerDouble)
-> (f (Double, Double) -> f TowerDouble)
-> f (Double, Double)
-> g TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Double, Double) -> TowerDouble)
-> f (Double, Double) -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Double, Double) -> TowerDouble
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' :: forall (f :: * -> *) (g :: * -> *).
(Functor f, Functor g) =>
(f TowerDouble -> g TowerDouble)
-> f (Double, Double) -> g (Double, Double)
duF' f TowerDouble -> g TowerDouble
f = (TowerDouble -> (Double, Double))
-> g TowerDouble -> g (Double, Double)
forall a b. (a -> b) -> g a -> g b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Double] -> (Double, Double)
forall a. Num a => [a] -> (a, a)
d' ([Double] -> (Double, Double))
-> (TowerDouble -> [Double]) -> TowerDouble -> (Double, Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TowerDouble -> [Double]
getADTower) (g TowerDouble -> g (Double, Double))
-> (f (Double, Double) -> g TowerDouble)
-> f (Double, Double)
-> g (Double, Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> g TowerDouble
f (f TowerDouble -> g TowerDouble)
-> (f (Double, Double) -> f TowerDouble)
-> f (Double, Double)
-> g TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Double, Double) -> TowerDouble)
-> f (Double, Double) -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Double, Double) -> TowerDouble
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 :: forall (f :: * -> *).
Functor f =>
(f TowerDouble -> TowerDouble) -> f [Double] -> [Double]
dus f TowerDouble -> TowerDouble
f = TowerDouble -> [Double]
getADTower (TowerDouble -> [Double])
-> (f [Double] -> TowerDouble) -> f [Double] -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> TowerDouble
f (f TowerDouble -> TowerDouble)
-> (f [Double] -> f TowerDouble) -> f [Double] -> TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Double] -> TowerDouble) -> f [Double] -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Double] -> TowerDouble
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 :: forall (f :: * -> *).
Functor f =>
(f TowerDouble -> TowerDouble) -> f [Double] -> [Double]
dus0 f TowerDouble -> TowerDouble
f = [Double] -> [Double]
forall a. Num a => [a] -> [a]
zeroPad ([Double] -> [Double])
-> (f [Double] -> [Double]) -> f [Double] -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TowerDouble -> [Double]
getADTower (TowerDouble -> [Double])
-> (f [Double] -> TowerDouble) -> f [Double] -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> TowerDouble
f (f TowerDouble -> TowerDouble)
-> (f [Double] -> f TowerDouble) -> f [Double] -> TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Double] -> TowerDouble) -> f [Double] -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Double] -> TowerDouble
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 :: forall (f :: * -> *) (g :: * -> *).
(Functor f, Functor g) =>
(f TowerDouble -> g TowerDouble) -> f [Double] -> g [Double]
dusF f TowerDouble -> g TowerDouble
f = (TowerDouble -> [Double]) -> g TowerDouble -> g [Double]
forall a b. (a -> b) -> g a -> g b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TowerDouble -> [Double]
getADTower (g TowerDouble -> g [Double])
-> (f [Double] -> g TowerDouble) -> f [Double] -> g [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> g TowerDouble
f (f TowerDouble -> g TowerDouble)
-> (f [Double] -> f TowerDouble) -> f [Double] -> g TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Double] -> TowerDouble) -> f [Double] -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Double] -> TowerDouble
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 :: forall (f :: * -> *) (g :: * -> *).
(Functor f, Functor g) =>
(f TowerDouble -> g TowerDouble) -> f [Double] -> g [Double]
dus0F f TowerDouble -> g TowerDouble
f = (TowerDouble -> [Double]) -> g TowerDouble -> g [Double]
forall a b. (a -> b) -> g a -> g b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TowerDouble -> [Double]
getADTower (g TowerDouble -> g [Double])
-> (f [Double] -> g TowerDouble) -> f [Double] -> g [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. f TowerDouble -> g TowerDouble
f (f TowerDouble -> g TowerDouble)
-> (f [Double] -> f TowerDouble) -> f [Double] -> g TowerDouble
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Double] -> TowerDouble) -> f [Double] -> f TowerDouble
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Double] -> TowerDouble
tower
{-# INLINE dus0F #-}