Hi everyone.

I am encountering a problem where I want to solve and simplify a specific set of equations. Even in a very simple use case I cannot get `simplify(expr)`

to do simple substitutions if the elements to be substituted are themselves part of other expressions.

An example of the simple case is as follows. We consider the equation f(t) = ax(t) + by(t), and now let z(t) = x(t) + y(t). It is clear that f(t) = (a+b)z(t), but I cannot seem to get an expression like this when using `simplify`

, `substitute`

, or when providing a rule using `SymbolicUtils.jl`

, so my guess is that I am doing something wrong or that I am missing something (perhaps trivial).

Here is the code

```
julia> using Symbolics
julia> @variables t, a, b, x(t), y(t)
julia> f = a*x + b*y
julia> z = x + y
a*x(t) + b*y(t)
julia> substitute(f, Dict([x+y => z]))
a*x(t) + b*y(t)
julia> simplify(substitute(f, Dict([x+y => z])))
a*x(t) + b*y(t)
```

In other words, I never get the expected simplification (a+b)z(t). Is there a way to enforce such simplifications? Of course, in my real problem my equation is more complex, but the same substitution is needed to simplify.

I have noticed that with `SymbolicUtils.jl`

you can provide a ‘rule’, e.g.

```
julia> r = @rule ~x + ~y => ~z
julia> simplify(f; rewriter=r)
ERROR: Failed to apply rule ~x + ~y => ~z on expression a*x(t) + b*y(t)
caused by: KeyError: key :z not found
```

but this raises a `KeyError`

, so I suspect I am using the `@rule`

wrong. How does one use a rule for substitution? Or is this how rules should be used?

Any help or pointers would be greatly appreciated! Thanks!

That’s not quite the way to think about it. It’s just not even represented like how it’s shown. That’s how it’s printed, not how it’s stored. We should allow for some nicer ways of changing printing, but note that it’s not just an operation tree under the hood.

So what is the way to think about it? I admit that I know very little about symbolic programming in general, let alone how `Symbolics.jl`

does it – but substitutions like these are very widespread and seem very logical to me.

You also mention ‘nice ways of printing’, but does this suggest that, under the hood, the equation *is* like f(x) = (a+b)z(t)? Do I just need to call a different printing function?

Perhaps I am missing something here, but isn’t (a+b)z(t) = (a+b)(x(t)+y(t)) = ax(t) + bx(t) + ay(t) + by(t) which is not your f.

Also you z has a value before you substitute. Here are some possibilities

```
julia> using Symbolics
julia> @variables t, a, b, x(t), y(t), z(t)
6-element Vector{Num}:
t
a
b
x(t)
y(t)
z(t)
julia> f = a*x + b*x + a*y + b*y
a*x(t) + a*y(t) + b*x(t) + b*y(t)
julia> substitute(f, Dict([x+y=>z]))
a*x(t) + a*y(t) + b*x(t) + b*y(t)
julia> substitute(simplify(f), Dict([x+y=>z]))
(a + b)*z(t)
julia> substitute(f, Dict([x=>z-y]))
a*(z(t) - y(t)) + b*(z(t) - y(t)) + a*y(t) + b*y(t)
julia> simplify(substitute(f, Dict([x=>z-y])))
(a + b)*z(t)
```

1 Like

You were indeed *not* missing something – I made a stupid and very critical error. I edited my question to represent my mistake. I also learned that I should make the variable `z(t)`

and not define it as `z = x+y`

beforehand. However there are still some simplifications that are not caught by my (naive) implementation.

(Let’s just hope I am correct this time…)

First, to replicate what you have done:

```
julia> using Symbolics
julia> @variables t, a, b, c, x(t), y(t), z(t)
7-element Vector{Num}:
t
a
b
c
x(t)
y(t)
z(t)
julia> f = a*(x+y) + b*(x+y)
a*(x(t) + y(t)) + b*(x(t) + y(t))
julia> substitute(f, Dict([x+y=>z]))
a*z(t) + b*z(t)
julia> simplify(substitute(f, Dict([x+y=>z])))
(a + b)*z(t)
julia> substitute(simplify(f), Dict([x+y=>z]))
(a + b)*z(t)
```

But consider

```
julia> g = (a+b)*x + (a+c)*y
(a + b)*x(t) + (a + c)*y(t)
julia> h = g - b*x - c*y
(a + b)*x(t) + (a + c)*y(t) - b*x(t) - c*y(t)
julia> simplify(substitute(h, Dict([x+y=>z])))
(a + b)*x(t) + (a + c)*y(t) - b*x(t) - c*y(t)
julia> substitute(simplify(h), Dict([x+y=>z]))
(a + b)*x(t) + (a + c)*y(t) - b*x(t) - c*y(t)
julia> simplify(h)
(a + b)*x(t) + (a + c)*y(t) - b*x(t) - c*y(t)
```

Even though here it is obvious that the result should be

\begin{align}
h(t) &= (a+b)x(t) + (a+c)y(t) - bx(t) - cy(t) \\
&= ax(t) + ay(t) + bx(t) + cy(t) - bx(t) - cy(t) \\
&= az(t)
\end{align}

`simplify`

comes with the `expand`

keyword for cases like this!

```
julia> substitute(simplify(h), Dict([x+y=>z]))
(a + b)*x(t) + (a + c)*y(t) - b*x(t) - c*y(t)
julia> substitute(simplify(h, expand=true), Dict([x+y=>z]))
a*z(t)
```

1 Like