如何加速在sympy中展开非常大的多项式?

5
我正在使用sympy处理非常大的多项式,我需要将它们展开以查找特定的项和系数。然而,展开这些多项式需要很长时间。有没有一种快速展开多项式或以不同方式获取某些项和系数的方法?
我可以找到展开后的多项式中的项,但展开它的时间是限制因素。
这些多项式非常大,例如:
(x + y + z + a + b + c) ** 24
我已经尝试了sympy.expand()和Add.as_poly()。并发现Add.as_poly()更快,但仍然非常缓慢。
my_poly = (x + y + z + a + b + c) ** 24
# expand using Add.as_poly()
my_poly.as_poly()
# this takes multiple minutes to execute

我希望能够通过搜索扩展的多项式中包含其他项的项来查找:
(伪代码)x ** 3 * y z a ** 2是否包含在500 * x ** 5 * y ** 2 * z * a ** 4 * b * c ** 2中, 如果包含,则要检索该项的系数。

我正在寻找加快扩展速度或使用不同方法以更少的时间找到所需项的方法。


展开式中有 (24+5)! / (24! 5!) = 118755 个项。 - Reblochon Masque
1个回答

2
多项式的系数可以在不展开表达式的情况下确定。例如,(a + b + c + x + y + z)**5将具有指数总和为5的项。您提供的示例必须是当系数为15时的一个项(但系数将为113513400)。
def mcoeff(*args):
    """return multinomial coefficient of a terms in the expansion of
    (x_1 + x_2 + x_3 + ... x_n)**m from the given exponents in the
    term of interest

    EXAMPLES
    ========

    >>> from sympy import expand
    >>> from sympy.abc import x, y, z
    >>> eq = (x + y + z)**4
    >>> eq.expand().coeff(x**2*y**2)
    6
    >>> mcoeff(2,2)
    6
    >>> 
    """
    from sympy import binomial
    from sympy.utilities.misc import as_int
    assert all(as_int(i)>=0 for i in args)
    if len(args) == 2:
        return binomial(sum(args), sorted(args)[0])
    if len(set(args)) == 1:
        return factorial(sum(args))/factorial(args[0])**len(args)
    def runsum(a):
        t = 0
        for i in a:
            t += i
            yield t
    return Mul(*[
        binomial(j, k) for j, k in zip(runsum(args), args)])

如果您想找到类似于F = x**3*yza**2的系数(包括符号)...那么这很困难,但并非不可能。如果您在展开式(a + b + c + x + y + z)**8中寻找这些因子(我选择了8,以便有多个具有该因子的项;如果指数为7,则只有一个这样的项,因为3 + 1 + 1 + 2 = 项的指数总和 = 7),则该因子将与任何其他x,y,z,a,b,c的因子一起出现,这些因子将给出总指数为8。在这种情况下很容易,因为我们只需要添加1,因此具有因子F的潜在项为x * F,y * F,z * F,a * F,b * F,c * F。考虑x,y,z,a,b,c的指数元组更容易,它们在F中为(3,1,1,2,0,0):
x*F -> (4,1,1,2,0,0)
y*F -> (3,2,1,2,0,0)
z*F -> (3,1,2,2,0,0)
a*F -> (3,1,1,3,0,0)
b*F -> (3,1,1,2,1,0)
c*F -> (3,1,1,2,0,1)

每个项都有一个数值系数和一个符号残差(乘以 F 的因子),所以展开式中 F 的系数将是它们的总和:

>>> from sympy.abc import x, y, z, a, b, c, e
>>> coeff = []; t = [3,1,1,2,0,0]
for i,f in enumerate((x, y, z, a, b, c)):
...     t[i] += 1
...     coeff.append(f*mcoeff(*t))
...     t[i] -= 1
>>> Add(*coeff)
1120*a + 3360*b + 3360*c + 840*x + 1680*y + 1680*z
>>> F = x**3*y*z*a**2
>>> ((x + y + z + a + b + c)**8).expand().subs(F, e).coeff(e)  # wait for it...
1120*a + 3360*b + 3360*c + 840*x + 1680*y + 1680*z

当您想要找到因子较小的术语时,情况会变得更加复杂,因为这时您必须将指数和不足(在本例中只有1个)分配给所有符号,但是思路是相同的。
mcoeff取自此处并进行了一些修改)

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