兩部分的方法:
LinearOperator的想法是簡單而強大的:它是一個虛擬的線性算, 或實際上是兩個:
Aop = Linop(A) # see below
A.dot(x) -> Aop.matvec(x)
A.T.dot(y) -> Aop.rmatvec(y)
x = solver(Aop, b ...) # uses matvec and rmatvec, not A.dot A.T.dot
這裏matvec
和rmatvec
可以做任何事情(合理範圍內)。例如,他們可以在任何類型的參數x
和y
附近線性化可怕的非線性方程 。 不幸的是aslinearoperator
不適用於稀疏x
asis。 的文檔表明實施LinearOperator
兩種方式,但
每當有什麼事情可以通過兩種方式來完成,有人會混淆。
反正Linop
下面稀疏x
工程 - 用gist.github.com/denis-bz下修補lsmr.py
, 。 其他稀疏迭代求解器?不知道。
如果你真的想要做的是:
減少| A X - B |
並且還保留| x |小,又名正規化,在L1或L2規範
那麼你一定要看看 scikit-learn。 它的目標不同角落
速度 - 準確性 - 問題 - 人(SAPP)空間 比scipy.sparse.isolve。 我發現scikit-學習固體,愉快,相當有據可查, ,但沒有比較兩個真正的問題。
你的問題有多大,多少稀疏?你能指出網絡上的測試案例嗎?
""" Linop(A): .matvec .rmatvec(sparse vecs)
http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.LinearOperator.html
http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsmr.html
"""
from __future__ import division
import numpy as np
from scipy import sparse
from scipy.sparse.linalg import LinearOperator # $scipy/sparse/linalg/interface.py
__version__ = "2015-12-24 dec denis + safe_sparse_dot"
#...............................................................................
class Linop(LinearOperator): # subclass ?
""" Aop = Linop(scipy sparse matrix A)
-> Aop.matvec(x) = A dot x, x ndarray or sparse
Aop.rmatvec(x) = A.T dot x
for scipy.sparse.linalg solvers like lsmr
"""
def __init__(self, A):
self.A = A
def matvec(self, x):
return safe_sparse_dot(self.A, x)
def rmatvec(self, y):
return safe_sparse_dot(self.A.T, y)
# LinearOperator subclass should implement at least one of _matvec and _matmat.
def _matvec(self, b):
raise NotImplementedError("_matvec")
# not _matvec only:
# $scipy/sparse/linalg/interface.py
# def matvec(self, x):
# x = np.asanyarray(x) <-- kills sparse x, should raise an error
def _rmatvec(self, b):
raise NotImplementedError("_rmatvec")
@property
def shape(self):
return self.A.shape
def safe_sparse_dot(a, b):
""" -> a * b or np.dot(a, b) """
# from sklearn
if sparse.issparse(a) or sparse.issparse(b):
try:
return a * b
except ValueError: # dimension mismatch: print shapes
print "error: %s %s * %s %s" % (
type(a).__name__, a.shape,
type(b).__name__, b.shape)
raise
else:
return np.dot(a, b)
#...........................................................................
if __name__ == "__main__":
import sys
from lsmr import lsmr # patched $scipy/sparse/linalg/lsmr.py
np.set_printoptions(threshold=20, edgeitems=10, linewidth=100, suppress=True,
formatter = dict(float = lambda x: "%.2g" % x))
# test sparse.rand A m n, x n 1, b m 1
m = 10
n = 100
density = .1
bdense = 0
seed = 0
damp = 1
# to change these params in sh or ipython, run this.py a=1 b=None c=[3] ...
for arg in sys.argv[1:]:
exec(arg)
np.random.seed(seed)
print "\n", 80 * "-"
paramstr = "%s m %d n %d density %g bdense %d seed %d damp %g " % (
__file__, m, n, density, bdense, seed, damp)
print paramstr
A = sparse.rand(m, n, density, format="csr", random_state=seed)
x = sparse.rand(n, 1, density, format="csr", random_state=seed)
b = sparse.rand(m, 1, density, format="csr", random_state=seed)
if bdense:
b = b.toarray().squeeze() # matrix (m,1) -> ndarray (m,)
#...........................................................................
Aop = Linop(A)
# aslinearoperator(A): not for sparse x
# check Aop matvec rmatvec --
Ax = Aop.matvec(x)
bA = Aop.rmatvec(b)
for nm in "A Aop x b Ax bA ".split():
x = eval(nm)
print "%s: %s %s " % (nm, x.shape, type(x))
print ""
print "lsmr(Aop, b)"
#...........................................................................
xetc = lsmr(Aop, b, damp=damp, show=1)
#...........................................................................
x, istop, niter, normr, normar, norma, conda, normx = xetc
x = getattr(x, "A", x) .squeeze()
print "x:", x.shape, x
# print "lsmr(A, b) -- Valueerror in $scipy/sparse/linalg/interface.py"
# xetc = lsmr(A, b, damp=damp, show=1) # Valueerror
safe_sparse_dot(A, b.T) # ValueError: dimension mismatch
該文檔說'矩陣或array'爲'B',不'sparse'。該錯誤由'linalg.utils.make_system'發出。 – hpaulj
我知道(正如我寫的),它不回答任何問題。爲什麼不支持稀疏的右手邊? – Christoph90
scipy中的稀疏求解器都不支持多個右手邊,所以'b'無論如何都必須是等級1。鑑於這種限制,我的猜測是,開發人員認爲'b'不會太長而且稀疏,以至於無法將其表示爲密集陣列。更重要的是,我懷疑底層SuperLU解算器會接受'b'的稀疏矩陣。 –