代码之家  ›  专栏  ›  技术社区  ›  adhanlon

有没有可能在同一个符号中构造反共模的符号?

  •  3
  • adhanlon  · 技术社区  · 8 年前

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

    Symphy或其他图书馆有这种能力吗?如果不是,那么我自己实现它的最佳方式是什么(例如,我应该自己创建一个符号库,扩展Symphy,等等)?

    2 回复  |  直到 8 年前
        1
  •  3
  •   Wrzlprmft    8 年前

    您可以创建一个新类继承自 Symbol 改变它的乘法行为( __mul__ )到所需的一个。 为了使其有用,您无论如何都需要一个规范的排序,它应该与SymPy‘‘s相同(快速一看,它似乎是按名称排序的,即。, 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)
    

    请注意,我可能仍然没有解释所有可能发生的情况。

        2
  •  0
  •   Connor Behan    6 年前

    Wrzlprmft的回答是一个很好的开始,所以我将添加下一个逻辑步骤。由于您要求反计算符号由计算机代数系统处理,因此有理由假设您希望能够区分它们。这将需要一个函数来覆盖Symphy的产品规则。

    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