Skip to content

Commit d435213

Browse files
committed
ENH: port fixes from scipy/scipy #9352
1 parent 8a2b946 commit d435213

1 file changed

Lines changed: 37 additions & 11 deletions

File tree

sklearn/utils/lobpcg.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ def save(ar, fileName):
2121
# Used only when verbosity level > 10.
2222
np.savetxt(fileName, ar, precision=8)
2323

24+
def _report_nonhermitian(M, a, b, name):
25+
"""
26+
Report if `M` is not a hermitian matrix given the tolerances `a`, `b`.
27+
"""
28+
from scipy.linalg import norm
29+
30+
md = M - M.T.conj()
31+
32+
nmd = norm(md, 1)
33+
tol = max(np.spacing(10**a), (10**b)*norm(M, 1))
34+
if nmd > tol:
35+
print('matrix %s is not enough Hermitian for a=%d, b=%d:'
36+
% (name, a, b))
37+
print('condition: %.e < %e' % (nmd, tol))
2438

2539
def as2d(ar):
2640
"""
@@ -85,6 +99,15 @@ def _b_orthonormalize(B, blockVectorV, blockVectorBV=None, retInvR=False):
8599
else:
86100
return blockVectorV, blockVectorBV
87101

102+
def _get_indx(_lambda, num, largest):
103+
"""Get `num` indices into `_lambda` depending on `largest` option."""
104+
ii = np.argsort(_lambda)
105+
if largest:
106+
ii = ii[:-num-1:-1]
107+
else:
108+
ii = ii[:num]
109+
110+
return ii
88111

89112
def lobpcg(A, X,
90113
B=None, M=None, Y=None,
@@ -299,7 +322,14 @@ def lobpcg(A, X,
299322

300323
A_dense = A(np.eye(n))
301324
B_dense = None if B is None else B(np.eye(n))
302-
return eigh(A_dense, B_dense, eigvals=eigvals, check_finite=False)
325+
326+
vals, vecs = eigh(A_dense, B_dense, eigvals=eigvals, check_finite=False)
327+
if largest:
328+
# Reverse order to be compatible with eigs() in 'LM' mode.
329+
vals = vals[::-1]
330+
vecs = vecs[:, ::-1]
331+
332+
return vals, vecs
303333

304334
if residualTolerance is None:
305335
residualTolerance = np.sqrt(1e-15) * n
@@ -332,11 +362,7 @@ def lobpcg(A, X,
332362
gramXAX = np.dot(blockVectorX.T.conj(), blockVectorAX)
333363

334364
_lambda, eigBlockVector = eigh(gramXAX, check_finite=False)
335-
336-
if largest:
337-
ii = np.argsort(-_lambda)[:sizeX]
338-
else:
339-
ii = np.argsort(_lambda)[:sizeX]
365+
ii = _get_indx(_lambda, sizeX, largest)
340366
_lambda = _lambda[ii]
341367

342368
eigBlockVector = np.asarray(eigBlockVector[:, ii])
@@ -456,17 +482,17 @@ def lobpcg(A, X,
456482
gramB = np.bmat([[ident0, xbw],
457483
[xbw.T.conj(), ident]])
458484

485+
if verbosityLevel > 0:
486+
_report_nonhermitian(gramA, 3, -1, 'gramA')
487+
_report_nonhermitian(gramB, 3, -1, 'gramB')
488+
459489
if verbosityLevel > 10:
460490
save(gramA, 'gramA')
461491
save(gramB, 'gramB')
462492

463493
# Solve the generalized eigenvalue problem.
464494
_lambda, eigBlockVector = eigh(gramA, gramB, check_finite=False)
465-
466-
if largest:
467-
ii = np.argsort(-_lambda)[: sizeX]
468-
else:
469-
ii = np.argsort(_lambda)[: sizeX]
495+
ii = _get_indx(_lambda, sizeX, largest)
470496

471497
if verbosityLevel > 10:
472498
print(ii)

0 commit comments

Comments
 (0)