Coverage Report

Created: 2023-09-25 06:04

/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