问题
I have an expression of type Mul
called term
in the code below. Within term
is a type Symbol
called zhat
. I want to perform something like term.subs(zhat, vec)
where vec
is of type BaseVector
. I am subbing a symbol for a vector. The output is assigned to out_actual
in the code.
The issue is that out_actual
is of type Mul
when I need it to be of type VectorMul
. The variable out_ideal
is what I would expect from the substitution. Any way to obtain out_ideal
?
import sympy as sp
from sympy.vector import CoordSys3D
N = CoordSys3D('N')
Q, eps, zhat = sp.symbols('Q \epsilon_0 \\hat{\\mathbf{z}}')
vec = N.k
term = Q*eps*zhat
out_ideal = Q*eps*vec
out_actual = term.subs(zhat, vec)
回答1:
It's not particularly pleasant or generalizable, but you could do the following to convert any Mul
into a VectorMul
whenever appropriate (and leaving it as a Mul
otherwise):
import sympy as sp
from sympy.vector import CoordSys3D
from sympy.core.mul import Mul
N = CoordSys3D('N')
def multiply_args(obj):
'''Gets the result of multiplying all of the Mul's args together.'''
if not isinstance(obj, Mul):
raise ValueError('Input must be an instance of Mul')
args = obj.args
prod = args[0]
for e in args[1:]:
prod = prod * e
return prod
Q, eps, zhat = sp.symbols('Q \epsilon_0 \\hat{\\mathbf{z}}')
vec = N.k
term = Q*eps*zhat
sub_result = term.subs(zhat, vec)
sub_result = multiply_args(sub_result)
The reason this is necessary is that subs
, a method which belongs to the Basic
class, simply looks at all of the arguments (e.g. Q
, eps
, zhat
) of the Mul
object (term
) and replaces each that matches the substitution target, and gives the result as a Mul
but with an amended list of args
(i.e. zhat
has been replaced with vec
). It doesn't do any further evaluation on the result, and leaves the argument as a Mul
.
To convert it to a VectorMul
, you can just multiply the resulting arguments together manually, like you did to get out_ideal
. All multiply_args
does is manually multiplies the arguments together, which then promotes to a VectorMul
if any of the arguments is a Vector
. Obviously this only works because you know you have started with a Mul
; you'd need to generalize this to deal with other types if you needed to.
If could be worth putting in a feature reqeust to the SymPy Github repository for this functionality.
来源:https://stackoverflow.com/questions/62844801/sympy-substitute-symbol-for-vector