~ubuntu-branches/ubuntu/trusty/igraph/trusty-proposed

« back to all changes in this revision

Viewing changes to src/lapack/dsaup2.c

  • Committer: Package Import Robot
  • Author(s): Mathieu Malaterre
  • Date: 2013-05-27 14:01:54 UTC
  • mfrom: (4.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20130527140154-oxwwmr0gj3kdy4ol
Tags: 0.6.5-2
Upload to sid

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  -- translated by f2c (version 20100827).
 
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
{
 
209
    /* System generated locals */
 
210
    integer h_dim1, h_offset, q_dim1, q_offset, v_dim1, v_offset, i__1, i__2, 
 
211
            i__3;
 
212
    doublereal d__1, d__2, d__3;
 
213
 
 
214
    /* Builtin functions */
 
215
    double pow_dd(doublereal *, doublereal *);
 
216
    integer s_cmp(char *, char *, ftnlen, ftnlen);
 
217
    /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
 
218
    double sqrt(doublereal);
 
219
 
 
220
    /* Local variables */
 
221
    integer j;
 
222
    real t0, t1, t2, t3;
 
223
    integer kp[3];
 
224
    IGRAPH_F77_SAVE integer np0;
 
225
    integer nbx;
 
226
    IGRAPH_F77_SAVE integer nev0;
 
227
    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, 
 
228
            integer *);
 
229
    IGRAPH_F77_SAVE doublereal eps23;
 
230
    integer ierr;
 
231
    IGRAPH_F77_SAVE integer iter;
 
232
    doublereal temp;
 
233
    integer nevd2;
 
234
    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
 
235
    IGRAPH_F77_SAVE logical getv0;
 
236
    integer nevm2;
 
237
    IGRAPH_F77_SAVE logical cnorm;
 
238
    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, 
 
239
            doublereal *, integer *), igraphdswap_(integer *, doublereal *, integer 
 
240
            *, doublereal *, integer *);
 
241
    IGRAPH_F77_SAVE integer nconv;
 
242
    IGRAPH_F77_SAVE logical initv;
 
243
    IGRAPH_F77_SAVE doublereal rnorm;
 
244
    real tmvbx;
 
245
    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, 
 
246
            integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
 
247
            , integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer *
 
248
            , logical *, integer *, integer *, doublereal *, integer *, 
 
249
            doublereal *, doublereal *, integer *, doublereal *, integer *);
 
250
    integer msaup2=0;
 
251
    real tsaup2;
 
252
    extern doublereal igraphdlamch_(char *);
 
253
    integer nevbef;
 
254
    extern /* Subroutine */ int igraphsecond_(real *);
 
255
    integer logfil=0, ndigit;
 
256
    extern /* Subroutine */ int igraphdseigt_(doublereal *, integer *, doublereal *,
 
257
             integer *, doublereal *, doublereal *, doublereal *, integer *);
 
258
    IGRAPH_F77_SAVE logical update;
 
259
    extern /* Subroutine */ int igraphdsaitr_(integer *, char *, integer *, integer 
 
260
            *, integer *, integer *, doublereal *, doublereal *, doublereal *,
 
261
             integer *, doublereal *, integer *, integer *, doublereal *, 
 
262
            integer *), igraphdsgets_(integer *, char *, integer *, integer 
 
263
            *, doublereal *, doublereal *, doublereal *), igraphdsapps_(
 
264
            integer *, integer *, integer *, doublereal *, doublereal *, 
 
265
            integer *, doublereal *, integer *, doublereal *, doublereal *, 
 
266
            integer *, doublereal *), igraphdsconv_(integer *, doublereal *, 
 
267
            doublereal *, doublereal *, integer *);
 
268
    IGRAPH_F77_SAVE logical ushift;
 
269
    char wprime[2];
 
270
    IGRAPH_F77_SAVE integer msglvl;
 
271
    integer nptemp;
 
272
    extern /* Subroutine */ int igraphdsortr_(char *, logical *, integer *, 
 
273
            doublereal *, doublereal *);
 
274
    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
    --workd;
 
323
    --resid;
 
324
    --workl;
 
325
    --bounds;
 
326
    --ritz;
 
327
    v_dim1 = *ldv;
 
328
    v_offset = 1 + v_dim1;
 
329
    v -= v_offset;
 
330
    h_dim1 = *ldh;
 
331
    h_offset = 1 + h_dim1;
 
332
    h__ -= h_offset;
 
333
    q_dim1 = *ldq;
 
334
    q_offset = 1 + q_dim1;
 
335
    q -= q_offset;
 
336
    --ipntr;
 
337
 
 
338
    /* Function Body */
 
339
    if (*ido == 0) {
 
340
 
 
341
/*        %-------------------------------%   
 
342
          | Initialize timing statistics  |   
 
343
          | & message level for debugging |   
 
344
          %-------------------------------% */
 
345
 
 
346
        igraphsecond_(&t0);
 
347
        msglvl = msaup2;
 
348
 
 
349
/*        %---------------------------------%   
 
350
          | Set machine dependent constant. |   
 
351
          %---------------------------------% */
 
352
 
 
353
        eps23 = igraphdlamch_("Epsilon-Machine");
 
354
        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
        nev0 = *nev;
 
362
        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
        kplusp = nev0 + np0;
 
374
        nconv = 0;
 
375
        iter = 0;
 
376
 
 
377
/*        %--------------------------------------------%   
 
378
          | Set flags for computing the first NEV steps |   
 
379
          | of the Lanczos factorization.              |   
 
380
          %--------------------------------------------% */
 
381
 
 
382
        getv0 = TRUE_;
 
383
        update = FALSE_;
 
384
        ushift = FALSE_;
 
385
        cnorm = FALSE_;
 
386
 
 
387
        if (*info != 0) {
 
388
 
 
389
/*        %--------------------------------------------%   
 
390
          | User provides the initial residual vector. |   
 
391
          %--------------------------------------------% */
 
392
 
 
393
            initv = TRUE_;
 
394
            *info = 0;
 
395
        } else {
 
396
            initv = FALSE_;
 
397
        }
 
398
    }
 
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
    if (getv0) {
 
408
        igraphdgetv0_(ido, bmat, &c__1, &initv, n, &c__1, &v[v_offset], ldv, &resid[
 
409
                1], &rnorm, &ipntr[1], &workd[1], info);
 
410
 
 
411
        if (*ido != 99) {
 
412
            goto L9000;
 
413
        }
 
414
 
 
415
        if (rnorm == 0.) {
 
416
 
 
417
/*           %-----------------------------------------%   
 
418
             | The initial vector is zero. Error exit. |   
 
419
             %-----------------------------------------% */
 
420
 
 
421
            *info = -9;
 
422
            goto L1200;
 
423
        }
 
424
        getv0 = FALSE_;
 
425
        *ido = 0;
 
426
    }
 
427
 
 
428
/*     %------------------------------------------------------------%   
 
429
       | Back from reverse communication: continue with update step |   
 
430
       %------------------------------------------------------------% */
 
431
 
 
432
    if (update) {
 
433
        goto L20;
 
434
    }
 
435
 
 
436
/*     %-------------------------------------------%   
 
437
       | Back from computing user specified shifts |   
 
438
       %-------------------------------------------% */
 
439
 
 
440
    if (ushift) {
 
441
        goto L50;
 
442
    }
 
443
 
 
444
/*     %-------------------------------------%   
 
445
       | Back from computing residual norm   |   
 
446
       | at the end of the current iteration |   
 
447
       %-------------------------------------% */
 
448
 
 
449
    if (cnorm) {
 
450
        goto L100;
 
451
    }
 
452
 
 
453
/*     %----------------------------------------------------------%   
 
454
       | Compute the first NEV steps of the Lanczos factorization |   
 
455
       %----------------------------------------------------------% */
 
456
 
 
457
    igraphdsaitr_(ido, bmat, n, &c__0, &nev0, mode, &resid[1], &rnorm, &v[v_offset],
 
458
             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
    if (*ido != 99) {
 
466
        goto L9000;
 
467
    }
 
468
 
 
469
    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
        *np = *info;
 
478
        *mxiter = iter;
 
479
        *info = -9999;
 
480
        goto L1200;
 
481
    }
 
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
L1000:
 
492
 
 
493
    ++iter;
 
494
 
 
495
    if (msglvl > 0) {
 
496
        igraphivout_(&logfil, &c__1, &iter, &ndigit, "_saup2: **** Start of major "
 
497
                "iteration number ****", (ftnlen)49);
 
498
    }
 
499
    if (msglvl > 1) {
 
500
        igraphivout_(&logfil, &c__1, nev, &ndigit, "_saup2: The length of the curr"
 
501
                "ent Lanczos factorization", (ftnlen)55);
 
502
        igraphivout_(&logfil, &c__1, np, &ndigit, "_saup2: Extend the Lanczos fact"
 
503
                "orization by", (ftnlen)43);
 
504
    }
 
505
 
 
506
/*        %------------------------------------------------------------%   
 
507
          | Compute NP additional steps of the Lanczos factorization. |   
 
508
          %------------------------------------------------------------% */
 
509
 
 
510
    *ido = 0;
 
511
L20:
 
512
    update = TRUE_;
 
513
 
 
514
    igraphdsaitr_(ido, bmat, n, nev, np, mode, &resid[1], &rnorm, &v[v_offset], ldv,
 
515
             &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
    if (*ido != 99) {
 
523
        goto L9000;
 
524
    }
 
525
 
 
526
    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
        *np = *info;
 
535
        *mxiter = iter;
 
536
        *info = -9999;
 
537
        goto L1200;
 
538
    }
 
539
    update = FALSE_;
 
540
 
 
541
    if (msglvl > 1) {
 
542
        igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_saup2: Current B-norm of r"
 
543
                "esidual for factorization", (ftnlen)52);
 
544
    }
 
545
 
 
546
/*        %--------------------------------------------------------%   
 
547
          | Compute the eigenvalues and corresponding error bounds |   
 
548
          | of the current symmetric tridiagonal matrix.           |   
 
549
          %--------------------------------------------------------% */
 
550
 
 
551
    igraphdseigt_(&rnorm, &kplusp, &h__[h_offset], ldh, &ritz[1], &bounds[1], &
 
552
            workl[1], &ierr);
 
553
 
 
554
    if (ierr != 0) {
 
555
        *info = -8;
 
556
        goto L1200;
 
557
    }
 
558
 
 
559
/*        %----------------------------------------------------%   
 
560
          | Make a copy of eigenvalues and corresponding error |   
 
561
          | bounds obtained from _seigt.                       |   
 
562
          %----------------------------------------------------% */
 
563
 
 
564
    igraphdcopy_(&kplusp, &ritz[1], &c__1, &workl[kplusp + 1], &c__1);
 
565
    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
    *nev = nev0;
 
578
    *np = np0;
 
579
    igraphdsgets_(ishift, which, nev, np, &ritz[1], &bounds[1], &workl[1]);
 
580
 
 
581
/*        %-------------------%   
 
582
          | Convergence test. |   
 
583
          %-------------------% */
 
584
 
 
585
    igraphdcopy_(nev, &bounds[*np + 1], &c__1, &workl[*np + 1], &c__1);
 
586
    igraphdsconv_(nev, &ritz[*np + 1], &workl[*np + 1], tol, &nconv);
 
587
 
 
588
    if (msglvl > 2) {
 
589
        kp[0] = *nev;
 
590
        kp[1] = *np;
 
591
        kp[2] = nconv;
 
592
        igraphivout_(&logfil, &c__3, kp, &ndigit, "_saup2: NEV, NP, NCONV are", (
 
593
                ftnlen)26);
 
594
        igraphdvout_(&logfil, &kplusp, &ritz[1], &ndigit, "_saup2: The eigenvalues"
 
595
                " of H", (ftnlen)28);
 
596
        igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_saup2: Ritz estimate"
 
597
                "s of the current NCV Ritz values", (ftnlen)53);
 
598
    }
 
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
    nptemp = *np;
 
611
    i__1 = nptemp;
 
612
    for (j = 1; j <= i__1; ++j) {
 
613
        if (bounds[j] == 0.) {
 
614
            --(*np);
 
615
            ++(*nev);
 
616
        }
 
617
/* L30: */
 
618
    }
 
619
 
 
620
    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
        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
            s_copy(wprime, "SA", (ftnlen)2, (ftnlen)2);
 
642
            igraphdsortr_(wprime, &c_true, &kplusp, &ritz[1], &bounds[1])
 
643
                    ;
 
644
            nevd2 = *nev / 2;
 
645
            nevm2 = *nev - nevd2;
 
646
            if (*nev > 1) {
 
647
                i__1 = min(nevd2,*np);
 
648
/* Computing MAX */
 
649
                i__2 = kplusp - nevd2 + 1, i__3 = kplusp - *np + 1;
 
650
                igraphdswap_(&i__1, &ritz[nevm2 + 1], &c__1, &ritz[max(i__2,i__3)], 
 
651
                        &c__1);
 
652
                i__1 = min(nevd2,*np);
 
653
/* Computing MAX */
 
654
                i__2 = kplusp - nevd2 + 1, i__3 = kplusp - *np;
 
655
                igraphdswap_(&i__1, &bounds[nevm2 + 1], &c__1, &bounds[max(i__2,
 
656
                        i__3) + 1], &c__1);
 
657
            }
 
658
 
 
659
        } 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
            if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
 
671
                s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
 
672
            }
 
673
            if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
 
674
                s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
 
675
            }
 
676
            if (s_cmp(which, "LA", (ftnlen)2, (ftnlen)2) == 0) {
 
677
                s_copy(wprime, "SA", (ftnlen)2, (ftnlen)2);
 
678
            }
 
679
            if (s_cmp(which, "SA", (ftnlen)2, (ftnlen)2) == 0) {
 
680
                s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2);
 
681
            }
 
682
 
 
683
            igraphdsortr_(wprime, &c_true, &kplusp, &ritz[1], &bounds[1])
 
684
                    ;
 
685
 
 
686
        }
 
687
 
 
688
/*           %--------------------------------------------------%   
 
689
             | Scale the Ritz estimate of each Ritz value       |   
 
690
             | by 1 / max(eps23,magnitude of the Ritz value).   |   
 
691
             %--------------------------------------------------% */
 
692
 
 
693
        i__1 = nev0;
 
694
        for (j = 1; j <= i__1; ++j) {
 
695
/* Computing MAX */
 
696
            d__2 = eps23, d__3 = (d__1 = ritz[j], abs(d__1));
 
697
            temp = max(d__2,d__3);
 
698
            bounds[j] /= temp;
 
699
/* L35: */
 
700
        }
 
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
        s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2);
 
710
        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
        i__1 = nev0;
 
718
        for (j = 1; j <= i__1; ++j) {
 
719
/* Computing MAX */
 
720
            d__2 = eps23, d__3 = (d__1 = ritz[j], abs(d__1));
 
721
            temp = max(d__2,d__3);
 
722
            bounds[j] *= temp;
 
723
/* L40: */
 
724
        }
 
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
        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
            s_copy(wprime, "LA", (ftnlen)2, (ftnlen)2);
 
742
            igraphdsortr_(wprime, &c_true, &nconv, &ritz[1], &bounds[1]);
 
743
 
 
744
        } 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
            igraphdsortr_(which, &c_true, &nconv, &ritz[1], &bounds[1]);
 
753
 
 
754
        }
 
755
 
 
756
/*           %------------------------------------------%   
 
757
             |  Use h( 1,1 ) as storage to communicate  |   
 
758
             |  rnorm to _seupd if needed               |   
 
759
             %------------------------------------------% */
 
760
 
 
761
        h__[h_dim1 + 1] = rnorm;
 
762
 
 
763
        if (msglvl > 1) {
 
764
            igraphdvout_(&logfil, &kplusp, &ritz[1], &ndigit, "_saup2: Sorted Ritz"
 
765
                    " values.", (ftnlen)27);
 
766
            igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_saup2: Sorted ri"
 
767
                    "tz estimates.", (ftnlen)30);
 
768
        }
 
769
 
 
770
/*           %------------------------------------%   
 
771
             | Max iterations have been exceeded. |   
 
772
             %------------------------------------% */
 
773
 
 
774
        if (iter > *mxiter && nconv < *nev) {
 
775
            *info = 1;
 
776
        }
 
777
 
 
778
/*           %---------------------%   
 
779
             | No shifts to apply. |   
 
780
             %---------------------% */
 
781
 
 
782
        if (*np == 0 && nconv < nev0) {
 
783
            *info = 2;
 
784
        }
 
785
 
 
786
        *np = nconv;
 
787
        goto L1100;
 
788
 
 
789
    } 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
        nevbef = *nev;
 
798
/* Computing MIN */
 
799
        i__1 = nconv, i__2 = *np / 2;
 
800
        *nev += min(i__1,i__2);
 
801
        if (*nev == 1 && kplusp >= 6) {
 
802
            *nev = kplusp / 2;
 
803
        } else if (*nev == 1 && kplusp > 2) {
 
804
            *nev = 2;
 
805
        }
 
806
        *np = kplusp - *nev;
 
807
 
 
808
/*           %---------------------------------------%   
 
809
             | If the size of NEV was just increased |   
 
810
             | resort the eigenvalues.               |   
 
811
             %---------------------------------------% */
 
812
 
 
813
        if (nevbef < *nev) {
 
814
            igraphdsgets_(ishift, which, nev, np, &ritz[1], &bounds[1], &workl[1]);
 
815
        }
 
816
 
 
817
    }
 
818
 
 
819
    if (msglvl > 0) {
 
820
        igraphivout_(&logfil, &c__1, &nconv, &ndigit, "_saup2: no. of \"converge"
 
821
                "d\" Ritz values at this iter.", (ftnlen)52);
 
822
        if (msglvl > 1) {
 
823
            kp[0] = *nev;
 
824
            kp[1] = *np;
 
825
            igraphivout_(&logfil, &c__2, kp, &ndigit, "_saup2: NEV and NP are", (
 
826
                    ftnlen)22);
 
827
            igraphdvout_(&logfil, nev, &ritz[*np + 1], &ndigit, "_saup2: \"wante"
 
828
                    "d\" Ritz values.", (ftnlen)29);
 
829
            igraphdvout_(&logfil, nev, &bounds[*np + 1], &ndigit, "_saup2: Ritz es"
 
830
                    "timates of the \"wanted\" values ", (ftnlen)46);
 
831
        }
 
832
    }
 
833
 
 
834
    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
        ushift = TRUE_;
 
843
        *ido = 3;
 
844
        goto L9000;
 
845
    }
 
846
 
 
847
L50:
 
848
 
 
849
/*        %------------------------------------%   
 
850
          | Back from reverse communication;   |   
 
851
          | User specified shifts are returned |   
 
852
          | in WORKL(1:*NP)                   |   
 
853
          %------------------------------------% */
 
854
 
 
855
    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
    if (*ishift == 0) {
 
865
        igraphdcopy_(np, &workl[1], &c__1, &ritz[1], &c__1);
 
866
    }
 
867
 
 
868
    if (msglvl > 2) {
 
869
        igraphivout_(&logfil, &c__1, np, &ndigit, "_saup2: The number of shifts to"
 
870
                " apply ", (ftnlen)38);
 
871
        igraphdvout_(&logfil, np, &workl[1], &ndigit, "_saup2: shifts selected", (
 
872
                ftnlen)23);
 
873
        if (*ishift == 1) {
 
874
            igraphdvout_(&logfil, np, &bounds[1], &ndigit, "_saup2: corresponding "
 
875
                    "Ritz estimates", (ftnlen)36);
 
876
        }
 
877
    }
 
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
    igraphdsapps_(n, nev, np, &ritz[1], &v[v_offset], ldv, &h__[h_offset], ldh, &
 
888
            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
    cnorm = TRUE_;
 
897
    igraphsecond_(&t2);
 
898
    if (*(unsigned char *)bmat == 'G') {
 
899
        ++nbx;
 
900
        igraphdcopy_(n, &resid[1], &c__1, &workd[*n + 1], &c__1);
 
901
        ipntr[1] = *n + 1;
 
902
        ipntr[2] = 1;
 
903
        *ido = 2;
 
904
 
 
905
/*           %----------------------------------%   
 
906
             | Exit in order to compute B*RESID |   
 
907
             %----------------------------------% */
 
908
 
 
909
        goto L9000;
 
910
    } else if (*(unsigned char *)bmat == 'I') {
 
911
        igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1);
 
912
    }
 
913
 
 
914
L100:
 
915
 
 
916
/*        %----------------------------------%   
 
917
          | Back from reverse communication; |   
 
918
          | WORKD(1:N) := B*RESID            |   
 
919
          %----------------------------------% */
 
920
 
 
921
    if (*(unsigned char *)bmat == 'G') {
 
922
        igraphsecond_(&t3);
 
923
        tmvbx += t3 - t2;
 
924
    }
 
925
 
 
926
    if (*(unsigned char *)bmat == 'G') {
 
927
        rnorm = igraphddot_(n, &resid[1], &c__1, &workd[1], &c__1);
 
928
        rnorm = sqrt((abs(rnorm)));
 
929
    } else if (*(unsigned char *)bmat == 'I') {
 
930
        rnorm = igraphdnrm2_(n, &resid[1], &c__1);
 
931
    }
 
932
    cnorm = FALSE_;
 
933
/* L130: */
 
934
 
 
935
    if (msglvl > 2) {
 
936
        igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_saup2: B-norm of residual "
 
937
                "for NEV factorization", (ftnlen)48);
 
938
        igraphdvout_(&logfil, nev, &h__[(h_dim1 << 1) + 1], &ndigit, "_saup2: main"
 
939
                " diagonal of compressed H matrix", (ftnlen)44);
 
940
        i__1 = *nev - 1;
 
941
        igraphdvout_(&logfil, &i__1, &h__[h_dim1 + 2], &ndigit, "_saup2: subdiagon"
 
942
                "al of compressed H matrix", (ftnlen)42);
 
943
    }
 
944
 
 
945
    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
L1100:
 
954
 
 
955
    *mxiter = iter;
 
956
    *nev = nconv;
 
957
 
 
958
L1200:
 
959
    *ido = 99;
 
960
 
 
961
/*     %------------%   
 
962
       | Error exit |   
 
963
       %------------% */
 
964
 
 
965
    igraphsecond_(&t1);
 
966
    tsaup2 = t1 - t0;
 
967
 
 
968
L9000:
 
969
    return 0;
 
970
 
 
971
/*     %---------------%   
 
972
       | End of dsaup2 |   
 
973
       %---------------% */
 
974
 
 
975
} /* igraphdsaup2_ */
 
976