是否可以在 SymPy 中构建反通勤的符号?
Is it possible to construct symbols in SymPy that anticommute?
我需要在 python 中实现一些 Grassmann 变量(即反通勤变量)。换句话说,我想要一些行为如下
>>> from sympy import *
>>> x, y = symbols('x y')
>>> y*x
-x*y
>>> y*y
0
我需要的另一个功能是能够对我的变量进行规范排序。当我输入 >>> y*x
时,输出 y*x
而不是 -x*y
肯定是有效的。但是,我希望能够选择 x
应该出现在 y
的左侧(也许只有在调用函数 simplify(y*x)
之后)。
SymPy 或其他库是否具有此功能?如果没有,我自己实现它的最佳方法是什么(例如,我应该自己创建一个符号库,扩展 SymPy 等)吗?
您可以创建一个新的 class 继承自 Symbol
并将其乘法 (__mul__
) 的行为更改为所需的行为。
为了使它有用,无论如何你都需要一个规范的排序,它应该与 SymPy 的排序相同(乍一看似乎是名字,即 Symbol.name
)以避免出现问题。
from sympy import Symbol, S
class AnticomSym(Symbol):
def __new__(cls,*args,**kwargs):
return super().__new__(cls,*args,**kwargs,commutative=False)
def __mul__(self,other):
if isinstance(other,AnticomSym):
if other==self:
return S.Zero
elif other.name<self.name:
return -Symbol.__mul__(other,self)
return super().__mul__(other)
def __pow__(self,exponent):
if exponent>=2:
return S.Zero
else:
return super().__pow__(exponent)
x = AnticomSym("x")
y = AnticomSym("y")
assert y*x == -x*y
assert y*y == 0
assert y**2 == 0
assert y**1 == y
assert ((x+y)**2).expand() == 0
assert x*y-y*x == 2*x*y
现在,这仍然无法正确解析 x*y*x*y
等复杂产品。
为此,我们可以编写一个对任意产品进行排序的函数(使用冒泡排序):
from sympy import Mul
def sort_product(product):
while True:
if not isinstance(product,Mul):
return product
arglist = list(product.args)
i = 0
while i < len(arglist)-1:
slice_prod = arglist[i]*arglist[i+1]
is_mul = isinstance(slice_prod,Mul)
arglist[i:i+2] = slice_prod.args if is_mul else [slice_prod]
i += 1
new_product = Mul(*arglist)
if product == new_product:
return new_product
product = new_product
z = AnticomSym("z")
assert sort_product(y*(-x)) == x*y
assert sort_product(x*y*x*y) == 0
assert sort_product(z*y*x) == -x*y*z
最后,我们可以编写一个函数,通过遍历表达式树并对遇到的每个产品应用 sort_product
来对表达式中的所有产品进行排序:
def sort_products(expr):
if expr.is_Atom:
return expr
else:
simplified_args = (sort_products(arg) for arg in expr.args)
if isinstance(expr,Mul):
return sort_product(Mul(*simplified_args))
else:
return expr.func(*simplified_args)
from sympy import exp
assert sort_products(exp(y*(-x))) == exp(x*y)
assert sort_products(exp(x*y*x*y)-exp(z*y*z*x)) == 0
assert sort_products(exp(z*y*x)) == exp(-x*y*z)
请注意,我可能还没有考虑到所有可能发生的情况。
Wrzlprmft 的回答是一个很好的开始,所以我将添加下一个合乎逻辑的步骤。由于您要求计算机代数系统处理反通勤符号,因此可以合理地假设您希望能够区分它们。这将需要一个函数来覆盖 sympy 的乘积规则。
from sympy import Add, Mul, prod
from sympy.ntheory.multinomial import multinomial_coefficients_iterator
def AnticomDeriv(ptr, s, n):
args = ptr.args
m = len(args)
terms = []
factor = S.One
if isinstance(s, AnticomSym):
if n > 1:
return S.Zero
args = list(args)
for i in range(len(args)):
d = args[i].diff(s)
terms.append(factor * reduce(lambda x, y: x*y, (args[:i] + [d] + args[i + 1:]), S.One))
if isinstance(args[i], AnticomSym):
factor *= -1
return Add.fromiter(terms)
for kvals, c in multinomial_coefficients_iterator(m, n):
p = prod([arg.diff((s, k)) for k, arg in zip(kvals, args)])
terms.append(c * p)
return Add(*terms)
Mul._eval_derivative_n_times = AnticomDeriv
这将给出以下(正确的)行为。
>>> x = AnticomSym('x')
>>> y = AnticomSym('y')
>>> expr = x*y
>>> expr.diff(x)
y
>>> expr.diff(y)
-x
我需要在 python 中实现一些 Grassmann 变量(即反通勤变量)。换句话说,我想要一些行为如下
>>> from sympy import *
>>> x, y = symbols('x y')
>>> y*x
-x*y
>>> y*y
0
我需要的另一个功能是能够对我的变量进行规范排序。当我输入 >>> y*x
时,输出 y*x
而不是 -x*y
肯定是有效的。但是,我希望能够选择 x
应该出现在 y
的左侧(也许只有在调用函数 simplify(y*x)
之后)。
SymPy 或其他库是否具有此功能?如果没有,我自己实现它的最佳方法是什么(例如,我应该自己创建一个符号库,扩展 SymPy 等)吗?
您可以创建一个新的 class 继承自 Symbol
并将其乘法 (__mul__
) 的行为更改为所需的行为。
为了使它有用,无论如何你都需要一个规范的排序,它应该与 SymPy 的排序相同(乍一看似乎是名字,即 Symbol.name
)以避免出现问题。
from sympy import Symbol, S
class AnticomSym(Symbol):
def __new__(cls,*args,**kwargs):
return super().__new__(cls,*args,**kwargs,commutative=False)
def __mul__(self,other):
if isinstance(other,AnticomSym):
if other==self:
return S.Zero
elif other.name<self.name:
return -Symbol.__mul__(other,self)
return super().__mul__(other)
def __pow__(self,exponent):
if exponent>=2:
return S.Zero
else:
return super().__pow__(exponent)
x = AnticomSym("x")
y = AnticomSym("y")
assert y*x == -x*y
assert y*y == 0
assert y**2 == 0
assert y**1 == y
assert ((x+y)**2).expand() == 0
assert x*y-y*x == 2*x*y
现在,这仍然无法正确解析 x*y*x*y
等复杂产品。
为此,我们可以编写一个对任意产品进行排序的函数(使用冒泡排序):
from sympy import Mul
def sort_product(product):
while True:
if not isinstance(product,Mul):
return product
arglist = list(product.args)
i = 0
while i < len(arglist)-1:
slice_prod = arglist[i]*arglist[i+1]
is_mul = isinstance(slice_prod,Mul)
arglist[i:i+2] = slice_prod.args if is_mul else [slice_prod]
i += 1
new_product = Mul(*arglist)
if product == new_product:
return new_product
product = new_product
z = AnticomSym("z")
assert sort_product(y*(-x)) == x*y
assert sort_product(x*y*x*y) == 0
assert sort_product(z*y*x) == -x*y*z
最后,我们可以编写一个函数,通过遍历表达式树并对遇到的每个产品应用 sort_product
来对表达式中的所有产品进行排序:
def sort_products(expr):
if expr.is_Atom:
return expr
else:
simplified_args = (sort_products(arg) for arg in expr.args)
if isinstance(expr,Mul):
return sort_product(Mul(*simplified_args))
else:
return expr.func(*simplified_args)
from sympy import exp
assert sort_products(exp(y*(-x))) == exp(x*y)
assert sort_products(exp(x*y*x*y)-exp(z*y*z*x)) == 0
assert sort_products(exp(z*y*x)) == exp(-x*y*z)
请注意,我可能还没有考虑到所有可能发生的情况。
Wrzlprmft 的回答是一个很好的开始,所以我将添加下一个合乎逻辑的步骤。由于您要求计算机代数系统处理反通勤符号,因此可以合理地假设您希望能够区分它们。这将需要一个函数来覆盖 sympy 的乘积规则。
from sympy import Add, Mul, prod
from sympy.ntheory.multinomial import multinomial_coefficients_iterator
def AnticomDeriv(ptr, s, n):
args = ptr.args
m = len(args)
terms = []
factor = S.One
if isinstance(s, AnticomSym):
if n > 1:
return S.Zero
args = list(args)
for i in range(len(args)):
d = args[i].diff(s)
terms.append(factor * reduce(lambda x, y: x*y, (args[:i] + [d] + args[i + 1:]), S.One))
if isinstance(args[i], AnticomSym):
factor *= -1
return Add.fromiter(terms)
for kvals, c in multinomial_coefficients_iterator(m, n):
p = prod([arg.diff((s, k)) for k, arg in zip(kvals, args)])
terms.append(c * p)
return Add(*terms)
Mul._eval_derivative_n_times = AnticomDeriv
这将给出以下(正确的)行为。
>>> x = AnticomSym('x')
>>> y = AnticomSym('y')
>>> expr = x*y
>>> expr.diff(x)
y
>>> expr.diff(y)
-x