Spec-Zone.ru › OCaml

Модуль 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 : (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
| Float16 : (float, float16_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
    | 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

См. 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
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

Spec-Zone.ru

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