首页 > 解决方案 > Sympy:多元多项式组合

问题描述

我在变量 (x,y) 中有一个复杂的多元多项式,我需要通过设置在变量 (a,b) 中获得一个新的多项式

x = (a+b) / sqrt(2)
y = -i (a-b) / sqrt(2)

您可能会将其识别为变量从/到复杂坐标的变化。

我知道函数“compose”,但它似乎只替换了我的多项式的“x”变量,有没有办法进行多元组合?

谢谢,马可

标签: pythonpython-3.xsympy

解决方案


正如评论中所指出的,使用方法可以同时替换sympy.core.basic.Basic.subs,例如:

import sympy

a, b, x, y = sympy.symbols('a b x y')

poly = sympy.poly(x + y)
let = {x: (a + b) / sympy.sqrt(2), y: - sympy.I * (a - b) / sympy.sqrt(2)}
new_poly = poly.subs(let, simultaneous=True)
# at this point, `new_poly` is:
# Poly(sqrt(2)*a/2 - sqrt(2)*I*a/2 + sqrt(2)*b/2 + sqrt(2)*I*b/2,
#      sqrt(2)*(a + b)/2, -sqrt(2)*I*(a - b)/2, domain='EX')
# so the following assertions pass
assert str(new_poly.gens) == '(sqrt(2)*(a + b)/2, -sqrt(2)*I*(a - b)/2)', (
    new_poly.gens)
assert new_poly.monoms() == [(0, 0)], new_poly.monoms()
# worth remarking that
assert new_poly.free_symbols == {a, b}, new_poly.free_symbols
# by converting from an instance of the class `sympy.polys.polytools.Poly`
# to an instance of the class `sympy.core.expr.Expr`, and
# back to an instance of the class `sympy.polys.polytools.Poly`,
# the generators become as expected
new_poly = new_poly.as_expr().as_poly()
    # the previous statement is equivalent, as far as I know,
    # to the statement:
    # `new_poly = sympy.poly(new_poly.as_expr())`
    # However, the latter raises an exception for some expressions
    # (for an example, see below).
    # The exception is avoided by using the expression method `as_poly`.
assert str(new_poly.gens) == '(a, b, sqrt(2))', new_poly.gens
assert new_poly.monoms() == [(1, 0, 1), (0, 1, 1)], new_poly.monoms()
assert new_poly.free_symbols == {a, b}, new_poly.free_symbols
print(f'polynomial: {new_poly}')
print(f'generators: {new_poly.gens}')
print(f'monomials: {new_poly.monoms()}')
print(f'coefficients: {new_poly.coeffs()}')

打印:

polynomial: Poly((1/2 - I/2)*a*(sqrt(2)) + (1/2 + I/2)*b*(sqrt(2)), a, b, sqrt(2), domain='QQ_I')
generators: (a, b, sqrt(2))
monomials: [(1, 0, 1), (0, 1, 1)]
coefficients: [1/2 - I/2, 1/2 + I/2]

并确保按照评论中的要求,生成的多项式具有作为生成器的表达式,如果我们从头开始构建新的多项式,我们会期望得到这些表达式,即,

import sympy

a, b = sympy.symbols('a b')
expr = (
    (1/2 - sympy.I/2) * a * (sympy.sqrt(2))
    + (1/2 + sympy.I/2) * b *(sympy.sqrt(2)))
new_poly = expr.as_poly()
assert str(new_poly.gens) == '(a, b, sqrt(2))', new_poly.gens

事实上,以这种方式获得的多项式是相等的,但表示方式略有不同,特别是用小数而不是分数,即new_poly在这种情况下是Poly((0.5 - I/2)*a*(sqrt(2)) + (0.5 + I/2)*b*(sqrt(2)), a, b, sqrt(2), domain='EX')

值得注意的是,仅当poly是 类的实例时,才需要上述从多项式到表达式并返回到多项式的转换sympy.polys.polytools.Poly,如上所述。

使用表达式避免了将最终结果从多项式转换为表达式再转换回多项式的需要。相反,从表达式转换为多项式就足够了,如下所示(如果有兴趣调用方法,则需要转换为多项式monoms,因为表达式是类的实例sympy.core.expr.Expr,它没有方法monoms):

import sympy

a, b, x, y = sympy.symbols('a b x y')

poly = x + y
let = {x: (a + b) / sympy.sqrt(2), y: - sympy.I * (a - b) / sympy.sqrt(2)}
new_poly = poly.subs(let, simultaneous=True)
# at this point, `new_poly` is an instance of the
# class `sympy.core.expr.Expr`,
# so it does not have methods `monoms` and `gens`,
# thus a conversion to polynomial is needed.
# This conversion creates the expected generators, monomials,
# and coefficients, as follows.
new_poly = new_poly.as_expr().as_poly()
assert str(new_poly.gens) == '(a, b, sqrt(2))', new_poly.gens
assert new_poly.monoms() == [(1, 0, 1), (0, 1, 1)], new_poly.monoms()
assert new_poly.free_symbols == {a, b}, new_poly.free_symbols
print(f'polynomial: {new_poly}')
print(f'generators: {new_poly.gens}')
print(f'monomials: {new_poly.monoms()}')
print(f'coefficients: {new_poly.coeffs()}')

此代码块打印与第一个代码块相同的输出。

并对感兴趣的多项式重复上述两种方法x**2 + y**2(该多项式在评论中注明):

import sympy

a, b, x, y = sympy.symbols('a b x y')

poly = sympy.poly(x**2 + y**2)
let = {x: (a + b) / sympy.sqrt(2), y: - sympy.I * (a - b) / sympy.sqrt(2)}
new_poly = poly.subs(let, simultaneous=True)
# at this point, `new_poly` is:
# Poly(2*a*b, sqrt(2)*(a + b)/2, -sqrt(2)*I*(a - b)/2, domain='ZZ[a,b]')
# so the following assertions pass
assert str(new_poly.gens) == '(sqrt(2)*(a + b)/2, -sqrt(2)*I*(a - b)/2)', (
    new_poly.gens)
assert new_poly.monoms() == [(0, 0)], new_poly.monoms()
# worth remarking that
assert new_poly.free_symbols == {a, b}, new_poly.free_symbols
# by converting from an instance of the class `sympy.polys.polytools.Poly`
# to an instance of the class `sympy.core.expr.Expr`, and
# back to an instance of the class `sympy.polys.polytools.Poly`,
# the generators become as expected
new_poly = new_poly.as_expr().as_poly()
assert str(new_poly.gens) == '(a, b)', new_poly.gens
assert new_poly.monoms() == [(1, 1)], new_poly.monoms()
assert new_poly.free_symbols == {a, b}, new_poly.free_symbols
print(f'polynomial: {new_poly}')
print(f'generators: {new_poly.gens}')
print(f'monomials: {new_poly.monoms()}')
print(f'coefficients: {new_poly.coeffs()}')

打印输出:

polynomial: Poly(2*a*b, a, b, domain='ZZ')
generators: (a, b)
monomials: [(1, 1)]
coefficients: [2]

和代码块:

import sympy

a, b, x, y = sympy.symbols('a b x y')

poly = x**2 + y**2
let = {x: (a + b) / sympy.sqrt(2), y: - sympy.I * (a - b) / sympy.sqrt(2)}
new_poly = poly.subs(let, simultaneous=True)
# at this point, `new_poly` is an instance of the
# class `sympy.core.expr.Expr`,
# so it does not have methods `monoms` and `gens`,
# thus a conversion to polynomial is needed.
# This conversion creates the expected generators, monomials,
# and coefficients, as follows.
new_poly = new_poly.as_expr().as_poly()
    # if the previous statement is replaced with the statement:
    # `new_poly = sympy.poly(new_poly.as_expr())`
    # then an exception is raised:
    # `CoercionFailed: expected an integer, got 1/2`
assert str(new_poly.gens) == '(a, b)', new_poly.gens
assert new_poly.monoms() == [(1, 1)], new_poly.monoms()
assert new_poly.free_symbols == {a, b}, new_poly.free_symbols
print(f'polynomial: {new_poly}')
print(f'generators: {new_poly.gens}')
print(f'monomials: {new_poly.monoms()}')
print(f'coefficients: {new_poly.coeffs()}')

它打印与前一个代码块相同的输出。

有关该方法的其他文档subs可以sympy文档中找到(即使讨论是根据表达式实例进行的,它也适用于多项式的实例,因为它们都是类的子类Basic而不覆盖方法subs)。

还要注意,不是标识符的子表达式的替换大致通过在表达式的语法树中搜索与要替换的子表达式的语法树匹配的子树并替换子树来进行。但是,如本答案和方法的文档字符串中所述,对一些启发式方法有一个警告sympy.core.basic.Basic.subs

(此外,问题中似乎缺少乘号。)


推荐阅读