Spec-Zone.ru › OCaml 5.0

Модуль 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 (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 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 : (float, float32_elt) kind
| Float64 : (float, float64_elt) kind
| Int8_signed : (int, int8_signed_elt) kind
| Int8_unsigned : (int, int8_unsigned_elt) kind
| Int16_signed : (int, int16_signed_elt) kind
| Int16_unsigned : (int, int16_unsigned_elt) kind
| Int32 : (int32, int32_elt) kind
| Int64 : (int64, int64_elt) kind
| Int : (int, int_elt) kind
| Nativeint : (nativeint, nativeint_elt) kind
| Complex32 : (Complex.t, complex32_elt) kind
| Complex64 : (Complex.t, complex64_elt) kind
| Char : (char, int8_unsigned_elt) kind

Для каждого типа элемента существует соответствующий тип 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
    | Int8_signed -> 0 | Int8_unsigned -> 0
    | Int16_signed -> 0 | Int16_unsigned -> 0
    | Int32 -> 0l | Int64 -> 0L
    | Int -> 0 | Nativeint -> 0n
    | Char -> '\000'
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 типа float32_elt и float64_elt доступны с помощью типа OCaml float. Bigarrays сложных типов complex32_elt, complex64_elt доступны с помощью типа OCaml Complex.t. Bigarrays целочисленных типов доступны с помощью наименьшего типа OCaml целых чисел, достаточно большого для представления элементов массива: int для 8- и 16-битных целочисленных Bigarrays, а также Bigarrays целых чисел OCaml; 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.0

Схемы расположения массивов

type c_layout = 
| C_layout_typ

См. Bigarray.fortran_layout.

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 : c_layout layout
| Fortran_layout : fortran_layout 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.0
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.0
  • 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.0
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.

Действительно, при наличии конфликтов данных программы не завершатся с ошибкой, но наблюдаемое поведение может не соответствовать последовательному переплетению операций из различных областей.

Разрывы данных

Bigarrays имеют отличительную особенность в случае конфликтов данных: одновременные операции с 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

Bigarray res может содержать значения, которые не являются ни Complex.i, ни Complex.one (например, 1 + i).

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/5.0/htmlman/libref/Bigarray.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API