Vectorizing groups of function calls



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








2















I am trying to write a functionality, (using macro, generated function or something), that effectively vectorizes Julia function calls to functions that I've written. Basically, I'm trying to write my own version of the @. macro, but instead, I'd like it to accept functions instead of a for loop--- if I understand this correctly. Here are some documents that I've read on the subject:



https://docs.julialang.org/en/v1/manual/functions/#man-vectorized-1



https://github.com/JuliaLang/julia/blob/master/base/broadcast.jl



https://julialang.org/blog/2017/01/moredots



https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#Code-Generation-1



Here is my preliminary toy example that I'm working with to achieve such a functionality:



function add!(v_add::VectorFloat64, a_add::Float64, j::Int64)
v_add[j] = v_add[j]+a_add
end

function add!(v_add::VectorFloat64, a_add::Float64)
for j in 1:length(v_add)
v_add[j] = v_add[j]+a_add
end
end

macro vectorize(args)
print("n****************** argsn")
print(args)
print("n******************n")
e = :(:call,
$args[1],
$args[2],
$args[3])
print("n****************** expressionn")
show(e)
print(e)
print("n******************n")
return e
end

function test!(v_test, a_test)
# # Traverse vector twice
# add!(v_test, a_test)
# add!(v_test, a_test)
# Traverse vector once
args = [
add!, v_test, a_test,
add!, v_test, a_test
]
e = @vectorize(args)
# eval(e) # Next step
end

v_main = Vector([Float64(i) for i in 1:3])
a_main = Float64(2.0)
print("n",v_main, "n")
Main.test!(v_main, a_main)
print("n",v_main, "n")


The problem I'm having so far is that I can't even get the de-vectorized version running using macros. This example results in the LoadError: UndefVarError: args not defined. I would definitely appreciate any help in getting this script working as expected (input is [1, 2, 3], and output should be [5, 6, 7]).



Any help/suggestions are greatly appreciated.



Update



More concretely, given the following defined functions:



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end
function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end


I would like to be able to use a macro to convert the following lines of code:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
@vectorize_I_would_like_to_define(
# I don't know the exact form that the args to this macro should take.
add!(v, a),
add!(v, b)
)


To generate code that is compiled like this:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
add!(v, a, j)
add!(v, b, j)
end


My goal is to write code that requires a single memory traversal.



Even better, if I could generate code that looks like this at compile time:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
v[j]+= a # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= b # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
end


But I'm not sure if this is as feasable for more complex cases that I'm considering compared to this toy example.



** Update 2**



Here is a MWE of @Bogumił Kamiński's solution---except that I've moved the macro call into a function, so now it doesn't work because it complains that v_test is not defined.



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end

function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

function test!(v_test, a_test, b_test)
@vectorize(
add!(v_test, a_test),
add!(v_test, b_test)
)
end

test!(v, a, b)









share|improve this question
























  • I am not 100% clear what you want to achieve. Could you please give a description of an input and expected processing workflow?

    – Bogumił Kamiński
    Nov 15 '18 at 6:56











  • @BogumiłKamiński, I added a more concrete example of the functionality that I'm looking to achieve.

    – Charles
    Nov 15 '18 at 16:04











  • EDIT and EDIT 2 in my answer work with your example (I leave both of them as I think it is helpful to analyze the difference between them).

    – Bogumił Kamiński
    Nov 15 '18 at 22:09

















2















I am trying to write a functionality, (using macro, generated function or something), that effectively vectorizes Julia function calls to functions that I've written. Basically, I'm trying to write my own version of the @. macro, but instead, I'd like it to accept functions instead of a for loop--- if I understand this correctly. Here are some documents that I've read on the subject:



https://docs.julialang.org/en/v1/manual/functions/#man-vectorized-1



https://github.com/JuliaLang/julia/blob/master/base/broadcast.jl



https://julialang.org/blog/2017/01/moredots



https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#Code-Generation-1



Here is my preliminary toy example that I'm working with to achieve such a functionality:



function add!(v_add::VectorFloat64, a_add::Float64, j::Int64)
v_add[j] = v_add[j]+a_add
end

function add!(v_add::VectorFloat64, a_add::Float64)
for j in 1:length(v_add)
v_add[j] = v_add[j]+a_add
end
end

macro vectorize(args)
print("n****************** argsn")
print(args)
print("n******************n")
e = :(:call,
$args[1],
$args[2],
$args[3])
print("n****************** expressionn")
show(e)
print(e)
print("n******************n")
return e
end

function test!(v_test, a_test)
# # Traverse vector twice
# add!(v_test, a_test)
# add!(v_test, a_test)
# Traverse vector once
args = [
add!, v_test, a_test,
add!, v_test, a_test
]
e = @vectorize(args)
# eval(e) # Next step
end

v_main = Vector([Float64(i) for i in 1:3])
a_main = Float64(2.0)
print("n",v_main, "n")
Main.test!(v_main, a_main)
print("n",v_main, "n")


The problem I'm having so far is that I can't even get the de-vectorized version running using macros. This example results in the LoadError: UndefVarError: args not defined. I would definitely appreciate any help in getting this script working as expected (input is [1, 2, 3], and output should be [5, 6, 7]).



Any help/suggestions are greatly appreciated.



Update



More concretely, given the following defined functions:



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end
function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end


I would like to be able to use a macro to convert the following lines of code:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
@vectorize_I_would_like_to_define(
# I don't know the exact form that the args to this macro should take.
add!(v, a),
add!(v, b)
)


To generate code that is compiled like this:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
add!(v, a, j)
add!(v, b, j)
end


My goal is to write code that requires a single memory traversal.



Even better, if I could generate code that looks like this at compile time:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
v[j]+= a # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= b # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
end


But I'm not sure if this is as feasable for more complex cases that I'm considering compared to this toy example.



** Update 2**



Here is a MWE of @Bogumił Kamiński's solution---except that I've moved the macro call into a function, so now it doesn't work because it complains that v_test is not defined.



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end

function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

function test!(v_test, a_test, b_test)
@vectorize(
add!(v_test, a_test),
add!(v_test, b_test)
)
end

test!(v, a, b)









share|improve this question
























  • I am not 100% clear what you want to achieve. Could you please give a description of an input and expected processing workflow?

    – Bogumił Kamiński
    Nov 15 '18 at 6:56











  • @BogumiłKamiński, I added a more concrete example of the functionality that I'm looking to achieve.

    – Charles
    Nov 15 '18 at 16:04











  • EDIT and EDIT 2 in my answer work with your example (I leave both of them as I think it is helpful to analyze the difference between them).

    – Bogumił Kamiński
    Nov 15 '18 at 22:09













2












2








2








I am trying to write a functionality, (using macro, generated function or something), that effectively vectorizes Julia function calls to functions that I've written. Basically, I'm trying to write my own version of the @. macro, but instead, I'd like it to accept functions instead of a for loop--- if I understand this correctly. Here are some documents that I've read on the subject:



https://docs.julialang.org/en/v1/manual/functions/#man-vectorized-1



https://github.com/JuliaLang/julia/blob/master/base/broadcast.jl



https://julialang.org/blog/2017/01/moredots



https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#Code-Generation-1



Here is my preliminary toy example that I'm working with to achieve such a functionality:



function add!(v_add::VectorFloat64, a_add::Float64, j::Int64)
v_add[j] = v_add[j]+a_add
end

function add!(v_add::VectorFloat64, a_add::Float64)
for j in 1:length(v_add)
v_add[j] = v_add[j]+a_add
end
end

macro vectorize(args)
print("n****************** argsn")
print(args)
print("n******************n")
e = :(:call,
$args[1],
$args[2],
$args[3])
print("n****************** expressionn")
show(e)
print(e)
print("n******************n")
return e
end

function test!(v_test, a_test)
# # Traverse vector twice
# add!(v_test, a_test)
# add!(v_test, a_test)
# Traverse vector once
args = [
add!, v_test, a_test,
add!, v_test, a_test
]
e = @vectorize(args)
# eval(e) # Next step
end

v_main = Vector([Float64(i) for i in 1:3])
a_main = Float64(2.0)
print("n",v_main, "n")
Main.test!(v_main, a_main)
print("n",v_main, "n")


The problem I'm having so far is that I can't even get the de-vectorized version running using macros. This example results in the LoadError: UndefVarError: args not defined. I would definitely appreciate any help in getting this script working as expected (input is [1, 2, 3], and output should be [5, 6, 7]).



Any help/suggestions are greatly appreciated.



Update



More concretely, given the following defined functions:



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end
function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end


I would like to be able to use a macro to convert the following lines of code:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
@vectorize_I_would_like_to_define(
# I don't know the exact form that the args to this macro should take.
add!(v, a),
add!(v, b)
)


To generate code that is compiled like this:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
add!(v, a, j)
add!(v, b, j)
end


My goal is to write code that requires a single memory traversal.



Even better, if I could generate code that looks like this at compile time:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
v[j]+= a # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= b # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
end


But I'm not sure if this is as feasable for more complex cases that I'm considering compared to this toy example.



** Update 2**



Here is a MWE of @Bogumił Kamiński's solution---except that I've moved the macro call into a function, so now it doesn't work because it complains that v_test is not defined.



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end

function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

function test!(v_test, a_test, b_test)
@vectorize(
add!(v_test, a_test),
add!(v_test, b_test)
)
end

test!(v, a, b)









share|improve this question
















I am trying to write a functionality, (using macro, generated function or something), that effectively vectorizes Julia function calls to functions that I've written. Basically, I'm trying to write my own version of the @. macro, but instead, I'd like it to accept functions instead of a for loop--- if I understand this correctly. Here are some documents that I've read on the subject:



https://docs.julialang.org/en/v1/manual/functions/#man-vectorized-1



https://github.com/JuliaLang/julia/blob/master/base/broadcast.jl



https://julialang.org/blog/2017/01/moredots



https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#Code-Generation-1



Here is my preliminary toy example that I'm working with to achieve such a functionality:



function add!(v_add::VectorFloat64, a_add::Float64, j::Int64)
v_add[j] = v_add[j]+a_add
end

function add!(v_add::VectorFloat64, a_add::Float64)
for j in 1:length(v_add)
v_add[j] = v_add[j]+a_add
end
end

macro vectorize(args)
print("n****************** argsn")
print(args)
print("n******************n")
e = :(:call,
$args[1],
$args[2],
$args[3])
print("n****************** expressionn")
show(e)
print(e)
print("n******************n")
return e
end

function test!(v_test, a_test)
# # Traverse vector twice
# add!(v_test, a_test)
# add!(v_test, a_test)
# Traverse vector once
args = [
add!, v_test, a_test,
add!, v_test, a_test
]
e = @vectorize(args)
# eval(e) # Next step
end

v_main = Vector([Float64(i) for i in 1:3])
a_main = Float64(2.0)
print("n",v_main, "n")
Main.test!(v_main, a_main)
print("n",v_main, "n")


The problem I'm having so far is that I can't even get the de-vectorized version running using macros. This example results in the LoadError: UndefVarError: args not defined. I would definitely appreciate any help in getting this script working as expected (input is [1, 2, 3], and output should be [5, 6, 7]).



Any help/suggestions are greatly appreciated.



Update



More concretely, given the following defined functions:



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end
function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end


I would like to be able to use a macro to convert the following lines of code:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
@vectorize_I_would_like_to_define(
# I don't know the exact form that the args to this macro should take.
add!(v, a),
add!(v, b)
)


To generate code that is compiled like this:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
add!(v, a, j)
add!(v, b, j)
end


My goal is to write code that requires a single memory traversal.



Even better, if I could generate code that looks like this at compile time:



v = [Float64(j) for j in 1:10]
a = 1
b = 2
for j in 1:length(v)
v[j]+= a # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= b # taken from add!(v::VectorFloat64, a::Float64, j::Int64)
end


But I'm not sure if this is as feasable for more complex cases that I'm considering compared to this toy example.



** Update 2**



Here is a MWE of @Bogumił Kamiński's solution---except that I've moved the macro call into a function, so now it doesn't work because it complains that v_test is not defined.



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end

function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

function test!(v_test, a_test, b_test)
@vectorize(
add!(v_test, a_test),
add!(v_test, b_test)
)
end

test!(v, a, b)






function macros julia vectorization metaprogramming






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 20:15







Charles

















asked Nov 14 '18 at 19:31









CharlesCharles

4071032




4071032












  • I am not 100% clear what you want to achieve. Could you please give a description of an input and expected processing workflow?

    – Bogumił Kamiński
    Nov 15 '18 at 6:56











  • @BogumiłKamiński, I added a more concrete example of the functionality that I'm looking to achieve.

    – Charles
    Nov 15 '18 at 16:04











  • EDIT and EDIT 2 in my answer work with your example (I leave both of them as I think it is helpful to analyze the difference between them).

    – Bogumił Kamiński
    Nov 15 '18 at 22:09

















  • I am not 100% clear what you want to achieve. Could you please give a description of an input and expected processing workflow?

    – Bogumił Kamiński
    Nov 15 '18 at 6:56











  • @BogumiłKamiński, I added a more concrete example of the functionality that I'm looking to achieve.

    – Charles
    Nov 15 '18 at 16:04











  • EDIT and EDIT 2 in my answer work with your example (I leave both of them as I think it is helpful to analyze the difference between them).

    – Bogumił Kamiński
    Nov 15 '18 at 22:09
















I am not 100% clear what you want to achieve. Could you please give a description of an input and expected processing workflow?

– Bogumił Kamiński
Nov 15 '18 at 6:56





I am not 100% clear what you want to achieve. Could you please give a description of an input and expected processing workflow?

– Bogumił Kamiński
Nov 15 '18 at 6:56













@BogumiłKamiński, I added a more concrete example of the functionality that I'm looking to achieve.

– Charles
Nov 15 '18 at 16:04





@BogumiłKamiński, I added a more concrete example of the functionality that I'm looking to achieve.

– Charles
Nov 15 '18 at 16:04













EDIT and EDIT 2 in my answer work with your example (I leave both of them as I think it is helpful to analyze the difference between them).

– Bogumił Kamiński
Nov 15 '18 at 22:09





EDIT and EDIT 2 in my answer work with your example (I leave both of them as I think it is helpful to analyze the difference between them).

– Bogumił Kamiński
Nov 15 '18 at 22:09












1 Answer
1






active

oldest

votes


















1














Is this what you want?



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end


and now



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

@vectorize(add!(v, a), add!(v, b))


Note that I have changed a and b definitions as your add! required Float64 as a second argument.



EDIT: If you want to use this macro inside a function the simplest thing to do is to esc its whole return value:



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
esc(quote
for j in 1:length(v)
$expr
end
end)
end


Then you can define e.g.:



function f()
v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0
@vectorize(add!(v, a), add!(v, b))
v
end


and run f() to get the same result as above in global scope.



EDIT 2: I just realized that actually I have to sanitize j as otherwise the following code will fail:



test!(v_test, j, b_test) =
@vectorize(add!(v_test, j), add!(v_test, b_test))


Here is how you should do it:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, j)
expr = :($expr; $a)
end
esc(quote
for $j in 1:length(v)
$expr
end
end)
end


As you can see developing macros is a non-obvious task (hopefully the final recipe is bug-free :)).



EDIT 3: Here is the code that correctly handles length. Also now in each expression actually you can pass a different value as a first argument (so you can independently process different vectors). If you do want to process the same vector check is a.args[2] is always the same symbol:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
var = a.args[2]
push!(a.args, j)
q = quote
for $j in 1:length($var)
$a
end
end
expr = :($expr; $q)
end
esc(expr)
end





share|improve this answer

























  • This is precisely what I need, except that I need the macro called within a function. I'll add a version of what I mean to the question.

    – Charles
    Nov 15 '18 at 20:12











  • I have added an example how to make all variables be resolved in macro call environment (including j - but in this case it is not a problem as j is guaranteed to be local to the for loop anyway and will not leak out). In a more complex situation you might have to be more careful and escape out only the variables that need to be resolved in macro call environment.

    – Bogumił Kamiński
    Nov 15 '18 at 21:04











  • Actually j should be sanitized - see my EDIT 2. Your example works cleanly now.

    – Bogumił Kamiński
    Nov 15 '18 at 22:08











  • This is close enough. The only thing that I would argue looks like is being cheated (which I suspect required some careful attention anyway) is the length(v) statement, which seems to use the scope for which v is defined. But I at least have an idea how this can be circumvented. Thanks!

    – Charles
    Nov 15 '18 at 22:44






  • 1





    This is easily changed - as you note. I did multiple loops on purpose to allow for possibility of varying size of the vector.

    – Bogumił Kamiński
    Nov 16 '18 at 19:45











Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307532%2fvectorizing-groups-of-function-calls%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














Is this what you want?



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end


and now



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

@vectorize(add!(v, a), add!(v, b))


Note that I have changed a and b definitions as your add! required Float64 as a second argument.



EDIT: If you want to use this macro inside a function the simplest thing to do is to esc its whole return value:



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
esc(quote
for j in 1:length(v)
$expr
end
end)
end


Then you can define e.g.:



function f()
v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0
@vectorize(add!(v, a), add!(v, b))
v
end


and run f() to get the same result as above in global scope.



EDIT 2: I just realized that actually I have to sanitize j as otherwise the following code will fail:



test!(v_test, j, b_test) =
@vectorize(add!(v_test, j), add!(v_test, b_test))


Here is how you should do it:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, j)
expr = :($expr; $a)
end
esc(quote
for $j in 1:length(v)
$expr
end
end)
end


As you can see developing macros is a non-obvious task (hopefully the final recipe is bug-free :)).



EDIT 3: Here is the code that correctly handles length. Also now in each expression actually you can pass a different value as a first argument (so you can independently process different vectors). If you do want to process the same vector check is a.args[2] is always the same symbol:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
var = a.args[2]
push!(a.args, j)
q = quote
for $j in 1:length($var)
$a
end
end
expr = :($expr; $q)
end
esc(expr)
end





share|improve this answer

























  • This is precisely what I need, except that I need the macro called within a function. I'll add a version of what I mean to the question.

    – Charles
    Nov 15 '18 at 20:12











  • I have added an example how to make all variables be resolved in macro call environment (including j - but in this case it is not a problem as j is guaranteed to be local to the for loop anyway and will not leak out). In a more complex situation you might have to be more careful and escape out only the variables that need to be resolved in macro call environment.

    – Bogumił Kamiński
    Nov 15 '18 at 21:04











  • Actually j should be sanitized - see my EDIT 2. Your example works cleanly now.

    – Bogumił Kamiński
    Nov 15 '18 at 22:08











  • This is close enough. The only thing that I would argue looks like is being cheated (which I suspect required some careful attention anyway) is the length(v) statement, which seems to use the scope for which v is defined. But I at least have an idea how this can be circumvented. Thanks!

    – Charles
    Nov 15 '18 at 22:44






  • 1





    This is easily changed - as you note. I did multiple loops on purpose to allow for possibility of varying size of the vector.

    – Bogumił Kamiński
    Nov 16 '18 at 19:45















1














Is this what you want?



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end


and now



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

@vectorize(add!(v, a), add!(v, b))


Note that I have changed a and b definitions as your add! required Float64 as a second argument.



EDIT: If you want to use this macro inside a function the simplest thing to do is to esc its whole return value:



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
esc(quote
for j in 1:length(v)
$expr
end
end)
end


Then you can define e.g.:



function f()
v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0
@vectorize(add!(v, a), add!(v, b))
v
end


and run f() to get the same result as above in global scope.



EDIT 2: I just realized that actually I have to sanitize j as otherwise the following code will fail:



test!(v_test, j, b_test) =
@vectorize(add!(v_test, j), add!(v_test, b_test))


Here is how you should do it:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, j)
expr = :($expr; $a)
end
esc(quote
for $j in 1:length(v)
$expr
end
end)
end


As you can see developing macros is a non-obvious task (hopefully the final recipe is bug-free :)).



EDIT 3: Here is the code that correctly handles length. Also now in each expression actually you can pass a different value as a first argument (so you can independently process different vectors). If you do want to process the same vector check is a.args[2] is always the same symbol:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
var = a.args[2]
push!(a.args, j)
q = quote
for $j in 1:length($var)
$a
end
end
expr = :($expr; $q)
end
esc(expr)
end





share|improve this answer

























  • This is precisely what I need, except that I need the macro called within a function. I'll add a version of what I mean to the question.

    – Charles
    Nov 15 '18 at 20:12











  • I have added an example how to make all variables be resolved in macro call environment (including j - but in this case it is not a problem as j is guaranteed to be local to the for loop anyway and will not leak out). In a more complex situation you might have to be more careful and escape out only the variables that need to be resolved in macro call environment.

    – Bogumił Kamiński
    Nov 15 '18 at 21:04











  • Actually j should be sanitized - see my EDIT 2. Your example works cleanly now.

    – Bogumił Kamiński
    Nov 15 '18 at 22:08











  • This is close enough. The only thing that I would argue looks like is being cheated (which I suspect required some careful attention anyway) is the length(v) statement, which seems to use the scope for which v is defined. But I at least have an idea how this can be circumvented. Thanks!

    – Charles
    Nov 15 '18 at 22:44






  • 1





    This is easily changed - as you note. I did multiple loops on purpose to allow for possibility of varying size of the vector.

    – Bogumił Kamiński
    Nov 16 '18 at 19:45













1












1








1







Is this what you want?



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end


and now



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

@vectorize(add!(v, a), add!(v, b))


Note that I have changed a and b definitions as your add! required Float64 as a second argument.



EDIT: If you want to use this macro inside a function the simplest thing to do is to esc its whole return value:



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
esc(quote
for j in 1:length(v)
$expr
end
end)
end


Then you can define e.g.:



function f()
v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0
@vectorize(add!(v, a), add!(v, b))
v
end


and run f() to get the same result as above in global scope.



EDIT 2: I just realized that actually I have to sanitize j as otherwise the following code will fail:



test!(v_test, j, b_test) =
@vectorize(add!(v_test, j), add!(v_test, b_test))


Here is how you should do it:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, j)
expr = :($expr; $a)
end
esc(quote
for $j in 1:length(v)
$expr
end
end)
end


As you can see developing macros is a non-obvious task (hopefully the final recipe is bug-free :)).



EDIT 3: Here is the code that correctly handles length. Also now in each expression actually you can pass a different value as a first argument (so you can independently process different vectors). If you do want to process the same vector check is a.args[2] is always the same symbol:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
var = a.args[2]
push!(a.args, j)
q = quote
for $j in 1:length($var)
$a
end
end
expr = :($expr; $q)
end
esc(expr)
end





share|improve this answer















Is this what you want?



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
quote
for j in 1:length(v)
$expr
end
end
end


and now



function add!(v::VectorFloat64, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end

function add!(v::VectorFloat64, a::Float64, j::Int64)
v[j]+= a
end

v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0

@vectorize(add!(v, a), add!(v, b))


Note that I have changed a and b definitions as your add! required Float64 as a second argument.



EDIT: If you want to use this macro inside a function the simplest thing to do is to esc its whole return value:



macro vectorize(args...)
expr = :()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, :j)
expr = :($expr; $a)
end
esc(quote
for j in 1:length(v)
$expr
end
end)
end


Then you can define e.g.:



function f()
v = [Float64(j) for j in 1:10]
a = 1.0
b = 2.0
@vectorize(add!(v, a), add!(v, b))
v
end


and run f() to get the same result as above in global scope.



EDIT 2: I just realized that actually I have to sanitize j as otherwise the following code will fail:



test!(v_test, j, b_test) =
@vectorize(add!(v_test, j), add!(v_test, b_test))


Here is how you should do it:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
push!(a.args, j)
expr = :($expr; $a)
end
esc(quote
for $j in 1:length(v)
$expr
end
end)
end


As you can see developing macros is a non-obvious task (hopefully the final recipe is bug-free :)).



EDIT 3: Here is the code that correctly handles length. Also now in each expression actually you can pass a different value as a first argument (so you can independently process different vectors). If you do want to process the same vector check is a.args[2] is always the same symbol:



macro vectorize(args...)
expr = :()
j = gensym()
for arg in args
a = deepcopy(arg) # for safety in case arg is also used somewhere else
var = a.args[2]
push!(a.args, j)
q = quote
for $j in 1:length($var)
$a
end
end
expr = :($expr; $q)
end
esc(expr)
end






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 16 '18 at 6:23

























answered Nov 15 '18 at 19:00









Bogumił KamińskiBogumił Kamiński

15.5k21422




15.5k21422












  • This is precisely what I need, except that I need the macro called within a function. I'll add a version of what I mean to the question.

    – Charles
    Nov 15 '18 at 20:12











  • I have added an example how to make all variables be resolved in macro call environment (including j - but in this case it is not a problem as j is guaranteed to be local to the for loop anyway and will not leak out). In a more complex situation you might have to be more careful and escape out only the variables that need to be resolved in macro call environment.

    – Bogumił Kamiński
    Nov 15 '18 at 21:04











  • Actually j should be sanitized - see my EDIT 2. Your example works cleanly now.

    – Bogumił Kamiński
    Nov 15 '18 at 22:08











  • This is close enough. The only thing that I would argue looks like is being cheated (which I suspect required some careful attention anyway) is the length(v) statement, which seems to use the scope for which v is defined. But I at least have an idea how this can be circumvented. Thanks!

    – Charles
    Nov 15 '18 at 22:44






  • 1





    This is easily changed - as you note. I did multiple loops on purpose to allow for possibility of varying size of the vector.

    – Bogumił Kamiński
    Nov 16 '18 at 19:45

















  • This is precisely what I need, except that I need the macro called within a function. I'll add a version of what I mean to the question.

    – Charles
    Nov 15 '18 at 20:12











  • I have added an example how to make all variables be resolved in macro call environment (including j - but in this case it is not a problem as j is guaranteed to be local to the for loop anyway and will not leak out). In a more complex situation you might have to be more careful and escape out only the variables that need to be resolved in macro call environment.

    – Bogumił Kamiński
    Nov 15 '18 at 21:04











  • Actually j should be sanitized - see my EDIT 2. Your example works cleanly now.

    – Bogumił Kamiński
    Nov 15 '18 at 22:08











  • This is close enough. The only thing that I would argue looks like is being cheated (which I suspect required some careful attention anyway) is the length(v) statement, which seems to use the scope for which v is defined. But I at least have an idea how this can be circumvented. Thanks!

    – Charles
    Nov 15 '18 at 22:44






  • 1





    This is easily changed - as you note. I did multiple loops on purpose to allow for possibility of varying size of the vector.

    – Bogumił Kamiński
    Nov 16 '18 at 19:45
















This is precisely what I need, except that I need the macro called within a function. I'll add a version of what I mean to the question.

– Charles
Nov 15 '18 at 20:12





This is precisely what I need, except that I need the macro called within a function. I'll add a version of what I mean to the question.

– Charles
Nov 15 '18 at 20:12













I have added an example how to make all variables be resolved in macro call environment (including j - but in this case it is not a problem as j is guaranteed to be local to the for loop anyway and will not leak out). In a more complex situation you might have to be more careful and escape out only the variables that need to be resolved in macro call environment.

– Bogumił Kamiński
Nov 15 '18 at 21:04





I have added an example how to make all variables be resolved in macro call environment (including j - but in this case it is not a problem as j is guaranteed to be local to the for loop anyway and will not leak out). In a more complex situation you might have to be more careful and escape out only the variables that need to be resolved in macro call environment.

– Bogumił Kamiński
Nov 15 '18 at 21:04













Actually j should be sanitized - see my EDIT 2. Your example works cleanly now.

– Bogumił Kamiński
Nov 15 '18 at 22:08





Actually j should be sanitized - see my EDIT 2. Your example works cleanly now.

– Bogumił Kamiński
Nov 15 '18 at 22:08













This is close enough. The only thing that I would argue looks like is being cheated (which I suspect required some careful attention anyway) is the length(v) statement, which seems to use the scope for which v is defined. But I at least have an idea how this can be circumvented. Thanks!

– Charles
Nov 15 '18 at 22:44





This is close enough. The only thing that I would argue looks like is being cheated (which I suspect required some careful attention anyway) is the length(v) statement, which seems to use the scope for which v is defined. But I at least have an idea how this can be circumvented. Thanks!

– Charles
Nov 15 '18 at 22:44




1




1





This is easily changed - as you note. I did multiple loops on purpose to allow for possibility of varying size of the vector.

– Bogumił Kamiński
Nov 16 '18 at 19:45





This is easily changed - as you note. I did multiple loops on purpose to allow for possibility of varying size of the vector.

– Bogumił Kamiński
Nov 16 '18 at 19:45



















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307532%2fvectorizing-groups-of-function-calls%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to how show current date and time by default on contact form 7 in WordPress without taking input from user in datetimepicker

Syphilis

Darth Vader #20