module Bigarray: Bigarray
Bigarray 可以包含以下種類的元素
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
捕獲了 OCaml 型別 'a
與在 Bigarray 中讀寫的值,以及代表 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
如上所示的值的型別所示,種類為 float16_elt
、float32_elt
和 float64_elt
的 Bigarray 是使用 OCaml 型別 float
存取的。複數種類 complex32_elt
、complex64_elt
的 Bigarray 是使用 OCaml 型別 Complex.t
存取的。整數種類的 Bigarray 是使用足夠大的 OCaml 整數型別來表示陣列元素存取的:對於 8 位元和 16 位元整數 Bigarray 以及 OCaml 整數 Bigarray,使用 int
;對於 32 位元整數 Bigarray,使用 int32
;對於 64 位元整數 Bigarray,使用 int64
;對於平台原生整數 Bigarray,使用 nativeint
。最後,種類為 int8_unsigned_elt
的 Bigarray 也可以使用種類值 char
而不是 int8_unsigned
,作為字元陣列存取,而不是小整數陣列。
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 程式碼互操作,此函式庫支援 Bigarray 的兩種不同記憶體配置,一種與 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
,如果通用 Bigarray 沒有剛好零維。val array1_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array1.t
傳回對應於給定通用 Bigarray 的一維 Bigarray。
Invalid_argument
,如果通用 Bigarray 沒有剛好一維。val array2_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array2.t
傳回對應於給定通用 Bigarray 的二維 Bigarray。
Invalid_argument
,如果通用 Bigarray 沒有剛好二維。val array3_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array3.t
傳回對應於給定通用 Bigarray 的三維 Bigarray。
Invalid_argument
,如果通用 Bigarray 沒有剛好三維。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
)。