Creating Julia function from a symbolic expression (using SymEngine)

metaprogramming
#1

Hello, what would be a good way to define a Julia function based on the result of symbolic calculations?

For the moment, using lambdify in SymEngine gives a rather slow result, as compared to “brute force” parsing of the SymEngine output:

using SymEngine
@vars x

# Complicated symbolic expression here
symf = x

fl = lambdify(symf, [x])

eval(Meta.parse("fm(x)="*SymEngine.toString(symf)))

This defines two functions fl and fm which evaluate the expression in symf. However, the variant with parsing the output is 20 times faster than lambdify:

@time sum(fl(y) for y in LinRange(0., 1., 10000000))
  0.924081 seconds (50.00 M allocations: 762.940 MiB, 3.03% gc time)
@time sum(fm(y) for y in LinRange(0., 1., 10000000))
  0.041786 seconds (7 allocations: 272 bytes)
1 Like

#2

Don’t benchmark in global scope.

0 Likes

#3

Although in this case it doesn’t matter.

0 Likes

#4

The real world problem was in local scope :slight_smile:

1 Like

#5

I would guess the issue is in the call to invokelatest here.

Using this modified function definition seems to have better performance, on par with an anonymous function:

Lambdify(ex, vars=free_symbols(ex)) = eval(Expr(:function,
                         Expr(:call, gensym(), map(Symbol,vars)...),
                              convert(Expr, ex)))

But if I recall correctly, calling invokelatest was necessary to avoid a world age problem.

1 Like

#6

World age problem depends on which context scope you call it from.

0 Likes

#7

Yes, seems this is the reason.

Maybe it is a good idea to add this as “lambdify_fast” to SymEngine.jl, or rename the curent version to “lambdify_robust” ?

0 Likes