我已经发布了一个用于求解延迟微分方程的小型数值库:http://github.com/masterdezign/dde
主要技术限制:
State
在给定的时刻。< / LI>
hmatrix
)的库集成。因此,作为输入/输出,我广泛使用Data.Vector.Storable。因此,与此解决方案不同:
How do I optimize numerical integration performance in Haskell (with example),
使用newtype State = State { _state :: V.Vector Double }
而不是data State = State {-# UNPACK #-} !Double {-# UNPACK #-} !Double
。但是,库现在运行速度慢了两倍。
问题:有没有办法为未指定数量的变量带来data State = State {-# UNPACK #-}...
的速度和newtype State = State { _state :: V.Vector Double }
的灵活性?我应该考虑模板Haskell在编译时创建data UNPACK
- 类似的结构吗?
答案 0 :(得分:2)
我不会使用任何特定的矢量实现。像Data.Vector
这样的可变长度类型是一个糟糕的选择,不仅因为当空间的维度较低时额外的长度信息是一个相当大的开销,还因为你失去了尺寸匹配的任何类型系统保证。
相反,你应该在矢量空间的选择上做出所有参数。即,您有效地使维度成为编译时变量,并且允许带有一些有意义的子变量的矢量类型。
import Data.VectorSpace
import Data.AdditiveGroup
newtype Stepper1 state = Stepper1 {
_stepper
:: Double
-> RHS state -- parameterised in a similar way
-> state
-> (Double, Double)
-> (Double, Double)
-> state
}
rk₄ :: VectorSpace v => Stepper1 v
rk₄ = Stepper1 _rk4
where _rk4 hStep rhs' y₀ ... = y₀ ^+^ (h/6)*^(k₁ ^+^ 2*^k₂ ^+^ 2*^k₃ ^+^ k₄)
where k₁ = rhs' (y₀, ...)
k₂ = rhs' (y₀ ^+^ (h/2)*^k₁, ...)
k₃ = rhs' (y₀ ^+^ (h/2)*^k₂, ...)
k₄ = rhs' (y₀ ^+^ h*^k₃, ...)
然后,用户可以选择具体的实现方式。对于二维向量,标准选择是来自linear
包的V2
;它使用free-vector-spaces中的VectorSpace
个实例重新导出。但是对于测试,您也可以使用普通的旧元组,vector-space中有VectorSpace
个实例。当然,也可以从hmatrix
包装类型,但这对性能来说真的不好 - 如果需要,最好只转换最终结果。
要获得最佳性能,您可能需要使用一些{-# INLINE #-}
pragma。 Bang模式OTOH通常不会带来太多性能优势 - 最重要的是类型是严格的,并且是未装箱的。毫无疑问,在每个变量定义之前进行先发制人 - 这些都不会产生任何影响,因为CAF仅在使用时进行评估。
我很高兴听到你最终获得的表现!如果它明显比原来的State {-# UNPACK #-} !Double {-# UNPACK #-} !Double
差,那就是我们应该调查的事情。