# Best Practices for converting a Mathematica expression to Julia

Thanks. Never heard of this Github Copilot.
Do you have an example of how you use it? It seems like a powerful thing.

Though it would be nice to find a julia solution…

Here is something you can copy and paste to see if it works for you:

``````using SymPy
const sympy_parsing_mathematica = SymPy.PyCall.pyimport("sympy.parsing.mathematica")

s = "(Sqrt[Pi])/(2*EllipticE[m])"
ex = sympy_parsing_mathematica.mathematica(s, Dict("EllipticE[x]"=>"elliptic_e(x)"))

SymPy.walk_expression(ex) #:((1 / 2) * pi ^ (1 / 2) * elliptic_e(m) ^ -1)

# or

SymPy.convert_expr(ex, use_julia_code=true) # :(sqrt(pi) ./ (2 * elliptic_e(m)))
``````
2 Likes

That is phenomenal!

Some things still do not work as expected, though.

The `walk_expression` gives me something different, and I do not know why:

``````s = "(Sqrt[Pi])/(2*EllipticE[m])"
ex = sympy_parsing_mathematica.mathematica(s, Dict("EllipticE[x]"=>"elliptic_e(x)"))

SymPy.walk_expression(ex) # what I should get :((1 / 2) * pi ^ (1 / 2) * elliptic_e(m) ^ -1)
# what I get is
# :((1 / 2) * SymPy.__POW__(pi, 1 / 2) * SymPy.__POW__(elliptic_e(m), -1))
``````

I can fix it using

``````SymPy.walk_expression(ex, fns=Dict("Pow"=>:^))
# :((1 / 2) * pi ^ (1 / 2) * elliptic_e(m) ^ -1)
``````

The `convert_expr` does not work well.
First, I do not like that it returns all operations with the vectorized dot notion like so

``````:(sqrt(pi) ./ (2 * elliptic_e(m)))
``````

The more problematic issue is that it does not deal with this expression for some reason

``````s = "Sqrt[2]/q2 EllipticF[x, 1 - q1^2/q2^2]"
ex = sympy_parsing_mathematica.mathematica(s, Dict("EllipticF[x, y]"=>"elliptic_e(x, y)"))

SymPy.convert_expr(ex, use_julia_code=true)
``````

gives

``````Base.Meta.ParseError("use \"x^y\" instead of \"x**y\" for exponentiation, and \"x...\" instead of \"**x\" for splatting.")

Stacktrace:
[1] #parse#3
@ ./meta.jl:236 [inlined]
[2] parse
@ ./meta.jl:232 [inlined]
[3] parse(str::String; raise::Bool, depwarn::Bool)
@ Base.Meta ./meta.jl:267
[4] parse(str::String)
@ Base.Meta ./meta.jl:266
[5] convert_expr(ex::Sym; fns::Dict{Any, Any}, values::Dict{Any, Any}, use_julia_code::Bool)
@ SymPy ~/.julia/packages/SymPy/mpN0u/src/lambdify.jl:260
[6] top-level scope
@ In[37]:5
``````

Sorry, `convert_expr` has some issues like this, hence the need for `walk_expression`. However, I realize I had some unpushed changes that are causing the differences you see with my example with `walk_expression`. I just made a PR, which I hope to tag once all the tests pass.

1 Like

Thanks again!

I see that the `walk_expression` does not know how to handle `sqrt` and it gives a power of `1/2` instead as can be seen here

Is there a way to get the `sqrt` from the `walk_expression`?
(The `convert_expr` gives `sqrt`, but as you said it has some issues).

Let me also mention for completeness that in the first time I run these functions I get the following warning:

``````sys:1: SymPyDeprecationWarning:

The ``mathematica`` function for the Mathematica parser is now
The parameter ``additional_translation`` can be replaced by SymPy's
.replace( ) or .subs( ) methods on the output expression instead.

See https://docs.sympy.org/latest/explanation/active-deprecations.html#mathematica-parser-new
for details.

This has been deprecated since SymPy version 1.11. It
will be removed in a future version of SymPy.
``````

Thanks. Looks like a need to update my sympy library!

Anyways, I just registered a fix to `lambdify` that should also give back `sqrt`, as you wanted.

2 Likes

Great. I saw that the `sqrt` was fixed!

Just mentioning that the issue with `convert_expr` is still there:

And also, this issue is still thereL

I extended @gangchern’s example to a package (GitHub - musoke/WolframExpr.jl). It’s bare bones, but does the basics of converting algebraic expressions from Mathematica to Julia. You can define mappings for special functions.

Example:

``````julia> using WolframExpr

julia> f = string_to_function("A[x,y]+y", [:A, :x, :y]);

julia> A(x, y) = x^2 + y^2;

julia> f(A, 1, 2)
7
``````
2 Likes

Running now on Julia 1.9.3, with `SymPy v2.0.1`, it does not have `convert_expr` and `walk_expression`.
Does anyone know what is the alternative to these functions?

They are buried behind another module now. For `ex` coming from `sympy_parsing_mathematica.mathematica` try:

``````SymPy.SymPyCore.walk_expression(Sym(ex))
``````
1 Like

Wonderful! that indeed works! thanks so much!

I have an issue with the `//` operation. The expression I get from sympy does not have parenthesis around the numbers, which causes then an error when I copy the expression into a function.

Here is an example:

``````using SymPy
const sympy_parsing_mathematica = SymPy.PyCall.pyimport("sympy.parsing.mathematica")

s = raw"1/Sqrt[(x+y)^3]"
ex = sympy_parsing_mathematica.mathematica(s)
SymPy.SymPyCore.walk_expression(Sym(ex))
# :(((x + y) ^ 3) ^ -1//2)

# my goal is to take the above output and make a function out of it.
# I want to do it often, so I want to automate it as much as possible.
# defining
ftest(x, y) = (((x + y) ^ 3) ^ -1//2)
# then results in an error
ftest(1, 1)
``````

Here is the error:

``````MethodError: no method matching //(::Float64, ::Int64)

Closest candidates are:
//(::Integer, ::Integer)
@ Base rational.jl:62
//(::Rational, ::Integer)
@ Base rational.jl:64
//(::Complex, ::Real)
@ Base rational.jl:78
...

Stacktrace:
[1] ftest(x::Int64, y::Int64)
@ Main ./In[58]:1
[2] top-level scope
@ In[59]:1

``````

Putting parenthesis around the `//` operation will solve it, but I want to do it automatically in the parsing. Is there a way to do that?

I have found some resolution using `@generated` macro:

``````s = raw"1/Sqrt[(x+y)^3]"
ex = sympy_parsing_mathematica.mathematica(s)
f_expr = SymPy.SymPyCore.walk_expression(Sym(ex))
# :(((x + y) ^ 3) ^ -1//2)
@generated ftest(x,y) = f_expr
ftest(1,0)
# 1.
``````

UPDATE:
Let me mention that SymPyCore is not needed anymore, and one should use `f_expr = SymPy.walk_expression(Sym(ex))` in the above code.

Looks like there’s still a long way to go, but MathLink.jl now has `W2JuliaExpr`. Its approach looks roughly similar to WolframExpr.jl, which certainly has lighter dependencies, but maybe closer integration with Wolfram could enable more flexible transformations.