Модуль Bigarray
module Bigarray: sig .. end
Большие многомерные числовые массивы.
Этот модуль реализует многомерные массивы целых чисел и чисел с плавающей точкой, далее называемые «Bigarrays», чтобы отличать их от стандартных массивов OCaml, описанных в Array.
Реализация позволяет эффективно обмениваться большими числовыми массивами между кодом OCaml и числовыми библиотеками C или Fortran.
Основные различия между «Bigarrays» и стандартными массивами OCaml следующие:
- Bigarrays не ограничены по размеру, в отличие от массивов OCaml. (Нормальные массивы с плавающей точкой ограничены 2 097 151 элементом на 32-битной платформе, а обычные массивы других типов — 4 194 303 элементами.)
- Bigarrays многомерные. Поддерживается любое количество измерений от 0 до 16. В отличие от этого, массивы OCaml одномерные и требуют кодирования многомерных массивов как массивов массивов.
- Bigarrays могут содержать только целые числа и числа с плавающей точкой, а массивы OCaml могут содержать произвольные типы данных OCaml.
- Bigarrays обеспечивают более экономичное хранение элементов целых чисел и чисел с плавающей точкой, чем обычные массивы OCaml, в частности, потому что они поддерживают «маленькие» типы, такие как числа с плавающей точкой одинарной точности и целые числа 8 и 16 бит, в дополнение к стандартным типам OCaml с плавающей точкой двойной точности и целыми числами 32 и 64 бит.
- Схема памяти Bigarrays полностью совместима со схемой памяти массивов C и Fortran, что позволяет передавать большие массивы туда и обратно между кодом OCaml и кодом C/Fortran без копирования данных.
- Bigarrays поддерживают интересные операции высокого уровня, которых обычные массивы не предоставляют эффективно, такие как извлечение подмассивов и «срезы» многомерного массива по определённым измерениям, всё без копирования.
Пользователям этого модуля рекомендуется сделать open Bigarray в своём коде, затем обращаться к типам массивов и операциям с помощью короткой нотации с точкой, например, Array1.t или Array2.sub.
Bigarrays поддерживают все адхоковые полиморфные операции OCaml:
- сравнения (
=,<>,<=, и т. д., а такжеcompare); - хеширование (модуль
Hash); - и структурированный ввод-вывод (функции из модуля
Marshal, а такжеoutput_valueиinput_value).
Типы элементов
Bigarrays могут содержать элементы следующих типов:
- Числа с плавающей точкой с полувысокой точностью IEEE (16 бит) (
Bigarray.float16_elt), - Числа с плавающей точкой с одинарной точностью IEEE (32 бит) (
Bigarray.float32_elt), - Числа с плавающей точкой с двойной точностью IEEE (64 бит) (
Bigarray.float64_elt), - Комплексные числа с плавающей точкой с одинарной точностью IEEE (2 * 32 бит) (
Bigarray.complex32_elt), - Комплексные числа с плавающей точкой с двойной точностью IEEE (2 * 64 бит) (
Bigarray.complex64_elt), - Целые числа 8 бит (со знаком или без знака) (
Bigarray.int8_signed_eltилиBigarray.int8_unsigned_elt), - Целые числа 16 бит (со знаком или без знака) (
Bigarray.int16_signed_eltилиBigarray.int16_unsigned_elt), - Целые числа OCaml (со знаком, 31 бит на 32-битных архитектурах, 63 бита на 64-битных архитектурах) (
Bigarray.int_elt), - 32-битные целые числа со знаком (
Bigarray.int32_elt), - 64-битные целые числа со знаком (
Bigarray.int64_elt), - целые числа с размером, родным для платформы (32 бит на 32-битных архитектурах, 64 бит на 64-битных архитектурах) (
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, который является типом значений OCaml, которые могут храниться в Bigarray или считываться из него. Этот тип не обязательно совпадает с типом элементов массива: например, Bigarray, элементы которого имеют тип float32_elt, содержит 32-битные числа с плавающей точкой одинарной точности, но чтение или запись одного из его элементов из OCaml использует тип OCaml float, который является числами с плавающей точкой двойной точности 64 бит.
Тип GADT ('a, 'b) kind захватывает это сопоставление типа OCaml 'a для значений, считываемых или записываемых в Bigarray, и типа элемента 'b, который представляет фактическое содержимое Bigarray. Его конструкторы перечисляют все возможные ассоциации типов 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'
- Since 5.2 Конструктор Float16 для GADT.
val float16 : (float, float16_elt) kind
См. Bigarray.char.
- Since 5.2
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
Как показано типами значений выше, Bigarrays типа float16_elt, float32_elt и float64_elt доступны с помощью типа OCaml float. Bigarrays сложных типов complex32_elt, complex64_elt доступны с типом OCaml Complex.t. Bigarrays целочисленных типов доступны с помощью наименьшего типа OCaml целых чисел, достаточно большого для представления элементов массива: int для 8- и 16-битных целых Bigarrays, а также OCaml-целых Bigarrays; int32 для 32-битных целых Bigarrays; int64 для 64-битных целых Bigarrays; и nativeint для Bigarrays целых чисел платформы. Наконец, Bigarrays типа int8_unsigned_elt также можно получить как массивы символов вместо массивов малых целых чисел, используя значение типа char вместо int8_unsigned.
val kind_size_in_bytes : ('a, 'b) kind -> int
kind_size_in_bytes k — это количество байтов, используемых для хранения элемента типа k.
- Since 4.03
Макеты массивов
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
Массивы трёх размерностей.
Преобразования между общими Bigarrays и Bigarrays фиксированной размерности
val genarray_of_array0 : ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t
Возвращает общий Bigarray, соответствующий заданному Bigarray нулевой размерности.
- Since 4.05
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.
- Since 4.05
-
Raises
Invalid_argumentесли у общего Bigarray не ровно ноль размерностей.
val array1_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array1.t
Возвращает одномерный Bigarray, соответствующий данному общему Bigarray.
-
Raises
Invalid_argumentесли у общего Bigarray не ровно одна размерность.
val array2_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array2.t
Возвращает двумерный Bigarray, соответствующий данному общему Bigarray.
-
Raises
Invalid_argumentесли у общего Bigarray не ровно две размерности.
val array3_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array3.t
Возвращает трёхмерный Bigarray, соответствующий данному общему Bigarray.
-
Raises
Invalid_argumentесли у общего Bigarray не ровно три размерности.
Изменение формы Bigarrays
val reshape : ('a, 'b, 'c) Genarray.t -> int array -> ('a, 'b, 'c) Genarray.t
reshape b [|d1;...;dN|] преобразует Bigarray b в N-мерный массив с размерами d1...dN. Возвращаемый массив и исходный массив b совместно используют данные и имеют тот же макет. Например, предположим, что b — это одномерный массив размерности 12, reshape b [|3;4|] возвращает двумерный массив b' с размерами 3 и 4. Если у b макет C, элемент (x,y) из b' соответствует элементу x * 3 + y из b. Если у b макет Fortran, элемент (x,y) из b' соответствует элементу x + (y - 1) * 4 из b. Возвращаемый Bigarray должен иметь ровно такое же количество элементов, как и исходный Bigarray b. То есть, произведение размеров b должно быть равно i1 * ... * iN. В противном случае, возникает Invalid_argument.
val reshape_0 : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t
Специализированная версия Bigarray.reshape для преобразования в массивы нулевой размерности.
- Since 4.05
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 для преобразования в трёхмерные массивы.
Bigarrays и безопасность при одновременном доступе
Необходимо быть внимательным при одновременном доступе к bigarrays из нескольких доменов: доступ к bigarray никогда не вызовет аварийную остановку программы, но несинхронизированные обращения могут привести к неожиданным (непоследовательным) результатам.
Атомарность
Каждая операция bigarray, которая обращается к большему количеству элементов массива, не является атомарной. Это включает срезку, копирование и заполнение bigarrays.
Например, рассмотрим следующую программу:
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.
Действительно, при наличии состязаний за данные программы не аварийно завершатся, но наблюдаемое поведение может не соответствовать никакому последовательному переплетению операций из разных доменов.
Разрыв
Большие массивы имеют явную особенность при наличии гонок за данные: одновременные операции с большими массивами могут давать неожиданные значения из-за разрыва. Более точно, чередование частичных записей и чтений может создавать значения, которые не существовали бы при последовательном выполнении. Например, в конце
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 могут содержаться значения, которые не являются ни Complex.i , ни Complex.one (например, 1 + i).
© 1995-2024 INRIA.
https://ocaml.org/manual/5.2/api/Bigarray.html