2012-07-11 44 views
5

当使用衍生塔的vector-space包(请参阅derivative towers)时,我遇到了区分积分的需求。 从数学是很清楚如何实现这一点:与函数如何区分积分与向量空间库(haskell)

g : R -> R 

例如

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

关于x的导数是:

f'(x) = g(x) 

我试图通过先定义一个类 “一体化” 得到这个行为

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

一个基本的例子是

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

integrateQAGS from hmatrix

问题带有b值代表衍生物的塔:

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

NC.T是从Numeric.Complex(数字-前奏)。 功能integrateD定义如下(但错误):

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) 

的函数不返回我想要的东西,它的来源积,而不是整体。问题是,我需要一个线性地图,返回f u。该a :> b定义如下:

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

我不知道如何定义derivative。任何帮助将不胜感激,谢谢

编辑:

我忘了提供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 

,我可以给我的意思的例子: 比方说,我有一个函数

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

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

(AR * *)表示代数的乘法。环(数字-前奏)

我很容易这个功能与上面的功能integrateD整合:

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

当我看一看f的衍生物:

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

并评估此在0pi/2我得到1和一些值:

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

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

现在,获得积分的时候,我得到的功能f的推导而不是它的上限

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

但我值期待:

> f (pi AF./ 2) 
D 23.140692632779267 ... 

回答

0

我终于找到了解决我的问题。 解决方案的关键是矢量空间包中的>-<函数,它代表链式规则。

所以,我定义一个函数integrateD'这样的:

integrateD' :: (Integration a b, HasTrie (Basis a), HasBasis a, AdditiveGroup b , b ~ Scalar b, VectorSpace b) => (a -> a :> b) -> a -> a -> (a:>b) -> (a :> b) 
integrateD' f l u d_one = ((\_ -> integrate (powVal . f) l (u)) >-< (\_ -> f u)) (d_one) 

d_one指推导变量及其衍生物必须为1。利用该函数I现在可以创建某些情况下像

instance Integration Double (Double :> Double) where 
integrate f l u = integrateD' f l u (idD 1) 

instance Integration (Double) (Double :> (NC.T Double)) where 
integrate f l u = liftD2 (NC.+:) (integrateD' (\x -> NC.real <$>> f x) l u (idD 1.0 :: Double :> Double)) (integrateD' (\x -> NC.imag <$>> f x) l u (idD 1.0 :: Double :> Double)) 

不幸的是开箱即用的复杂数值我不能使用integrateD,我必须使用liftD2。原因似乎是idD函数,我不知道是否有更优雅的解决方案。

当我看到在这个问题的例子,我现在让我期望的解决方案:

*Main> derivAtBasis (integrateD' f 0 (pi AF./ 2) (idD 1.0 :: Double :> Double))() 
D 23.140692632779267 ... 

或使用该实例:

*Main> derivAtBasis (integrate f 0 (pi AF./ 2))() 
D 23.140692632779267 ... 
0

“HMATRIX”是非常紧密地联系在一起双。您不能将其功能用于其他数字数据类型,如'vector-space'或'ad'所提供的数据类型。

+0

是的,这是真的。但是,当我在'Double:> Double'值上使用'powVal'函数时,它可以工作。但是,当然,我失去了有关衍生物的信息。我必须明确提供这些信息,这就是我卡住的地方:( – TheMADMAN 2012-07-11 19:01:39

1

如果你只想做一个AD功能涉及数字积分,而AD系统不知道如何整合本身,它应该“只是工作”。这是一个例子。 (这种集成例行很恶心,故名)。

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,...] 

唯一的限制条件是,该数值积分程序需要与AD发挥出色,并且也接受复杂的参数。一些更幼稚,像

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

是一体化的上限分段常数,需要积分限为枚举并因此不复杂,并且还常常评估由于此规定范围外的被积:

Prelude> last [0..9.5] 
10.0