Symbolics and substitution using broadcasting

Hello everyone,

I’m trying to substitute some variables by some strings in a matrix using broadcasting. The aim is to make the visually simplify the expression such that stuff like eta(Exx,Eyy,Exy) simply reads as eta in the output. This works nice if one does one substitution at a time, e.g.:

@variables Exx, Eyy, Exy, etaf(Exx,Eyy,Exy)
E    = [Exx, Eyy, Exy]
Dv   = [2etaf 0 0; 0 2etaf 0; 0 0 2etaf]
J    = Symbolics.jacobian( Dv*E, [Exx, Eyy, Exy] )
D_xx = Differential(Exx)
subs = [D_xx(etaf)=>"XX"]                              # here, only one substitution
#subs = Dict([D_xx(etaf)=>"XX", etaf=>"eta"])            # here, two
Symbolics.substitute.( J, subs )

However, if one tries to substitute several elements at the same time using a Dict, then it errors.
This can be seen by uncommenting the second substitution line in the above example.
I was wondering whether anyone had a simple solution?

Cheers and thanks!

You can’t broadcast over a Dict, but you can pass a Dict to substitute. You also can’t substitute strings for symbols. In this case, I think you’ll want to wrap the Dict in a Ref to prevent broadcasting:

julia> η, dη... = @variables η, η_xx, η_yy, η_xy
4-element Vector{Num}:
    η
 η_xx
 η_yy
 η_xy

julia> Symbolics.substitute.(J, Ref(Dict(etaf => η, (Symbolics.gradient(etaf, E) .=> dη)...)))
3×3 Matrix{Num}:
 2η + 2Exx*η_xx       2Exx*η_yy       2Exx*η_xy
      2Eyy*η_xx  2η + 2Eyy*η_yy       2Eyy*η_xy
      2Exy*η_xx       2Exy*η_yy  2η + 2Exy*η_xy

Note that with Latexify.jl (plus a few additional subscripts for E_xx, E_yy, E_xy) gives you a string that can be pasted into LaTeX:

julia> latexify(ans) |> clipboard
\begin{equation} \left[ \begin{array}{ccc}
 2 \eta + 2 E_{xx} \eta_{xx} & 2 E_{xx} \eta_{yy} & 2 E_{xx} \eta_{xy} \\
 2 E_{yy} \eta_{xx} & 2 \eta + 2 E_{yy} \eta_{yy} & 2 E_{yy} \eta_{xy} \\
 2 E_{xy} \eta_{xx} & 2 E_{xy} \eta_{yy} & 2 \eta + 2 E_{xy} \eta_{xy} \\
 \end{array} \right] \end{equation} 

image

Thanks a lot!
That’s very a helpful answer and elegant solution.
And thanks of the additional Latex hint.
(I’m transitioning from sympy…)

If I may continue a bit on this topic. I’ve shortened it down to

ε = @variables ε_xx, ε_yy, ε_xy
@variables eta(ε[1], ε[2], ε[3])
D_v  = [2eta 0 0; 0 2eta 0; 0 0 2eta]
J    = Symbolics.jacobian( D_v*ε, ε )
Symbolics.substitute.(J, Ref(Dict(eta => η, (Symbolics.gradient(eta, ε) .=> dη)...)))

which is already super nice. But would there be a way not to do what I’ve done on line 2 (@variables eta(ε[1], ε[2], ε[3])). I’ve tried @variables eta(ε) which would be very concise but does not yield the same results.

Also, I wondered whether there was a way to display a dot on top of the unicode character \varepsilon (LateX \dot\varepsilon), but I guess that’s yet another topic…

Intuitively, the ‘splat’ ... operator should work here, but it doesn’t:

julia> @variables η(ε...)
ERROR: MethodError: no method matching value(::Num, ::Num, ::Num)
Closest candidates are:
  value(::Num) at C:\Users\alexa\.julia\packages\Symbolics\mFWWM\src\num.jl:19
  value(::Any) at C:\Users\alexa\.julia\packages\Symbolics\mFWWM\src\num.jl:18
Stacktrace:
 [1] top-level scope
   @ REPL[17]:1

I filed an issue.

You can get an overlaid dot with \varepsilon<tab>\dot<tab>, or a double-dot with \ddot:

julia> @variables ε̇ ε̈
2-element Vector{Num}:
 ε̇
 ε̈

Thanks for the hints, really appreciated! Indeed, would have been great to use a splat operator here. Let’s see!