Spec-Zone.ru › OCaml

Модуль Bigarray

module Bigarray: sig .. end

Большие многомерные числовые массивы.

Этот модуль реализует многомерные массивы целых чисел и чисел с плавающей точкой, далее называемые «Bigarray», чтобы отличать их от стандартных массивов OCaml, описанных в Array.

Реализация позволяет эффективно совместно использовать большие числовые массивы между кодом OCaml и числовыми библиотеками на C или Fortran.

Основные отличия Bigarray от стандартных массивов OCaml:

  • Размер Bigarray не ограничен, в отличие от массивов OCaml. (Обычные массивы чисел с плавающей точкой ограничены 2 097 151 элементом на 32-разрядной платформе, а обычные массивы других типов — 4 194 303 элементами.)
  • Bigarray являются многомерными. Поддерживается любое число измерений от 0 до 16. Массивы OCaml, напротив, одномерны, а для представления многомерных массивов требуется использовать массивы массивов.
  • Bigarray могут содержать только целые числа и числа с плавающей точкой, тогда как массивы OCaml могут содержать данные произвольных типов OCaml.
  • Bigarray обеспечивают более экономичное хранение целочисленных элементов и элементов с плавающей точкой, чем обычные массивы OCaml, в частности потому, что поддерживают «малые» типы, такие как числа с плавающей точкой одинарной точности и 8- и 16-разрядные целые числа, в дополнение к стандартным типам OCaml: числам с плавающей точкой двойной точности и 32- и 64-разрядным целым числам.
  • Размещение Bigarray в памяти полностью совместимо с размещением массивов в C и Fortran, что позволяет передавать большие массивы между кодом OCaml и кодом на C / Fortran без копирования данных.
  • Bigarray поддерживают полезные высокоуровневые операции, которые обычные массивы не предоставляют эффективно, например извлечение подмассивов и «срезов» многомерного массива вдоль определённых измерений; все эти операции выполняются без копирования данных.

Пользователям этого модуля рекомендуется использовать open Bigarray в исходном коде, а затем обращаться к типам массивов и операциям с помощью краткой точечной записи, например Array1.t или Array2.sub.

Bigarray поддерживают все операции OCaml с ad-hoc-полиморфизмом:

  • сравнения (=, <>, <= и т. д., а также compare);
  • хеширование (модуль Hash);
  • структурированный ввод-вывод (функции модуля Marshal, а также output_value и input_value).

Типы элементов

Bigarray могут содержать элементы следующих типов:

  • числа с плавающей точкой половинной точности 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'
  • Начиная с версии 5.2 Конструктор Float16 для GADT.
val float16 : (float, float16_elt) kind

См. Bigarray.char.

  • Начиная с версии 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 и раздел Типы элементов.

Обратите внимание: это Bigarray, содержащий целые числа OCaml (со знаком, 31 бит на 32-разрядных архитектурах и 63 бита на 64-разрядных архитектурах); он не соответствует типу int в C.

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

Как видно из типов значений выше, доступ к Bigarray типов float16_elt, float32_elt и float64_elt осуществляется с использованием типа OCaml float. Доступ к Bigarray комплексных типов complex32_elt, complex64_elt осуществляется с использованием типа OCaml Complex.t. Доступ к Bigarray целочисленных типов осуществляется с использованием наименьшего типа целого числа OCaml, достаточного для представления элементов массива: int для Bigarray с 8- и 16-разрядными целыми числами, а также для Bigarray с целыми числами OCaml; int32 для Bigarray с 32-разрядными целыми числами; int64 для Bigarray с 64-разрядными целыми числами; и nativeint для Bigarray с целыми числами, размер которых зависит от платформы. Наконец, к Bigarray типа int8_unsigned_elt можно обращаться как к массивам символов, а не как к массивам малых целых чисел, используя значение типа char вместо int8_unsigned.

val kind_size_in_bytes : ('a, 'b) kind -> int

kind_size_in_bytes k — это количество байтов, используемых для хранения элемента типа k.

  • Начиная с версии 4.03

Размещение массивов

type c_layout = 
| C_layout_typ

См. Bigarray.fortran_layout.

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 : 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

Трёхмерные массивы.

Преобразования между обобщёнными Bigarray и Bigarray фиксированной размерности

val genarray_of_array0 : ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t

Возвращает обобщённый Bigarray, соответствующий заданному нульмерному Bigarray.

  • Начиная с версии 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.

  • Вызывает исключение 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 не имеет ровно три измерения.

Изменение формы Bigarray

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 для изменения формы на нульмерные массивы.

  • Начиная с версии 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 для изменения формы на трёхмерные массивы.

Bigarray и безопасность при параллельном выполнении

При одновременном доступе к 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

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

© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/api/Bigarray.html

Spec-Zone.ru

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