How to convert a string to a symbolic expression?

How can I convert a string to a symbolic expression?

The following code fails:

using Symbolics

@variables R a A Γ ρ U Q Q1

Q = 0.5A*R*a*Γ*ρ*(U^2)
Q_string::String = repr(Q)

# how to convert Q_string back into a symbolic expression of type Num?
# this is not doing what I want to
Q1=Num(Q_string)

tree = Symbolics.unwrap(Q)
tree1 = Symbolics.unwrap(Q1)
@assert istree(tree)

# this assertion fails
@assert istree(tree1)
1 Like

OK, this works:

using Symbolics

@variables R a A Γ ρ U Q Q1

Q = 0.5A*R*a*Γ*ρ*(U^2)
Q_string::String = repr(Q)

# how to convert Q_string back into a symbolic expression of type Num?
# this is not doing what I want to
Q1 = eval(Meta.parse(Q_string))

tree = Symbolics.unwrap(Q)
tree1 = Symbolics.unwrap(Q1)
@assert istree(tree)

# this assertion fails
@assert istree(tree1)

Can someone explain the difference between eval(Meta.parse(Q_string)) and eval(Q_string)?

To my understanding, eval treats everything you throw into it as a “literal” expression – that’s probably not the most accurate way of describing it, but what I mean is this:

julia> eval(1)
1

julia> eval(Main)
Main

julia> eval("println(\"a\")")
"println(\"a\")"

julia> expr = "println(\"a\")";

julia> eval(expr)
"println(\"a\")"

If you eval something that is not of type Expr, then you will just get back the thing itself (I don’t know the proper terminology, but I guess you could say these objects are also a kind of expression that represent only themselves, you can also dump any object, as shown below to see what kind of thing it represents).

Only if you use it on an “actual” expression, eval will evaluate it depending on what the expression is, e.g.

julia> expr = :(1 + 2)
:(1 + 2)

julia> eval(expr)
3

# `dump` shows how `eval` sees things
julia> dump(expr)
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol +
    2: Int64 1
    3: Int64 2

julia> dump(3)
Int64 3

In your case:

Q = 0.5A*R*a*Γ*ρ*(U^2)
Q_string::String = repr(Q)

julia> dump(Q_string)
String "0.5A*R*a*Γ*ρ*(U^2)"

julia> dump(Meta.parse(Q_string))
Expr
  head: Symbol call
  args: Array{Any}((7,))
    1: Symbol *
    2: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol *
        2: Float64 0.5
        3: Symbol A
    3: Symbol R
    4: Symbol a
    5: Symbol Γ
    6: Symbol ρ
    7: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol ^
        2: Symbol U
        3: Int64 2

Without Meta.parse you are evaluating exactly the string you wrote, hence it evals back to a string. But Meta.parse basically does the “treat this string as if it were Julia code”-equivalent thing to turn it into an expression that represents some code. Evaluating this gives you back a symbolic object.

1 Like