我有一个表达式列表

from sympy import *

x = symbols('x')

e0 = x
e1 = x**2
e2 = 2*x**2

如何找到线性独立表达式的最大子集?
您可以假设要对表达式进行排序,即首选具有较低索引的表达式。

我尝试迭代以下内容:
a = numbered_symbols('a')
a0 = next(a)
a1 = next(a)
a2 = next(a)

solve(a0*e0 + a1*e1, a0, a1)
# {a0: 0, a1: 0}

solve(a0*e0 + a1*e1 + a2*e2, a0, a1, a2)
# {a1: -2*a2, a0: 0}

所以我取e0和e1。要自动执行此操作:
from operator import mul
from toolz import take

def _linear_independent(exprs):
    c = list(take(len(exprs), numbered_symbols("c")))
    expr = sum(map(mul, exprs, c))
    res = solve(expr, c)
    return all(v == 0 for v in res.values())

def max_independent_set(exprs):
    max_set = [exprs[0]]
    for e in exprs[1:]:
        if _linear_independent(max_set + [e]):
            max_set.append(e)
    return max_set

max_independent_set([e0, e1, e2]) # [x, x**2]

有没有更有效(运行时)的方法来做到这一点?
目前,我需要调用solve N-1,并且要解决的系统正在增加。也许可以将其分解为更小的任务?

奖励:我也在寻找一种方法来使用多个自变量来做到这一点。我目前的方法不起作用(它不仅解决了系数):
x, y = symbols('x y')
e0 = x
e1 = y
exprs = [e0, e1]

c = list(take(len(exprs), numbered_symbols("c")))
expr = sum(map(mul, exprs, c))
res = solve(expr, c)  # [{c0: -c1*y/x}]

我的表达式描述了 R^N -> R 中的函数。以前我会在我的数据集上评估它们并根据相关性排除它们。

最佳答案

您可以使用一些矩阵例程来计算它。函数 linear_eq_to_matrix 将方程组转换为矩阵:

>>> A, b = linear_eq_to_matrix([x, x**2, 2*x**2], [x, x**2])
>>> pprint(A)
⎡1  0⎤
⎢    ⎥
⎢0  1⎥
⎢    ⎥
⎣0  2⎦

(如果您有常数因子,它们将作为等式的右侧放入 b 中)。这是您想要的转置,因为您想要的矩阵运算适用于列。 A.T.columnspace 将返回跨越 A.T 列的列:
>>> A, b = linear_eq_to_matrix([x, x**2, 2*x**2], [x, x**2])
>>> pprint(A.T.columnspace())
⎡⎡1⎤  ⎡0⎤⎤
⎢⎢ ⎥, ⎢ ⎥⎥
⎣⎣0⎦  ⎣1⎦⎦

这告诉您第一个和第二个元素跨越空间(因为您获得了 A.T 的第一列和第二列)。如果您还想知道如何根据那些线性无关的元素重写其他元素,请使用 A.T.nullspace()

例如:
>>> pprint(A.T.nullspace())
⎡⎡0 ⎤⎤
⎢⎢  ⎥⎥
⎢⎢-2⎥⎥
⎢⎢  ⎥⎥
⎣⎣1 ⎦⎦

这意味着 -2*(x**2) + 1*(2*x**2) = 0 (所以最后两个元素是线性无关的。

举一个更大的例子:
>>> A, b = linear_eq_to_matrix([x, 2*x, x**2, 2*x**2, x**3, x + x**2], [x, x**2, x**3])
>>> pprint(A.T)
⎡1  2  0  0  0  1⎤
⎢                ⎥
⎢0  0  1  2  0  1⎥
⎢                ⎥
⎣0  0  0  0  1  0⎦
>>> pprint(A.T.columnspace())
⎡⎡1⎤  ⎡0⎤  ⎡0⎤⎤
⎢⎢ ⎥  ⎢ ⎥  ⎢ ⎥⎥
⎢⎢0⎥, ⎢1⎥, ⎢0⎥⎥
⎢⎢ ⎥  ⎢ ⎥  ⎢ ⎥⎥
⎣⎣0⎦  ⎣0⎦  ⎣1⎦⎦
>>> pprint(A.T.nullspace())
⎡⎡-2⎤  ⎡0 ⎤  ⎡-1⎤⎤
⎢⎢  ⎥  ⎢  ⎥  ⎢  ⎥⎥
⎢⎢1 ⎥  ⎢0 ⎥  ⎢0 ⎥⎥
⎢⎢  ⎥  ⎢  ⎥  ⎢  ⎥⎥
⎢⎢0 ⎥  ⎢-2⎥  ⎢-1⎥⎥
⎢⎢  ⎥, ⎢  ⎥, ⎢  ⎥⎥
⎢⎢0 ⎥  ⎢1 ⎥  ⎢0 ⎥⎥
⎢⎢  ⎥  ⎢  ⎥  ⎢  ⎥⎥
⎢⎢0 ⎥  ⎢0 ⎥  ⎢0 ⎥⎥
⎢⎢  ⎥  ⎢  ⎥  ⎢  ⎥⎥
⎣⎣0 ⎦  ⎣0 ⎦  ⎣1 ⎦⎦

请注意,我们有 3 个零空间的生成向量和 3 个列空间的生成向量,它们与 rank-nullity theorem (3 + 3 = 6) 匹配。对于列空间,我们得到了 A.T 的第一、第二和第五列,这意味着它们是线性无关的元素(或者,我们可以将列乘以我们从中提取矩阵的项向量 Matrix([x, x**2, x**3]).T

在零空间中,每列中最后的 1 表示可以删除的元素,它上面的项(实际上是它们的否定)告诉您如何根据其他项(例如 2*x = -(-2)*x2*x**2 = -(2)*x**2x + x**2 = -(1)*x + -(1)*x**2 )重写它。

这确实要求您从您认为是术语的表达式列表开始(在本例中为 [x, x**2, x**3] )。这很重要。从对您的问题的评论中举个例子,如果您的术语只是 [cos(x), cos(x)*sin(y)] ,则 [cos(x)] 是线性相关的,但如果您的术语是 [cos(x), sin(y)] 则甚至不是线性系统(如果它们是 [cos(x), cos(x)*sin(y)] ,则甚至不是线性系统。

关于python - 找到最大的线性独立表达式子集的最有效方法是什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43008815/

10-13 05:13