用于矢量化数值计算的最佳Scala集合类型

sup*_*pyo 5 api scala numerical-computing scala-collections

寻找IndexedSeq[Double]在设计特定于域的数值计算库时使用的正确数据类型(例如).对于这个问题,我将范围限制在使用1维数组Double.该库将定义通常应用于1D阵列中每个元素的数字函数.

注意事项:

  • 首选不可变数据类型,例如VectorIndexedSeq
  • 希望最大限度地减少数据转换
  • 在空间和时间上合理有效
  • 对使用该库的其他人友好
  • 优雅而干净的API

我应该在集合层次结构中使用更高的东西,例如Seq

或者仅仅定义单元素函数并将映射/迭代留给最终用户更好?

这似乎效率较低(因为一些计算可以在每组调用中完成一次),但同时也是一个更灵活的API,因为它适用于任何类型的集合.

有什么建议?

Rex*_*err 11

如果您的计算是远程计算密集型的任何操作,请使用Arrayraw或自己的类包装.您可以提供与集合兼容的包装器,但只能使其成为互操作性的显式包装器.除了Array通用之外的所有东西都是盒装的,因此相对缓慢而笨重.

如果你不使用Array,人们将被迫放弃你拥有的任何东西,而只是Array在表现很重要时使用.也许那没关系; 也许你想要计算是为了方便而不是效率.在这种情况下,我建议使用IndexedSeq接口,假设你想让人们知道索引不是非常缓慢(例如不是List),并Vector在引擎盖下使用.Array[Double]对于大多数低功耗操作(例如乘法),您将使用大约4倍的内存,并且速度要慢3-10倍.

例如,这个:

val u = v.map(1.0 / _)   //  v is Vector[Double]
Run Code Online (Sandbox Code Playgroud)

大约比这慢三倍:

val u = new Array[Double](v.length)
var j = 0
while (j<u.length) {
  u(j) = 1.0/v(j)      // v is Array[Double]
  j += 1
}
Run Code Online (Sandbox Code Playgroud)

如果你使用这个map方法Array,那就像Vector[Double]路上一样慢; 操作Array是通用的,因此装箱.(这就是大部分惩罚来自的地方.)