# Symbolics substitute - what has changed?

**URL:** <https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826>\
**Category:** Modelling & Simulations\
**Created:** [July 9, 2024, 1:42pm UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826 "2024-07-09T13:42:08Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [July 9, 2024, 1:42pm UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/1 "2024-07-09T13:42:08Z")

</div>

What has changed with Symbolics substitute? In the past, I could compose two substitutions, but that doesn’t seem to work any more.

Concretely, I consider:

```julia
Asn = substitute(As, Dict(name_s .=> s_ss)) |> x -> substitute(x, default_vals) 

```

Here,

```julia
julia> Dict(name_s .=> s_ss)
Dict{SymbolicUtils.BasicSymbolic{Real}, Float64} with 5 entries:
  md_e(t) => 2.00009
  V(t) => 2.40023
  m(t) => 2.40023
  md_i(t) => 2.0
  h(t) => 0.480045

```

while:

```julia
julia> default_vals = ModelingToolkit.defaults(tank)
Dict{Any, Any} with 5 entries:
  h_ς => 3
  K => 5
  m(t) => 1.5A*ρ
  A => 5
  ρ => 1

```

It still works to do:

```julia
substitute(As, Dict(name_s .=> s_ss))

```

and

```julia
substitute(As, default_vals)

```

individually, but I cannot compose the substitutions – I get:

```julia
julia> substitute(As, Dict(name_s .=> s_ss)) |> x -> substitute(x, default_vals)
1×1 Matrix{SymbolicUtils.BasicSymbolic{Real}}:
 (-K) / (2A*h_ς*sqrt(0.48004505680494347 / h_ς)*ρ)

```

thus the second substitution is not carried out. Similarly:

```julia
julia> substitute(As, default_vals) |> x -> substitute(x, Dict(name_s .=> s_ss))
1×1 Matrix{SymbolicUtils.BasicSymbolic{Real}}:
 -1 / (6sqrt((1//3)*h(t)))

```

and, again, the second substitution is not carried out.

HOWEVER, if I _merge_ the dictionaries, and only carry out one substitute, things seems to work:

```julia
julia> substitute(As, merge(default_vals, Dict(name_s .=> s_ss)))
1×1 Matrix{Float64}:
 -0.41664711213839595

```

**Question 1** : What has changed wrt. `substitute`?

* * *

In the past, I also needed to pipe the result through an `unwrap` function. That doesn’t seem to be the case any more… In other words, in the past, I needed to do:

```julia
Asn = substitute(As, Dict(name_s .=> s_ss)) |> x -> substitute(x, default_vals) |> x -> Symbolics.unwrap.(x)

```

to get the proper matrix, while now, both

```julia
substitute(As, merge(default_vals, Dict(name_s .=> s_ss)))

```

and

```julia
substitute(As, merge(default_vals, Dict(name_s .=> s_ss))) |> x -> Symbolics.unwrap.(x)

```

seems to give the same result.

**Question 2:** Has the `unwrap` function been made redundant?

---

<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:** [July 10, 2024, 3:24am UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/2 "2024-07-10T03:24:08Z")

</div>

My understanding is nothing has changed here in a long time. Do you have a version where it worked differently? I would suspect something about the pipe syntax there.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [July 10, 2024, 6:22am UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/3 "2024-07-10T06:22:37Z")

</div>

Hm. OK, will check. I see from the documentation of piping that it says that piping in combination with anonymous functions requires the anonymous functions to be wrapped in parenthesis. I don’t recall that this was a requirement in the past.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [July 10, 2024, 10:52am UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/4 "2024-07-10T10:52:36Z")

</div>

> [@BLI](#):
>
> `Asn = substitute(As, Dict(name_s .=> s_ss)) |> x -> substitute(x, default_vals) |> x -> Symbolics.unwrap.(x)`

It is not possible changes in the piping operation that causes the change in behavior – so I assume it is either in Symbolics or in ModelingToolkit. The following code used to work some months ago:

```julia
mats, tank_ = ModelingToolkit.linearize_symbolic(tank, [md_i], [h])
mats.A

```

leading to:  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/7/1/71e1392ee9b1a704446aea5e0fe03408502a8bc3.png)

where:

```julia
julia> typeof(mats.A)
Matrix{Num} (alias for Array{Num, 2})

```

OBSERVE that here, the A matrix `mats.A` is produced by MTK. If I now substitute initial value unknowns + parameters:

```julia
substitute(mats.A, Dict(name_s .=> s_ss)) |> (x -> substitute(x, default_vals)) |> (x -> Symbolics.unwrap.(x))

```

this **used** to produce:

```julia
1×1 Matrix{Float64}:
 -0.41664711213839595

```

But now it produces:

```julia
1×1 Matrix{SymbolicUtils.BasicSymbolic{Real}}:
 (-K) / (2A*h_ς*NaNMath.sqrt(2.4002252840247174 / (A*h_ς*ρ))*ρ)

```

Even if I merge the dictionaries, and only substitute one time:

```julia
julia> substitute(mats.A, merge(Dict(name_s .=> s_ss), default_vals))
1×1 Matrix{SymbolicUtils.BasicSymbolic{Real}}:
 -1 / (6NaNMath.sqrt(0.1A*ρ))

```

On the other hand, if I produce the A matrix using my own symbolic linearization function (which only works for index 1 problems), I get the same A matrix (my linearization function has simplified the expression by utilizing that `m(t) = rho*A*h(t)`):  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/8/c8def55a29a6a286d7751f489cf1f56efa8a5cbe.png)

```julia
julia> typeof(As)
Matrix{Num} (alias for Array{Num, 2})

```

Next, for my linearization, the following **used to work** (but doesn’t work any more):

```julia
julia> substitute(As, Dict(name_s .=> s_ss)) |> x -> substitute(x, default_vals) |> x -> Symbolics.unwrap.(x)
substitute(As, Dict(name_s .=> s_ss)) |> x -> substitute(x, default_vals) |> x -> Symbolics.unwrap.(x)

```

HOWEVER, the following _works_ for my linearized model:

```julia
julia> substitute(As, merge(Dict(name_s .=> s_ss), default_vals))
1×1 Matrix{Float64}:
 -0.41664711213839595

```

So…

1. To me, it looks like something _has_ changed, either in `Symbolics` or the type of objects produced by `ModelingToolkit`, or as a consequence of other changes in Julia: it doesn’t work to `substitute` numeric values for symbolic values in a sequence of substitutions (`substitute(substitute(As, ...), ...)` produces the same result as when using piping).
2. The linearized symbolic matrices produced by my _own_ linearization function seem to correctly substitute numeric values for symbols when I _merge_ dictionaries for unknowns and parameters, and only substitute one time.
3. The linearized symbolic matrices produced by MTK seem to be the same as from my own linearization function, but substituting merged dictionaries for some weird reason does not work for the symbolic matrix produced by MTK.

For MTK, this is not a big problem, I guess, because it is possible to use numeric linearization (a different function than symbolic linearization) and get the correct results.

It is still puzzling that substitution of numeric values into the symbolic MTK matrix doesn’t seem to work for my case.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [July 11, 2024, 6:53am UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/5 "2024-07-11T06:53:46Z")

</div>

It looks like the element type of the returned matrices are no longer `Num`, does it work if you first do `Num.(A)`?

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [July 11, 2024, 9:55am UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/6 "2024-07-11T09:55:53Z")

</div>

Yes, then it works. A small caveat… I have streamlined the code slightly:

```julia
op_par = ModelingToolkit.defaults(tank) # tank is the model
name_s = unknowns(tank) # I use "_s" because I wrote the code when unknowns were still known as "states". 
op_unk = Dict(name_s .=> s_ss) # s_ss is the steady state/unknowns
op_point = merge(op_par, op_unk)

```

The following _works_:

```julia
julia> substitute(Num.(substitute(mats.A, op_unk)), op_par)
1×1 Matrix{Float64}:
 -0.416647112138396

```

What is still weird, is that the following does not work:

```julia
julia> substitute(mats.A, op_point)
1×1 Matrix{SymbolicUtils.BasicSymbolic{Real}}:
 -1 / (6NaNMath.sqrt(0.1A*ρ))

```

– here, if I use the `Num` mapping on this result, it is converted into a `Num` matrix, but the values for A and rho are still not inserted. Which is contrary to when I did the similar thing to the matrix generated from my own symbolic linearization function.

**In Summary** : something has changed in that substitution does not return a `Num` matrix any more. I don’t know whether that change lies in `Symbolics` or elsewhere, and whether it is intentional or not.

* * *

I have another problem with _numeric_ linearization, but I’ll open another thread for that problem.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [July 11, 2024, 10:45am UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/7 "2024-07-11T10:45:46Z")

</div>

I meant to call Num on A _before_ calling substitute.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [July 11, 2024, 2:15pm UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/8 "2024-07-11T14:15:14Z")

</div>

Ah. OK. But:  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/e/6e7a58fdd117901b28dd0b4a177bf132f3860ff1.png)

So it seems to me that the matrix _is_ of type `Num` when returned from the linearize function, and that `substitute` converts it into another type.

I tried to apply `Num` to the matrix prior to first `substitute`, but that had no effect.

---

<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:** [February 20, 2025, 6:01pm UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/9 "2025-02-20T18:01:39Z")

</div>

did you open an issue for this?

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [February 21, 2025, 11:11am UTC](https://discourse.julialang.org/t/symbolics-substitute-what-has-changed/116826/10 "2025-02-21T11:11:51Z")

</div>

It’s a long time ago… I don’t remember. Possibly not. Maybe I should post such questions as issues instead; I guess that makes it easier for developers to track.
