Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to differentiate integrals with vector-space library (haskell)

Tags:

haskell

When using the vector-space package for derivative towers (see derivative towers) I come across the need to differentiate integrals. From math it is quite clear how to achieve this:

f(x) = int g(y) dy from 0 to x

with a function

g : R -> R

for example.

The derivative with respect to x would be:

f'(x) = g(x)

I tried to get this behaviour by first defining a class "Integration"

class Integration a b where
--standard integration function
integrate :: (a -> b) -> a -> a -> b

a basic instance is

instance  Integration Double Double where
  integrate f a b = fst $ integrateQAGS prec 1000 f a b

with integrateQAGS from hmatrix

the problem comes with values b which represent towers of derivatives:

instance Integration Double (Double :> (NC.T Double)) where
  integrate = integrateD

NC.T is from Numeric.Complex (numeric-prelude). The function integrateD is defined as follows (but wrong):

integrateD ::(Integration a b, HasTrie (Basis a), HasBasis a, AdditiveGroup b) =>  (a -> a :> b) -> a -> a -> (a :> b)
integrateD f l u = D (integrate (powVal . f) l u) (derivative $ f u)

The function does not return what I want, it derives the integrand, but not the integral. The problem is, that I need a linear map which returns f u. The a :> b is defined as follows:

data a :> b = D { powVal :: b, derivative :: a :-* (a :> b) }

I don't know how to define derivative. Any help will be appreciated, thanks

edit:

I forgot to provide the instance for Integration Double (NC.T Double):

instance  Integration Double (NC.T Double) where
  integrate f a b = bc $ (\g -> integrate g a b) <$> [NC.real . f, NC.imag . f]
      where bc (x:y:[]) = x NC.+: y

and I can give an example of what I mean: Let's say I have a function

f(x) = exp(2*x)*sin(x)

>let f = \x -> (Prelude.exp ((pureD 2.0) AR.* (idD x))) * (sin (idD x)) :: Double :> Double 

(AR.*) means multiplication from Algebra.Ring (numeric-prelude)

I can easily integrate this function with the above function integrateD:

>integrateD f 0 1 :: Double :> Double
D 1.888605715258933 ...

When I take a look at the derivative of f:

f'(x) = 2*exp(2*x)*sin(x)+exp(2*x)*cos(x)

and evaluate this at 0 and pi/2 I get 1 and some value:

> derivAtBasis (f 0.0) ()
D 1.0 ...

> derivAtBasis (f (pi AF./ 2)) ()
D 46.281385265558534 ...

Now, when deriving the integral, I get the derivation of the function f not its value at the upper bound

> derivAtBasis (integrate f 0 (pi AF./ 2)) ()
D 46.281385265558534 ...

But I expect:

> f (pi AF./ 2)
D 23.140692632779267 ...
like image 613
TheMADMAN Avatar asked Nov 14 '22 02:11

TheMADMAN


1 Answers

If you just want to do AD on a function which involves numeric integration, without the AD system knowing about integration per-se, it should "just work". Here is an example. (This integration routine is pretty icky, hence the name.)

import Numeric.AD
import Data.Complex

intIcky :: (Integral a, Fractional b) => a -> (b -> b) -> b -> b -> b
intIcky n f a b = c/n' * sum [f (a+fromIntegral i*c/(n'-1)) | i<-[0..n-1]]
  where n' = fromIntegral n
        c = b-a

sinIcky t = intIcky 1000 cos 0 t
cosIcky t = diff sinIcky t

test1 = map sinIcky [0,pi/2..2*pi::Float]
 -- [0.0,0.9997853,-4.4734867e-7,-0.9966421,6.282018e-3]
test2 = map sin [0,pi/2..2*pi::Float]
 -- [0.0,1.0,-8.742278e-8,-1.0,-3.019916e-7]
test3 = map cosIcky [0,pi/2..2*pi::Float]
 -- [1.0,-2.8568506e-4,-0.998999,2.857402e-3,0.999997]
test4 = map cos [0,pi/2..2*pi::Float]
 -- [1.0,-4.371139e-8,-1.0,1.1924881e-8,1.0]
test5 = diffs sinIcky (2*pi::Float)
 -- [6.282019e-3,0.99999696,-3.143549e-3,-1.0004976,3.1454563e-3,1.0014982,-3.1479746e-3,...]
test6 = diffs sinIcky (2*pi::Complex Float)
 -- [6.282019e-3 :+ 0.0,0.99999696 :+ 0.0,(-3.143549e-3) :+ 0.0,(-1.0004976) :+ 0.0,...]

The only caveats are that the numeric integration routine needs to play well with AD, and also accept complex arguments. Something even more naive, like

intIcky' dx f x0 x1 = dx * sum [f x|x<-[x0,x0+dx..x1]]

is piecewise constant in the upper limit of integration, requires the limits of integration to be Enum and hence non-complex, and also often evaluates the integrand outside the given range due to this:

Prelude> last [0..9.5]
10.0
like image 92
Barak A. Pearlmutter Avatar answered Dec 31 '22 06:12

Barak A. Pearlmutter