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
.