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

OffsetArrays.jl

OffsetArrays предоставляет пользователям Julia массивы с произвольными индексами, аналогичные тем, которые можно найти в некоторых других языках программирования, таких как Fortran. Ниже приводятся базовое использование, описанное в файле сведений (README), а также несколько коротких примеров, иллюстрирующих обстоятельства, в которых может быть полезен пакет OffsetArrays. Более подробное обсуждение см. в этой публикации блога.

Использование

Такие массивы можно построить следующим образом:

OA = OffsetArray(A, axis1, axis2, ...)

где нужно, чтобы у OA была оболочка (axis1, axis2, ...), и индексирование выполнялось по значениям, которые попадают в диапазоны этих осей.

julia> using OffsetArrays


julia> A = Float64.(reshape(1:15, 3, 5))
3×5 Matrix{Float64}:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

julia> OA = OffsetArray(A, -1:1, 0:4) # У OA будут оси (-1:1, 0:4)
3×5 OffsetArray(::Matrix{Float64}, -1:1, 0:4) with eltype Float64 with indices -1:1×0:4:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

julia> OA = OffsetArray(A, CartesianIndex(-1, 0):CartesianIndex(1, 4))
3×5 OffsetArray(::Matrix{Float64}, -1:1, 0:4) with eltype Float64 with indices -1:1×0:4:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

julia> OA[-1,0], OA[1,4]
(1.0, 15.0)

Вы также можете передать целые числа в качестве смещений, где 0 означает, что смещения не применяются:

julia> OA = OffsetArray(A, -2, -1)
3×5 OffsetArray(::Matrix{Float64}, -1:1, 0:4) with eltype Float64 with indices -1:1×0:4:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

При создании нового OffsetArray поверх другого OffsetArray смещения накапливаются:

julia> OOA = OffsetArray(OA, 2, 1)
3×5 OffsetArray(::Matrix{Float64}, 1:3, 1:5) with eltype Float64 with indices 1:3×1:5:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

Для особых случаев, когда требуется компенсировать смещение до обычного массива, основанного на 1, можно использовать OffsetArrays.no_offset_view(A). Кроме того, вы можете использовать Base.require_one_based_indexing, если хотите, чтобы массив не имел смещений.

julia> OffsetArrays.no_offset_view(OA)
3×5 Matrix{Float64}:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

julia> Base.require_one_based_indexing(ans)
true

julia> Base.require_one_based_indexing(OA)
ERROR: ArgumentError: offset arrays are not supported but got an array with index other than 1

OffsetArrays.Origin может оказаться удобным, чтобы напрямую указать начало координат выходного OffsetArray. Он не будет автоматически вычислять соответствующие смещения. Например:

julia> OffsetArray(A, OffsetArrays.Origin(-1, -1))
3×5 OffsetArray(::Matrix{Float64}, -1:1, -1:3) with eltype Float64 with indices -1:1×-1:3:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

julia> OffsetArray(OA, OffsetArrays.Origin(-1, -1))
3×5 OffsetArray(::Matrix{Float64}, -1:1, -1:3) with eltype Float64 with indices -1:1×-1:3:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

Эквивалентным и, возможно, более удобным, способом указать начало массива является следующий:

julia> OffsetArrays.Origin(-1, -1)(A)
3×5 OffsetArray(::Matrix{Float64}, -1:1, -1:3) with eltype Float64 with indices -1:1×-1:3:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

Иногда бывает целесообразно сместить центральную координату заданного массива на (0, 0, ...). OffsetArrays.centered является вспомогательной функцией именно для этой цели:

julia> Ao = OffsetArrays.centered(A)
3×5 OffsetArray(::Matrix{Float64}, -1:1, -2:2) with eltype Float64 with indices -1:1×-2:2:
 1.0  4.0  7.0  10.0  13.0
 2.0  5.0  8.0  11.0  14.0
 3.0  6.0  9.0  12.0  15.0

julia> Ao[0, 0] == 8.0
true

и OffsetArrays.center указывает на центральную координату данного массива:

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

julia> A[c...] == 8.0
true

Пример: Релятивистская нотация

Предположим, у нас есть вектор положения r = [:x, :y, :z], который естественным образом основан на единице, т. е. r[1] == :x, r[2] == :y, r[3] == :z, и мы также хотим построить релятивистский вектор положения, который включает время как 0-ю компоненту. Это можно сделать с помощью OffsetArrays следующим образом:

julia> r = [:x, :y, :z];

julia> x = OffsetVector([:t, r...], 0:3)
4-element OffsetArray(::Vector{Symbol}, 0:3) with eltype Symbol with indices 0:3:
 :t
 :x
 :y
 :z

julia> x[0]
:t

julia> x[1:3]
3-element Vector{Symbol}:
 :x
 :y
 :z

Пример: Многочлены

Предположим, необходимо представить многочлен Лорана.

Коэффициенты этого многочлена представляют собой естественным образом основанный на -1 список, поскольку n-й элемент списка (считая от -1) 6, 5, -2, 3, 1 является коэффициентом, соответствующим n-й степени x. Этот многочлен Лорана может быть вычислен в точке x = 2 следующим образом.

julia> coeffs = OffsetVector([6, 5, -2, 3, 1], -1:3)
5-element OffsetArray(::Vector{Int64}, -1:3) with eltype Int64 with indices -1:3:
  6
  5
 -2
  3
  1

julia> polynomial(x, coeffs) = sum(coeffs[n]*x^n for n in eachindex(coeffs))
polynomial (generic function with 1 method)

julia> polynomial(2.0, coeffs)
24.0

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