SymPy:多元多项式组合

3

我有一个多元多项式,其中的变量是(x,y),我需要通过设置

x=a+b y=a-b

来获得一个新的多元多项式,其中的变量是(a,b)。

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

您可能会认出这是从/到复坐标的变量更改。

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

谢谢, 马尔科


2
我不理解你的问题。你不能只是使用subs来完成吗? - Oscar Benjamin
1
定义在此处:https://github.com/sympy/sympy/blob/cb57534f1d4d5dfc4c887ce4ffba608a5b04e949/sympy/core/basic.py#L764-L876 - 0 _
也适用于以下内容:https://dev59.com/yFwY5IYBdhLWcg3wK1H-#32930285 - 0 _
关于使用subs方法替换一般子表达式,以下链接很有用:https://dev59.com/w6Pia4cB1Zd3GeqP493-#45383358 - 0 _
2个回答

4
正如评论中指出的那样,可以使用方法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_polyPoly((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的docstring中描述。

(另外,问题中似乎缺少一个乘号。)


谢谢!然而,我在变量更改方面仍然遇到问题。新的多项式生成器不正确:它们不是a和b,而是其他一些表达式。这是有问题的,因为通过调用“monoms()”,我获得一个单一的零次单项式,其“系数”是整个多项式。实际上,它认为多项式是在C [a,b]上的。 - Marco Bellan
好的,我更新了答案以避免这种情况。我假设你所说的“作为符号”是指多项式的生成器,因为assert new_poly.free_symbols == {sympy.Symbol('a'), sympy.Symbol('b')}通过了,而确实str(new_poly.gens)(sqrt(2)*(a + b)/2, -sqrt(2)*I*(a - b)/2)(变量更换的表达式,正如你所指出的)。 - 0 _
在我的第一个答案版本中,我实际上正在构建表达式,这些表达式没有“monoms”方法。我假设你所说的“.monoms()”是指sympy.polys.polytools.Poly.monoms方法。因此需要将其转换为多项式。使用表达式并将最终结果转换为多项式,生成器与预期相同。但是直接使用多项式会产生意外的结果,这就需要将其转换为表达式,然后再转换回多项式。 - 0 _
对于多项式 x**2 + y**2,我没有得到一个空的 list(更新后的答案有更多细节),尽管通过比较从头构建相同的多项式,monoms 没有返回预期的结果。我不知道在生成器、单项式和系数方面的意外表示是否可以被认为是 sympy 包中的一个 bug。此外,我假设你的意思是 poly = x**2 + y**2(写成 x^2 会引发 TypeError: unsupported operand type(s) for ^: 'Symbol' and 'int')。 - 0 _
谢谢,我一会儿就去看看。是的,我指的是正确的Python语法。我在LaTeX和Python之间来回跳跃,所以我的符号有点乱! - Marco Bellan

0

也许你的意思是想将a和b重写为x和y的函数?

from sympy.abc import a,b,x,y
from sympy import I, sqrt, solve
eqs = [
x - (a+b) / sqrt(2),
y - -I* (a-b) / sqrt(2)]
>>> solve(eqs,(a,b))
{a: sqrt(2)*x/2 + sqrt(2)*I*y/2, b: sqrt(2)*x/2 - sqrt(2)*I*y/2}

不,我的意思是我有一个函数p(x,y) = x^2 + xy + y^4,我想要得到p( x(a,b), y(a,b) ),因此p(a,b)。 - Marco Bellan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接