Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ImmutableArrays prototype using metaprogramming
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
@twadleigh

This comment has been minimized.

Copy link

twadleigh commented Mar 27, 2013

It looks good. Nowhere near as unreadable as I was afraid it was going to be. The only concern I'd have (and I'm not sure it's valid) is defining the arithmetic in terms of getindex. I'm sure there are better definitions of getindex, but any definition is going to involve switching on the int argument. I'm no expert, but I think the optimal definition of the arithmetic operations involves mapping over the members directly. (I presume you would also agree with me that the arithmetic needs to be defined to be as fast as possible.)

In any case, this is a really good starting point, and, with your permission, I'll paste it into my module.

@jayschwa

This comment has been minimized.

Copy link
Owner Author

jayschwa commented Mar 27, 2013

In any case, this is a really good starting point, and, with your permission, I'll paste it into my module.

Knock yourself out.

@dronir

This comment has been minimized.

Copy link

dronir commented Mar 27, 2013

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?

@dronir

This comment has been minimized.

Copy link

dronir commented Mar 27, 2013

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.

@twadleigh

This comment has been minimized.

Copy link

twadleigh commented Mar 27, 2013

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.