问题描述
对于 Julia,通常使用从 1 开始的数组是一个不错的决定,但有时希望使用类似 Fortran 的数组,其索引跨越ℤ的某些子范围:
Generally having 1-based array for Julia is a good decision, but sometimes it is desirable to have Fortran-like array with indices that span some subranges of ℤ:
julia> x = FArray(Float64, -1:1,-7:7,-128:512)
有用的地方:
在教授的书《双曲偏微分方程的数值解》中的代码中.John A. Tragenstein 这些负指数被大量用于边界条件的鬼细胞.教授的 Clawpack(代表保护法包")也是如此.Randall J. LeVeque http://depts.washington.edu/clawpack/ 还有许多其他代码这样的索引是自然的.因此,此类辅助类对于快速翻译此类代码很有用.
in the codes accompanying the book Numerical Solution of Hyperbolic Partial Differential Equations by prof. John A. Trangenstein these negative indices are used intensively for ghost cells for boundary conditions.The same is true for Clawpack (stands for "Conservation Laws Package") by prof. Randall J. LeVeque http://depts.washington.edu/clawpack/ and there are many other codes where such indices would be natural.So such auxiliary class would be useful for speedy translation of such codes.
我刚刚开始实现这种辅助类型,但由于我对 Julia 很陌生,非常感谢您的帮助.
I just started to implement such an auxiliary type but as I'm quite new to Julia your help would be greatly appreciated.
我开始:
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
输出:
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] =
...
由于我对 Julia 完全陌生,因此我将不胜感激任何建议,尤其是提高效率的建议.
As I'm completely new to Julia any recommendations especially that lead to more efficient would be greatly appreciated.
这里已经讨论过这个话题:
The topic has been discussed here:
https://groups.google.com/forum/#!主题/julia-dev/NOF6MA6tb9Y
在讨论中,阐述了两种使用任意基数的 Julia 数组的方法:基于 SubArray 的示例用法是使用辅助函数:
During the discussion two ways to have Julia arrays with arbitrary base were elaborated:SubArray-based, sample usage is with a helper function:
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
请注意,边界没有被完全检查,更多细节在这里:https://github.com/JuliaLang/julia/issues/4044
Please note, that bounds are not checked fully more details are here:https://github.com/JuliaLang/julia/issues/4044
目前 SubArray 存在性能问题,但最终其性能可能会得到改善,另请参阅:
At the moment SubArray has performance issues but eventually its performance might be improved, see also:
https://github.com/JuliaLang/julia/issues/5117
https://github.com/JuliaLang/julia/issues/3496
另一种目前性能更好的方法,除了检查两个边界:
Another approach that has better performance at the moment, besides checks both bounds:
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 和 setindex!FArray 的方法受到 base/array.jl 代码的启发.
getindex and setindex! methods for FArray were inspired by base/array.jl code.
用例:
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
推荐答案
现在有两个包可以提供这种功能.对于具有任意起始索引的数组,请参阅 https://github.com/alsam/OffsetArrays.jl.如需更多灵活性,请参阅 https://github.com/mbauman/AxisArrays.jl,其中索引不必是整数.
There are now two packages that provide this kind of functionality. For arrays with arbitrary start indices, see https://github.com/alsam/OffsetArrays.jl. For even more flexibility see https://github.com/mbauman/AxisArrays.jl, where indices do not have to be integers.
这篇关于类似 Fortran 的数组,例如 Julia 中的 FArray(Float64, -1:1,-7:7,-128:512)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!