module Bigarray:sig
..end
大型、多維、數值陣列。
此模組實現整數和浮點數的多維陣列,以下稱為「Bigarrays」,以區別於 Array
中描述的標準 OCaml 陣列。
此實作允許 OCaml 程式碼和 C 或 Fortran 數值函式庫之間有效率地共享大型數值陣列。
「Bigarrays」和標準 OCaml 陣列之間的主要差異如下:
鼓勵此模組的使用者在其原始碼中執行 open Bigarray
,然後透過簡短的點表示法來引用陣列類型和操作,例如 Array1.t
或 Array2.sub
。
Bigarrays 支援所有 OCaml 特設多型操作
=
、<>
、<=
等,以及 compare
);Hash
);Marshal
模組的函式,以及 output_value
和 input_value
)。Bigarrays 可以包含以下種類的元素:
Bigarray.float16_elt
)、Bigarray.float32_elt
)、Bigarray.float64_elt
)、Bigarray.complex32_elt
)、Bigarray.complex64_elt
)、Bigarray.int8_signed_elt
或 Bigarray.int8_unsigned_elt
)、Bigarray.int16_signed_elt
或 Bigarray.int16_unsigned_elt
)、Bigarray.int_elt
)、Bigarray.int32_elt
)、Bigarray.int64_elt
)、Bigarray.nativeint_elt
)。每個元素種類在類型層級上都由以下定義的 *_elt
類型之一表示(由於技術上的注入原因,使用單一建構函式而非抽象類型定義)。
type
float16_elt =
| |
Float16_elt |
type
float32_elt =
| |
Float32_elt |
type
float64_elt =
| |
Float64_elt |
type
int8_signed_elt =
| |
Int8_signed_elt |
type
int8_unsigned_elt =
| |
Int8_unsigned_elt |
type
int16_signed_elt =
| |
Int16_signed_elt |
type
int16_unsigned_elt =
| |
Int16_unsigned_elt |
type
int32_elt =
| |
Int32_elt |
type
int64_elt =
| |
Int64_elt |
type
int_elt =
| |
Int_elt |
type
nativeint_elt =
| |
Nativeint_elt |
type
complex32_elt =
| |
Complex32_elt |
type
complex64_elt =
| |
Complex64_elt |
type ('a, 'b)
kind =
| |
Float32 : |
| |
Float64 : |
| |
Int8_signed : |
| |
Int8_unsigned : |
| |
Int16_signed : |
| |
Int16_unsigned : |
| |
Int32 : |
| |
Int64 : |
| |
Int : |
| |
Nativeint : |
| |
Complex32 : |
| |
Complex64 : |
| |
Char : |
| |
Float16 : |
每個元素種類都與一個 OCaml 類型相關聯,這是可以儲存在 Bigarray 中或從 Bigarray 讀回的 OCaml 值的類型。此類型不一定與陣列元素本身的類型相同:例如,其元素種類為 float32_elt
的 Bigarray 包含 32 位元單精度浮點數,但是從 OCaml 讀取或寫入其中一個元素會使用 OCaml 類型 float
,這是 64 位元雙精度浮點數。
GADT 類型 ('a, 'b) kind
捕獲 Bigarray 中讀取或寫入的值的 OCaml 類型 'a
與表示 Bigarray 實際內容的元素種類 'b
的關聯。其建構函式列出 OCaml 類型與元素種類的所有可能關聯,並為了向後相容性原因在下方重新匯出。
在此處使用廣義代數資料類型 (GADT) 可撰寫傳回類型取決於引數類型的類型良好的多型函式,例如
let zero : type a b. (a, b) kind -> a = function
| Float32 -> 0.0 | Complex32 -> Complex.zero
| Float64 -> 0.0 | Complex64 -> Complex.zero
| Float16 -> 0.0
| Int8_signed -> 0 | Int8_unsigned -> 0
| Int16_signed -> 0 | Int16_unsigned -> 0
| Int32 -> 0l | Int64 -> 0L
| Int -> 0 | Nativeint -> 0n
| Char -> '\000'
val float16 : (float, float16_elt) kind
請參閱 Bigarray.char
。
val float32 : (float, float32_elt) kind
請參閱 Bigarray.char
。
val float64 : (float, float64_elt) kind
請參閱 Bigarray.char
。
val complex32 : (Complex.t, complex32_elt) kind
請參閱 Bigarray.char
。
val complex64 : (Complex.t, complex64_elt) kind
請參閱 Bigarray.char
。
val int8_signed : (int, int8_signed_elt) kind
請參閱 Bigarray.char
。
val int8_unsigned : (int, int8_unsigned_elt) kind
請參閱 Bigarray.char
。
val int16_signed : (int, int16_signed_elt) kind
請參閱 Bigarray.char
。
val int16_unsigned : (int, int16_unsigned_elt) kind
請參閱 Bigarray.char
。
val int : (int, int_elt) kind
請參閱 Bigarray.char
。
val int32 : (int32, int32_elt) kind
請參閱 Bigarray.char
。
val int64 : (int64, int64_elt) kind
請參閱 Bigarray.char
。
val nativeint : (nativeint, nativeint_elt) kind
請參閱 Bigarray.char
。
val char : (char, int8_unsigned_elt) kind
如上述值的類型所示,使用 OCaml 類型 float
來存取種類為 float16_elt
、float32_elt
和 float64_elt
的 Bigarray。使用 OCaml 類型 Complex.t
來存取複數種類 complex32_elt
、complex64_elt
的 Bigarray。使用足以表示陣列元素的最小 OCaml 整數類型來存取整數種類的 Bigarray:對於 8 位和 16 位整數 Bigarray 以及 OCaml 整數 Bigarray,使用 int
;對於 32 位元整數 Bigarray,使用 int32
;對於 64 位元整數 Bigarray,使用 int64
;對於平台原生整數 Bigarray,使用 nativeint
。最後,使用種類值 char
而非 int8_unsigned
,也可以將種類為 int8_unsigned_elt
的 Bigarray 作為字元陣列而非小整數陣列來存取。
val kind_size_in_bytes : ('a, 'b) kind -> int
kind_size_in_bytes k
是用於儲存類型為 k
之元素的位元組數。
type
c_layout =
| |
C_layout_typ |
type
fortran_layout =
| |
Fortran_layout_typ |
為了方便與現有的 C 和 Fortran 程式碼互通,此函式庫支援 Bigarrays 的兩種不同記憶體佈局,一種與 C 慣例相容,另一種與 Fortran 慣例相容。
在 C 風格的佈局中,陣列索引從 0 開始,且多維陣列以行優先格式佈局。也就是說,對於二維陣列,第 0 行的所有元素在記憶體中都是連續的,然後是第 1 行的所有元素,依此類推。換句話說,(x,y)
和 (x, y+1)
的陣列元素在記憶體中相鄰。
在 Fortran 風格的佈局中,陣列索引從 1 開始,且多維陣列以列優先格式佈局。也就是說,對於二維陣列,第 0 列的所有元素在記憶體中都是連續的,然後是第 1 列的所有元素,依此類推。換句話說,(x,y)
和 (x+1, y)
的陣列元素在記憶體中相鄰。
每個佈局樣式都在類型層級上分別由虛擬類型 Bigarray.c_layout
和 Bigarray.fortran_layout
識別。
GADT 類型 'a layout
表示兩種支援的記憶體佈局之一:C 風格或 Fortran 風格。其建構函式作為值在下方重新匯出,以實現向後相容性。
type 'a
layout =
| |
C_layout : |
| |
Fortran_layout : |
val c_layout : c_layout layout
val fortran_layout : fortran_layout layout
module Genarray:sig
..end
module Array0:sig
..end
零維陣列。
module Array1:sig
..end
一維陣列。
module Array2:sig
..end
二維陣列。
module Array3:sig
..end
三維陣列。
val genarray_of_array0 : ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t
傳回對應於給定零維 Bigarray 的通用 Bigarray。
val genarray_of_array1 : ('a, 'b, 'c) Array1.t -> ('a, 'b, 'c) Genarray.t
傳回對應於給定一維 Bigarray 的通用 Bigarray。
val genarray_of_array2 : ('a, 'b, 'c) Array2.t -> ('a, 'b, 'c) Genarray.t
傳回對應於給定二維 Bigarray 的通用 Bigarray。
val genarray_of_array3 : ('a, 'b, 'c) Array3.t -> ('a, 'b, 'c) Genarray.t
傳回對應於給定三維 Bigarray 的通用 Bigarray。
val array0_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t
傳回對應於給定泛型 Bigarray 的零維 Bigarray。
Invalid_argument
異常。val array1_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array1.t
傳回對應於給定泛型 Bigarray 的一維 Bigarray。
Invalid_argument
異常。val array2_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array2.t
傳回對應於給定泛型 Bigarray 的二維 Bigarray。
Invalid_argument
異常。val array3_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array3.t
傳回對應於給定泛型 Bigarray 的三維 Bigarray。
Invalid_argument
異常。val reshape : ('a, 'b, 'c) Genarray.t ->
int array -> ('a, 'b, 'c) Genarray.t
reshape b [|d1;...;dN|]
將 Bigarray b
轉換為維度為 d1
...dN
的 N
維陣列。返回的陣列和原始陣列 b
共享它們的資料並具有相同的佈局。例如,假設 b
是一個維度為 12 的一維陣列,reshape b [|3;4|]
返回一個維度為 3 和 4 的二維陣列 b'
。如果 b
具有 C 佈局,則 b'
的元素 (x,y)
對應於 b
的元素 x * 3 + y
。如果 b
具有 Fortran 佈局,則 b'
的元素 (x,y)
對應於 b
的元素 x + (y - 1) * 4
。返回的 Bigarray 必須與原始 Bigarray b
具有完全相同的元素數量。也就是說,b
的維度乘積必須等於 i1 * ... * iN
。否則,會引發 Invalid_argument
異常。
val reshape_0 : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t
將 Bigarray.reshape
專門用於重新塑形為零維陣列的版本。
val reshape_1 : ('a, 'b, 'c) Genarray.t -> int -> ('a, 'b, 'c) Array1.t
將 Bigarray.reshape
專門用於重新塑形為一維陣列的版本。
val reshape_2 : ('a, 'b, 'c) Genarray.t ->
int -> int -> ('a, 'b, 'c) Array2.t
將 Bigarray.reshape
專門用於重新塑形為二維陣列的版本。
val reshape_3 : ('a, 'b, 'c) Genarray.t ->
int -> int -> int -> ('a, 'b, 'c) Array3.t
將 Bigarray.reshape
專門用於重新塑形為三維陣列的版本。
當從多個域並行存取 bigarray 時,必須小心:存取 bigarray 永遠不會使程式崩潰,但未同步的存取可能會產生令人驚訝的(非循序一致的)結果。
每個存取多個陣列元素的 bigarray 操作都不是原子的。這包括切片、複製和填充 bigarray。
例如,考慮以下程式
open Bigarray
let size = 100_000_000
let a = Array1.init Int C_layout size (fun _ -> 1)
let update f a () =
for i = 0 to size - 1 do a.{i} <- f a.{i} done
let d1 = Domain.spawn (update (fun x -> x + 1) a)
let d2 = Domain.spawn (update (fun x -> 2 * x + 1) a)
let () = Domain.join d1; Domain.join d2
執行此程式碼後,bigarray a
的每個欄位都是 2
、3
、4
或 5
。如果需要原子性,則使用者必須實作自己的同步機制(例如,使用 Mutex.t
)。
如果兩個域僅存取 bigarray 的不相交部分,則觀察到的行為等同於來自兩個域的操作的某些循序交錯。
當兩個域在沒有同步的情況下存取相同的 bigarray 元素,且至少有一個存取是寫入時,就會發生資料競爭。在沒有資料競爭的情況下,觀察到的行為等同於來自不同域的操作的某些循序交錯。
在可能的情況下,應避免資料競爭,方法是使用同步來協調對 bigarray 元素的存取。
實際上,在存在資料競爭的情況下,程式不會崩潰,但觀察到的行為可能不等同於來自不同域的操作的任何循序交錯。
在存在資料競爭的情況下,Bigarray 有一個明顯的警告:由於撕裂,並行的 bigarray 操作可能會產生令人驚訝的值。更精確地說,部分寫入和讀取的交錯可能會產生在循序執行中不存在的值。例如,在
let res = Array1.init Complex64 c_layout size (fun _ -> Complex.zero)
let d1 = Domain.spawn (fun () -> Array1.fill res Complex.one)
let d2 = Domain.spawn (fun () -> Array1.fill res Complex.i)
let () = Domain.join d1; Domain.join d2
之後,res
bigarray 可能包含既不是 Complex.i
也不是 Complex.one
的值(例如 1 + i
)。