/src/igraph/vendor/lapack/dsaitr.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 integer c__1 = 1; |
18 | | static logical c_false = FALSE_; |
19 | | static doublereal c_b24 = 1.; |
20 | | static doublereal c_b49 = 0.; |
21 | | static doublereal c_b57 = -1.; |
22 | | static integer c__2 = 2; |
23 | | |
24 | | /* ----------------------------------------------------------------------- |
25 | | \BeginDoc |
26 | | |
27 | | \Name: dsaitr |
28 | | |
29 | | \Description: |
30 | | Reverse communication interface for applying NP additional steps to |
31 | | a K step symmetric Arnoldi factorization. |
32 | | |
33 | | Input: OP*V_{k} - V_{k}*H = r_{k}*e_{k}^T |
34 | | |
35 | | with (V_{k}^T)*B*V_{k} = I, (V_{k}^T)*B*r_{k} = 0. |
36 | | |
37 | | Output: OP*V_{k+p} - V_{k+p}*H = r_{k+p}*e_{k+p}^T |
38 | | |
39 | | with (V_{k+p}^T)*B*V_{k+p} = I, (V_{k+p}^T)*B*r_{k+p} = 0. |
40 | | |
41 | | where OP and B are as in dsaupd. The B-norm of r_{k+p} is also |
42 | | computed and returned. |
43 | | |
44 | | \Usage: |
45 | | call dsaitr |
46 | | ( IDO, BMAT, N, K, NP, MODE, RESID, RNORM, V, LDV, H, LDH, |
47 | | IPNTR, WORKD, INFO ) |
48 | | |
49 | | \Arguments |
50 | | IDO Integer. (INPUT/OUTPUT) |
51 | | Reverse communication flag. |
52 | | ------------------------------------------------------------- |
53 | | IDO = 0: first call to the reverse communication interface |
54 | | IDO = -1: compute Y = OP * X where |
55 | | IPNTR(1) is the pointer into WORK for X, |
56 | | IPNTR(2) is the pointer into WORK for Y. |
57 | | This is for the restart phase to force the new |
58 | | starting vector into the range of OP. |
59 | | IDO = 1: compute Y = OP * X where |
60 | | IPNTR(1) is the pointer into WORK for X, |
61 | | IPNTR(2) is the pointer into WORK for Y, |
62 | | IPNTR(3) is the pointer into WORK for B * X. |
63 | | IDO = 2: compute Y = B * X where |
64 | | IPNTR(1) is the pointer into WORK for X, |
65 | | IPNTR(2) is the pointer into WORK for Y. |
66 | | IDO = 99: done |
67 | | ------------------------------------------------------------- |
68 | | When the routine is used in the "shift-and-invert" mode, the |
69 | | vector B * Q is already available and does not need to be |
70 | | recomputed in forming OP * Q. |
71 | | |
72 | | BMAT Character*1. (INPUT) |
73 | | BMAT specifies the type of matrix B that defines the |
74 | | semi-inner product for the operator OP. See dsaupd. |
75 | | B = 'I' -> standard eigenvalue problem A*x = lambda*x |
76 | | B = 'G' -> generalized eigenvalue problem A*x = lambda*M*x |
77 | | |
78 | | N Integer. (INPUT) |
79 | | Dimension of the eigenproblem. |
80 | | |
81 | | K Integer. (INPUT) |
82 | | Current order of H and the number of columns of V. |
83 | | |
84 | | NP Integer. (INPUT) |
85 | | Number of additional Arnoldi steps to take. |
86 | | |
87 | | MODE Integer. (INPUT) |
88 | | Signifies which form for "OP". If MODE=2 then |
89 | | a reduction in the number of B matrix vector multiplies |
90 | | is possible since the B-norm of OP*x is equivalent to |
91 | | the inv(B)-norm of A*x. |
92 | | |
93 | | RESID Double precision array of length N. (INPUT/OUTPUT) |
94 | | On INPUT: RESID contains the residual vector r_{k}. |
95 | | On OUTPUT: RESID contains the residual vector r_{k+p}. |
96 | | |
97 | | RNORM Double precision scalar. (INPUT/OUTPUT) |
98 | | On INPUT the B-norm of r_{k}. |
99 | | On OUTPUT the B-norm of the updated residual r_{k+p}. |
100 | | |
101 | | V Double precision N by K+NP array. (INPUT/OUTPUT) |
102 | | On INPUT: V contains the Arnoldi vectors in the first K |
103 | | columns. |
104 | | On OUTPUT: V contains the new NP Arnoldi vectors in the next |
105 | | NP columns. The first K columns are unchanged. |
106 | | |
107 | | LDV Integer. (INPUT) |
108 | | Leading dimension of V exactly as declared in the calling |
109 | | program. |
110 | | |
111 | | H Double precision (K+NP) by 2 array. (INPUT/OUTPUT) |
112 | | H is used to store the generated symmetric tridiagonal matrix |
113 | | with the subdiagonal in the first column starting at H(2,1) |
114 | | and the main diagonal in the second column. |
115 | | |
116 | | LDH Integer. (INPUT) |
117 | | Leading dimension of H exactly as declared in the calling |
118 | | program. |
119 | | |
120 | | IPNTR Integer array of length 3. (OUTPUT) |
121 | | Pointer to mark the starting locations in the WORK for |
122 | | vectors used by the Arnoldi iteration. |
123 | | ------------------------------------------------------------- |
124 | | IPNTR(1): pointer to the current operand vector X. |
125 | | IPNTR(2): pointer to the current result vector Y. |
126 | | IPNTR(3): pointer to the vector B * X when used in the |
127 | | shift-and-invert mode. X is the current operand. |
128 | | ------------------------------------------------------------- |
129 | | |
130 | | WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION) |
131 | | Distributed array to be used in the basic Arnoldi iteration |
132 | | for reverse communication. The calling program should not |
133 | | use WORKD as temporary workspace during the iteration !!!!!! |
134 | | On INPUT, WORKD(1:N) = B*RESID where RESID is associated |
135 | | with the K step Arnoldi factorization. Used to save some |
136 | | computation at the first step. |
137 | | On OUTPUT, WORKD(1:N) = B*RESID where RESID is associated |
138 | | with the K+NP step Arnoldi factorization. |
139 | | |
140 | | INFO Integer. (OUTPUT) |
141 | | = 0: Normal exit. |
142 | | > 0: Size of an invariant subspace of OP is found that is |
143 | | less than K + NP. |
144 | | |
145 | | \EndDoc |
146 | | |
147 | | ----------------------------------------------------------------------- |
148 | | |
149 | | \BeginLib |
150 | | |
151 | | \Local variables: |
152 | | xxxxxx real |
153 | | |
154 | | \Routines called: |
155 | | dgetv0 ARPACK routine to generate the initial vector. |
156 | | ivout ARPACK utility routine that prints integers. |
157 | | dmout ARPACK utility routine that prints matrices. |
158 | | dvout ARPACK utility routine that prints vectors. |
159 | | dlamch LAPACK routine that determines machine constants. |
160 | | dlascl LAPACK routine for careful scaling of a matrix. |
161 | | dgemv Level 2 BLAS routine for matrix vector multiplication. |
162 | | daxpy Level 1 BLAS that computes a vector triad. |
163 | | dscal Level 1 BLAS that scales a vector. |
164 | | dcopy Level 1 BLAS that copies one vector to another . |
165 | | ddot Level 1 BLAS that computes the scalar product of two vectors. |
166 | | dnrm2 Level 1 BLAS that computes the norm of a vector. |
167 | | |
168 | | \Author |
169 | | Danny Sorensen Phuong Vu |
170 | | Richard Lehoucq CRPC / Rice University |
171 | | Dept. of Computational & Houston, Texas |
172 | | Applied Mathematics |
173 | | Rice University |
174 | | Houston, Texas |
175 | | |
176 | | \Revision history: |
177 | | xx/xx/93: Version ' 2.4' |
178 | | |
179 | | \SCCS Information: @(#) |
180 | | FILE: saitr.F SID: 2.6 DATE OF SID: 8/28/96 RELEASE: 2 |
181 | | |
182 | | \Remarks |
183 | | The algorithm implemented is: |
184 | | |
185 | | restart = .false. |
186 | | Given V_{k} = [v_{1}, ..., v_{k}], r_{k}; |
187 | | r_{k} contains the initial residual vector even for k = 0; |
188 | | Also assume that rnorm = || B*r_{k} || and B*r_{k} are already |
189 | | computed by the calling program. |
190 | | |
191 | | betaj = rnorm ; p_{k+1} = B*r_{k} ; |
192 | | For j = k+1, ..., k+np Do |
193 | | 1) if ( betaj < tol ) stop or restart depending on j. |
194 | | if ( restart ) generate a new starting vector. |
195 | | 2) v_{j} = r(j-1)/betaj; V_{j} = [V_{j-1}, v_{j}]; |
196 | | p_{j} = p_{j}/betaj |
197 | | 3) r_{j} = OP*v_{j} where OP is defined as in dsaupd |
198 | | For shift-invert mode p_{j} = B*v_{j} is already available. |
199 | | wnorm = || OP*v_{j} || |
200 | | 4) Compute the j-th step residual vector. |
201 | | w_{j} = V_{j}^T * B * OP * v_{j} |
202 | | r_{j} = OP*v_{j} - V_{j} * w_{j} |
203 | | alphaj <- j-th component of w_{j} |
204 | | rnorm = || r_{j} || |
205 | | betaj+1 = rnorm |
206 | | If (rnorm > 0.717*wnorm) accept step and go back to 1) |
207 | | 5) Re-orthogonalization step: |
208 | | s = V_{j}'*B*r_{j} |
209 | | r_{j} = r_{j} - V_{j}*s; rnorm1 = || r_{j} || |
210 | | alphaj = alphaj + s_{j}; |
211 | | 6) Iterative refinement step: |
212 | | If (rnorm1 > 0.717*rnorm) then |
213 | | rnorm = rnorm1 |
214 | | accept step and go back to 1) |
215 | | Else |
216 | | rnorm = rnorm1 |
217 | | If this is the first time in step 6), go to 5) |
218 | | Else r_{j} lies in the span of V_{j} numerically. |
219 | | Set r_{j} = 0 and rnorm = 0; go to 1) |
220 | | EndIf |
221 | | End Do |
222 | | |
223 | | \EndLib |
224 | | |
225 | | ----------------------------------------------------------------------- |
226 | | |
227 | | Subroutine */ int igraphdsaitr_(integer *ido, char *bmat, integer *n, integer *k, |
228 | | integer *np, integer *mode, doublereal *resid, doublereal *rnorm, |
229 | | doublereal *v, integer *ldv, doublereal *h__, integer *ldh, integer * |
230 | | ipntr, doublereal *workd, integer *info) |
231 | 0 | { |
232 | | /* Initialized data */ |
233 | |
|
234 | 0 | IGRAPH_F77_SAVE logical first = TRUE_; |
235 | | |
236 | | /* System generated locals */ |
237 | 0 | integer h_dim1, h_offset, v_dim1, v_offset, i__1; |
238 | | |
239 | | /* Builtin functions */ |
240 | 0 | double sqrt(doublereal); |
241 | | |
242 | | /* Local variables */ |
243 | 0 | integer i__; |
244 | 0 | IGRAPH_F77_SAVE integer j; |
245 | 0 | IGRAPH_F77_SAVE real t0, t1, t2, t3, t4, t5; |
246 | 0 | integer jj; |
247 | 0 | IGRAPH_F77_SAVE integer ipj, irj; |
248 | 0 | integer nbx = 0; |
249 | 0 | IGRAPH_F77_SAVE integer ivj; |
250 | 0 | extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, |
251 | 0 | integer *); |
252 | 0 | IGRAPH_F77_SAVE integer ierr, iter; |
253 | 0 | integer nopx = 0; |
254 | 0 | IGRAPH_F77_SAVE integer itry; |
255 | 0 | extern doublereal igraphdnrm2_(integer *, doublereal *, integer *); |
256 | 0 | doublereal temp1; |
257 | 0 | IGRAPH_F77_SAVE logical orth1, orth2, step3, step4; |
258 | 0 | extern /* Subroutine */ int igraphdscal_(integer *, doublereal *, doublereal *, |
259 | 0 | integer *), igraphdgemv_(char *, integer *, integer *, doublereal *, |
260 | 0 | doublereal *, integer *, doublereal *, integer *, doublereal *, |
261 | 0 | doublereal *, integer *); |
262 | 0 | integer infol; |
263 | 0 | extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, |
264 | 0 | doublereal *, integer *); |
265 | 0 | doublereal xtemp[2]; |
266 | 0 | real tmvbx = 0; |
267 | 0 | extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, |
268 | 0 | integer *, char *, ftnlen); |
269 | 0 | IGRAPH_F77_SAVE doublereal wnorm; |
270 | 0 | extern /* Subroutine */ int igraphivout_(integer *, integer *, integer *, |
271 | 0 | integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer *, |
272 | 0 | logical *, integer *, integer *, doublereal *, integer *, |
273 | 0 | doublereal *, doublereal *, integer *, doublereal *, integer *); |
274 | 0 | IGRAPH_F77_SAVE doublereal rnorm1; |
275 | 0 | extern doublereal igraphdlamch_(char *); |
276 | 0 | extern /* Subroutine */ int igraphdlascl_(char *, integer *, integer *, |
277 | 0 | doublereal *, doublereal *, integer *, integer *, doublereal *, |
278 | 0 | integer *, integer *), igraphsecond_(real *); |
279 | 0 | integer logfil; |
280 | 0 | IGRAPH_F77_SAVE doublereal safmin; |
281 | 0 | integer ndigit = 0, nitref = 0; |
282 | 0 | real titref = 0; |
283 | 0 | integer msaitr = 0; |
284 | 0 | IGRAPH_F77_SAVE integer msglvl; |
285 | 0 | real tsaitr = 0; |
286 | 0 | integer nrorth = 0; |
287 | 0 | IGRAPH_F77_SAVE logical rstart; |
288 | 0 | integer nrstrt = 0; |
289 | 0 | real tmvopx = 0; |
290 | | |
291 | | |
292 | | /* %----------------------------------------------------% |
293 | | | Include files for debugging and timing information | |
294 | | %----------------------------------------------------% |
295 | | |
296 | | |
297 | | %------------------% |
298 | | | Scalar Arguments | |
299 | | %------------------% |
300 | | |
301 | | |
302 | | %-----------------% |
303 | | | Array Arguments | |
304 | | %-----------------% |
305 | | |
306 | | |
307 | | %------------% |
308 | | | Parameters | |
309 | | %------------% |
310 | | |
311 | | |
312 | | %---------------% |
313 | | | Local Scalars | |
314 | | %---------------% |
315 | | |
316 | | |
317 | | %-----------------------% |
318 | | | Local Array Arguments | |
319 | | %-----------------------% |
320 | | |
321 | | |
322 | | %----------------------% |
323 | | | External Subroutines | |
324 | | %----------------------% |
325 | | |
326 | | |
327 | | %--------------------% |
328 | | | External Functions | |
329 | | %--------------------% |
330 | | |
331 | | |
332 | | %-----------------% |
333 | | | Data statements | |
334 | | %-----------------% |
335 | | |
336 | | Parameter adjustments */ |
337 | 0 | --workd; |
338 | 0 | --resid; |
339 | 0 | v_dim1 = *ldv; |
340 | 0 | v_offset = 1 + v_dim1; |
341 | 0 | v -= v_offset; |
342 | 0 | h_dim1 = *ldh; |
343 | 0 | h_offset = 1 + h_dim1; |
344 | 0 | h__ -= h_offset; |
345 | 0 | --ipntr; |
346 | | |
347 | | /* Function Body |
348 | | |
349 | | %-----------------------% |
350 | | | Executable Statements | |
351 | | %-----------------------% */ |
352 | |
|
353 | 0 | if (first) { |
354 | 0 | first = FALSE_; |
355 | | |
356 | | /* %--------------------------------% |
357 | | | safmin = safe minimum is such | |
358 | | | that 1/sfmin does not overflow | |
359 | | %--------------------------------% */ |
360 | |
|
361 | 0 | safmin = igraphdlamch_("safmin"); |
362 | 0 | } |
363 | |
|
364 | 0 | if (*ido == 0) { |
365 | | |
366 | | /* %-------------------------------% |
367 | | | Initialize timing statistics | |
368 | | | & message level for debugging | |
369 | | %-------------------------------% */ |
370 | |
|
371 | 0 | igraphsecond_(&t0); |
372 | 0 | msglvl = msaitr; |
373 | | |
374 | | /* %------------------------------% |
375 | | | Initial call to this routine | |
376 | | %------------------------------% */ |
377 | |
|
378 | 0 | *info = 0; |
379 | 0 | step3 = FALSE_; |
380 | 0 | step4 = FALSE_; |
381 | 0 | rstart = FALSE_; |
382 | 0 | orth1 = FALSE_; |
383 | 0 | orth2 = FALSE_; |
384 | | |
385 | | /* %--------------------------------% |
386 | | | Pointer to the current step of | |
387 | | | the factorization to build | |
388 | | %--------------------------------% */ |
389 | |
|
390 | 0 | j = *k + 1; |
391 | | |
392 | | /* %------------------------------------------% |
393 | | | Pointers used for reverse communication | |
394 | | | when using WORKD. | |
395 | | %------------------------------------------% */ |
396 | |
|
397 | 0 | ipj = 1; |
398 | 0 | irj = ipj + *n; |
399 | 0 | ivj = irj + *n; |
400 | 0 | } |
401 | | |
402 | | /* %-------------------------------------------------% |
403 | | | When in reverse communication mode one of: | |
404 | | | STEP3, STEP4, ORTH1, ORTH2, RSTART | |
405 | | | will be .true. | |
406 | | | STEP3: return from computing OP*v_{j}. | |
407 | | | STEP4: return from computing B-norm of OP*v_{j} | |
408 | | | ORTH1: return from computing B-norm of r_{j+1} | |
409 | | | ORTH2: return from computing B-norm of | |
410 | | | correction to the residual vector. | |
411 | | | RSTART: return from OP computations needed by | |
412 | | | dgetv0. | |
413 | | %-------------------------------------------------% */ |
414 | |
|
415 | 0 | if (step3) { |
416 | 0 | goto L50; |
417 | 0 | } |
418 | 0 | if (step4) { |
419 | 0 | goto L60; |
420 | 0 | } |
421 | 0 | if (orth1) { |
422 | 0 | goto L70; |
423 | 0 | } |
424 | 0 | if (orth2) { |
425 | 0 | goto L90; |
426 | 0 | } |
427 | 0 | if (rstart) { |
428 | 0 | goto L30; |
429 | 0 | } |
430 | | |
431 | | /* %------------------------------% |
432 | | | Else this is the first step. | |
433 | | %------------------------------% |
434 | | |
435 | | %--------------------------------------------------------------% |
436 | | | | |
437 | | | A R N O L D I I T E R A T I O N L O O P | |
438 | | | | |
439 | | | Note: B*r_{j-1} is already in WORKD(1:N)=WORKD(IPJ:IPJ+N-1) | |
440 | | %--------------------------------------------------------------% */ |
441 | | |
442 | 0 | L1000: |
443 | |
|
444 | 0 | if (msglvl > 2) { |
445 | 0 | igraphivout_(&logfil, &c__1, &j, &ndigit, "_saitr: generating Arnoldi vect" |
446 | 0 | "or no.", (ftnlen)37); |
447 | 0 | igraphdvout_(&logfil, &c__1, rnorm, &ndigit, "_saitr: B-norm of the curren" |
448 | 0 | "t residual =", (ftnlen)40); |
449 | 0 | } |
450 | | |
451 | | /* %---------------------------------------------------------% |
452 | | | Check for exact zero. Equivalent to determing whether a | |
453 | | | j-step Arnoldi factorization is present. | |
454 | | %---------------------------------------------------------% */ |
455 | |
|
456 | 0 | if (*rnorm > 0.) { |
457 | 0 | goto L40; |
458 | 0 | } |
459 | | |
460 | | /* %---------------------------------------------------% |
461 | | | Invariant subspace found, generate a new starting | |
462 | | | vector which is orthogonal to the current Arnoldi | |
463 | | | basis and continue the iteration. | |
464 | | %---------------------------------------------------% */ |
465 | | |
466 | 0 | if (msglvl > 0) { |
467 | 0 | igraphivout_(&logfil, &c__1, &j, &ndigit, "_saitr: ****** restart at step " |
468 | 0 | "******", (ftnlen)37); |
469 | 0 | } |
470 | | |
471 | | /* %---------------------------------------------% |
472 | | | ITRY is the loop variable that controls the | |
473 | | | maximum amount of times that a restart is | |
474 | | | attempted. NRSTRT is used by stat.h | |
475 | | %---------------------------------------------% */ |
476 | |
|
477 | 0 | ++nrstrt; |
478 | 0 | itry = 1; |
479 | 0 | L20: |
480 | 0 | rstart = TRUE_; |
481 | 0 | *ido = 0; |
482 | 0 | L30: |
483 | | |
484 | | /* %--------------------------------------% |
485 | | | If in reverse communication mode and | |
486 | | | RSTART = .true. flow returns here. | |
487 | | %--------------------------------------% */ |
488 | |
|
489 | 0 | igraphdgetv0_(ido, bmat, &itry, &c_false, n, &j, &v[v_offset], ldv, &resid[1], |
490 | 0 | rnorm, &ipntr[1], &workd[1], &ierr); |
491 | 0 | if (*ido != 99) { |
492 | 0 | goto L9000; |
493 | 0 | } |
494 | 0 | if (ierr < 0) { |
495 | 0 | ++itry; |
496 | 0 | if (itry <= 3) { |
497 | 0 | goto L20; |
498 | 0 | } |
499 | | |
500 | | /* %------------------------------------------------% |
501 | | | Give up after several restart attempts. | |
502 | | | Set INFO to the size of the invariant subspace | |
503 | | | which spans OP and exit. | |
504 | | %------------------------------------------------% */ |
505 | | |
506 | 0 | *info = j - 1; |
507 | 0 | igraphsecond_(&t1); |
508 | 0 | tsaitr += t1 - t0; |
509 | 0 | *ido = 99; |
510 | 0 | goto L9000; |
511 | 0 | } |
512 | | |
513 | 0 | L40: |
514 | | |
515 | | /* %---------------------------------------------------------% |
516 | | | STEP 2: v_{j} = r_{j-1}/rnorm and p_{j} = p_{j}/rnorm | |
517 | | | Note that p_{j} = B*r_{j-1}. In order to avoid overflow | |
518 | | | when reciprocating a small RNORM, test against lower | |
519 | | | machine bound. | |
520 | | %---------------------------------------------------------% */ |
521 | |
|
522 | 0 | igraphdcopy_(n, &resid[1], &c__1, &v[j * v_dim1 + 1], &c__1); |
523 | 0 | if (*rnorm >= safmin) { |
524 | 0 | temp1 = 1. / *rnorm; |
525 | 0 | igraphdscal_(n, &temp1, &v[j * v_dim1 + 1], &c__1); |
526 | 0 | igraphdscal_(n, &temp1, &workd[ipj], &c__1); |
527 | 0 | } else { |
528 | | |
529 | | /* %-----------------------------------------% |
530 | | | To scale both v_{j} and p_{j} carefully | |
531 | | | use LAPACK routine SLASCL | |
532 | | %-----------------------------------------% */ |
533 | |
|
534 | 0 | igraphdlascl_("General", &i__, &i__, rnorm, &c_b24, n, &c__1, &v[j * v_dim1 |
535 | 0 | + 1], n, &infol); |
536 | 0 | igraphdlascl_("General", &i__, &i__, rnorm, &c_b24, n, &c__1, &workd[ipj], |
537 | 0 | n, &infol); |
538 | 0 | } |
539 | | |
540 | | /* %------------------------------------------------------% |
541 | | | STEP 3: r_{j} = OP*v_{j}; Note that p_{j} = B*v_{j} | |
542 | | | Note that this is not quite yet r_{j}. See STEP 4 | |
543 | | %------------------------------------------------------% */ |
544 | |
|
545 | 0 | step3 = TRUE_; |
546 | 0 | ++nopx; |
547 | 0 | igraphsecond_(&t2); |
548 | 0 | igraphdcopy_(n, &v[j * v_dim1 + 1], &c__1, &workd[ivj], &c__1); |
549 | 0 | ipntr[1] = ivj; |
550 | 0 | ipntr[2] = irj; |
551 | 0 | ipntr[3] = ipj; |
552 | 0 | *ido = 1; |
553 | | |
554 | | /* %-----------------------------------% |
555 | | | Exit in order to compute OP*v_{j} | |
556 | | %-----------------------------------% */ |
557 | |
|
558 | 0 | goto L9000; |
559 | 0 | L50: |
560 | | |
561 | | /* %-----------------------------------% |
562 | | | Back from reverse communication; | |
563 | | | WORKD(IRJ:IRJ+N-1) := OP*v_{j}. | |
564 | | %-----------------------------------% */ |
565 | |
|
566 | 0 | igraphsecond_(&t3); |
567 | 0 | tmvopx += t3 - t2; |
568 | |
|
569 | 0 | step3 = FALSE_; |
570 | | |
571 | | /* %------------------------------------------% |
572 | | | Put another copy of OP*v_{j} into RESID. | |
573 | | %------------------------------------------% */ |
574 | |
|
575 | 0 | igraphdcopy_(n, &workd[irj], &c__1, &resid[1], &c__1); |
576 | | |
577 | | /* %-------------------------------------------% |
578 | | | STEP 4: Finish extending the symmetric | |
579 | | | Arnoldi to length j. If MODE = 2 | |
580 | | | then B*OP = B*inv(B)*A = A and | |
581 | | | we don't need to compute B*OP. | |
582 | | | NOTE: If MODE = 2 WORKD(IVJ:IVJ+N-1) is | |
583 | | | assumed to have A*v_{j}. | |
584 | | %-------------------------------------------% */ |
585 | |
|
586 | 0 | if (*mode == 2) { |
587 | 0 | goto L65; |
588 | 0 | } |
589 | 0 | igraphsecond_(&t2); |
590 | 0 | if (*(unsigned char *)bmat == 'G') { |
591 | 0 | ++nbx; |
592 | 0 | step4 = TRUE_; |
593 | 0 | ipntr[1] = irj; |
594 | 0 | ipntr[2] = ipj; |
595 | 0 | *ido = 2; |
596 | | |
597 | | /* %-------------------------------------% |
598 | | | Exit in order to compute B*OP*v_{j} | |
599 | | %-------------------------------------% */ |
600 | |
|
601 | 0 | goto L9000; |
602 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
603 | 0 | igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1); |
604 | 0 | } |
605 | 0 | L60: |
606 | | |
607 | | /* %-----------------------------------% |
608 | | | Back from reverse communication; | |
609 | | | WORKD(IPJ:IPJ+N-1) := B*OP*v_{j}. | |
610 | | %-----------------------------------% */ |
611 | |
|
612 | 0 | if (*(unsigned char *)bmat == 'G') { |
613 | 0 | igraphsecond_(&t3); |
614 | 0 | tmvbx += t3 - t2; |
615 | 0 | } |
616 | |
|
617 | 0 | step4 = FALSE_; |
618 | | |
619 | | /* %-------------------------------------% |
620 | | | The following is needed for STEP 5. | |
621 | | | Compute the B-norm of OP*v_{j}. | |
622 | | %-------------------------------------% */ |
623 | |
|
624 | 0 | L65: |
625 | 0 | if (*mode == 2) { |
626 | | |
627 | | /* %----------------------------------% |
628 | | | Note that the B-norm of OP*v_{j} | |
629 | | | is the inv(B)-norm of A*v_{j}. | |
630 | | %----------------------------------% */ |
631 | |
|
632 | 0 | wnorm = igraphddot_(n, &resid[1], &c__1, &workd[ivj], &c__1); |
633 | 0 | wnorm = sqrt((abs(wnorm))); |
634 | 0 | } else if (*(unsigned char *)bmat == 'G') { |
635 | 0 | wnorm = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1); |
636 | 0 | wnorm = sqrt((abs(wnorm))); |
637 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
638 | 0 | wnorm = igraphdnrm2_(n, &resid[1], &c__1); |
639 | 0 | } |
640 | | |
641 | | /* %-----------------------------------------% |
642 | | | Compute the j-th residual corresponding | |
643 | | | to the j step factorization. | |
644 | | | Use Classical Gram Schmidt and compute: | |
645 | | | w_{j} <- V_{j}^T * B * OP * v_{j} | |
646 | | | r_{j} <- OP*v_{j} - V_{j} * w_{j} | |
647 | | %-----------------------------------------% |
648 | | |
649 | | |
650 | | %------------------------------------------% |
651 | | | Compute the j Fourier coefficients w_{j} | |
652 | | | WORKD(IPJ:IPJ+N-1) contains B*OP*v_{j}. | |
653 | | %------------------------------------------% */ |
654 | |
|
655 | 0 | if (*mode != 2) { |
656 | 0 | igraphdgemv_("T", n, &j, &c_b24, &v[v_offset], ldv, &workd[ipj], &c__1, & |
657 | 0 | c_b49, &workd[irj], &c__1); |
658 | 0 | } else if (*mode == 2) { |
659 | 0 | igraphdgemv_("T", n, &j, &c_b24, &v[v_offset], ldv, &workd[ivj], &c__1, & |
660 | 0 | c_b49, &workd[irj], &c__1); |
661 | 0 | } |
662 | | |
663 | | /* %--------------------------------------% |
664 | | | Orthgonalize r_{j} against V_{j}. | |
665 | | | RESID contains OP*v_{j}. See STEP 3. | |
666 | | %--------------------------------------% */ |
667 | |
|
668 | 0 | igraphdgemv_("N", n, &j, &c_b57, &v[v_offset], ldv, &workd[irj], &c__1, &c_b24, |
669 | 0 | &resid[1], &c__1); |
670 | | |
671 | | /* %--------------------------------------% |
672 | | | Extend H to have j rows and columns. | |
673 | | %--------------------------------------% */ |
674 | |
|
675 | 0 | h__[j + (h_dim1 << 1)] = workd[irj + j - 1]; |
676 | 0 | if (j == 1 || rstart) { |
677 | 0 | h__[j + h_dim1] = 0.; |
678 | 0 | } else { |
679 | 0 | h__[j + h_dim1] = *rnorm; |
680 | 0 | } |
681 | 0 | igraphsecond_(&t4); |
682 | |
|
683 | 0 | orth1 = TRUE_; |
684 | 0 | iter = 0; |
685 | |
|
686 | 0 | igraphsecond_(&t2); |
687 | 0 | if (*(unsigned char *)bmat == 'G') { |
688 | 0 | ++nbx; |
689 | 0 | igraphdcopy_(n, &resid[1], &c__1, &workd[irj], &c__1); |
690 | 0 | ipntr[1] = irj; |
691 | 0 | ipntr[2] = ipj; |
692 | 0 | *ido = 2; |
693 | | |
694 | | /* %----------------------------------% |
695 | | | Exit in order to compute B*r_{j} | |
696 | | %----------------------------------% */ |
697 | |
|
698 | 0 | goto L9000; |
699 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
700 | 0 | igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1); |
701 | 0 | } |
702 | 0 | L70: |
703 | | |
704 | | /* %---------------------------------------------------% |
705 | | | Back from reverse communication if ORTH1 = .true. | |
706 | | | WORKD(IPJ:IPJ+N-1) := B*r_{j}. | |
707 | | %---------------------------------------------------% */ |
708 | |
|
709 | 0 | if (*(unsigned char *)bmat == 'G') { |
710 | 0 | igraphsecond_(&t3); |
711 | 0 | tmvbx += t3 - t2; |
712 | 0 | } |
713 | |
|
714 | 0 | orth1 = FALSE_; |
715 | | |
716 | | /* %------------------------------% |
717 | | | Compute the B-norm of r_{j}. | |
718 | | %------------------------------% */ |
719 | |
|
720 | 0 | if (*(unsigned char *)bmat == 'G') { |
721 | 0 | *rnorm = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1); |
722 | 0 | *rnorm = sqrt((abs(*rnorm))); |
723 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
724 | 0 | *rnorm = igraphdnrm2_(n, &resid[1], &c__1); |
725 | 0 | } |
726 | | |
727 | | /* %-----------------------------------------------------------% |
728 | | | STEP 5: Re-orthogonalization / Iterative refinement phase | |
729 | | | Maximum NITER_ITREF tries. | |
730 | | | | |
731 | | | s = V_{j}^T * B * r_{j} | |
732 | | | r_{j} = r_{j} - V_{j}*s | |
733 | | | alphaj = alphaj + s_{j} | |
734 | | | | |
735 | | | The stopping criteria used for iterative refinement is | |
736 | | | discussed in Parlett's book SEP, page 107 and in Gragg & | |
737 | | | Reichel ACM TOMS paper; Algorithm 686, Dec. 1990. | |
738 | | | Determine if we need to correct the residual. The goal is | |
739 | | | to enforce ||v(:,1:j)^T * r_{j}|| .le. eps * || r_{j} || | |
740 | | %-----------------------------------------------------------% */ |
741 | |
|
742 | 0 | if (*rnorm > wnorm * .717f) { |
743 | 0 | goto L100; |
744 | 0 | } |
745 | 0 | ++nrorth; |
746 | | |
747 | | /* %---------------------------------------------------% |
748 | | | Enter the Iterative refinement phase. If further | |
749 | | | refinement is necessary, loop back here. The loop | |
750 | | | variable is ITER. Perform a step of Classical | |
751 | | | Gram-Schmidt using all the Arnoldi vectors V_{j} | |
752 | | %---------------------------------------------------% */ |
753 | |
|
754 | 0 | L80: |
755 | |
|
756 | 0 | if (msglvl > 2) { |
757 | 0 | xtemp[0] = wnorm; |
758 | 0 | xtemp[1] = *rnorm; |
759 | 0 | igraphdvout_(&logfil, &c__2, xtemp, &ndigit, "_saitr: re-orthonalization ;" |
760 | 0 | " wnorm and rnorm are", (ftnlen)48); |
761 | 0 | } |
762 | | |
763 | | /* %----------------------------------------------------% |
764 | | | Compute V_{j}^T * B * r_{j}. | |
765 | | | WORKD(IRJ:IRJ+J-1) = v(:,1:J)'*WORKD(IPJ:IPJ+N-1). | |
766 | | %----------------------------------------------------% */ |
767 | |
|
768 | 0 | igraphdgemv_("T", n, &j, &c_b24, &v[v_offset], ldv, &workd[ipj], &c__1, &c_b49, |
769 | 0 | &workd[irj], &c__1); |
770 | | |
771 | | /* %----------------------------------------------% |
772 | | | Compute the correction to the residual: | |
773 | | | r_{j} = r_{j} - V_{j} * WORKD(IRJ:IRJ+J-1). | |
774 | | | The correction to H is v(:,1:J)*H(1:J,1:J) + | |
775 | | | v(:,1:J)*WORKD(IRJ:IRJ+J-1)*e'_j, but only | |
776 | | | H(j,j) is updated. | |
777 | | %----------------------------------------------% */ |
778 | |
|
779 | 0 | igraphdgemv_("N", n, &j, &c_b57, &v[v_offset], ldv, &workd[irj], &c__1, &c_b24, |
780 | 0 | &resid[1], &c__1); |
781 | |
|
782 | 0 | if (j == 1 || rstart) { |
783 | 0 | h__[j + h_dim1] = 0.; |
784 | 0 | } |
785 | 0 | h__[j + (h_dim1 << 1)] += workd[irj + j - 1]; |
786 | |
|
787 | 0 | orth2 = TRUE_; |
788 | 0 | igraphsecond_(&t2); |
789 | 0 | if (*(unsigned char *)bmat == 'G') { |
790 | 0 | ++nbx; |
791 | 0 | igraphdcopy_(n, &resid[1], &c__1, &workd[irj], &c__1); |
792 | 0 | ipntr[1] = irj; |
793 | 0 | ipntr[2] = ipj; |
794 | 0 | *ido = 2; |
795 | | |
796 | | /* %-----------------------------------% |
797 | | | Exit in order to compute B*r_{j}. | |
798 | | | r_{j} is the corrected residual. | |
799 | | %-----------------------------------% */ |
800 | |
|
801 | 0 | goto L9000; |
802 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
803 | 0 | igraphdcopy_(n, &resid[1], &c__1, &workd[ipj], &c__1); |
804 | 0 | } |
805 | 0 | L90: |
806 | | |
807 | | /* %---------------------------------------------------% |
808 | | | Back from reverse communication if ORTH2 = .true. | |
809 | | %---------------------------------------------------% */ |
810 | |
|
811 | 0 | if (*(unsigned char *)bmat == 'G') { |
812 | 0 | igraphsecond_(&t3); |
813 | 0 | tmvbx += t3 - t2; |
814 | 0 | } |
815 | | |
816 | | /* %-----------------------------------------------------% |
817 | | | Compute the B-norm of the corrected residual r_{j}. | |
818 | | %-----------------------------------------------------% */ |
819 | |
|
820 | 0 | if (*(unsigned char *)bmat == 'G') { |
821 | 0 | rnorm1 = igraphddot_(n, &resid[1], &c__1, &workd[ipj], &c__1); |
822 | 0 | rnorm1 = sqrt((abs(rnorm1))); |
823 | 0 | } else if (*(unsigned char *)bmat == 'I') { |
824 | 0 | rnorm1 = igraphdnrm2_(n, &resid[1], &c__1); |
825 | 0 | } |
826 | |
|
827 | 0 | if (msglvl > 0 && iter > 0) { |
828 | 0 | igraphivout_(&logfil, &c__1, &j, &ndigit, "_saitr: Iterative refinement fo" |
829 | 0 | "r Arnoldi residual", (ftnlen)49); |
830 | 0 | if (msglvl > 2) { |
831 | 0 | xtemp[0] = *rnorm; |
832 | 0 | xtemp[1] = rnorm1; |
833 | 0 | igraphdvout_(&logfil, &c__2, xtemp, &ndigit, "_saitr: iterative refine" |
834 | 0 | "ment ; rnorm and rnorm1 are", (ftnlen)51); |
835 | 0 | } |
836 | 0 | } |
837 | | |
838 | | /* %-----------------------------------------% |
839 | | | Determine if we need to perform another | |
840 | | | step of re-orthogonalization. | |
841 | | %-----------------------------------------% */ |
842 | |
|
843 | 0 | if (rnorm1 > *rnorm * .717f) { |
844 | | |
845 | | /* %--------------------------------% |
846 | | | No need for further refinement | |
847 | | %--------------------------------% */ |
848 | |
|
849 | 0 | *rnorm = rnorm1; |
850 | |
|
851 | 0 | } else { |
852 | | |
853 | | /* %-------------------------------------------% |
854 | | | Another step of iterative refinement step | |
855 | | | is required. NITREF is used by stat.h | |
856 | | %-------------------------------------------% */ |
857 | |
|
858 | 0 | ++nitref; |
859 | 0 | *rnorm = rnorm1; |
860 | 0 | ++iter; |
861 | 0 | if (iter <= 1) { |
862 | 0 | goto L80; |
863 | 0 | } |
864 | | |
865 | | /* %-------------------------------------------------% |
866 | | | Otherwise RESID is numerically in the span of V | |
867 | | %-------------------------------------------------% */ |
868 | | |
869 | 0 | i__1 = *n; |
870 | 0 | for (jj = 1; jj <= i__1; ++jj) { |
871 | 0 | resid[jj] = 0.; |
872 | | /* L95: */ |
873 | 0 | } |
874 | 0 | *rnorm = 0.; |
875 | 0 | } |
876 | | |
877 | | /* %----------------------------------------------% |
878 | | | Branch here directly if iterative refinement | |
879 | | | wasn't necessary or after at most NITER_REF | |
880 | | | steps of iterative refinement. | |
881 | | %----------------------------------------------% */ |
882 | | |
883 | 0 | L100: |
884 | |
|
885 | 0 | rstart = FALSE_; |
886 | 0 | orth2 = FALSE_; |
887 | |
|
888 | 0 | igraphsecond_(&t5); |
889 | 0 | titref += t5 - t4; |
890 | | |
891 | | /* %----------------------------------------------------------% |
892 | | | Make sure the last off-diagonal element is non negative | |
893 | | | If not perform a similarity transformation on H(1:j,1:j) | |
894 | | | and scale v(:,j) by -1. | |
895 | | %----------------------------------------------------------% */ |
896 | |
|
897 | 0 | if (h__[j + h_dim1] < 0.) { |
898 | 0 | h__[j + h_dim1] = -h__[j + h_dim1]; |
899 | 0 | if (j < *k + *np) { |
900 | 0 | igraphdscal_(n, &c_b57, &v[(j + 1) * v_dim1 + 1], &c__1); |
901 | 0 | } else { |
902 | 0 | igraphdscal_(n, &c_b57, &resid[1], &c__1); |
903 | 0 | } |
904 | 0 | } |
905 | | |
906 | | /* %------------------------------------% |
907 | | | STEP 6: Update j = j+1; Continue | |
908 | | %------------------------------------% */ |
909 | |
|
910 | 0 | ++j; |
911 | 0 | if (j > *k + *np) { |
912 | 0 | igraphsecond_(&t1); |
913 | 0 | tsaitr += t1 - t0; |
914 | 0 | *ido = 99; |
915 | |
|
916 | 0 | if (msglvl > 1) { |
917 | 0 | i__1 = *k + *np; |
918 | 0 | igraphdvout_(&logfil, &i__1, &h__[(h_dim1 << 1) + 1], &ndigit, "_saitr" |
919 | 0 | ": main diagonal of matrix H of step K+NP.", (ftnlen)47); |
920 | 0 | if (*k + *np > 1) { |
921 | 0 | i__1 = *k + *np - 1; |
922 | 0 | igraphdvout_(&logfil, &i__1, &h__[h_dim1 + 2], &ndigit, "_saitr: s" |
923 | 0 | "ub diagonal of matrix H of step K+NP.", (ftnlen)46); |
924 | 0 | } |
925 | 0 | } |
926 | |
|
927 | 0 | goto L9000; |
928 | 0 | } |
929 | | |
930 | | /* %--------------------------------------------------------% |
931 | | | Loop back to extend the factorization by another step. | |
932 | | %--------------------------------------------------------% */ |
933 | | |
934 | 0 | goto L1000; |
935 | | |
936 | | /* %---------------------------------------------------------------% |
937 | | | | |
938 | | | E N D O F M A I N I T E R A T I O N L O O P | |
939 | | | | |
940 | | %---------------------------------------------------------------% */ |
941 | | |
942 | 0 | L9000: |
943 | 0 | return 0; |
944 | | |
945 | | /* %---------------% |
946 | | | End of dsaitr | |
947 | | %---------------% */ |
948 | |
|
949 | 0 | } /* igraphdsaitr_ */ |
950 | | |