/src/igraph/vendor/lapack/dsaup2.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -- translated by f2c (version 20191129). |
2 | | You must link the resulting object file with libf2c: |
3 | | on Microsoft Windows system, link with libf2c.lib; |
4 | | on Linux or Unix systems, link with .../path/to/libf2c.a -lm |
5 | | or, if you install libf2c.a in a standard place, with -lf2c -lm |
6 | | -- in that order, at the end of the command line, as in |
7 | | cc *.o -lf2c -lm |
8 | | Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., |
9 | | |
10 | | http://www.netlib.org/f2c/libf2c.zip |
11 | | */ |
12 | | |
13 | | #include "f2c.h" |
14 | | |
15 | | /* Table of constant values */ |
16 | | |
17 | | static doublereal c_b3 = .66666666666666663; |
18 | | static integer c__1 = 1; |
19 | | static integer c__0 = 0; |
20 | | static integer c__3 = 3; |
21 | | static logical c_true = TRUE_; |
22 | | static integer c__2 = 2; |
23 | | |
24 | | /* ----------------------------------------------------------------------- |
25 | | \BeginDoc |
26 | | |
27 | | \Name: dsaup2 |
28 | | |
29 | | \Description: |
30 | | Intermediate level interface called by dsaupd. |
31 | | |
32 | | \Usage: |
33 | | call dsaup2 |
34 | | ( IDO, BMAT, N, WHICH, NEV, NP, TOL, RESID, MODE, IUPD, |
35 | | ISHIFT, MXITER, V, LDV, H, LDH, RITZ, BOUNDS, Q, LDQ, WORKL, |
36 | | IPNTR, WORKD, INFO ) |
37 | | |
38 | | \Arguments |
39 | | |
40 | | IDO, BMAT, N, WHICH, NEV, TOL, RESID: same as defined in dsaupd. |
41 | | MODE, ISHIFT, MXITER: see the definition of IPARAM in dsaupd. |
42 | | |
43 | | NP Integer. (INPUT/OUTPUT) |
44 | | Contains the number of implicit shifts to apply during |
45 | | each Arnoldi/Lanczos iteration. |
46 | | If ISHIFT=1, NP is adjusted dynamically at each iteration |
47 | | to accelerate convergence and prevent stagnation. |
48 | | This is also roughly equal to the number of matrix-vector |
49 | | products (involving the operator OP) per Arnoldi iteration. |
50 | | The logic for adjusting is contained within the current |
51 | | subroutine. |
52 | | If ISHIFT=0, NP is the number of shifts the user needs |
53 | | to provide via reverse comunication. 0 < NP < NCV-NEV. |
54 | | NP may be less than NCV-NEV since a leading block of the current |
55 | | upper Tridiagonal matrix has split off and contains "unwanted" |
56 | | Ritz values. |
57 | | Upon termination of the IRA iteration, NP contains the number |
58 | | of "converged" wanted Ritz values. |
59 | | |
60 | | IUPD Integer. (INPUT) |
61 | | IUPD .EQ. 0: use explicit restart instead implicit update. |
62 | | IUPD .NE. 0: use implicit update. |
63 | | |
64 | | V Double precision N by (NEV+NP) array. (INPUT/OUTPUT) |
65 | | The Lanczos basis vectors. |
66 | | |
67 | | LDV Integer. (INPUT) |
68 | | Leading dimension of V exactly as declared in the calling |
69 | | program. |
70 | | |
71 | | H Double precision (NEV+NP) by 2 array. (OUTPUT) |
72 | | H is used to store the generated symmetric tridiagonal matrix |
73 | | The subdiagonal is stored in the first column of H starting |
74 | | at H(2,1). The main diagonal is stored in the second column |
75 | | of H starting at H(1,2). If dsaup2 converges store the |
76 | | B-norm of the final residual vector in H(1,1). |
77 | | |
78 | | LDH Integer. (INPUT) |
79 | | Leading dimension of H exactly as declared in the calling |
80 | | program. |
81 | | |
82 | | RITZ Double precision array of length NEV+NP. (OUTPUT) |
83 | | RITZ(1:NEV) contains the computed Ritz values of OP. |
84 | | |
85 | | BOUNDS Double precision array of length NEV+NP. (OUTPUT) |
86 | | BOUNDS(1:NEV) contain the error bounds corresponding to RITZ. |
87 | | |
88 | | Q Double precision (NEV+NP) by (NEV+NP) array. (WORKSPACE) |
89 | | Private (replicated) work array used to accumulate the |
90 | | rotation in the shift application step. |
91 | | |
92 | | LDQ Integer. (INPUT) |
93 | | Leading dimension of Q exactly as declared in the calling |
94 | | program. |
95 | | |
96 | | WORKL Double precision array of length at least 3*(NEV+NP). (INPUT/WORKSPACE) |
97 | | Private (replicated) array on each PE or array allocated on |
98 | | the front end. It is used in the computation of the |
99 | | tridiagonal eigenvalue problem, the calculation and |
100 | | application of the shifts and convergence checking. |
101 | | If ISHIFT .EQ. O and IDO .EQ. 3, the first NP locations |
102 | | of WORKL are used in reverse communication to hold the user |
103 | | supplied shifts. |
104 | | |
105 | | IPNTR Integer array of length 3. (OUTPUT) |
106 | | Pointer to mark the starting locations in the WORKD for |
107 | | vectors used by the Lanczos iteration. |
108 | | ------------------------------------------------------------- |
109 | | IPNTR(1): pointer to the current operand vector X. |
110 | | IPNTR(2): pointer to the current result vector Y. |
111 | | IPNTR(3): pointer to the vector B * X when used in one of |
112 | | the spectral transformation modes. X is the current |
113 | | operand. |
114 | | ------------------------------------------------------------- |
115 | | |
116 | | WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION) |
117 | | Distributed array to be used in the basic Lanczos iteration |
118 | | for reverse communication. The user should not use WORKD |
119 | | as temporary workspace during the iteration !!!!!!!!!! |
120 | | See Data Distribution Note in dsaupd. |
121 | | |
122 | | INFO Integer. (INPUT/OUTPUT) |
123 | | If INFO .EQ. 0, a randomly initial residual vector is used. |
124 | | If INFO .NE. 0, RESID contains the initial residual vector, |
125 | | possibly from a previous run. |
126 | | Error flag on output. |
127 | | = 0: Normal return. |
128 | | = 1: All possible eigenvalues of OP has been found. |
129 | | NP returns the size of the invariant subspace |
130 | | spanning the operator OP. |
131 | | = 2: No shifts could be applied. |
132 | | = -8: Error return from trid. eigenvalue calculation; |
133 | | This should never happen. |
134 | | = -9: Starting vector is zero. |
135 | | = -9999: Could not build an Lanczos factorization. |
136 | | Size that was built in returned in NP. |
137 | | |
138 | | \EndDoc |
139 | | |
140 | | ----------------------------------------------------------------------- |
141 | | |
142 | | \BeginLib |
143 | | |
144 | | \References: |
145 | | 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in |
146 | | a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), |
147 | | pp 357-385. |
148 | | 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly |
149 | | Restarted Arnoldi Iteration", Rice University Technical Report |
150 | | TR95-13, Department of Computational and Applied Mathematics. |
151 | | 3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall, |
152 | | 1980. |
153 | | 4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program", |
154 | | Computer Physics Communications, 53 (1989), pp 169-179. |
155 | | 5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to |
156 | | Implement the Spectral Transformation", Math. Comp., 48 (1987), |
157 | | pp 663-673. |
158 | | 6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos |
159 | | Algorithm for Solving Sparse Symmetric Generalized Eigenproblems", |
160 | | SIAM J. Matr. Anal. Apps., January (1993). |
161 | | 7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines |
162 | | for Updating the QR decomposition", ACM TOMS, December 1990, |
163 | | Volume 16 Number 4, pp 369-377. |
164 | | |
165 | | \Routines called: |
166 | | dgetv0 ARPACK initial vector generation routine. |
167 | | dsaitr ARPACK Lanczos factorization routine. |
168 | | dsapps ARPACK application of implicit shifts routine. |
169 | | dsconv ARPACK convergence of Ritz values routine. |
170 | | dseigt ARPACK compute Ritz values and error bounds routine. |
171 | | dsgets ARPACK reorder Ritz values and error bounds routine. |
172 | | dsortr ARPACK sorting routine. |
173 | | ivout ARPACK utility routine that prints integers. |
174 | | second ARPACK utility routine for timing. |
175 | | dvout ARPACK utility routine that prints vectors. |
176 | | dlamch LAPACK routine that determines machine constants. |
177 | | dcopy Level 1 BLAS that copies one vector to another. |
178 | | ddot Level 1 BLAS that computes the scalar product of two vectors. |
179 | | dnrm2 Level 1 BLAS that computes the norm of a vector. |
180 | | dscal Level 1 BLAS that scales a vector. |
181 | | dswap Level 1 BLAS that swaps two vectors. |
182 | | |
183 | | \Author |
184 | | Danny Sorensen Phuong Vu |
185 | | Richard Lehoucq CRPC / Rice University |
186 | | Dept. of Computational & Houston, Texas |
187 | | Applied Mathematics |
188 | | Rice University |
189 | | Houston, Texas |
190 | | |
191 | | \Revision history: |
192 | | 12/15/93: Version ' 2.4' |
193 | | xx/xx/95: Version ' 2.4'. (R.B. Lehoucq) |
194 | | |
195 | | \SCCS Information: @(#) |
196 | | FILE: saup2.F SID: 2.6 DATE OF SID: 8/16/96 RELEASE: 2 |
197 | | |
198 | | \EndLib |
199 | | |
200 | | ----------------------------------------------------------------------- |
201 | | |
202 | | Subroutine */ int igraphdsaup2_(integer *ido, char *bmat, integer *n, char * |
203 | | which, integer *nev, integer *np, doublereal *tol, doublereal *resid, |
204 | | integer *mode, integer *iupd, integer *ishift, integer *mxiter, |
205 | | doublereal *v, integer *ldv, doublereal *h__, integer *ldh, |
206 | | doublereal *ritz, doublereal *bounds, doublereal *q, integer *ldq, |
207 | | doublereal *workl, integer *ipntr, doublereal *workd, integer *info) |
208 | 0 | { |
209 | | /* System generated locals */ |
210 | 0 | integer h_dim1, h_offset, q_dim1, q_offset, v_dim1, v_offset, i__1, i__2, |
211 | 0 | i__3; |
212 | 0 | doublereal d__1, d__2, d__3; |
213 | | |
214 | | /* Builtin functions */ |
215 | 0 | double pow_dd(doublereal *, doublereal *); |
216 | 0 | integer s_cmp(char *, char *, ftnlen, ftnlen); |
217 | 0 | /* Subroutine */ void s_copy(char *, char *, ftnlen, ftnlen); |
218 | 0 | double sqrt(doublereal); |
219 | | |
220 | | /* Local variables */ |
221 | 0 | integer j; |
222 | 0 | IGRAPH_F77_SAVE real t0, t1, t2, t3; |
223 | 0 | integer kp[3]; |
224 | 0 | IGRAPH_F77_SAVE integer np0; |
225 | 0 | integer nbx = 0; |
226 | 0 | IGRAPH_F77_SAVE integer nev0; |
227 | 0 | extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, |
228 | 0 | integer *); |
229 | 0 | IGRAPH_F77_SAVE doublereal eps23; |
230 | 0 | integer ierr; |
231 | 0 | IGRAPH_F77_SAVE integer iter; |
232 | 0 | doublereal temp; |
233 | 0 | integer nevd2; |
234 | 0 | extern doublereal igraphdnrm2_(integer *, doublereal *, integer *); |
235 | 0 | IGRAPH_F77_SAVE logical getv0; |
236 | 0 | integer nevm2; |
237 | 0 | IGRAPH_F77_SAVE logical cnorm; |
238 | 0 | extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, |
239 | 0 | doublereal *, integer *), igraphdswap_(integer *, doublereal *, integer |
240 | 0 | *, doublereal *, integer *); |
241 | 0 | IGRAPH_F77_SAVE integer nconv; |
242 | 0 | IGRAPH_F77_SAVE logical initv; |
243 | 0 | IGRAPH_F77_SAVE doublereal rnorm; |
244 | 0 | real tmvbx = 0.0; |
245 | 0 | extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, |
246 | 0 | integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer * |
247 | 0 | , integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer * |
248 | 0 | , logical *, integer *, integer *, doublereal *, integer *, |
249 | 0 | doublereal *, doublereal *, integer *, doublereal *, integer *); |
250 | 0 | integer msaup2 = 0; |
251 | 0 | real tsaup2; |
252 | 0 | extern doublereal igraphdlamch_(char *); |
253 | 0 | integer nevbef; |
254 | 0 | extern /* Subroutine */ int igraphsecond_(real *); |
255 | 0 | integer logfil = 0, ndigit; |
256 | 0 | extern /* Subroutine */ int igraphdseigt_(doublereal *, integer *, doublereal *, |
257 | 0 | integer *, doublereal *, doublereal *, doublereal *, integer *); |
258 | 0 | IGRAPH_F77_SAVE logical update; |
259 | 0 | extern /* Subroutine */ int igraphdsaitr_(integer *, char *, integer *, integer |
260 | 0 | *, integer *, integer *, doublereal *, doublereal *, doublereal *, |
261 | 0 | integer *, doublereal *, integer *, integer *, doublereal *, |
262 | 0 | integer *), igraphdsgets_(integer *, char *, integer *, integer |
263 | 0 | *, doublereal *, doublereal *, doublereal *), igraphdsapps_( |
264 | 0 | integer *, integer *, integer *, doublereal *, doublereal *, |
265 | 0 | integer *, doublereal *, integer *, doublereal *, doublereal *, |
266 | 0 | integer *, doublereal *), igraphdsconv_(integer *, doublereal *, |
267 | 0 | doublereal *, doublereal *, integer *); |
268 | 0 | IGRAPH_F77_SAVE logical ushift; |
269 | 0 | char wprime[2]; |
270 | 0 | IGRAPH_F77_SAVE integer msglvl; |
271 | 0 | integer nptemp; |
272 | 0 | extern /* Subroutine */ int igraphdsortr_(char *, logical *, integer *, |
273 | 0 | doublereal *, doublereal *); |
274 | 0 | IGRAPH_F77_SAVE integer kplusp; |
275 | | |
276 | | |
277 | | /* %----------------------------------------------------% |
278 | | | Include files for debugging and timing information | |
279 | | %----------------------------------------------------% |
280 | | |
281 | | |
282 | | %------------------% |
283 | | | Scalar Arguments | |
284 | | %------------------% |
285 | | |
286 | | |
287 | | %-----------------% |
288 | | | Array Arguments | |
289 | | %-----------------% |
290 | | |
291 | | |
292 | | %------------% |
293 | | | Parameters | |
294 | | %------------% |
295 | | |
296 | | |
297 | | %---------------% |
298 | | | Local Scalars | |
299 | | %---------------% |
300 | | |
301 | | |
302 | | %----------------------% |
303 | | | External Subroutines | |
304 | | %----------------------% |
305 | | |
306 | | |
307 | | %--------------------% |
308 | | | External Functions | |
309 | | %--------------------% |
310 | | |
311 | | |
312 | | %---------------------% |
313 | | | Intrinsic Functions | |
314 | | %---------------------% |
315 | | |
316 | | |
317 | | %-----------------------% |
318 | | | Executable Statements | |
319 | | %-----------------------% |
320 | | |
321 | | Parameter adjustments */ |
322 | 0 | --workd; |
323 | 0 | --resid; |
324 | 0 | --workl; |
325 | 0 | --bounds; |
326 | 0 | --ritz; |
327 | 0 | v_dim1 = *ldv; |
328 | 0 | v_offset = 1 + v_dim1; |
329 | 0 | v -= v_offset; |
330 | 0 | h_dim1 = *ldh; |
331 | 0 | h_offset = 1 + h_dim1; |
332 | 0 | h__ -= h_offset; |
333 | 0 | q_dim1 = *ldq; |
334 | 0 | q_offset = 1 + q_dim1; |
335 | 0 | q -= q_offset; |
336 | 0 | --ipntr; |
337 | | |
338 | | /* Function Body */ |
339 | 0 | if (*ido == 0) { |
340 | | |
341 | | /* %-------------------------------% |
342 | | | Initialize timing statistics | |
343 | | | & message level for debugging | |
344 | | %-------------------------------% */ |
345 | |
|
346 | 0 | igraphsecond_(&t0); |
347 | 0 | msglvl = msaup2; |
348 | | |
349 | | /* %---------------------------------% |
350 | | | Set machine dependent constant. | |
351 | | %---------------------------------% */ |
352 | |
|
353 | 0 | eps23 = igraphdlamch_("Epsilon-Machine"); |
354 | 0 | eps23 = pow_dd(&eps23, &c_b3); |
355 | | |
356 | | /* %-------------------------------------% |
357 | | | nev0 and np0 are integer variables | |
358 | | | hold the initial values of NEV & NP | |
359 | | %-------------------------------------% */ |
360 | |
|
361 | 0 | nev0 = *nev; |
362 | 0 | np0 = *np; |
363 | | |
364 | | /* %-------------------------------------% |
365 | | | kplusp is the bound on the largest | |
366 | | | Lanczos factorization built. | |
367 | | | nconv is the current number of | |
368 | | | "converged" eigenvlues. | |
369 | | | iter is the counter on the current | |
370 | | | iteration step. | |
371 | | %-------------------------------------% */ |
372 | |
|
373 | 0 | kplusp = nev0 + np0; |
374 | 0 | nconv = 0; |
375 | 0 | iter = 0; |
376 | | |
377 | | /* %--------------------------------------------% |
378 | | | Set flags for computing the first NEV steps | |
379 | | | of the Lanczos factorization. | |
380 | | %--------------------------------------------% */ |
381 | |
|
382 | 0 | getv0 = TRUE_; |
383 | 0 | update = FALSE_; |
384 | 0 | ushift = FALSE_; |
385 | 0 | cnorm = FALSE_; |
386 | |
|
387 | 0 | if (*info != 0) { |
388 | | |
389 | | /* %--------------------------------------------% |
390 | | | User provides the initial residual vector. | |
391 | | %--------------------------------------------% */ |
392 | |
|
393 | 0 | initv = TRUE_; |
394 | 0 | *info = 0; |
395 | 0 | } else { |
396 | 0 | initv = FALSE_; |
397 | 0 | } |
398 | 0 | } |
399 | | |
400 | | /* %---------------------------------------------% |
401 | | | Get a possibly random starting vector and | |
402 | | | force it into the range of the operator OP. | |
403 | | %---------------------------------------------% |
404 | | |
405 | | L10: */ |
406 | |
|
407 | 0 | if (getv0) { |
408 | 0 | igraphdgetv0_(ido, bmat, &c__1, &initv, n, &c__1, &v[v_offset], ldv, &resid[ |
409 | 0 | 1], &rnorm, &ipntr[1], &workd[1], info); |
410 | |
|
411 | 0 | if (*ido != 99) { |
412 | 0 | goto L9000; |
413 | 0 | } |
414 | | |
415 | 0 | if (rnorm == 0.) { |
416 | | |
417 | | /* %-----------------------------------------% |
418 | | | The initial vector is zero. Error exit. | |
419 | | %-----------------------------------------% */ |
420 | |
|
421 | 0 | *info = -9; |
422 | 0 | goto L1200; |
423 | 0 | } |
424 | 0 | getv0 = FALSE_; |
425 | 0 | *ido = 0; |
426 | 0 | } |
427 | | |
428 | | /* %------------------------------------------------------------% |
429 | | | Back from reverse communication: continue with update step | |
430 | | %------------------------------------------------------------% */ |
431 | | |
432 | 0 | if (update) { |
433 | 0 | goto L20; |
434 | 0 | } |
435 | | |
436 | | /* %-------------------------------------------% |
437 | | | Back from computing user specified shifts | |
438 | | %-------------------------------------------% */ |
439 | | |
440 | 0 | if (ushift) { |
441 | 0 | goto L50; |
442 | 0 | } |
443 | | |
444 | | /* %-------------------------------------% |
445 | | | Back from computing residual norm | |
446 | | | at the end of the current iteration | |
447 | | %-------------------------------------% */ |
448 | | |
449 | 0 | if (cnorm) { |
450 | 0 | goto L100; |
451 | 0 | } |
452 | | |
453 | | /* %----------------------------------------------------------% |
454 | | | Compute the first NEV steps of the Lanczos factorization | |
455 | | %----------------------------------------------------------% */ |
456 | | |
457 | 0 | igraphdsaitr_(ido, bmat, n, &c__0, &nev0, mode, &resid[1], &rnorm, &v[v_offset], |
458 | 0 | ldv, &h__[h_offset], ldh, &ipntr[1], &workd[1], info); |
459 | | |
460 | | /* %---------------------------------------------------% |
461 | | | ido .ne. 99 implies use of reverse communication | |
462 | | | to compute operations involving OP and possibly B | |
463 | | %---------------------------------------------------% */ |
464 | |
|
465 | 0 | if (*ido != 99) { |
466 | 0 | goto L9000; |
467 | 0 | } |
468 | | |
469 | 0 | if (*info > 0) { |
470 | | |
471 | | /* %-----------------------------------------------------% |
472 | | | dsaitr was unable to build an Lanczos factorization | |
473 | | | of length NEV0. INFO is returned with the size of | |
474 | | | the factorization built. Exit main loop. | |
475 | | %-----------------------------------------------------% */ |
476 | |
|
477 | 0 | *np = *info; |
478 | 0 | *mxiter = iter; |
479 | 0 | *info = -9999; |
480 | 0 | goto L1200; |
481 | 0 | } |
482 | | |
483 | | /* %--------------------------------------------------------------% |
484 | | | | |
485 | | | M A I N LANCZOS I T E R A T I O N L O O P | |
486 | | | Each iteration implicitly restarts the Lanczos | |
487 | | | factorization in place. | |
488 | | | | |
489 | | %--------------------------------------------------------------% */ |
490 | | |
491 | 0 | L1000: |
492 | |
|
493 | 0 | ++iter; |
494 | |
|
495 | 0 | if (msglvl > 0) { |
496 | 0 | igraphivout_(&logfil, &c__1, &iter, &ndigit, "_saup2: **** Start of major " |
497 | 0 | "iteration number ****", (ftnlen)49); |
498 | 0 | } |
499 | 0 | if (msglvl > 1) { |
500 | 0 | igraphivout_(&logfil, &c__1, nev, &ndigit, "_saup2: The length of the curr" |
501 | 0 | "ent Lanczos factorization", (ftnlen)55); |
502 | 0 | igraphivout_(&logfil, &c__1, np, &ndigit, "_saup2: Extend the Lanczos fact" |
503 | 0 | "orization by", (ftnlen)43); |
504 | 0 | } |
505 | | |
506 | | /* %------------------------------------------------------------% |
507 | | | Compute NP additional steps of the Lanczos factorization. | |
508 | | %------------------------------------------------------------% */ |
509 | |
|
510 | 0 | *ido = 0; |
511 | 0 | L20: |
512 | 0 | update = TRUE_; |
513 | |
|
514 | 0 | igraphdsaitr_(ido, bmat, n, nev, np, mode, &resid[1], &rnorm, &v[v_offset], ldv, |
515 | 0 | &h__[h_offset], ldh, &ipntr[1], &workd[1], info); |
516 | | |
517 | | /* %---------------------------------------------------% |
518 | | | ido .ne. 99 implies use of reverse communication | |
519 | | | to compute operations involving OP and possibly B | |
520 | | %---------------------------------------------------% */ |
521 | |
|
522 | 0 | if (*ido != 99) { |
523 | 0 | goto L9000; |
524 | 0 | } |
525 | | |
526 | 0 | if (*info > 0) { |
527 | | |
528 | | /* %-----------------------------------------------------% |
529 | | | dsaitr was unable to build an Lanczos factorization | |
530 | | | of length NEV0+NP0. INFO is returned with the size | |
531 | | | of the factorization built. Exit main loop. | |
532 | | %-----------------------------------------------------% */ |
533 | |
|
534 | 0 | *np = *info; |
535 | 0 | *mxiter = iter; |
536 | 0 | *info = -9999; |
537 | 0 | goto L1200; |
538 | 0 | } |
539 | 0 | update = FALSE_; |
540 | |
|
541 | 0 | if (msglvl > 1) { |
542 | 0 | igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_saup2: Current B-norm of r" |
543 | 0 | "esidual for factorization", (ftnlen)52); |
544 | 0 | } |
545 | | |
546 | | /* %--------------------------------------------------------% |
547 | | | Compute the eigenvalues and corresponding error bounds | |
548 | | | of the current symmetric tridiagonal matrix. | |
549 | | %--------------------------------------------------------% */ |
550 | |
|
551 | 0 | igraphdseigt_(&rnorm, &kplusp, &h__[h_offset], ldh, &ritz[1], &bounds[1], & |
552 | 0 | workl[1], &ierr); |
553 | |
|
554 | 0 | if (ierr != 0) { |
555 | 0 | *info = -8; |
556 | 0 | goto L1200; |
557 | 0 | } |
558 | | |
559 | | /* %----------------------------------------------------% |
560 | | | Make a copy of eigenvalues and corresponding error | |
561 | | | bounds obtained from _seigt. | |
562 | | %----------------------------------------------------% */ |
563 | | |
564 | 0 | igraphdcopy_(&kplusp, &ritz[1], &c__1, &workl[kplusp + 1], &c__1); |
565 | 0 | igraphdcopy_(&kplusp, &bounds[1], &c__1, &workl[(kplusp << 1) + 1], &c__1); |
566 | | |
567 | | /* %---------------------------------------------------% |
568 | | | Select the wanted Ritz values and their bounds | |
569 | | | to be used in the convergence test. | |
570 | | | The selection is based on the requested number of | |
571 | | | eigenvalues instead of the current NEV and NP to | |
572 | | | prevent possible misconvergence. | |
573 | | | * Wanted Ritz values := RITZ(NP+1:NEV+NP) | |
574 | | | * Shifts := RITZ(1:NP) := WORKL(1:NP) | |
575 | | %---------------------------------------------------% */ |
576 | |
|
577 | 0 | *nev = nev0; |
578 | 0 | *np = np0; |
579 | 0 | igraphdsgets_(ishift, which, nev, np, &ritz[1], &bounds[1], &workl[1]); |
580 | | |
581 | | /* %-------------------% |
582 | | | Convergence test. | |
583 | | %-------------------% */ |
584 | |
|
585 | 0 | igraphdcopy_(nev, &bounds[*np + 1], &c__1, &workl[*np + 1], &c__1); |
586 | 0 | igraphdsconv_(nev, &ritz[*np + 1], &workl[*np + 1], tol, &nconv); |
587 | |
|
588 | 0 | if (msglvl > 2) { |
589 | 0 | kp[0] = *nev; |
590 | 0 | kp[1] = *np; |
591 | 0 | kp[2] = nconv; |
592 | 0 | igraphivout_(&logfil, &c__3, kp, &ndigit, "_saup2: NEV, NP, NCONV are", ( |
593 | 0 | ftnlen)26); |
594 | 0 | igraphdvout_(&logfil, &kplusp, &ritz[1], &ndigit, "_saup2: The eigenvalues" |
595 | 0 | " of H", (ftnlen)28); |
596 | 0 | igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_saup2: Ritz estimate" |
597 | 0 | "s of the current NCV Ritz values", (ftnlen)53); |
598 | 0 | } |
599 | | |
600 | | /* %---------------------------------------------------------% |
601 | | | Count the number of unwanted Ritz values that have zero | |
602 | | | Ritz estimates. If any Ritz estimates are equal to zero | |
603 | | | then a leading block of H of order equal to at least | |
604 | | | the number of Ritz values with zero Ritz estimates has | |
605 | | | split off. None of these Ritz values may be removed by | |
606 | | | shifting. Decrease NP the number of shifts to apply. If | |
607 | | | no shifts may be applied, then prepare to exit | |
608 | | %---------------------------------------------------------% */ |
609 | |
|
610 | 0 | nptemp = *np; |
611 | 0 | i__1 = nptemp; |
612 | 0 | for (j = 1; j <= i__1; ++j) { |
613 | 0 | if (bounds[j] == 0.) { |
614 | 0 | --(*np); |
615 | 0 | ++(*nev); |
616 | 0 | } |
617 | | /* L30: */ |
618 | 0 | } |
619 | |
|
620 | 0 | if (nconv >= nev0 || iter > *mxiter || *np == 0) { |
621 | | |
622 | | /* %------------------------------------------------% |
623 | | | Prepare to exit. Put the converged Ritz values | |
624 | | | and corresponding bounds in RITZ(1:NCONV) and | |
625 | | | BOUNDS(1:NCONV) respectively. Then sort. Be | |
626 | | | careful when NCONV > NP since we don't want to | |
627 | | | swap overlapping locations. | |
628 | | %------------------------------------------------% */ |
629 | |
|
630 | 0 | if (s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) { |
631 | | |
632 | | /* %-----------------------------------------------------% |
633 | | | Both ends of the spectrum are requested. | |
634 | | | Sort the eigenvalues into algebraically decreasing | |
635 | | | order first then swap low end of the spectrum next | |
636 | | | to high end in appropriate locations. | |
637 | | | NOTE: when np < floor(nev/2) be careful not to swap | |
638 | | | overlapping locations. | |
639 | | %-----------------------------------------------------% */ |
640 | |
|
641 | 0 | s_copy(wprime, "SA", (ftnlen)2, (ftnlen)2); |
642 | 0 | igraphdsortr_(wprime, &c_true, &kplusp, &ritz[1], &bounds[1]) |
643 | 0 | ; |
644 | 0 | nevd2 = *nev / 2; |
645 | 0 | nevm2 = *nev - nevd2; |
646 | 0 | if (*nev > 1) { |
647 | 0 | i__1 = min(nevd2,*np); |
648 | | /* Computing MAX */ |
649 | 0 | i__2 = kplusp - nevd2 + 1, i__3 = kplusp - *np + 1; |
650 | 0 | igraphdswap_(&i__1, &ritz[nevm2 + 1], &c__1, &ritz[max(i__2,i__3)], |
651 | 0 | &c__1); |
652 | 0 | i__1 = min(nevd2,*np); |
653 | | /* Computing MAX */ |
654 | 0 | i__2 = kplusp - nevd2 + 1, i__3 = kplusp - *np; |
655 | 0 | igraphdswap_(&i__1, &bounds[nevm2 + 1], &c__1, &bounds[max(i__2, |
656 | 0 | i__3) + 1], &c__1); |
657 | 0 | } |
658 | |
|
659 | 0 | } else { |
660 | | |
661 | | /* %--------------------------------------------------% |
662 | | | LM, SM, LA, SA case. | |
663 | | | Sort the eigenvalues of H into the an order that | |
664 | | | is opposite to WHICH, and apply the resulting | |
665 | | | order to BOUNDS. The eigenvalues are sorted so | |
666 | | | that the wanted part are always within the first | |
667 | | | NEV locations. | |
668 | | %--------------------------------------------------% */ |
669 | |
|
670 | 0 | if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) { |
671 | 0 | s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2); |
672 | 0 | } |
673 | 0 | if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) { |
674 | 0 | s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2); |
675 | 0 | } |
676 | 0 | if (s_cmp(which, "LA", (ftnlen)2, (ftnlen)2) == 0) { |
677 | 0 | s_copy(wprime, "SA", (ftnlen)2, (ftnlen)2); |
678 | 0 | } |
679 | 0 | if (s_cmp(which, "SA", (ftnlen)2, (ftnlen)2) == 0) { |
680 | 0 | s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2); |
681 | 0 | } |
682 | |
|
683 | 0 | igraphdsortr_(wprime, &c_true, &kplusp, &ritz[1], &bounds[1]) |
684 | 0 | ; |
685 | |
|
686 | 0 | } |
687 | | |
688 | | /* %--------------------------------------------------% |
689 | | | Scale the Ritz estimate of each Ritz value | |
690 | | | by 1 / max(eps23,magnitude of the Ritz value). | |
691 | | %--------------------------------------------------% */ |
692 | |
|
693 | 0 | i__1 = nev0; |
694 | 0 | for (j = 1; j <= i__1; ++j) { |
695 | | /* Computing MAX */ |
696 | 0 | d__2 = eps23, d__3 = (d__1 = ritz[j], abs(d__1)); |
697 | 0 | temp = max(d__2,d__3); |
698 | 0 | bounds[j] /= temp; |
699 | | /* L35: */ |
700 | 0 | } |
701 | | |
702 | | /* %----------------------------------------------------% |
703 | | | Sort the Ritz values according to the scaled Ritz | |
704 | | | esitmates. This will push all the converged ones | |
705 | | | towards the front of ritzr, ritzi, bounds | |
706 | | | (in the case when NCONV < NEV.) | |
707 | | %----------------------------------------------------% */ |
708 | |
|
709 | 0 | s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2); |
710 | 0 | igraphdsortr_(wprime, &c_true, &nev0, &bounds[1], &ritz[1]); |
711 | | |
712 | | /* %----------------------------------------------% |
713 | | | Scale the Ritz estimate back to its original | |
714 | | | value. | |
715 | | %----------------------------------------------% */ |
716 | |
|
717 | 0 | i__1 = nev0; |
718 | 0 | for (j = 1; j <= i__1; ++j) { |
719 | | /* Computing MAX */ |
720 | 0 | d__2 = eps23, d__3 = (d__1 = ritz[j], abs(d__1)); |
721 | 0 | temp = max(d__2,d__3); |
722 | 0 | bounds[j] *= temp; |
723 | | /* L40: */ |
724 | 0 | } |
725 | | |
726 | | /* %--------------------------------------------------% |
727 | | | Sort the "converged" Ritz values again so that | |
728 | | | the "threshold" values and their associated Ritz | |
729 | | | estimates appear at the appropriate position in | |
730 | | | ritz and bound. | |
731 | | %--------------------------------------------------% */ |
732 | |
|
733 | 0 | if (s_cmp(which, "BE", (ftnlen)2, (ftnlen)2) == 0) { |
734 | | |
735 | | /* %------------------------------------------------% |
736 | | | Sort the "converged" Ritz values in increasing | |
737 | | | order. The "threshold" values are in the | |
738 | | | middle. | |
739 | | %------------------------------------------------% */ |
740 | |
|
741 | 0 | s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2); |
742 | 0 | igraphdsortr_(wprime, &c_true, &nconv, &ritz[1], &bounds[1]); |
743 | |
|
744 | 0 | } else { |
745 | | |
746 | | /* %----------------------------------------------% |
747 | | | In LM, SM, LA, SA case, sort the "converged" | |
748 | | | Ritz values according to WHICH so that the | |
749 | | | "threshold" value appears at the front of | |
750 | | | ritz. | |
751 | | %----------------------------------------------% */ |
752 | 0 | igraphdsortr_(which, &c_true, &nconv, &ritz[1], &bounds[1]); |
753 | |
|
754 | 0 | } |
755 | | |
756 | | /* %------------------------------------------% |
757 | | | Use h( 1,1 ) as storage to communicate | |
758 | | | rnorm to _seupd if needed | |
759 | | %------------------------------------------% */ |
760 | |
|
761 | 0 | h__[h_dim1 + 1] = rnorm; |
762 | |
|
763 | 0 | if (msglvl > 1) { |
764 | 0 | igraphdvout_(&logfil, &kplusp, &ritz[1], &ndigit, "_saup2: Sorted Ritz" |
765 | 0 | " values.", (ftnlen)27); |
766 | 0 | igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_saup2: Sorted ri" |
767 | 0 | "tz estimates.", (ftnlen)30); |
768 | 0 | } |
769 | | |
770 | | /* %------------------------------------% |
771 | | | Max iterations have been exceeded. | |
772 | | %------------------------------------% */ |
773 | |
|
774 | 0 | if (iter > *mxiter && nconv < *nev) { |
775 | 0 | *info = 1; |
776 | 0 | } |
777 | | |
778 | | /* %---------------------% |
779 | | | No shifts to apply. | |
780 | | %---------------------% */ |
781 | |
|
782 | 0 | if (*np == 0 && nconv < nev0) { |
783 | 0 | *info = 2; |
784 | 0 | } |
785 | |
|
786 | 0 | *np = nconv; |
787 | 0 | goto L1100; |
788 | |
|
789 | 0 | } else if (nconv < *nev && *ishift == 1) { |
790 | | |
791 | | /* %---------------------------------------------------% |
792 | | | Do not have all the requested eigenvalues yet. | |
793 | | | To prevent possible stagnation, adjust the number | |
794 | | | of Ritz values and the shifts. | |
795 | | %---------------------------------------------------% */ |
796 | |
|
797 | 0 | nevbef = *nev; |
798 | | /* Computing MIN */ |
799 | 0 | i__1 = nconv, i__2 = *np / 2; |
800 | 0 | *nev += min(i__1,i__2); |
801 | 0 | if (*nev == 1 && kplusp >= 6) { |
802 | 0 | *nev = kplusp / 2; |
803 | 0 | } else if (*nev == 1 && kplusp > 2) { |
804 | 0 | *nev = 2; |
805 | 0 | } |
806 | 0 | *np = kplusp - *nev; |
807 | | |
808 | | /* %---------------------------------------% |
809 | | | If the size of NEV was just increased | |
810 | | | resort the eigenvalues. | |
811 | | %---------------------------------------% */ |
812 | |
|
813 | 0 | if (nevbef < *nev) { |
814 | 0 | igraphdsgets_(ishift, which, nev, np, &ritz[1], &bounds[1], &workl[1]); |
815 | 0 | } |
816 | |
|
817 | 0 | } |
818 | | |
819 | 0 | if (msglvl > 0) { |
820 | 0 | igraphivout_(&logfil, &c__1, &nconv, &ndigit, "_saup2: no. of \"converge" |
821 | 0 | "d\" Ritz values at this iter.", (ftnlen)52); |
822 | 0 | if (msglvl > 1) { |
823 | 0 | kp[0] = *nev; |
824 | 0 | kp[1] = *np; |
825 | 0 | igraphivout_(&logfil, &c__2, kp, &ndigit, "_saup2: NEV and NP are", ( |
826 | 0 | ftnlen)22); |
827 | 0 | igraphdvout_(&logfil, nev, &ritz[*np + 1], &ndigit, "_saup2: \"wante" |
828 | 0 | "d\" Ritz values.", (ftnlen)29); |
829 | 0 | igraphdvout_(&logfil, nev, &bounds[*np + 1], &ndigit, "_saup2: Ritz es" |
830 | 0 | "timates of the \"wanted\" values ", (ftnlen)46); |
831 | 0 | } |
832 | 0 | } |
833 | |
|
834 | 0 | if (*ishift == 0) { |
835 | | |
836 | | /* %-----------------------------------------------------% |
837 | | | User specified shifts: reverse communication to | |
838 | | | compute the shifts. They are returned in the first | |
839 | | | NP locations of WORKL. | |
840 | | %-----------------------------------------------------% */ |
841 | |
|
842 | 0 | ushift = TRUE_; |
843 | 0 | *ido = 3; |
844 | 0 | goto L9000; |
845 | 0 | } |
846 | | |
847 | 0 | L50: |
848 | | |
849 | | /* %------------------------------------% |
850 | | | Back from reverse communication; | |
851 | | | User specified shifts are returned | |
852 | | | in WORKL(1:*NP) | |
853 | | %------------------------------------% */ |
854 | |
|
855 | 0 | ushift = FALSE_; |
856 | | |
857 | | |
858 | | /* %---------------------------------------------------------% |
859 | | | Move the NP shifts to the first NP locations of RITZ to | |
860 | | | free up WORKL. This is for the non-exact shift case; | |
861 | | | in the exact shift case, dsgets already handles this. | |
862 | | %---------------------------------------------------------% */ |
863 | |
|
864 | 0 | if (*ishift == 0) { |
865 | 0 | igraphdcopy_(np, &workl[1], &c__1, &ritz[1], &c__1); |
866 | 0 | } |
867 | |
|
868 | 0 | if (msglvl > 2) { |
869 | 0 | igraphivout_(&logfil, &c__1, np, &ndigit, "_saup2: The number of shifts to" |
870 | 0 | " apply ", (ftnlen)38); |
871 | 0 | igraphdvout_(&logfil, np, &workl[1], &ndigit, "_saup2: shifts selected", ( |
872 | 0 | ftnlen)23); |
873 | 0 | if (*ishift == 1) { |
874 | 0 | igraphdvout_(&logfil, np, &bounds[1], &ndigit, "_saup2: corresponding " |
875 | 0 | "Ritz estimates", (ftnlen)36); |
876 | 0 | } |
877 | 0 | } |
878 | | |
879 | | /* %---------------------------------------------------------% |
880 | | | Apply the NP0 implicit shifts by QR bulge chasing. | |
881 | | | Each shift is applied to the entire tridiagonal matrix. | |
882 | | | The first 2*N locations of WORKD are used as workspace. | |
883 | | | After dsapps is done, we have a Lanczos | |
884 | | | factorization of length NEV. | |
885 | | %---------------------------------------------------------% */ |
886 | |
|
887 | 0 | igraphdsapps_(n, nev, np, &ritz[1], &v[v_offset], ldv, &h__[h_offset], ldh, & |
888 | 0 | resid[1], &q[q_offset], ldq, &workd[1]); |
889 | | |
890 | | /* %---------------------------------------------% |
891 | | | Compute the B-norm of the updated residual. | |
892 | | | Keep B*RESID in WORKD(1:N) to be used in | |
893 | | | the first step of the next call to dsaitr. | |
894 | | %---------------------------------------------% */ |
895 | |
|
896 | 0 | cnorm = TRUE_; |
897 | 0 | igraphsecond_(&t2); |
898 | 0 | if (*(unsigned char *)bmat == 'G') { |
899 | 0 | ++nbx; |
900 | 0 | igraphdcopy_(n, &resid[1], &c__1, &workd[*n + 1], &c__1); |
901 | 0 | ipntr[1] = *n + 1; |
902 | 0 | ipntr[2] = 1; |
903 | 0 | *ido = 2; |
904 | | |
905 | | /* %----------------------------------% |
906 | | | Exit in order to compute B*RESID | |
907 | | %----------------------------------% */ |
908 | |
|
909 | 0 | goto L9000; |
910 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
911 | 0 | igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1); |
912 | 0 | } |
913 | | |
914 | 0 | L100: |
915 | | |
916 | | /* %----------------------------------% |
917 | | | Back from reverse communication; | |
918 | | | WORKD(1:N) := B*RESID | |
919 | | %----------------------------------% */ |
920 | |
|
921 | 0 | if (*(unsigned char *)bmat == 'G') { |
922 | 0 | igraphsecond_(&t3); |
923 | 0 | tmvbx += t3 - t2; |
924 | 0 | } |
925 | |
|
926 | 0 | if (*(unsigned char *)bmat == 'G') { |
927 | 0 | rnorm = igraphddot_(n, &resid[1], &c__1, &workd[1], &c__1); |
928 | 0 | rnorm = sqrt((abs(rnorm))); |
929 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
930 | 0 | rnorm = igraphdnrm2_(n, &resid[1], &c__1); |
931 | 0 | } |
932 | 0 | cnorm = FALSE_; |
933 | | /* L130: */ |
934 | |
|
935 | 0 | if (msglvl > 2) { |
936 | 0 | igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_saup2: B-norm of residual " |
937 | 0 | "for NEV factorization", (ftnlen)48); |
938 | 0 | igraphdvout_(&logfil, nev, &h__[(h_dim1 << 1) + 1], &ndigit, "_saup2: main" |
939 | 0 | " diagonal of compressed H matrix", (ftnlen)44); |
940 | 0 | i__1 = *nev - 1; |
941 | 0 | igraphdvout_(&logfil, &i__1, &h__[h_dim1 + 2], &ndigit, "_saup2: subdiagon" |
942 | 0 | "al of compressed H matrix", (ftnlen)42); |
943 | 0 | } |
944 | |
|
945 | 0 | goto L1000; |
946 | | |
947 | | /* %---------------------------------------------------------------% |
948 | | | | |
949 | | | E N D O F M A I N I T E R A T I O N L O O P | |
950 | | | | |
951 | | %---------------------------------------------------------------% */ |
952 | | |
953 | 0 | L1100: |
954 | |
|
955 | 0 | *mxiter = iter; |
956 | 0 | *nev = nconv; |
957 | |
|
958 | 0 | L1200: |
959 | 0 | *ido = 99; |
960 | | |
961 | | /* %------------% |
962 | | | Error exit | |
963 | | %------------% */ |
964 | |
|
965 | 0 | igraphsecond_(&t1); |
966 | 0 | tsaup2 = t1 - t0; |
967 | |
|
968 | 0 | L9000: |
969 | 0 | return 0; |
970 | | |
971 | | /* %---------------% |
972 | | | End of dsaup2 | |
973 | | %---------------% */ |
974 | |
|
975 | 0 | } /* igraphdsaup2_ */ |
976 | | |