Hi
I have a small problem regarding the dynamic creation of functions from expressions. My situation is the following: A process dynamically generates a random expression which is then evaluated on given samples and an error is calculated with regard to expected outputs. This information is later used to update the creation process for the expressions etc.
Here is what I currently do:
function run(X, Y, root)
s = sample(root) #Gives me the random expression
f = eval(:(x -> $s))
ev = [Base.invokelatest(f, x) for x in X]
return mse(ev, Y)
end
This works, but the expressions I get are pretty quick to evaluate, so I have the feeling that invokelatest
adds quite a bit of overhead (Testing for some small functions it seems that invokelatest
is about 10 times slower than just directly calling a function)
Is this really the best I can do in Julia? I just want to create a local function dynamically. It does not depend on any global things and it only has to be available in this scope, so I am slightly confused why this is made so difficult and also slow.
Or did I just miss something and this can be done in a fundamentally different way?
1 Like
What exactly goes wrong if you just invoke the new function?
ev = [f(x) for x in X]
You can define a function that run the rest of the current function and invokelast
that.
And no you can’t do better than that since it’s the most the compiler can infer about your code.
I get
MethodError: no method matching (::##11#12)(::Float64)
The applicable method may be too new: running in world age 31743, while current world is 31744.
Closest candidates are:
#11(::Any) atptree.jl:205 (method too new to be called from this world context.)
run(::Array{Float64,1}, ::Array{Float64,1}, ::ChoiceNode) at ptree.jl:217
include_string(::String, ::String) at loading.jl:515
eval(::Module, ::Any) at boot.jl:235
...
Which seems to be a new restriction introduced in v0.6 (if I understood that correctly(
FWIW, since f
can’t be inferred either on old versions, this is the performance you’ve got on older julia versions all along.
Hmm. Yes, that’s what I don’t really get.
I define something like f = eval(:(x -> x*x+sin(x)))
and then I want to call it on a Float64. So I would just expect that it is then compiled for a Float and executed. The problem does not seem to be that the compiler is not able to infer anything but that Julia just prevents me from calling the function I just created in a normal way.
And it is possible since in Julia v0.5 it works.
But wrapping it in another function and calling that one once using invokelatest
is probably a reasonable solution.
Thanks
OK. So it was just better hidden? Thanks!
It’s not hidden, the function f
itself is inferred, the caller is not, that also the only difference invokelatest
has.