Tablice podobne do Fortrana, takie jak FArray (Float64, -1: 1, -7: 7, -128: 512) w Julii

Ogólnie rzecz biorąc, posiadanie tablicy opartej na 1 dla Julii jest dobrą decyzją, ale czasami pożądane jest posiadanie tablicy podobnej do Fortrana z indeksami, które obejmują niektóre podzakresy ℤ:

julia> x = FArray(Float64, -1:1,-7:7,-128:512)

gdzie byłoby to przydatne:

w kodach towarzyszących książce Numeryczne rozwiązanie hiperbolicznych równań różniczkowych cząstkowych autorstwa prof. John A. Trangenstein te negatywne wskaźniki są intensywnie wykorzystywane do komórek widmowych w warunkach brzegowych. To samo dotyczy Clawpack (skrót od „Conservation Laws Package”) autorstwa prof. Randall J. LeVequehttp://depts.washington.edu/clawpack/i istnieje wiele innych kodów, w których takie wskaźniki byłyby naturalne. Taka klasa pomocnicza byłaby przydatna do szybkiego tłumaczenia takich kodów.

Właśnie zacząłem implementować taki typ pomocniczy, ale ponieważ jestem całkiem nowy dla Julii, twoja pomoc byłaby bardzo mile widziana.

Zacząłem od:

type FArray
    ranges
    array::Array
    function FArray(T, r::Range1{Int}...)
        dims = map((x) -> length(x), r)
        array = Array(T, dims)
        new(r, array)
    end
end

Wydajność:

julia> include ("FortranArray.jl")
julia> x = FArray(Float64, -1:1,-7:7,-128:512)
FArray((-1:1,-7:7,-128:512),3x15x641 Array{Float64,3}:
[:, :, 1] =
6.90321e-310  2.6821e-316   1.96042e-316  0.0  0.0  0.0  9.84474e-317  …  1.83233e-316  2.63285e-316  0.0           9.61618e-317  0.0        
6.90321e-310  6.32404e-322  2.63285e-316  0.0  0.0  0.0  2.63292e-316     2.67975e-316
...
[:, :, 2] =
...

Ponieważ jestem całkowicie nowy w Julii, wszelkie zalecenia, które prowadzą do zwiększenia wydajności, zostaną bardzo docenione.

[Edytować]

Temat został omówiony tutaj:

https://groups.google.com/forum/#!topic/julia-dev/NOF6MA6tb9Y

Podczas dyskusji opracowano dwa sposoby, aby tablice Julii z dowolną bazą zostały opracowane: Oparte na podzakresie, przykładowe użycie ma funkcję pomocniczą:

function farray(T, r::Range1{Int64}...)
    dims = map((x) -> length(x), r)
    array = Array(T, dims)
    sub_indices = map((x) -> -minimum(x) + 2 : maximum(x), r)
    sub(array, sub_indices)
end

julia> y[-1,-7,-128] = 777
777

julia> y[-1,-7,-128] + 33
810.0

julia> y[-2,-7,-128]
ERROR: BoundsError()
 in getindex at subarray.jl:200

julia> y[2,-7,-128]
2.3977385e-316

Pamiętaj, że granice nie są w pełni sprawdzane, więcej szczegółów jest tutaj:https://github.com/JuliaLang/julia/issues/4044

Obecnie SubArray ma problemy z wydajnością, ale w końcu jego wydajność może ulec poprawie, zobacz także:

https://github.com/JuliaLang/julia/issues/5117

https://github.com/JuliaLang/julia/issues/3496

Inne podejście, które ma obecnie lepszą wydajność, oprócz sprawdzania obu granic:

type FArray{T<:Number, N, A<:AbstractArray} <: AbstractArray

    ranges
    offsets::NTuple{N,Int}
    array::A

    function FArray(r::Range1{Int}...)
        dims = map((x) -> length(x), r)
        array = Array(T, dims)
        offs = map((x) -> 1 - minimum(x), r)
        new(r, offs, array)
    end
end

FArray(T, r::Range1{Int}...) = FArray{T, length(r,), Array{T, length(r,)}}(r...)

getindex{T<:Number}(FA::FArray{T}, i1::Int) = FA.array[i1+FA.offsets[1]]
getindex{T<:Number}(FA::FArray{T}, i1::Int, i2::Int) = FA.array[i1+FA.offsets[1], i2+FA.offsets[2]]
getindex{T<:Number}(FA::FArray{T}, i1::Int, i2::Int, i3::Int) = FA.array[i1+FA.offsets[1], i2+FA.offsets[2], i3+FA.offsets[3]]

setindex!{T}(FA::FArray{T}, x, i1::Int) = arrayset(FA.array, convert(T,x), i1+FA.offsets[1])
setindex!{T}(FA::FArray{T}, x, i1::Int, i2::Int) = arrayset(FA.array, convert(T,x), i1+FA.offsets[1], i2+FA.offsets[2])
setindex!{T}(FA::FArray{T}, x, i1::Int, i2::Int, i3::Int) = arrayset(FA.array, convert(T,x), i1+FA.offsets[1], i2+FA.offsets[2], i3+FA.offsets[3])

getindex i setindex! metody FArray zostały zainspirowane kodem base / array.jl.

Przypadków użycia:

julia> y = FArray(Float64, -1:1,-7:7,-128:512);

julia> y[-1,-7,-128] = 777
777

julia> y[-1,-7,-128] + 33
810.0

julia> y[-1,2,3]
0.0

julia> y[-2,-7,-128]
ERROR: BoundsError()
 in getindex at FortranArray.jl:27

julia> y[2,-7,-128]
ERROR: BoundsError()
 in getindex at FortranArray.jl:27

questionAnswers(1)

yourAnswerToTheQuestion