-
-
Save jayschwa/5250636 to your computer and use it in GitHub Desktop.
module ImmutableArrays | |
export Vector2, Vector3, Vector4 | |
importall Base | |
for n = 2:4 | |
local Typ = symbol(string("Vector", n)) | |
local TypT = Expr(:curly, Typ, :T) | |
local definition = :(immutable $TypT <: AbstractVector{T} end) | |
for i = 1:n | |
element = symbol(string("e", i)) | |
push!(definition.args[3].args, :($element::T)) | |
end | |
eval(definition) | |
@eval function getindex(x::$Typ, i::Integer) | |
element = symbol(string("e", i)) | |
return x.(element) | |
end | |
@eval -(a::$Typ) = $Typ(ntuple($n, x-> -a[x])...) | |
@eval +(a::$Typ, b::$Typ) = $Typ(ntuple($n, x-> a[x]+b[x])...) | |
@eval -(a::$Typ, b::$Typ) = $Typ(ntuple($n, x-> a[x]-b[x])...) | |
@eval .*{T}(a::$TypT, b::Number) = $TypT(ntuple($n, x-> convert(T, a[x]*b))...) | |
@eval .*(a::Number, b::$Typ) = .*(b, a) | |
@eval ./{T}(a::$TypT, b::Number) = $TypT(ntuple($n, x-> convert(T, a[x]/b))...) | |
@eval similar{T}(::$TypT, t::DataType, dims::Dims) = Array(t, dims) | |
@eval size(::$Typ) = ($n,) | |
end | |
end |
I tested this one a bit and the operations are really inefficient.
Here's a benchmark with the operations as defined in this gist. It takes almost one second to add together two 3-vectors a hundred thousand times. The equivalent loop for two ordinary Julia Vectors takes about 0.02 seconds.
julia> require("src/ImmutableArrays.jl")
julia> using ImmutableArrays
julia> a = Vector3(0.1, 0.2, 5.0) ; b = Vector3(-0.1, 0.8, 15.0) ;
julia> a+b
3-element Float64 Vector3:
0.0
1.0
20.0
julia> @elapsed for i = 1:100000
c = a + b
end
0.884444887
Then I defined a sum function explicitly:
julia> p(a::Vector3, b::Vector3) = Vector3(a.e1 + b.e1, a.e2 + b.e2, a.e3 + b.e3)
# methods for generic function p
p(a::Vector3{T},b::Vector3{T}) at none:1
julia> p(a,b)
3-element Float64 Vector3:
0.0
1.0
20.0
julia> @elapsed for i = 1:100000
c = p(a,b)
end
0.004634279
Performance increase of a factor of 200 over the definition of this gist, and a factor of 5 to Julia Vectors. I suppose it's the call to ntuple
that makes it slow?
Forgot to add, it's probably not about the getindex
. I tried to get rid of it that by replacing the ntuple($n, x-> a[x]+b[x])
by ntuple($n, x-> a.(symbol(string("e", x)))+b.(symbol(string("e", x))))
and it didn't affect the numbers. But I'm not sure if I did that right.
@dronir: Would you mind retrying this exercise with what I put in the repo. Even better, if you could make a benchmark script to go in the test directory to automate what you've done here, that would be awesome.
I've defined the arithmetic in terms of a higher-order function (zipWith) that I guess I'm hoping gets inlined away. If it doesn't we'll brute force the inlining in the automatic code generation.
Knock yourself out.