Generate and evaluate functions programmatically

Hi,
I wonder what is the best way (performance-wise) to generate and evaluate functions programmatically. The functions I need are generated dynamically via a Genetic Programming algorithm (i.e., they are based on previous other functions that are quite “good”, but with little changes here and there).
I came up with the piece of code below and I doubt that the performance is far from optimal, but I am not sure how to improve it. For example, the current code is in global scope. How to make it non-local? When I tried to put it in a function, the world age error shows up. Base.invokelatest(f, args…) can fix that, but any better way?

f = :(function g(x,y)
       z = 1
       return z
       end)

# prev_expr is a vector of previous "good" Expr, such as :(2x + y) #
# mutation is a function to create mutation in an Expr #
now_expr = [mutation(prev_expr[i]) for i in 1:100]

# Substitute its Expr in now_expr to previously defined function f #
# and call function eval_expr( ) to evaluate its performance. #
# eval_expr() is a custom made function. #
for i in 1:100
     # substitute z = 1 by z = :(...) with (...) from now_expr #
     f.args[2].args[3].args[2] = now_expr(i)  
     # save performance in a vector arr_perf for later use # 
     arr_perf[i] = eval_expr(eval(f))                
end
...
1 Like

If you are ok with limiting the “primitives” used to construct your functions, I think the approach from DynamicExpressions.jl is good for performance (ie don’t use quoted code, use runtime values). SymbolicRegression.jl optimizes them (also with a genetic algorithm iirc).

2 Likes

DynamicExpressions.jl seems to be what I am looking for. Thank you!

1 Like