@@ -41,7 +41,7 @@ def spectral_embedding(adjacency, n_components=8, mode=None,
41
41
n_components: integer, optional
42
42
The dimension of the projection subspace.
43
43
44
- mode: {None, 'arpack' or 'amg'}
44
+ mode: {None, 'arpack', 'lobpcg', or 'amg'}
45
45
The eigenvalue decomposition strategy to use. AMG requires pyamg
46
46
to be installed. It can be faster on very large, sparse problems,
47
47
but may also lead to instabilities
@@ -78,6 +78,9 @@ def spectral_embedding(adjacency, n_components=8, mode=None,
78
78
# XXX: Should we check that the matrices given is symmetric
79
79
if mode is None :
80
80
mode = 'arpack'
81
+ elif not mode in ('arpack' , 'lobpcg' , 'amg' ):
82
+ raise ValueError ("Unknown value for mode: '%s'."
83
+ "Should be 'amg' or 'arpack'" % mode )
81
84
laplacian , dd = graph_laplacian (adjacency ,
82
85
normed = True , return_diag = True )
83
86
if (mode == 'arpack'
@@ -118,25 +121,39 @@ def spectral_embedding(adjacency, n_components=8, mode=No
10000
ne,
118
121
# near 1.0 and leads to much faster convergence: potentially an
119
122
# orders-of-magnitude speedup over simply using keyword which='LA'
120
123
# in standard mode.
121
- lambdas , diffusion_map = eigsh (- laplacian , k = n_components ,
122
- sigma = 1.0 , which = 'LM' )
123
- embedding = diffusion_map .T [::- 1 ] * dd
124
- elif mode == 'amg' :
124
+ try :
125
+ lambdas , diffusion_map = eigsh (- laplacian , k = n_components ,
126
+ sigma = 1.0 , which = 'LM' )
127
+ embedding = diffusion_map .T [::- 1 ] * dd
128
+ except RuntimeError :
129
+ # When submatrices are exactly singular, an LU decomposition
130
+ # in arpack fails. We fallback to lobpcg
131
+ mode = "lobpcg"
132
+
133
+ if mode == 'amg' :
125
134
# Use AMG to get a preconditioner and speed up the eigenvalue
126
135
# problem.
127
136
laplacian = laplacian .astype (np .float ) # lobpcg needs native floats
128
137
ml = smoothed_aggregation_solver (laplacian .tocsr ())
138
+ M = ml .aspreconditioner ()
129
139
X = random_state .rand (laplacian .shape [0 ], n_components )
130
140
X [:, 0 ] = 1. / dd .ravel ()
131
- M = ml .aspreconditioner ()
132
141
lambdas , diffusion_map = lobpcg (laplacian , X , M = M , tol = 1.e-12 ,
133
142
largest = False )
134
143
embedding = diffusion_map .T * dd
135
144
if embedding .shape [0 ] == 1 :
136
145
raise ValueError
137
- else :
138
- raise ValueError ("Unknown value for mode: '%s'."
139
- "Should be 'amg' or 'arpack'" % mode )
146
+ elif mode == "lobpcg" :
147
+ # We increase the number of eigenvectors requested, as lobpcg
148
+ # doesn't behave well in low dimension
149
+ X = random_state .rand (laplacian .shape [0 ], n_components + 4 )
150
+ X [:, 0 ] = 1. / dd .ravel ()
151
+ lambdas , diffusion_map = lobpcg (laplacian , X , tol = 1e-15 ,
152
+ largest = False , maxiter = 2000 ,
153
+ verbosityLevel = 20 )
154
+ embedding = diffusion_map .T [:n_components ] * dd
155
+ if embedding .shape [0 ] == 1 :
156
+ raise ValueError
140
157
return embedding
141
158
142
159
0 commit comments