Skip to content

Instantly share code, notes, and snippets.

@alsam
Last active April 13, 2016 16:47
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save alsam/8283205 to your computer and use it in GitHub Desktop.
Save alsam/8283205 to your computer and use it in GitHub Desktop.
Julia implementation Fortran-like array with arbitrary starting indices, negative or zero. Incurs a reasonable overhead vs. Base.Array, expected performance degradation should be strictly less than 2x.
# Fortran-like array with arbitrary starting indices
#
# usage:
#
# julia> include("FArray.jl")
# size (generic function with 51 methods)
#
# julia> y = FArray(Float64, -1:1, -7:7, -128:512, -5:5, -1:1, -3:3, -2:2, -1:1);
#
# julia> y[-1,-7,-128,-5,-1,-3,-2,-1] = 14
# 14
#
# julia> y[-1,-7,-128,-5,-1,-3,-2,-1] += 5
# 19.0
#
# questions, found bugs and proposals for performance improvement please send to the author
# Alexander Samoilov (alexander.samoilov@gmail.com, asamoilov@nvidia.com)
type FArray{T<:Number, N, A<:AbstractArray} <: AbstractArray
offsets::NTuple{N,Int}
array::A
o1::Int
o2::Int
o3::Int
o4::Int
o5::Int
function FArray(r::Range1{Int})
array = Array(T, length(r))
offs = (1 - minimum(r),)
new(offs, array, offs[1])
end
function FArray(r1::Range1{Int}, r2::Range1{Int})
dims = (length(r1), length(r2))
array = Array(T, dims)
offs = (1 - minimum(r1), 1 - minimum(r2))
new(offs, array, offs[1], offs[2])
end
function FArray(r1::Range1{Int}, r2::Range1{Int}, r3::Range1{Int})
dims = (length(r1), length(r2), length(r3))
array = Array(T, dims)
offs = (1 - minimum(r1), 1 - minimum(r2), 1 - minimum(r3))
new(offs, array, offs[1], offs[2], offs[3])
end
function FArray(r1::Range1{Int}, r2::Range1{Int}, r3::Range1{Int}, r4::Range1{Int})
dims = (length(r1), length(r2), length(r3), length(r4))
array = Array(T, dims)
offs = (1 - minimum(r1), 1 - minimum(r2), 1 - minimum(r3), 1 - minimum(r4))
new(offs, array, offs[1], offs[2], offs[3], offs[4])
end
function FArray(r1::Range1{Int}, r2::Range1{Int}, r3::Range1{Int}, r4::Range1{Int}, r5::Range1{Int})
dims = (length(r1), length(r2), length(r3), length(r4), length(r5))
array = Array(T, dims)
offs = (1 - minimum(r1), 1 - minimum(r2), 1 - minimum(r3), 1 - minimum(r4), 1 - minimum(r5))
new(offs, array, offs[1], offs[2], offs[3], offs[4], offs[5])
end
function FArray(r::Range1{Int}...)
dims = map((x) -> length(x), r)
array = Array(T, dims)
offs = map((x) -> 1 - minimum(x), r)
new(offs, array)
end
end
FArray(T, r::Range1{Int}...) = FArray{T, length(r,), Array{T, length(r,)}}(r...)
getindex{T<:Number}(FA::FArray{T,1}, i1::Int) = FA.array[i1+FA.o1]
getindex{T<:Number}(FA::FArray{T,2}, i1::Int, i2::Int) = FA.array[i1+FA.o1, i2+FA.o2]
getindex{T<:Number}(FA::FArray{T,3}, i1::Int, i2::Int, i3::Int) = FA.array[i1+FA.o1, i2+FA.o2, i3+FA.o3]
getindex{T<:Number}(FA::FArray{T,4}, i1::Int, i2::Int, i3::Int, i4::Int) = FA.array[i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4]
getindex{T<:Number}(FA::FArray{T,5}, i1::Int, i2::Int, i3::Int, i4::Int, i5::Int) = FA.array[i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4, i5+FA.o5]
# a generic not very efficient case
getindex{T<:Number,N}(FA::FArray{T,N}, I::Int...) = let ind = [I[i] + FA.offsets[i] for i = 1:length(I)]; return FA.array[ind...] end
setindex!{T<:Number}(FA::FArray{T,1}, x, i1::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1)
setindex!{T<:Number}(FA::FArray{T,2}, x, i1::Int, i2::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2)
setindex!{T<:Number}(FA::FArray{T,3}, x, i1::Int, i2::Int, i3::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2, i3+FA.o3)
setindex!{T<:Number}(FA::FArray{T,4}, x, i1::Int, i2::Int, i3::Int, i4::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4)
setindex!{T<:Number}(FA::FArray{T,5}, x, i1::Int, i2::Int, i3::Int, i4::Int, i5::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4, i5+FA.o5)
# a generic not very efficient case
setindex!{T<:Number,N}(FA::FArray{T,N}, x, I::Int...) = let ind = [I[i] + FA.offsets[i] for i = 1:length(I)]; arrayset(FA.array, convert(T,x), ind...) end
Base.print(a::FArray) = Base.print(a.array)
Base.display(a::FArray) = Base.display(a.array)
Base.size(a::FArray) = arraysize(a.array)
Base.size(a::FArray, d) = arraysize(a.array, d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment