如何简化 sympy 向量?

How to simplify sympy vectors?

我正在使用 sympy 进行一些符号向量计算,但我无法以适当的方式简化向量 class 的参数。考虑这段代码:

from sympy.physics.mechanics import ReferenceFrame, dot, cross
from sympy import symbols, sin, cos, simplify

alpha, theta, l = symbols('alpha theta l')

def Rodrigues(v, k, angle):
    return cos(angle) * v + cross(k, v) * sin(angle) + k * dot(k, v) * (1- cos(angle))

N = ReferenceFrame('N')
P0 = -l * N.y

P2 = Rodrigues(
    Rodrigues(P0, -N.z, alpha), 
    Rodrigues(N.x, -N.z, alpha), 
    theta)

哪个returns:

         

尝试 simplify(P2) 我得到错误:

AttributeError: 'function' object has no attribute 'x'

我认为这是因为 simplify 需要一个 sympy 表达式对象。尝试 dir(P2) 有一个 simplify 方法 returns:

<bound method Vector.simplify of - l*sin(alpha)*cos(theta)*N.x - l*cos(alpha)*cos(theta)*N.y + (-l*sin(alpha)**2 - l*cos(alpha)**2)*sin(theta)*N.z>

我不知道它是什么!尝试 P2.args 我得到:

[(Matrix([
  [                       -l*sin(alpha)*cos(theta)],
  [                       -l*cos(alpha)*cos(theta)],
  [(-l*sin(alpha)**2 - l*cos(alpha)**2)*sin(theta)]]), N)]

这是具有嵌套 3x1 sympy 矩阵的二维元组的一维列表!我不知道是谁的选择让向量 class 如此晦涩,但现在我可以用 simplify(P2.args[0][0][2]) 简化最后一个元素并将函数更改为:

def Rodrigues(v, k, angle):
    tmpVec = cos(angle) * v + cross(k, v) * sin(angle) + k * dot(k, v) * (1- cos(angle))
    tmpFrame = tmpVec.args[0][1]
    return simplify(tmpVec.args[0][0][0]) * tmpFrame.x + simplify(tmpVec.args[0][0][1]) * tmpFrame.y + simplify(tmpVec.args[0][0][2]) * tmpFrame.z

这对我来说似乎是一个非常糟糕的解决方案。

我想知道您是否可以帮助我了解是否有更 Pythonic 的方法来执行此操作。例如,强制 sympy 默认简化所有表达式。或者我可能以错误的方式使用了 vector.simplify 方法?提前感谢您的支持。

P.S。 Rodrigues旋转公式

您需要像 print(P2.simplify()) 一样调用此方法,而不是 print(P2.simplify)。之后你将得到 - l*sin(alpha)*cos(theta)*N.x - l*cos(alpha)*cos(theta)*N.y - l*sin(theta)*N.z 作为输出,这与你的 def Rodrigues.

的上一个版本相同

另一种解决方案是默认强制 sympy 简化所有向量:

from sympy.physics.vector import Vector
Vector.simp = True

更多信息here