2012-12-05 54 views
4

在設計特定於領域的數值計算庫時尋找適當的數據類型(例如IndexedSeq[Double])。對於這個問題,我將範圍限制爲使用1維數組Double。該庫將定義通常應用於1D陣列中每個元素的數字函數。向量化數值計算的最佳Scala集合類型

注意事項:

  • 不想一成不變的數據類型,如VectorIndexedSeq
  • 要儘量減少數據轉換
  • 在空間和時間上合理有效
  • 友好使用其他人圖書館
  • 高雅清潔的API

我應該使用更高一些的收集層次結構,如Seq

或者只是定義單元素函數並將映射/迭代保留給最終用戶會更好嗎?

這似乎效率較低(因爲某些計算可能會在每組調用中完成一次),但同時還有一個更靈活的API,因爲它可以處理任何類型的集合。

有什麼建議嗎?

+1

如果你會有值拳擊問題,你可以看看[debox](https://github.com/non/debox) –

回答

11

如果您的計算要做任何遠程計算密集型的工作,請使用Array,無論是原始還是包裝在您自己的類中。您可以提供一個兼容集合的包裝器,但只是爲了互操作性做一個明確的包裝。除Array之外的所有內容都是通用的,因此是盒裝的,因此相對較慢且體積較大。

如果您不使用Array,那麼人們將被迫放棄您擁有的任何東西,只有在性能很重要時才使用Array。也許沒關係;也許你希望計算在那裏以方便而不是效率。在這種情況下,我建議使用IndexedSeq作爲接口,假設您想讓人們知道索引不是非常慢(例如,不是List),並且在底層使用Vector。您將使用比Array[Double]大約4倍的內存,並且對於大多數低效操作(例如乘法),速度會降低3-10倍。

例如,這樣的:

val u = v.map(1.0/_) // v is Vector[Double] 

比這慢大約三倍:

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 
} 

如果您使用Arraymap方法,它只是爲Vector[Double]方式速度慢; Array上的操作是通用的,因此裝箱。 (這是大多數的懲罰來自於。)

3

我在處理數值時一直使用Vectors,因爲它提供了非常有效的隨機訪問以及append/prepend。

另請注意,不可變索引序列的當前默認集合是Vector,因此如果您編寫一些代碼(如for (i <- 0 until n) yield {...}),它將返回IndexedSeq[...],但運行時類型爲Vector。因此,總是使用Vectors可能是一個好主意,因爲一些採用兩個序列作爲輸入的二元運算符可能受益於這兩個參數具有相同實現類型的事實。 (現在情況並非如此,但有人指出矢量級聯可能處於log(N)時間,與當前線性時間相反,因爲第二個參數被簡單地視爲一般序列)。

不過,我相信Seq[Double]應該已經提供了大部分你需要的功能接口。由於Range的映射結果並不直接產生Vector,所以我通常把Seq[Double]作爲參數類型作爲我的輸入,所以它具有一些通用性。我期望效率在底層實現中得到優化。

希望有所幫助。