我可以在 sympy 中使用符号叉积运算吗
Can I use symbolic cross product operations in sympy
嗨,
我正在尝试编写用于计算 3D 多项式的符号库
以分析方式(变量是实数值 t,多项式的单项式是 3D 向量)。特别是,我想计算两个多项式的叉积(在 that question 的跟进中)。在 Sympy 中,我发现我可以:
- 使用 sympy.physics.mechanics 包中的显式向量变量(具有实数值),在本例中定义了叉积。
- 使用矩阵符号,但没有为这些符号定义叉积。
有什么方法可以象征性地表示 sympy 中的叉积?
编辑:特别是,我感兴趣的是使两个相同向量的叉积无效,并在根据其中一个向量分解多项式时考虑反对易属性。
新编辑:
为了让自己更清楚,我想留在"symbolic level"上。那是,
我不想沿着每个变量开发我的向量项。
例如,这里是计算贝塞尔曲线的代码:
from sympy import *
init_printing(use_unicode=True)
from scipy.special import binom
#default control points of a Bezier curve
p_is = [symbols('p'+str(i)) for i in range(5)]
class Bezier:
#eq is the equation of the curve, pis are the stored control point
#for special purpose such as the derivatives
def __init__(self, deg, eq = None, pis = None):
assert(deg)
self.deg = deg;
n_pts = deg +1
if pis == None:
self.pis = p_is[:n_pts]
else:
self.pis = pis[:];
if eq == None:
#computing the bernstein polynoms for a given degree
factors = [binom(deg,i) * t**i * (1-t)**(deg-i)*pis[i] for i in range(n_pts)]
self.eq = sum(factors);
else:
self.eq = eq
def __repr__(self):
res = "Degree : " + str(self.deg)
res += "\nEquation : " + self.eq.__repr__()
res += "\nwaypoints :\n" + str(self.pis)
return res
def __str__(self):
return self.__repr__()
b = Bezier(3)
print b
# Degree : 3
# Equation : 1.0*p0*(-t + 1)**3 + 3.0*p1*t*(-t + 1)**2 + 3.0*p2*t**2*(-t + 1) + 1.0*p3*t**3
# waypoints :
# [p0, p1, p2, p3]
print b.eq
# 1.0*p0*(-t + 1)**3 + 3.0*p1*t*(-t + 1)**2 + 3.0*p2*t**2*(-t + 1) + 1.0*p3*t**3
正如你所看到的,变量 p_is 是矢量这一事实并不真正相关,除非出现叉积的情况。
如果我要计算 b 与自身的叉积,那么几个项将消失,因为一些向量将与自身交叉。
我试图做的是 "emulate" 叉积与一个简单的乘法,然后遍历生成的方程以删除所有平方项(对应于零)。但这还不够
因为乘积不保留叉积的反交换方面。
我真正想要的是实际的叉积符号(比如 X)出现在等式中。我希望我更清楚
非常感谢您的帮助
史蒂夫
我找到了适合我的情况的解决方案(我只应用一次叉积,需要一些思考才能考虑扩展)。这个想法是使用额外的符号来表示实现叉积的偏斜对称矩阵。比如p0 ^ p1会写成Cp0 * p1。我实现了一种实现此目的的方法,并且还确保如果 pi ^ pi = 0.
为了更好地分解,我根据符号的字母顺序引入了任意顺序的转换。
这意味着 p2 ^ p1 将被写成 -Cp1 * p2
这样做的原因是 sympy 不会检测到其他简化,例如 Cp2 ^ p1 + Cp1 ^p2 = 0。
无论如何,这有点老套,但就我而言,它允许我编写我的库,所以就在这里。
执行叉积的方法是 "cross",在文件末尾。
#declaring vector symbols variables
p_is = [symbols('p'+str(i)) for i in range(20)]
#the cross product will be represented
#by the skew symmetric matrix Cpi for a vector pi.
#Since in the resulting equation, symbols seem to appeer
#in alphabetic order, the matrix multiplication will be coherent
p_isX = [symbols('Cp'+str(i)+'') for i in range(20)]
#achieves the cross product between two elements
#s0 and s1 are the considered vector symbols (here, two pis)
#e0 and e1 are the scalar multiplier of each term
def crossElement(s0,e0,s1,e1):
if s0 == s1:
return 0
else:
# here, take order of apparition into account to allow
# future factorization. Otherwise
# something like p0 X p1 + p1 X p0 will not be dientified as zero
id0 = p_is.index(s0)
id1 = p_is.index(s1)
if(id0 < id1):
return simplify(e1*e0*p_isX[id0]*s1)
else:
return simplify((-e1)*e0*p_isX[id1]*s0)
#retrieve all the pis and associate scalar factors
#from an equation
def getAllSymbols(eq):
res = []
for el in p_is:
dic = eq.as_poly(el).as_dict()
if(len(dic) > 1):
res += [(el, dic[(1,)])]
return res;
#generates the cross product of two equations,
#where each pi term is a vector, and others
#are scalar variable.
#cross product
def cross(eq1,eq2):
decomp1 = getAllSymbols(eq1)
decomp2 = getAllSymbols(eq2)
res = 0
#applies distributive cross product between
#all terms of both equations
for (s0, e0) in decomp1:
for (s1, e1) in decomp2:
res += crossElement(s0,e0,s1,e1)
return res
嗨,
我正在尝试编写用于计算 3D 多项式的符号库 以分析方式(变量是实数值 t,多项式的单项式是 3D 向量)。特别是,我想计算两个多项式的叉积(在 that question 的跟进中)。在 Sympy 中,我发现我可以:
- 使用 sympy.physics.mechanics 包中的显式向量变量(具有实数值),在本例中定义了叉积。
- 使用矩阵符号,但没有为这些符号定义叉积。
有什么方法可以象征性地表示 sympy 中的叉积?
编辑:特别是,我感兴趣的是使两个相同向量的叉积无效,并在根据其中一个向量分解多项式时考虑反对易属性。
新编辑: 为了让自己更清楚,我想留在"symbolic level"上。那是, 我不想沿着每个变量开发我的向量项。
例如,这里是计算贝塞尔曲线的代码:
from sympy import *
init_printing(use_unicode=True)
from scipy.special import binom
#default control points of a Bezier curve
p_is = [symbols('p'+str(i)) for i in range(5)]
class Bezier:
#eq is the equation of the curve, pis are the stored control point
#for special purpose such as the derivatives
def __init__(self, deg, eq = None, pis = None):
assert(deg)
self.deg = deg;
n_pts = deg +1
if pis == None:
self.pis = p_is[:n_pts]
else:
self.pis = pis[:];
if eq == None:
#computing the bernstein polynoms for a given degree
factors = [binom(deg,i) * t**i * (1-t)**(deg-i)*pis[i] for i in range(n_pts)]
self.eq = sum(factors);
else:
self.eq = eq
def __repr__(self):
res = "Degree : " + str(self.deg)
res += "\nEquation : " + self.eq.__repr__()
res += "\nwaypoints :\n" + str(self.pis)
return res
def __str__(self):
return self.__repr__()
b = Bezier(3)
print b
# Degree : 3
# Equation : 1.0*p0*(-t + 1)**3 + 3.0*p1*t*(-t + 1)**2 + 3.0*p2*t**2*(-t + 1) + 1.0*p3*t**3
# waypoints :
# [p0, p1, p2, p3]
print b.eq
# 1.0*p0*(-t + 1)**3 + 3.0*p1*t*(-t + 1)**2 + 3.0*p2*t**2*(-t + 1) + 1.0*p3*t**3
正如你所看到的,变量 p_is 是矢量这一事实并不真正相关,除非出现叉积的情况。 如果我要计算 b 与自身的叉积,那么几个项将消失,因为一些向量将与自身交叉。
我试图做的是 "emulate" 叉积与一个简单的乘法,然后遍历生成的方程以删除所有平方项(对应于零)。但这还不够 因为乘积不保留叉积的反交换方面。
我真正想要的是实际的叉积符号(比如 X)出现在等式中。我希望我更清楚
非常感谢您的帮助
史蒂夫
我找到了适合我的情况的解决方案(我只应用一次叉积,需要一些思考才能考虑扩展)。这个想法是使用额外的符号来表示实现叉积的偏斜对称矩阵。比如p0 ^ p1会写成Cp0 * p1。我实现了一种实现此目的的方法,并且还确保如果 pi ^ pi = 0.
为了更好地分解,我根据符号的字母顺序引入了任意顺序的转换。 这意味着 p2 ^ p1 将被写成 -Cp1 * p2 这样做的原因是 sympy 不会检测到其他简化,例如 Cp2 ^ p1 + Cp1 ^p2 = 0。
无论如何,这有点老套,但就我而言,它允许我编写我的库,所以就在这里。
执行叉积的方法是 "cross",在文件末尾。
#declaring vector symbols variables
p_is = [symbols('p'+str(i)) for i in range(20)]
#the cross product will be represented
#by the skew symmetric matrix Cpi for a vector pi.
#Since in the resulting equation, symbols seem to appeer
#in alphabetic order, the matrix multiplication will be coherent
p_isX = [symbols('Cp'+str(i)+'') for i in range(20)]
#achieves the cross product between two elements
#s0 and s1 are the considered vector symbols (here, two pis)
#e0 and e1 are the scalar multiplier of each term
def crossElement(s0,e0,s1,e1):
if s0 == s1:
return 0
else:
# here, take order of apparition into account to allow
# future factorization. Otherwise
# something like p0 X p1 + p1 X p0 will not be dientified as zero
id0 = p_is.index(s0)
id1 = p_is.index(s1)
if(id0 < id1):
return simplify(e1*e0*p_isX[id0]*s1)
else:
return simplify((-e1)*e0*p_isX[id1]*s0)
#retrieve all the pis and associate scalar factors
#from an equation
def getAllSymbols(eq):
res = []
for el in p_is:
dic = eq.as_poly(el).as_dict()
if(len(dic) > 1):
res += [(el, dic[(1,)])]
return res;
#generates the cross product of two equations,
#where each pi term is a vector, and others
#are scalar variable.
#cross product
def cross(eq1,eq2):
decomp1 = getAllSymbols(eq1)
decomp2 = getAllSymbols(eq2)
res = 0
#applies distributive cross product between
#all terms of both equations
for (s0, e0) in decomp1:
for (s1, e1) in decomp2:
res += crossElement(s0,e0,s1,e1)
return res