I am trying to use Symbolics to define and manipulate my problem before moving to numerical methods to actually solve my problem.
After initial manipulations, I want to replace all symbolic variables with their actual values. This worked well for me as long as I used matrices of scalar symbolic variables. I am now trying to move to symbolic arrays, and substitute
no longer substitutes all symbolic variables. I tried build_function
which managed better, but which also seems to only work on sufficiently simple expressions.
The behaviour I expected is that all symbolic variables are replaced by numerical values in all cases.
I fail to solve my problem using either of substitute
or build_function
, with build_function
managing more complicated expressions, but not the ones I need it for.
I would appreciate any help.
The following is the smallest test case I have showing the issue:
import Pkg
Pkg.activate(".")
Pkg.add("Symbolics")
Pkg.status(outdated=true)
import Symbolics
import Symbolics: @variables, get_variables, substitute, build_function
@variables K[1:2, 1:2]
exprs = [ -K[1,1] -(K[1,1]) (-K)[1,1] ]
subs = Dict(K[1,1] => 1)
for expr in exprs
println("------------------------")
@show expr get_variables(expr)
try
@show substitute(expr, subs)
catch e
@show e
end
f = build_function(expr, K, expression = false)
@show f([1 2; 3 4])
end
@variables A[1:2, 1:2] B[1:2, 1:1] P[1:2, 1:2]
Pre1 = A*[1.0 0.0 0.0; 0.0 1.0 0.0]
Pre2 = broadcast(+, A*[1.0 0.0 0.0; 0.0 1.0 0.0], B*[0.0 0.0 1.0])
Post = Symbolics.Num[1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 (broadcast(-, K))[1, 1] (broadcast(-, K))[1, 2]]
for expr in [ Pre1, Pre2, Post, Pre1*Post, Pre2*Post ]
println("---------------------------")
@show expr
fs = build_function(expr, A, B, K, P, expression=false)
for f in fs
try
value = f(randn(2,2), randn(2,1), randn(1,2), randn(2,2))
@show value unique(vcat(get_variables.(value)...))
catch e
end
end
end
The output I get is
Status `~/Workspace/Project.toml`
⌅ [0c5d862f] Symbolics v5.14.1 (<v5.16.1): julia
------------------------
expr = -K[1, 1]
get_variables(expr) = Any[K[1, 1]]
substitute(expr, subs) = -1
f([1 2; 3 4]) = -1
------------------------
expr = -K[1, 1]
get_variables(expr) = Any[K[1, 1]]
substitute(expr, subs) = -1
f([1 2; 3 4]) = -1
------------------------
expr = (broadcast(-, K))[1, 1]
get_variables(expr) = Any[(broadcast(-, K))[1, 1]]
e = MethodError(Core.kwcall, ((metadata = nothing,), SymbolicUtils.similarterm, broadcast(-, K), broadcast, Any[-, K], AbstractMatrix{Real}), 0x0000000000008337)
f([1 2; 3 4]) = -1
---------------------------
expr = (A*[1.0 0.0 0.0; 0.0 1.0 0.0])[Base.OneTo(2),Base.OneTo(3)]
value = [0.8426921154384049 1.3855828533066428 0.0; 2.245360817652516 0.45372334877928383 0.0]
unique(vcat(get_variables.(value)...)) = Any[]
---------------------------
expr = (broadcast(+, A*[1.0 0.0 0.0; 0.0 1.0 0.0], B*[0.0 0.0 1.0]))[Base.OneTo(2),Base.OneTo(3)]
value = [1.3634561500672868 -1.1694430577347337 1.6690534965623611; 1.581800165321597 1.1989213984343103 0.8634154223268747]
unique(vcat(get_variables.(value)...)) = Any[]
---------------------------
expr = Symbolics.Num[1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 (broadcast(-, K))[1, 1] (broadcast(-, K))[1, 2]]
value = [1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 -0.4432466306968838 0.3592732607253264]
unique(vcat(get_variables.(value)...)) = Any[]
---------------------------
expr = ((A*[1.0 0.0 0.0; 0.0 1.0 0.0])*Symbolics.Num[1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 (broadcast(-, K))[1, 1] (broadcast(-, K))[1, 2]])[Base.OneTo(2),Base.OneTo(4)]
value = Symbolics.Num[-1.873960325836164 1.416262070648973 0.0 0.0; -1.4423420994229887 -0.31731200550770267 0.0 0.0]
unique(vcat(get_variables.(value)...)) = Any[]
---------------------------
expr = (broadcast(+, A*[1.0 0.0 0.0; 0.0 1.0 0.0], B*[0.0 0.0 1.0])*Symbolics.Num[1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 (broadcast(-, K))[1, 1] (broadcast(-, K))[1, 2]])[Base.OneTo(2),Base.OneTo(4)]
value = Symbolics.Num[0.45315331007912363 -1.367295212832985 0.20383264427229145(broadcast(-, K))[1, 1] 0.20383264427229145(broadcast(-, K))[1, 2]; -1.3151182967142874 -1.1121032853446047 -0.25979763416747165(broadcast(-, K))[1, 1] -0.25979763416747165(broadcast(-, K))[1, 2]]
unique(vcat(get_variables.(value)...)) = Any[(broadcast(-, K))[1, 1], (broadcast(-, K))[1, 2]]
The first part of the output shows that substitute
works for me in some cases, but fails as soon as broadcast
is introduced into the expressions.
The second part of the output shows that build_function
manages to replace all symbolic variables in the expressions Pre1
, Pre2
, Post
and Pre1*Post
, but fails in Pre2*Post
.