# Substitution and simplification of terms that do not appear explicitly, using \`Symbolics.jl\` (and \`SymbolicUtils.jl\`)

**URL:** <https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458>\
**Category:** New to Julia\
**Tags:** symbolics, symbolic-utils\
**Created:** [March 22, 2023, 4:16pm UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458 "2023-03-22T16:16:29Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![johannesnauta](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannesnauta/32/47434_2.png) [@johannesnauta](https://discourse.julialang.org/u/johannesnauta)\
**Post date:** [March 22, 2023, 4:16pm UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458/1 "2023-03-22T16:16:29Z")

</div>

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
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
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!

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [March 22, 2023, 5:06pm UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458/2 "2023-03-22T17:06:10Z")

</div>

> [@johannesnauta](#):
>
> In other words, I never get the expected simplification (a+b)z(t)(a+b)z(t)(a+b)z(t). Is there a way to enforce such simplifications?

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.

---

<div class="post-metadata">

**Author:** ![johannesnauta](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannesnauta/32/47434_2.png) [@johannesnauta](https://discourse.julialang.org/u/johannesnauta)\
**Post date:** [March 23, 2023, 9:07am UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458/3 "2023-03-23T09:07:19Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [March 23, 2023, 11:47am UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458/4 "2023-03-23T11:47:51Z")

</div>

> [@johannesnauta](#):
>
> 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)f(x)=(a+b)z(t)f(x) = (a+b)z(t)? Do I just need to call a different printing function?

That’s worth an issue.

---

<div class="post-metadata">

**Author:** ![Andrew\_Swann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrew_swann/32/32106_2.png) [@Andrew\_Swann](https://discourse.julialang.org/u/Andrew_Swann)\
**Post date:** [March 23, 2023, 4:05pm UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458/5 "2023-03-23T16:05:17Z")

</div>

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
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)

```

---

<div class="post-metadata">

**Author:** ![johannesnauta](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannesnauta/32/47434_2.png) [@johannesnauta](https://discourse.julialang.org/u/johannesnauta)\
**Post date:** [March 23, 2023, 4:51pm UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458/6 "2023-03-23T16:51:08Z")

</div>

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
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
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}

---

<div class="post-metadata">

**Author:** ![lnguyen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lnguyen/32/42613_2.png) [@lnguyen](https://discourse.julialang.org/u/lnguyen)\
**Post date:** [March 23, 2023, 5:50pm UTC](https://discourse.julialang.org/t/substitution-and-simplification-of-terms-that-do-not-appear-explicitly-using-symbolics-jl-and-symbolicutils-jl/96458/7 "2023-03-23T17:50:39Z")

</div>

`simplify` comes with the `expand` keyword for cases like this!

```julia
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)

```
