对衍生塔使用vector-space包时(参见derivative towers)我觉得需要区分积分。 从数学来看,如何实现这一点非常清楚:
f(x) = int g(y) dy from 0 to x
带有功能
g : R -> R
例如。
关于x的衍生物将是:
f'(x) = g(x)
我试图通过首先定义一个类“Integration”
来获得这种行为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
来自hmatrix 的integrateQAGS
问题伴随着代表衍生品塔的价值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。*)表示从Algebra.Ring(数字前奏)
的乘法我可以轻松地将此功能与上述功能integrateD
:
>integrateD f 0 1 :: Double :> Double
D 1.888605715258933 ...
当我看一下f:
的衍生物时f'(x) = 2*exp(2*x)*sin(x)+exp(2*x)*cos(x)
并在0
和pi/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 :(得分:1)
如果您只想对涉及数字集成的函数执行AD,而AD系统不了解集成 per-se ,则它应该“正常工作”。这是一个例子。 (这个集成程序非常狡猾,因此得名。)
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]]
在积分上限中是分段常数,要求积分限制为Enum,因此非复杂,并且还经常评估给定范围之外的被积函数:
Prelude> last [0..9.5]
10.0
答案 1 :(得分:0)
'hmatrix'与Double紧密相关。您不能将其功能与“矢量空间”或“广告”提供的其他数字数据类型一起使用。
答案 2 :(得分:0)
我终于找到了解决问题的方法。
解决方案的关键是vector-space包中的>-<
函数,它代表链规则。
所以,我定义了一个函数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.使用此函数,我现在可以创建一些实例,如
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 ...