2012-07-11 43 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