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