3

我需要在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 等)?

4

2 回答 2

3

You can make a new class inheriting from Symbol and change its behaviour on multiplication (__mul__) to the desired one. To make this any useful, you need a canonic ordering anyway, which should be the same as SymPy’s (which at a quick glance appears to be by name, i.e., Symbol.name) to avoid problems.

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

Now, this still does not resolve complex products such as x*y*x*y correctly. For this, we can write a function that sorts an arbitrary product (using bubble sort):

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

Finally, we can write a function that sorts all products within an expression by iterating through the expression tree and applying sort_product to every product it encounters:

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)

Note that I may still not have accounted for every eventuality.

于 2018-02-09T21:16:49.667 回答
0

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
于 2020-05-10T13:31:29.873 回答