未确定线性系统的随机解

时间:2017-04-15 07:14:37

标签: python numpy scipy linear-algebra

考虑一个欠定的线性方程组Ax=b

我想找到一组向量x_1, ..., x_n,使它们都解决Ax=b,并且它们尽可能彼此不同。

第二部分实际上不太重要;我很满意每次调用它时返回Ax=b随机解的算法。

我知道scipy.sparse.linalg.lsqrnumpy.linalg.lstsq会返回一个未确定的线性系统Ax=b的稀疏解(就最小二乘方而言),但我不关心它的属性解;我只想要Ax=b的任何解决方案,只要我能够生成一堆不同的解决方案。

事实上,scipy.sparse.linalg.lsqrnumpy.linalg.lstsq应该遵循从解决方案跳到另一个解决方案的迭代过程,直到找到一个似乎在最小二乘方面最小的解决方案。那么,是否有一个python模块可以让我在没有特定目标的情况下在解决方案之间跳转并返回它们?

2 个答案:

答案 0 :(得分:1)

以下是我的评论中附带的代码。它使用Scipy Cookbook中的rank_nullspace.py模块。

import numpy as np
from numpy.linalg import lstsq

from rank_nullspace import nullspace
# rank_nullspace from
# http://scipy-cookbook.readthedocs.io/items/RankNullspace.html


def randsol(A, b, num=1, check=False):
    xLS, *_ = lstsq(A, b)

    colsOfNullspace = nullspace(A)
    nullrank = colsOfNullspace.shape[1]
    if check:
        assert(np.allclose(np.dot(A, xLS), b))
        assert(np.allclose(np.dot(A, xLS + np.dot(colsOfNullspace,
                                                  np.random.randn(nullrank))),
                           b))

    sols = xLS[:, np.newaxis] + np.dot(colsOfNullspace,
                                       np.random.randn(nullrank, num))
    return sols


A = np.random.randn(2, 10)
b = np.random.randn(2)
x = randsol(A, b, num=50, check=True)
assert(np.allclose(np.dot(A, x), b[:, np.newaxis]))

使用x中的一系列解决方案,您可以选择彼此“不同”的解决方案,但是您定义的是“不同”。

答案 1 :(得分:1)

对于欠定系统 A = b ,您可以计算null space您的系数矩阵 A 。零空间 Z 是一组基础向量,跨越 A 的子空间,以便 A·Z = 0 。换句话说, Z 的列是与 A 中的所有行正交的向量。这意味着对于任何解决方案 x' A·x = b ,然后 x' + Z·c 也必须是任意解决方案矢量 c

因此,如果您想对 A·x = b 的随机解决方案进行抽样,那么您可以以下内容:

  1. 找到任何解决方案 x' A·x = b 即可。您可以使用np.linalg.lstsq执行此操作,this previous question会找到最小化 x' 的L2规范的解决方案。
  2. 找到 A 的空格。有许多不同的方法可以做到这一点,其中大部分都包含在What is the difference between sorted(list) vs list.sort() ?
  3. 抽样随机向量 c ,并计算 x' + Z· ç即可。这将是 A·x = b 的解决方案。
  4. 例如:

    import numpy as np
    from scipy.linalg import qr
    
    
    def qr_null(A, tol=None):
        """Computes the null space of A using a rank-revealing QR decomposition"""
        Q, R, P = qr(A.T, mode='full', pivoting=True)
        tol = np.finfo(R.dtype).eps if tol is None else tol
        rnk = min(A.shape) - np.abs(np.diag(R))[::-1].searchsorted(tol)
        return Q[:, rnk:].conj()
    
    
    # An underdetermined system with nullity 2
    A = np.array([[1, 4, 9, 6, 9, 2, 7],
                  [6, 3, 8, 5, 2, 7, 6],
                  [7, 4, 5, 7, 6, 3, 2],
                  [5, 2, 7, 4, 7, 5, 4],
                  [9, 3, 8, 6, 7, 3, 1]])
    b = np.array([0, 4, 1, 3, 2])
    
    # Find an initial solution using `np.linalg.lstsq`
    x_lstsq = np.linalg.lstsq(A, b)[0]
    
    # Compute the null space of `A`
    Z = qr_null(A)
    nullity = Z.shape[1]
    
    # Sample some random solutions
    for _ in range(5):
        x_rand = x_lstsq + Z.dot(np.random.rand(nullity))
        # If `x_rand` is a solution then `||A·x_rand - b||` should be very small
        print(np.linalg.norm(A.dot(x_rand) - b))
    

    示例输出:

    3.33066907388e-15
    3.58036167305e-15
    4.63775652864e-15
    4.67877015036e-15
    4.31132637123e-15
    

    可能的 c 向量的空间是无限的 - 你必须做出一些选择,以便你如何对它们进行采样。