将sympy表达式转换为向量以找到线性独立的子集

时间:2015-01-16 20:37:39

标签: sympy

我有一个像4.0*x[0] + 5.0*x[10] + 1 = 0这样的表达式列表 我想根据像[4.0, 0, 0, ..., 5.0, ... , 1]这样的系数将它们变成向量。原因是我的一些方程可能是线性相关的,我想从numpy库运行QR,所以我可以找到一个线性独立的子集。

我可以通过expr.replace(x[i], 0)使用i通配符索引来获得常量项。我还可以通过expr.atoms(Mul)获取大部分其他字词,这样就可以获得4.0*x[0], 5.0*x[10]集合,然后对于每个表达式,我都可以expr.atoms(Indexed).pop()expr.atoms(Float).pop()来分割部分。

问题在于我有一个像x[0] + 5.0*x[10] + 1 = 0这样的表达式,其中第一个变量出现的隐式系数为1。该术语不再被识别为Mul对象。

无论如何,我认为可能有更好的方法来实现我的目标?

2 个答案:

答案 0 :(得分:4)

如果您给符号指定特定顺序,如下面的代码所示,您可以将表达式转换为多项式并获得其系数:

>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> a1, a2, a3, a4 = symbols('a[1], a[2], a[3], a[4]')
>>> used_symbols = (a1, a2, a3, a4)
>>> replacements = [(n, x**(enu+1)) for enu,n in enumerate(used_symbols)]
>>> expr = 5 + a1 + 4*a4
>>> Poly(expr.subs(replacements)).all_coeffs()
[4, 0, 0, 1, 5]

如果事先不知道使用以下递归函数,您也可以检索已使用符号的列表:

def retrieve_used_symbols(expr):
    """Return the symbols used in the `expr` in a list."""
    used_symbols = []
    for term in expr.args:
        if term.is_Atom and term.is_Symbol:
            used_symbols.append(term)
        else:
            used_symbols.extend(retrieve_used_symbols(term))
    return used_symbols

当你有混合符号时,后者会派上用场:

>>> crazy_expr = expr + 10*y-2*z
>>> crazy_expr
a[1] + 4*a[4] + 10*y - 2*z + 5
>>> used_symbols = retrieve_used_symbols(crazy_expr)
>>> replacements = [(n, x**(enu+1)) for enu,n in enumerate(used_symbols)]
>>> Poly(crazy_expr.subs(replacements)).all_coeffs()
[4, -2, 1, 10, 5]
>>> list(reversed(used_symbols))
[a[4], z, a[1], y]

对于IndexedBase对象,它甚至更简单:

coeffs = [expr.coeff(x[i]) for i in range(10)]

但是你仍然需要添加常量术语,就像你说的那样,你可以从通配符替换中获得:

ind = Wild('i')
constant_term = expr.replace(x[ind], 0)

答案 1 :(得分:2)

{按照@(Oliver W。)的要求}

鉴于

>>> x = IndexedBase('x')
>>> eqs = 4*x[0] + 5*x[5] + 1, x[1] - x[2]
>>> v = list(ordered(Tuple(*eqs).atoms(Indexed)))

可以这样做

>>> [[eq.coeff(vi) for vi in v] + [eq.as_coeff_Add()[0]] for eq in eqs] 
[[4, 0, 0, 5, 1], [0, 1, -1, 0, 0]]

但是大部分内容都可以通过矩阵方法jacobian获得。但要使用它,你必须用符号替换x [i](因为diff仅适用于函数是符号,IIRC):

>>> d = [Dummy() for vi in v]
>>> z = dict(zip(d, [0]*len(d)))
>>> m = Matrix([eq.xreplace(dict(zip(v, d))) for eq in eqs])
>>> m.jacobian(d)
Matrix([
[4, 0,  0, 5],
[0, 1, -1, 0]])
>>> m.subs(z)
Matrix([
[1],
[0]])