Документация Engee

Справка

OffsetArray(A, indices...)

Возвращает AbstractArray, который использует тип и размер элемента совместно с первым аргументом, но применяет предоставленные индексы (indices) для вывода его осей. Если все индексы являются AbstractUnitRange, они напрямую используются в качестве осевого интервала в каждом измерении. Другие допустимые типы см. в примерах ниже.

В качестве альтернативы можно указать координаты одного угла массива, и тогда оси будут вычисляться автоматически из размера A. Этот конструктор позволяет выполнять смещение к произвольному начальному индексу вдоль каждой оси, например к нулевой схеме индексирования, используемой в массивах в таких языках, как C и Python. См. OffsetArrays.Origin и примеры ниже.

Пример: смещения

Существует два типа indices: целые числа и диапазоноподобные типы.

Целые числа распознаются как смещения, где 0 означает, что смещения не применяются:

julia> A = OffsetArray(reshape(1:6, 2, 3), -1, -2)
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
 1  3  5
 2  4  6

julia> A[0, 1]
5

Примеры диапазоноподобных типов: UnitRange (например, -1:2), CartesianIndices и Colon() (или сокращенно :). UnitRange указывает на интервал оси вдоль одного конкретного измерения, CartesianIndices указывает на интервалы вдоль нескольких измерений, а Colon является заполнителем, указывающим, что OffsetArray использует свою ось совместно с родительским объектом вдоль этого измерения.

julia> OffsetArray(reshape(1:6, 2, 3), 0:1, -1:1)
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
 1  3  5
 2  4  6

julia> OffsetArray(reshape(1:6, 2, 3), :, -1:1) # : как заполнитель, указывающий, что смещение не должно применяться к первому измерению.
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 1:2, -1:1) with eltype Int64 with indices 1:2×-1:1:
 1  3  5
 2  4  6

Используйте CartesianIndices, чтобы указать координаты двух диагонально противоположных углов:

julia> OffsetArray(reshape(1:6, 2, 3), CartesianIndex(0, -1):CartesianIndex(1, 1))
2×3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
 1  3  5
 2  4  6

Целые числа и диапазоноподобные типы нельзя объединять в одном вызове:

julia> OffsetArray(reshape(1:6, 2, 3), 0, -1:1)
ERROR: [...]

Пример: начало

OffsetArrays.Origin можно использовать для указания начала OffsetArray. Термин «начало» здесь означает угол с наименьшими значениями координат, например левый край для AbstractVector, левый нижний угол для AbstractMatrix и так далее. Координаты начала задают начальный индекс массива вдоль каждого измерения.

julia> a = [1 2; 3 4];

julia> OffsetArray(a, OffsetArrays.Origin(0, 1))
2×2 OffsetArray(::Matrix{Int64}, 0:1, 1:2) with eltype Int64 with indices 0:1×1:2:
 1  2
 3  4

julia> OffsetArray(a, OffsetArrays.Origin(0)) # задает нулевое начало по каждому измерению
2×2 OffsetArray(::Matrix{Int64}, 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
 1  2
 3  4
OffsetVector(v, index)

Псевдоним типа и вспомогательный конструктор для одномерных OffsetArray.

OffsetMatrix(A, index1, index2)

Псевдоним типа и вспомогательный конструктор для двумерных OffsetArray.

Origin(indices...)
Origin(origin::Tuple)
Origin(origin::CartesianIndex)

Вспомогательный тип для построения OffsetArray с заданным началом. Не экспортируется.

origin массива определяется как кортеж первого индекса вдоль каждой оси, то есть first.(axes(A)).

Пример

julia> a = [1 2; 3 4];

julia> using OffsetArrays: Origin

julia> OffsetArray(a, Origin(0, 1))
2×2 OffsetArray(::Matrix{Int64}, 0:1, 1:2) with eltype Int64 with indices 0:1×1:2:
 1  2
 3  4

julia> OffsetArray(a, Origin(0)) # краткое обозначение для `Origin(0, 0)`
2×2 OffsetArray(::Matrix{Int64}, 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
 1  2
 3  4

Объект Origin является вызываемым, и он может сместить начало массива в указанную точку.

julia> b = Origin(0)(a) # смещение начала массива в точку (0,0)
2×2 OffsetArray(::Matrix{Int64}, 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
 1  2
 3  4

Тип Origin, вызванный с AbstractArray в качестве аргумента, возвратит экземпляр, соответствующий началу массива.

julia> origin_b = Origin(b) # получение начала массива в виде экземпляра Origin
Origin(0, 0)

julia> origin_b(ones(2,2)) # смещение начала другого массива к началу массива b, в данном случае в точку (0,0)
2×2 OffsetArray(::Matrix{Float64}, 0:1, 0:1) with eltype Float64 with indices 0:1×0:1:
 1.0  1.0
 1.0  1.0

Можно транслировать экземпляр Origin на несколько массивов, чтобы сместить их все в одно начало.

julia> using OffsetArrays: Origin

julia> a = [1 2; 3 4]; # начало в точке (1,1)

julia> b = Origin(2,3)(a); # начало в точке (2,3)

julia> c = Origin(4)(a); # начало в точке (4,4)

julia> ao, bo, co = Origin(0).((a, b, c)); # смещение всех начал в точку (0,0)

julia> first.(axes(ao)) == first.(axes(bo)) == first.(axes(co)) == (0,0)
true

julia> ao, bo, co = Origin(b).((a, b, c)); # смещение всех начал в начало массива b

julia> first.(axes(ao)) == first.(axes(bo)) == first.(axes(co)) == (2,3)
true

julia> ao, bo, co = OffsetArray.((a, b, c), Origin(b)); # другой способ выполнения того же самого

julia> first.(axes(ao)) == first.(axes(bo)) == first.(axes(co)) == (2,3)
true
ro = IdOffsetRange(r::AbstractUnitRange, offset=0)

Строит «диапазон смещения тождественности». Численно collect(ro) == collect(r) .+ offset, с дополнительным свойством, так что axes(ro, 1) = axes(r, 1) .+ offset. Когда r начинается с 1, тогда ro[i] == i и даже ro[ro] == ro, т. е. это «тождество», которое является началом «Id» в IdOffsetRange.

Примеры

Самый распространенный случай — это смещение диапазона, который начинается с 1 (либо 1:n, либо Base.OneTo(n)):

julia> using OffsetArrays: IdOffsetRange

julia> ro = IdOffsetRange(1:3, -2)
IdOffsetRange(values=-1:1, indices=-1:1)

julia> axes(ro, 1)
IdOffsetRange(values=-1:1, indices=-1:1)

julia> ro[-1]
-1

julia> ro[3]
ERROR: BoundsError: attempt to access 3-element OffsetArrays.IdOffsetRange{Int64, UnitRange{Int64}} with indices -1:1 at index [3]

Если диапазон не начинается с 1, значения могут отличаться от индексов:

julia> ro = IdOffsetRange(11:13, -2)
IdOffsetRange(values=9:11, indices=-1:1)

julia> axes(ro, 1)     # 11:13 индексируется по 1:3, и это смещение также применяется к осям
IdOffsetRange(values=-1:1, indices=-1:1)

julia> ro[-1]
9

julia> ro[3]
ERROR: BoundsError: attempt to access 3-element OffsetArrays.IdOffsetRange{Int64, UnitRange{Int64}} with indices -1:1 at index [3]

Расширенная справка

Построение/принуждение сохраняет (смещенные) значения входного диапазона, но может изменять индексы, если этого требуют указанные типы. Пример:

r = OffsetArrays.IdOffsetRange{Int,UnitRange{Int}}(3:4)

имеет r[1] == 3 и r[2] == 4, в то время как

r = OffsetArrays.IdOffsetRange{Int,Base.OneTo{Int}}(3:4)

имеет r[3] == 3 и r[4] == 4, а r[1] вызовет ошибку BoundsError. В этом последнем случае потребовалось смещение осей, поскольку диапазоны Base.OneTo должны начинаться со значения 1.

В будущем преобразование будет сохранять как значения, так и

индексы, выдавая ошибку, если это невозможно. Например:

    r = convert(OffsetArrays.IdOffsetRange{Int,UnitRange{Int}}, 3:4)

имеет `r[1] == 3` и `r[2] == 4` и удовлетворяет `r == 3:4`, тогда как

```julia
julia> convert(OffsetArrays.IdOffsetRange{Int,Base.OneTo{Int}}, 3:4)    # future behavior, not present behavior
ERROR: ArgumentError: first element must be 1, got 3

ERROR: ArgumentError: first element must be 1, got 3

```
где возникнет ошибка, поскольку результат не может иметь те же оси, что и входные данные.

Важным следствием является то, что `typeof(r1)(r2)` и `oftype(r1, r2)` будут вести себя по-разному:

первый принуждает r2 быть типом r1, а второй преобразует. Разработчикам рекомендуется «обезопасить» свой код на будущее, выбрав поведение, подходящее для каждого случая использования.

no_offset_view(A)

Возвращает AbstractArray, имеющий общую структуру и базовые данные с аргументом, но использующий индексирование на основе 1. Может просто возвращать аргумент, если это применимо. Не экспортируется.

В реализации по умолчанию применяется OffsetArrays, но другие типы должны использовать что-то более конкретное, чтобы устранить уровень косвенности, когда это применимо.

julia> A = [1 3 5; 2 4 6];

julia> O = OffsetArray(A, 0:1, -1:1)
2×3 OffsetArray(::Matrix{Int64}, 0:1, -1:1) with eltype Int64 with indices 0:1×-1:1:
 1  3  5
 2  4  6

julia> OffsetArrays.no_offset_view(O)[1,1] = -9
-9

julia> A
2×3 Matrix{Int64}:
 -9  3  5
  2  4  6
OffsetArrays.AxisConversionStyle(typeof(indices))

AxisConversionStyle определяет, следует ли преобразовывать indices в один AbstractUnitRange{Int} или в Tuple{Vararg{AbstractUnitRange{Int}}} при разложении пользовательских типов на индексы. Этот метод вызывается после to_indices(A::Array, axes(A), indices), чтобы предоставить дополнительную информацию в случае, если to_indices не возвращает Tuple из AbstractUnitRange{Int}.

Пользовательские типы индексов должны расширять AxisConversionStyle и возвращать либо OffsetArray.SingleRange(), который используется по умолчанию, либо OffsetArray.TupleOfRanges(). В первом случае тип T должен определять Base.convert(::Type{AbstractUnitRange{Int}}, ::T), а во втором — Base.convert(::Type{Tuple{Vararg{AbstractUnitRange{Int}}}}, ::T).

Примером последнего является CartesianIndices, который преобразуется в кортеж (Tuple) из AbstractUnitRange{Int} при разложении на индексы.

Пример

julia> struct NTupleOfUnitRanges{N}
           x ::NTuple{N, UnitRange{Int}}
       end

julia> Base.to_indices(A, inds, t::Tuple{NTupleOfUnitRanges{N}}) where {N} = t;

julia> OffsetArrays.AxisConversionStyle(::Type{NTupleOfUnitRanges{N}}) where {N} = OffsetArrays.TupleOfRanges();

julia> Base.convert(::Type{Tuple{Vararg{AbstractUnitRange{Int}}}}, t::NTupleOfUnitRanges) = t.x;

julia> a = zeros(3, 3);

julia> inds = NTupleOfUnitRanges((3:5, 2:4));

julia> oa = OffsetArray(a, inds);

julia> axes(oa, 1) == 3:5
true

julia> axes(oa, 2) == 2:4
true
center(A, [r::RoundingMode=RoundDown])::Dims

Возвращает координату центра заданного массива A. Если значение является size(A, k) четным числом, то будет применена процедура округления с режимом r.

Совместимость: OffsetArrays 1.9

Для этого метода требуется версия OffsetArrays не ниже 1.9.

Примеры

julia> A = reshape(collect(1:9), 3, 3)
3×3 Matrix{Int64}:
 1  4  7
 2  5  8
 3  6  9

julia> c = OffsetArrays.center(A)
(2, 2)

julia> A[c...]
5

julia> Ao = OffsetArray(A, -2, -2); # оси (-1:1, -1:1)

julia> c = OffsetArrays.center(Ao)
(0, 0)

julia> Ao[c...]
5

Чтобы сместить центральную координату заданного массива в точку (0, 0, ...), можно использовать centered.

centered(A, cp=center(A)) -> Ao

Смещает центральную координату/точку cp массива A в точку (0, 0, ..., 0). Внутренне это эквивалентно OffsetArray(A, .-cp).

Совместимость: OffsetArrays 1.9

Для этого метода требуется версия OffsetArrays не ниже 1.9.

Примеры

julia> A = reshape(collect(1:9), 3, 3)
3×3 Matrix{Int64}:
 1  4  7
 2  5  8
 3  6  9

julia> Ao = OffsetArrays.centered(A); # оси (-1:1, -1:1)

julia> Ao[0, 0]
5

julia> Ao = OffsetArray(A, OffsetArrays.Origin(0)); # оси (0:2, 0:2)

julia> Aoo = OffsetArrays.centered(Ao); # оси (-1:1, -1:1)

julia> Aoo[0, 0]
5

Пользователи могут передавать cp, чтобы изменить интерпретацию «центральной точки», но значение выходного массива также должно быть переосмыслено. Например, если cp = map(last, axes(A)), то эта функция смещает уже не центральную точку, а правую нижнюю точку в точку (0, 0, ..., 0). Обычно cp используется для изменения поведения округления, когда массив имеет четное значение размера в некотором измерении:

julia> A = reshape(collect(1:4), 2, 2) # В идеале центр должен быть в точке (1.5, 1.5), но OffsetArrays поддерживают только целочисленные смещения.
2×2 Matrix{Int64}:
 1  3
 2  4

julia> OffsetArrays.centered(A, OffsetArrays.center(A, RoundUp)) # задание (2, 2) в качестве центральной точки
2×2 OffsetArray(::Matrix{Int64}, -1:0, -1:0) with eltype Int64 with indices -1:0×-1:0:
 1  3
 2  4

julia> OffsetArrays.centered(A, OffsetArrays.center(A, RoundDown)) # задание (1, 1) в качестве центральной точки
2×2 OffsetArray(::Matrix{Int64}, 0:1, 0:1) with eltype Int64 with indices 0:1×0:1:
 1  3
 2  4

См. также описание center.