I am having trouble substituting numerical values into symbolic arrays and matrices.
I have read about lambdify
, but I still fail to provide numerical values for the arguments in a consistent way.
As an example, consider the following Julia
code
julia> using Sympy
julia> n = 4;
julia> η = [symbols("η$i", positive=true) for i in 1:n];
julia> α = [(i<3) ? 1 : symbols("α", positive=true) for i in 1:n];
julia> η .*= α
4-element Vector{Sym}:
η₁
η₂
α⋅η₃
α⋅η₄
julia> syms = Symbol.(free_symbols(tensors[:η]))
5-element Vector{Symbol}:
:α
:η1
:η2
:η3
:η4
julia> f = lambdify(η, syms)
#122 (generic function with 1 method)
julia> f.(0.5,1.0,1.0,1.0,1.0)
4-element Vector{Float64}:
1.0
1.0
0.5
0.5
As expected, the outcome is indeed the substitution for α=0.5
and all η=1.0
. However, my problem arises from the fact that I would like to feed the expressions from arrays or tuples, i.e. what I would like is:
julia> values = (0.5, 1.0, 1.0, 1.0, 1.0);
julia> f.(values)
ERROR: MethodError: no method matching var"##339"(::Float64)
Closest candidates are:
var"##339"(::Any, ::Any, ::Any, ::Any, ::Any)
@ SymPy none:0
Stacktrace:
[1] invokelatest(::Any, ::Any, ::Vararg{Any}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ Base ./essentials.jl:816
[2] invokelatest(::Any, ::Any, ::Vararg{Any})
@ Base ./essentials.jl:813
[3] (::SymPy.var"#118#119"{SymPy.var"###339"})(::Float64, ::Vararg{Float64})
@ SymPy ~/.julia/packages/SymPy/gkr7m/src/lambdify.jl:223
[4] map(::Function, ::Float64)
@ Base ./number.jl:284
[5] _broadcast_getindex_evalf
@ ./broadcast.jl:683 [inlined]
[6] _broadcast_getindex
@ ./broadcast.jl:656 [inlined]
[7] getindex
@ ./broadcast.jl:610 [inlined]
[8] copy
@ ./broadcast.jl:912 [inlined]
[9] materialize
@ ./broadcast.jl:873 [inlined]
[10] (::SymPy.var"#122#124"{Vector{SymPy.var"#118#119"}})(args::Float64)
@ SymPy ~/.julia/packages/SymPy/gkr7m/src/lambdify.jl:253
[11] _broadcast_getindex_evalf
@ ./broadcast.jl:683 [inlined]
[12] _broadcast_getindex
@ ./broadcast.jl:656 [inlined]
[13] #31
@ ./broadcast.jl:1088 [inlined]
[14] macro expansion
@ ./ntuple.jl:72 [inlined]
[15] ntuple
@ ./ntuple.jl:69 [inlined]
[16] copy
@ ./broadcast.jl:1088 [inlined]
[17] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple}, Nothing, SymPy.var"#122#124"{Vector{SymPy.var"#118#119"}}, Tuple{NTuple{5, Float64}}})
@ Base.Broadcast ./broadcast.jl:873
[18] top-level scope
@ REPL[199]:1
The reason that I want this is so that I can make all of my symbolic arrays into “lambdified” expressions and evaluate them, for example at multiple points in parallel. Additionally, when the array is instead a matrix, I also do not wish to manually input all the matrix elements – especially when the sizes of the matrices grow.
Consider for example,
julia> M = [symbols("M$i$j") for i in 1:3 for j in 1:3].reshape(3,3)
3×3 Matrix{Sym}:
M₁₁ M₁₂ M₁₃
M₂₁ M₂₂ M₂₃
M₃₁ M₃₂ M₃₃
julia> syms_M = free_symbols.(M)
3×3 Matrix{Vector{Sym}}:
[M11] [M12] [M13]
[M21] [M22] [M23]
[M31] [M32] [M33]
julia> fM = lambdify(M, syms_M)
#122 (generic function with 1 method)
How do I use fM
to return a numeric valued matrix, e.g. when Mvals = rand(3,3)
? Any help would be greatly appreciated!