How to simplify a symbolic expression

I want to simplify an expression by replacing a sub-expression with a new variable, called Q.

The following code doesn’t work:

# simplify an expression
using Symbolics

@variables t
@syms ω(t) Pg(t) Pge(t) Pgc(t)
@variables A R a b Γ ρ U J Q

expr = (0.5A*R*a*Γ*ρ*(U^2)) / (J*ω(t)) - J*((0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U) - Pgc(t) - Pge(t)) / ((J^2)*(ω(t)^2)))
# Q = 0.5A*R*a*Γ*ρ

# how to substitute 0.5A*R*a*Γ*ρ by Q in expr?
expr2 = substitute(expr, Dict([0.5A*R*a*Γ*ρ => Q]))

Q does not appear in expr2, the substitute command has no effect.

Why?

EDIT:
Is it possible to solve this task with Symbolics, or should I try other packages like GitHub - chakravala/Reduce.jl: Symbolic parser for Julia language term rewriting using REDUCE algebra ?

This needs to be done with a rule application, not substitute.

1 Like

Good suggestion, but not yet working.

using Symbolics

@variables t
@syms ω(t) Pg(t) Pge(t) Pgc(t)
@variables A R a b Γ ρ U J Q

expr = (0.5A*R*a*Γ*ρ*(U^2)) / (J*ω(t)) - J*((0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U) - Pgc(t) - Pge(t)) / ((J^2)*(ω(t)^2)))

r1 = @rule 0.5A*R*a*Γ*ρ => Q
# Q = 0.5A*R*a*Γ*ρ

# how to substitute 0.5A*R*a*Γ*ρ by Q in expr?
expr2 = r1(expr)

The output is empty.

Any suggestion how to do this correctly?

Perhaps I should ask different questions. For example:

  • is expr above actually an expression, because it is of type Num?
  • how can I iterate over the elements of such an expression?
  • what is the difference between @syms and @variables ?

Maybe you should use the package SymbolicUtils

Well, I think Symbolics re-exports SymbolicUtils, so that makes no difference…

On paper this is trivial, why is it so hard with Julia?

substitute currently only allows you to substitute variables for other expressions, not the other way around unfortunately…

To walk the expression, tree = Symbolics.unwrap(expr) which removes the Num <: Real wrapper.

Then you can use the expression walking interface: https://github.com/JuliaSymbolics/SymbolicUtils.jl/blob/master/page/interface.md

If I run this script:

using Symbolics

@variables t
@syms ω(t) Pg(t) Pge(t) Pgc(t) A
@variables R a b Γ ρ U J Q

expr = (0.5A*R*a*Γ*ρ*(U^2)) / (J*ω(t)) - J*((0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U) - Pgc(t) - Pge(t)) / ((J^2)*(ω(t)^2)))

tree = Symbolics.unwrap(expr)

function walk(tree, level=0)
    for arg in arguments(tree)
        indent = " "^level
        println(indent, arg)
        if istree(arg)
            level += 1
            walk(arg, level)
            level -= 1
        end
    end
end

walk(tree)

the output is:

(Pgc(t) + Pge(t) - 0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U)) / (J*(ω(t)^2))
 Pgc(t) + Pge(t) - 0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U)
  -0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U)
   -0.5
   A
   Γ
   ρ
   U^3
    U
    3
   b + (R*a*ω(t)) / U
    b
    (R*a*ω(t)) / U
     R*a*ω(t)
      R
      a
      ω(t)
       t
     U
  Pgc(t)
   t
  Pge(t)
   t
 J*(ω(t)^2)
  J
  ω(t)^2
   ω(t)
    t
   2
(0.5A*R*a*Γ*ρ*(U^2)) / (J*ω(t))
 0.5A*R*a*Γ*ρ*(U^2)
  0.5
  A
  R
  a
  Γ
  ρ
  U^2
   U
   2
 J*ω(t)
  J
  ω(t)
   t

So I can walk the tree. :slight_smile:

Next questions are how to identify the expression I want to replace, how to replace it, and then how to re-assemble it.

Next question: How can I check if two expressions are equal?

Q=0.5A*R*a*Γ*ρ*(U^2)
# now check if another expression is equal to Q
Q==0.5A*R*a*Γ*ρ*(U^2)
# the output is another expression, and not true or false
(0.5A*R*a*Γ*ρ*(U^2)) == (0.5A*R*a*Γ*ρ*(U^2))

EDIT:
I am using now:

repr(subexpr) == "0.5A*R*a*Γ*ρ*(U^2)"

Definitly not a robust solution, but works for now…

My current solution:

using Symbolics

@variables t
@syms ω(t) Pg(t) Pge(t) Pgc(t)
@variables R a b Γ ρ U J Q A

expr = (0.5A*R*a*Γ*ρ*(U^2)) / (J*ω(t)) - J*((0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U) - Pgc(t) - Pge(t)) / ((J^2)*(ω(t)^2)))

Qs = "0.5A*R*a*Γ*ρ"

# how to substitute 0.5A*R*a*Γ*ρ by Q in expr?

function subst(expr, from="", to="")
    sexpr = repr(expr)
    sres = replace(sexpr, from => to)
    eval(Meta.parse(sres))
end

simple = subst(expr, Qs, "Q")

Output:

(Pgc(t) + Pge(t) - 0.5A*Γ*ρ*(U^3)*(b + (R*a*ω(t)) / U)) / (J*(ω(t)^2)) + (Q*(U^2)) / (J*ω(t))

Not a good solution because it uses eval and requires to the symbolic variables to be defined globally.

I will create two issues on this topic: