Skip to content

Instantly share code, notes, and snippets.

@grayclhn
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grayclhn/2e43a628e67c007446e0 to your computer and use it in GitHub Desktop.
Save grayclhn/2e43a628e67c007446e0 to your computer and use it in GitHub Desktop.
Code for Julia Macros post
# Copyright (c) 2014 Gray Calhoun.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# This code accompanies a blog post at
# http://pseudotrue.com/notes/julia-macros
#
# -- Gray Calhoun 10/13/2014
x = fill(1., 80_000_000)
y = rand(80_000_000)
# Define some useful functions
getvecs(s::Symbol) = s
getvecs(e::Expr) = [[getvecs(a) for a in e.args[2:end]]...]
getindex(s::Symbol, i) = Expr(:ref, s, i)
getindex(e::Expr, i) = Expr(e.head, e.args[1], [getindex(a, i) for a in e.args[2:end]]...)
# Devectorization macro
macro our_devec(e)
vecs = getvecs(e.args[2])
check_lengths = Expr(:comparison) # Part 2
check_lengths.args = Array(Any, 2 * length(vecs) - 1)
check_lengths.args[1:2:end] = map(s -> Expr(:call, :length, s), vecs)
check_lengths.args[2:2:end] = :(==)
quote
@assert $check_lengths
firstval = $(getindex(e.args[2], 1)) # Part 1
if length($(vecs[1])) > 1 # Part 3
$(esc(e.args[1])) = similar($(vecs[1]), typeof(firstval))
$(esc(e.args[1]))[1] = firstval
@inbounds for i = 2:length($(vecs[1]))
$(esc(e.args[1]))[i] = $(getindex(e.args[2], :i))
end
else
$(esc(e.args[1])) = firstval # new but easy
end
end
end
# Define different versions of "vectorized" code
version1(x, y) = exp(-abs(x - y))
function version2(x, y)
r = similar(x)
for i = 1:length(x)
r[i] = exp(-abs(x[i] - y[i]))
end
r
end
function version3(x, y)
@assert length(x) == length(y)
firstval = exp(-abs(x[1] - y[1]))
if length(x) > 1
r = similar(x, typeof(firstval))
r[1] = firstval
@inbounds for i = 2:length(x)
r[i] = exp(-abs(x[i] - y[i]))
end
else
r = firstval
end
r
end
version4(x, y) = @our_devec r = exp(-abs(x - y))
# Compile everything
version1(x[1:2], y[1:2])
version2(x[1:2], y[1:2])
version3(x[1:2], y[1:2])
version4(x[1:2], y[1:2])
# Time!
@time version1(x, y);
@time version2(x, y);
@time version3(x, y);
@time version4(x, y);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment