Я пытаюсь написать функциональность (используя макрос, сгенерированную функцию или что-то еще), которая эффективно векторизует вызовы функций Джулии для написанных мной функций.По сути, я пытаюсь написать свою собственную версию @.макрос, но вместо этого я хотел бы, чтобы он принимал функции вместо цикла for --- если я правильно понимаю.Вот некоторые документы, которые я прочитал по этому вопросу:
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
Вот мой предварительный игрушечный пример, с которым я работаю для достижения такой функциональности:
function add!(v_add::Vector{Float64}, a_add::Float64, j::Int64)
v_add[j] = v_add[j]+a_add
end
function add!(v_add::Vector{Float64}, 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****************** args\n")
print(args)
print("\n******************\n")
e = :(:call,
$args[1],
$args[2],
$args[3])
print("\n****************** expression\n")
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")
Проблема, с которой я до сих пор сталкиваюсь, заключается в том, что я не могу даже получитьверсия, работающая с использованием макросов.Этот пример приводит к тому, что LoadError: UndefVarError: args не определено.Я определенно буду признателен за любую помощь в том, чтобы этот скрипт работал должным образом (входные данные [1, 2, 3], а выходные данные должны быть [5, 6, 7]).
Любая помощь / предложения приветствуются.
Обновление
Более конкретно, учитывая следующие определенные функции:
function add!(v::Vector{Float64}, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end
function add!(v::Vector{Float64}, a::Float64, j::Int64)
v[j]+= a
end
Я хотел бы иметь возможность использовать макрос для преобразованияследующие строки кода:
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)
)
Чтобы сгенерировать код, скомпилированный следующим образом:
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
Моя цель - написать код, требующий одного обхода памяти.
Еще лучше, если бы я мог генерировать код, который выглядит так во время компиляции:
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::Vector{Float64}, a::Float64, j::Int64)
v[j]+= b # taken from add!(v::Vector{Float64}, a::Float64, j::Int64)
end
Но я не уверен, насколько это возможно для более сложных случаев, которые я рассматриваю по сравнению с этимпример с игрушкой.
** Обновление 2 **
Вот MWE решения @ Bogumił Kamiński - за исключением того, что я переместил вызов макроса в функцию, так что теперь он нене работает, потому что жалуется, что v_test
не определено.
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::Vector{Float64}, a::Float64)
for j in 1:length(v)
v[j]+= a
end
end
function add!(v::Vector{Float64}, 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)