001:       SUBROUTINE SGSVJ0( JOBV, M, N, A, LDA, D, SVA, MV, V, LDV, EPS,
002:      &        SFMIN, TOL, NSWEEP, WORK, LWORK, INFO )
003: *
004: *  -- LAPACK routine (version 3.2)                                    --
005: *
006: *  -- Contributed by Zlatko Drmac of the University of Zagreb and     --
007: *  -- Kresimir Veselic of the Fernuniversitaet Hagen                  --
008: *  -- November 2008                                                   --
009: *
010: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
011: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
012: *
013: * This routine is also part of SIGMA (version 1.23, October 23. 2008.)
014: * SIGMA is a library of algorithms for highly accurate algorithms for
015: * computation of SVD, PSVD, QSVD, (H,K)-SVD, and for solution of the
016: * eigenvalue problems Hx = lambda M x, H M x = lambda x with H, M > 0.
017: *
018: *     Scalar Arguments
019: *
020:       IMPLICIT    NONE
021:       INTEGER     INFO, LDA, LDV, LWORK, M, MV, N, NSWEEP
022:       REAL        EPS, SFMIN, TOL
023:       CHARACTER*1 JOBV
024: *
025: *     Array Arguments
026: *
027:       REAL        A( LDA, * ), SVA( N ), D( N ), V( LDV, * ),
028:      &            WORK( LWORK )
029: *     ..
030: *
031: *  Purpose
032: *  ~~~~~~~
033: *  SGSVJ0 is called from SGESVJ as a pre-processor and that is its main
034: *  purpose. It applies Jacobi rotations in the same way as SGESVJ does, but
035: *  it does not check convergence (stopping criterion). Few tuning
036: *  parameters (marked by [TP]) are available for the implementer.
037: *
038: *  Further details
039: *  ~~~~~~~~~~~~~~~
040: *  SGSVJ0 is used just to enable SGESVJ to call a simplified version of
041: *  itself to work on a submatrix of the original matrix.
042: *
043: *  Contributors
044: *  ~~~~~~~~~~~~
045: *  Zlatko Drmac (Zagreb, Croatia) and Kresimir Veselic (Hagen, Germany)
046: *
047: *  Bugs, Examples and Comments
048: *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~
049: *  Please report all bugs and send interesting test examples and comments to
050: *  drmac@math.hr. Thank you.
051: *
052: *  Arguments
053: *  ~~~~~~~~~
054: *
055: *  JOBV    (input) CHARACTER*1
056: *          Specifies whether the output from this procedure is used
057: *          to compute the matrix V:
058: *          = 'V': the product of the Jacobi rotations is accumulated
059: *                 by postmulyiplying the N-by-N array V.
060: *                (See the description of V.)
061: *          = 'A': the product of the Jacobi rotations is accumulated
062: *                 by postmulyiplying the MV-by-N array V.
063: *                (See the descriptions of MV and V.)
064: *          = 'N': the Jacobi rotations are not accumulated.
065: *
066: *  M       (input) INTEGER
067: *          The number of rows of the input matrix A.  M >= 0.
068: *
069: *  N       (input) INTEGER
070: *          The number of columns of the input matrix A.
071: *          M >= N >= 0.
072: *
073: *  A       (input/output) REAL array, dimension (LDA,N)
074: *          On entry, M-by-N matrix A, such that A*diag(D) represents
075: *          the input matrix.
076: *          On exit,
077: *          A_onexit * D_onexit represents the input matrix A*diag(D)
078: *          post-multiplied by a sequence of Jacobi rotations, where the
079: *          rotation threshold and the total number of sweeps are given in
080: *          TOL and NSWEEP, respectively.
081: *          (See the descriptions of D, TOL and NSWEEP.)
082: *
083: *  LDA     (input) INTEGER
084: *          The leading dimension of the array A.  LDA >= max(1,M).
085: *
086: *  D       (input/workspace/output) REAL array, dimension (N)
087: *          The array D accumulates the scaling factors from the fast scaled
088: *          Jacobi rotations.
089: *          On entry, A*diag(D) represents the input matrix.
090: *          On exit, A_onexit*diag(D_onexit) represents the input matrix
091: *          post-multiplied by a sequence of Jacobi rotations, where the
092: *          rotation threshold and the total number of sweeps are given in
093: *          TOL and NSWEEP, respectively.
094: *          (See the descriptions of A, TOL and NSWEEP.)
095: *
096: *  SVA     (input/workspace/output) REAL array, dimension (N)
097: *          On entry, SVA contains the Euclidean norms of the columns of
098: *          the matrix A*diag(D).
099: *          On exit, SVA contains the Euclidean norms of the columns of
100: *          the matrix onexit*diag(D_onexit).
101: *
102: *  MV      (input) INTEGER
103: *          If JOBV .EQ. 'A', then MV rows of V are post-multipled by a
104: *                           sequence of Jacobi rotations.
105: *          If JOBV = 'N',   then MV is not referenced.
106: *
107: *  V       (input/output) REAL array, dimension (LDV,N)
108: *          If JOBV .EQ. 'V' then N rows of V are post-multipled by a
109: *                           sequence of Jacobi rotations.
110: *          If JOBV .EQ. 'A' then MV rows of V are post-multipled by a
111: *                           sequence of Jacobi rotations.
112: *          If JOBV = 'N',   then V is not referenced.
113: *
114: *  LDV     (input) INTEGER
115: *          The leading dimension of the array V,  LDV >= 1.
116: *          If JOBV = 'V', LDV .GE. N.
117: *          If JOBV = 'A', LDV .GE. MV.
118: *
119: *  EPS     (input) INTEGER
120: *          EPS = SLAMCH('Epsilon')
121: *
122: *  SFMIN   (input) INTEGER
123: *          SFMIN = SLAMCH('Safe Minimum')
124: *
125: *  TOL     (input) REAL
126: *          TOL is the threshold for Jacobi rotations. For a pair
127: *          A(:,p), A(:,q) of pivot columns, the Jacobi rotation is
128: *          applied only if ABS(COS(angle(A(:,p),A(:,q)))) .GT. TOL.
129: *
130: *  NSWEEP  (input) INTEGER
131: *          NSWEEP is the number of sweeps of Jacobi rotations to be
132: *          performed.
133: *
134: *  WORK    (workspace) REAL array, dimension LWORK.
135: *
136: *  LWORK   (input) INTEGER
137: *          LWORK is the dimension of WORK. LWORK .GE. M.
138: *
139: *  INFO    (output) INTEGER
140: *          = 0 : successful exit.
141: *          < 0 : if INFO = -i, then the i-th argument had an illegal value
142: *
143: *     Local Parameters
144:       REAL        ZERO,         HALF,         ONE,         TWO
145:       PARAMETER ( ZERO = 0.0E0, HALF = 0.5E0, ONE = 1.0E0, TWO = 2.0E0 )
146: 
147: *     Local Scalars
148:       REAL      AAPP, AAPP0, AAPQ, AAQQ, APOAQ, AQOAP, BIG, BIGTHETA,
149:      &          CS, MXAAPQ, MXSINJ, ROOTBIG, ROOTEPS, ROOTSFMIN,
150:      &          ROOTTOL, SMALL, SN, T, TEMP1, THETA, THSIGN
151:       INTEGER   BLSKIP, EMPTSW, i, ibr, IERR, igl, IJBLSK, ir1, ISWROT,
152:      &          jbc, jgl, KBL, LKAHEAD, MVL, NBL, NOTROT, p, PSKIPPED,
153:      &          q, ROWSKIP, SWBAND
154:       LOGICAL   APPLV, ROTOK, RSVEC
155: 
156: *     Local Arrays
157:       REAL      FASTR(5)
158: *
159: *     Intrinsic Functions
160:       INTRINSIC ABS, AMAX1, AMIN1, FLOAT, MIN0, SIGN, SQRT
161: *
162: *     External Functions
163:       REAL      SDOT, SNRM2
164:       INTEGER   ISAMAX
165:       LOGICAL   LSAME
166:       EXTERNAL  ISAMAX, LSAME, SDOT, SNRM2
167: *
168: *     External Subroutines
169:       EXTERNAL  SAXPY, SCOPY, SLASCL, SLASSQ, SROTM, SSWAP
170: *
171: *     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
172: *
173:       APPLV = LSAME(JOBV,'A')
174:       RSVEC = LSAME(JOBV,'V')
175:       IF ( .NOT.( RSVEC .OR. APPLV .OR. LSAME(JOBV,'N'))) THEN
176:          INFO = -1
177:       ELSE IF ( M .LT. 0 ) THEN
178:          INFO = -2
179:       ELSE IF ( ( N .LT. 0 ) .OR. ( N .GT. M )) THEN
180:          INFO = -3
181:       ELSE IF ( LDA .LT. M ) THEN
182:          INFO = -5
183:       ELSE IF ( MV .LT. 0 ) THEN
184:          INFO = -8
185:       ELSE IF ( LDV .LT. M ) THEN
186:          INFO = -10
187:       ELSE IF ( TOL .LE. EPS ) THEN
188:          INFO = -13
189:       ELSE IF ( NSWEEP .LT. 0 ) THEN
190:          INFO = -14
191:       ELSE IF ( LWORK .LT. M ) THEN
192:          INFO = -16
193:       ELSE
194:          INFO = 0
195:       END IF
196: *
197: *     #:(
198:       IF ( INFO .NE. 0 ) THEN
199:          CALL XERBLA( 'SGSVJ0', -INFO )
200:          RETURN
201:       END IF
202: *
203:       IF ( RSVEC ) THEN
204:          MVL = N
205:       ELSE IF ( APPLV ) THEN
206:          MVL = MV
207:       END IF
208:       RSVEC = RSVEC .OR. APPLV
209: 
210:       ROOTEPS     = SQRT(EPS)
211:       ROOTSFMIN   = SQRT(SFMIN)
212:       SMALL       = SFMIN  / EPS
213:       BIG         = ONE   / SFMIN
214:       ROOTBIG     = ONE  / ROOTSFMIN
215:       BIGTHETA    = ONE  / ROOTEPS
216:       ROOTTOL     = SQRT(TOL)
217: *
218: *
219: *     -#- Row-cyclic Jacobi SVD algorithm with column pivoting -#-
220: *
221:       EMPTSW   = ( N * ( N - 1 ) ) / 2
222:       NOTROT   = 0
223:       FASTR(1) = ZERO
224: *
225: *     -#- Row-cyclic pivot strategy with de Rijk's pivoting -#-
226: *
227: 
228:       SWBAND = 0
229: *[TP] SWBAND is a tuning parameter. It is meaningful and effective
230: *     if SGESVJ is used as a computational routine in the preconditioned
231: *     Jacobi SVD algorithm SGESVJ. For sweeps i=1:SWBAND the procedure
232: *     ......
233: 
234:       KBL = MIN0( 8, N )
235: *[TP] KBL is a tuning parameter that defines the tile size in the
236: *     tiling of the p-q loops of pivot pairs. In general, an optimal
237: *     value of KBL depends on the matrix dimensions and on the
238: *     parameters of the computer's memory.
239: *
240:       NBL = N / KBL
241:       IF ( ( NBL * KBL ) .NE. N ) NBL = NBL + 1
242: 
243:       BLSKIP = ( KBL**2 ) + 1
244: *[TP] BLKSKIP is a tuning parameter that depends on SWBAND and KBL.
245: 
246:       ROWSKIP = MIN0( 5, KBL )
247: *[TP] ROWSKIP is a tuning parameter.
248: 
249:       LKAHEAD = 1
250: *[TP] LKAHEAD is a tuning parameter.
251:       SWBAND = 0
252:       PSKIPPED = 0
253: *
254:       DO 1993 i = 1, NSWEEP
255: *     .. go go go ...
256: *
257:       MXAAPQ = ZERO
258:       MXSINJ = ZERO
259:       ISWROT = 0
260: *
261:       NOTROT = 0
262:       PSKIPPED = 0
263: *
264:       DO 2000 ibr = 1, NBL
265: 
266:       igl = ( ibr - 1 ) * KBL + 1
267: *
268:       DO 1002 ir1 = 0, MIN0( LKAHEAD, NBL - ibr )
269: *
270:       igl = igl + ir1 * KBL
271: *
272:       DO 2001 p = igl, MIN0( igl + KBL - 1, N - 1)
273: 
274: *     .. de Rijk's pivoting
275:       q   = ISAMAX( N-p+1, SVA(p), 1 ) + p - 1
276:       IF ( p .NE. q ) THEN
277:          CALL SSWAP( M, A(1,p), 1, A(1,q), 1 )
278:          IF ( RSVEC ) CALL SSWAP( MVL, V(1,p), 1, V(1,q), 1 )
279:          TEMP1   = SVA(p)
280:          SVA(p)  = SVA(q)
281:          SVA(q)  = TEMP1
282:          TEMP1   = D(p)
283:          D(p) = D(q)
284:          D(q) = TEMP1
285:       END IF
286: *
287:       IF ( ir1 .EQ. 0 ) THEN
288: *
289: *        Column norms are periodically updated by explicit
290: *        norm computation.
291: *        Caveat:
292: *        Some BLAS implementations compute SNRM2(M,A(1,p),1)
293: *        as SQRT(SDOT(M,A(1,p),1,A(1,p),1)), which may result in
294: *        overflow for ||A(:,p)||_2 > SQRT(overflow_threshold), and
295: *        undeflow for ||A(:,p)||_2 < SQRT(underflow_threshold).
296: *        Hence, SNRM2 cannot be trusted, not even in the case when
297: *        the true norm is far from the under(over)flow boundaries.
298: *        If properly implemented SNRM2 is available, the IF-THEN-ELSE
299: *        below should read "AAPP = SNRM2( M, A(1,p), 1 ) * D(p)".
300: *
301:          IF ((SVA(p) .LT. ROOTBIG) .AND. (SVA(p) .GT. ROOTSFMIN)) THEN
302:             SVA(p) = SNRM2( M, A(1,p), 1 ) * D(p)
303:          ELSE
304:             TEMP1 = ZERO
305:             AAPP  = ZERO
306:             CALL SLASSQ( M, A(1,p), 1, TEMP1, AAPP )
307:             SVA(p) = TEMP1 * SQRT(AAPP) * D(p)
308:          END IF
309:          AAPP = SVA(p)
310:       ELSE
311:          AAPP = SVA(p)
312:       END IF
313: 
314: *
315:       IF ( AAPP .GT. ZERO ) THEN
316: *
317:       PSKIPPED = 0
318: *
319:       DO 2002 q = p + 1, MIN0( igl + KBL - 1, N )
320: *
321:       AAQQ = SVA(q)
322: 
323:       IF ( AAQQ .GT. ZERO ) THEN
324: *
325:          AAPP0 = AAPP
326:          IF ( AAQQ .GE. ONE ) THEN
327:             ROTOK  = ( SMALL*AAPP ) .LE. AAQQ
328:             IF ( AAPP .LT. ( BIG / AAQQ ) ) THEN
329:                AAPQ = ( SDOT(M, A(1,p), 1, A(1,q), 1 ) *
330:      &                  D(p) * D(q) / AAQQ ) / AAPP
331:             ELSE
332:                CALL SCOPY( M, A(1,p), 1, WORK, 1 )
333:                CALL SLASCL( 'G', 0, 0, AAPP, D(p), M,
334:      &              1, WORK, LDA, IERR )
335:                AAPQ = SDOT( M, WORK,1, A(1,q),1 )*D(q) / AAQQ
336:             END IF
337:          ELSE
338:             ROTOK  = AAPP .LE. ( AAQQ / SMALL )
339:             IF ( AAPP .GT.  ( SMALL / AAQQ ) ) THEN
340:                AAPQ = ( SDOT( M, A(1,p), 1, A(1,q), 1 ) *
341:      &               D(p) * D(q) / AAQQ ) / AAPP
342:             ELSE
343:                CALL SCOPY( M, A(1,q), 1, WORK, 1 )
344:                CALL SLASCL( 'G', 0, 0, AAQQ, D(q), M,
345:      &              1, WORK, LDA, IERR )
346:                AAPQ = SDOT( M, WORK,1, A(1,p),1 )*D(p) / AAPP
347:             END IF
348:          END IF
349: *
350:          MXAAPQ = AMAX1( MXAAPQ, ABS(AAPQ) )
351: *
352: *        TO rotate or NOT to rotate, THAT is the question ...
353: *
354:          IF ( ABS( AAPQ ) .GT. TOL ) THEN
355: *
356: *           .. rotate
357: *           ROTATED = ROTATED + ONE
358: *
359:             IF ( ir1 .EQ. 0 ) THEN
360:                NOTROT   = 0
361:                PSKIPPED = 0
362:                ISWROT   = ISWROT  + 1
363:             END IF
364: *
365:             IF ( ROTOK ) THEN
366: *
367:                AQOAP = AAQQ / AAPP
368:                APOAQ = AAPP / AAQQ
369:                THETA = - HALF * ABS( AQOAP - APOAQ ) / AAPQ
370: *
371:                IF ( ABS( THETA ) .GT. BIGTHETA ) THEN
372: *
373:                   T        = HALF / THETA
374:                   FASTR(3) =   T * D(p) / D(q)
375:                   FASTR(4) = - T * D(q) / D(p)
376:                   CALL SROTM( M,   A(1,p), 1, A(1,q), 1, FASTR )
377:                   IF ( RSVEC )
378:      &            CALL SROTM( MVL, V(1,p), 1, V(1,q), 1, FASTR )
379:                   SVA(q) = AAQQ*SQRT( AMAX1(ZERO,ONE + T*APOAQ*AAPQ) )
380:                   AAPP   = AAPP*SQRT( ONE - T*AQOAP*AAPQ )
381:                   MXSINJ = AMAX1( MXSINJ, ABS(T) )
382: *
383:                ELSE
384: *
385: *                 .. choose correct signum for THETA and rotate
386: *
387:                   THSIGN =  - SIGN(ONE,AAPQ)
388:                   T  = ONE / ( THETA + THSIGN*SQRT(ONE+THETA*THETA) )
389:                   CS = SQRT( ONE / ( ONE + T*T ) )
390:                   SN = T * CS
391: *
392:                   MXSINJ = AMAX1( MXSINJ, ABS(SN) )
393:                   SVA(q) = AAQQ*SQRT( AMAX1(ZERO, ONE+T*APOAQ*AAPQ) )
394:                   AAPP   = AAPP*SQRT( AMAX1(ZERO, ONE-T*AQOAP*AAPQ) )
395: *
396:                   APOAQ = D(p) / D(q)
397:                   AQOAP = D(q) / D(p)
398:                   IF ( D(p) .GE. ONE ) THEN
399:                      IF ( D(q) .GE.  ONE ) THEN
400:                         FASTR(3) =   T * APOAQ
401:                         FASTR(4) = - T * AQOAP
402:                         D(p)  = D(p) * CS
403:                         D(q)  = D(q) * CS
404:                         CALL SROTM( M,   A(1,p),1, A(1,q),1, FASTR )
405:                         IF ( RSVEC )
406:      &                  CALL SROTM( MVL, V(1,p),1, V(1,q),1, FASTR )
407:                      ELSE
408:                         CALL SAXPY( M,    -T*AQOAP, A(1,q),1, A(1,p),1 )
409:                         CALL SAXPY( M, CS*SN*APOAQ, A(1,p),1, A(1,q),1 )
410:                         D(p) = D(p) * CS
411:                         D(q) = D(q) / CS
412:                         IF ( RSVEC ) THEN
413:                         CALL SAXPY(MVL,   -T*AQOAP, V(1,q),1,V(1,p),1)
414:                         CALL SAXPY(MVL,CS*SN*APOAQ, V(1,p),1,V(1,q),1)
415:                         END IF
416:                      END IF
417:                   ELSE
418:                      IF ( D(q) .GE. ONE ) THEN
419:                         CALL SAXPY( M,     T*APOAQ, A(1,p),1, A(1,q),1 )
420:                         CALL SAXPY( M,-CS*SN*AQOAP, A(1,q),1, A(1,p),1 )
421:                         D(p) = D(p) / CS
422:                         D(q) = D(q) * CS
423:                         IF ( RSVEC ) THEN
424:                         CALL SAXPY(MVL, T*APOAQ,    V(1,p),1,V(1,q),1)
425:                         CALL SAXPY(MVL,-CS*SN*AQOAP,V(1,q),1,V(1,p),1)
426:                         END IF
427:                      ELSE
428:                         IF ( D(p) .GE. D(q) ) THEN
429:                            CALL SAXPY( M,-T*AQOAP,   A(1,q),1,A(1,p),1 )
430:                            CALL SAXPY( M,CS*SN*APOAQ,A(1,p),1,A(1,q),1 )
431:                            D(p) = D(p) * CS
432:                            D(q) = D(q) / CS
433:                            IF ( RSVEC ) THEN
434:                            CALL SAXPY(MVL, -T*AQOAP,  V(1,q),1,V(1,p),1)
435:                            CALL SAXPY(MVL,CS*SN*APOAQ,V(1,p),1,V(1,q),1)
436:                            END IF
437:                         ELSE
438:                            CALL SAXPY( M, T*APOAQ,    A(1,p),1,A(1,q),1)
439:                            CALL SAXPY( M,-CS*SN*AQOAP,A(1,q),1,A(1,p),1)
440:                            D(p) = D(p) / CS
441:                            D(q) = D(q) * CS
442:                           IF ( RSVEC ) THEN
443:                           CALL SAXPY(MVL, T*APOAQ,    V(1,p),1,V(1,q),1)
444:                           CALL SAXPY(MVL,-CS*SN*AQOAP,V(1,q),1,V(1,p),1)
445:                           END IF
446:                         END IF
447:                      END IF
448:                   ENDIF
449:                END IF
450: *
451:             ELSE
452: *              .. have to use modified Gram-Schmidt like transformation
453:                CALL SCOPY( M, A(1,p), 1, WORK, 1 )
454:                CALL SLASCL( 'G',0,0,AAPP,ONE,M,1,WORK,LDA,IERR )
455:                CALL SLASCL( 'G',0,0,AAQQ,ONE,M,1,   A(1,q),LDA,IERR )
456:                TEMP1 = -AAPQ * D(p) / D(q)
457:                CALL SAXPY ( M, TEMP1, WORK, 1, A(1,q), 1 )
458:                CALL SLASCL( 'G',0,0,ONE,AAQQ,M,1,   A(1,q),LDA,IERR )
459:                SVA(q) = AAQQ*SQRT( AMAX1( ZERO, ONE - AAPQ*AAPQ ) )
460:                MXSINJ = AMAX1( MXSINJ, SFMIN )
461:             END IF
462: *           END IF ROTOK THEN ... ELSE
463: *
464: *           In the case of cancellation in updating SVA(q), SVA(p)
465: *           recompute SVA(q), SVA(p).
466:             IF ( (SVA(q) / AAQQ )**2 .LE. ROOTEPS  ) THEN
467:                IF ((AAQQ .LT. ROOTBIG).AND.(AAQQ .GT. ROOTSFMIN)) THEN
468:                   SVA(q) = SNRM2( M, A(1,q), 1 ) * D(q)
469:                ELSE
470:                   T    = ZERO
471:                   AAQQ = ZERO
472:                   CALL SLASSQ( M, A(1,q), 1, T, AAQQ )
473:                   SVA(q) = T * SQRT(AAQQ) * D(q)
474:                END IF
475:             END IF
476:             IF ( ( AAPP / AAPP0) .LE. ROOTEPS  ) THEN
477:                IF ((AAPP .LT. ROOTBIG).AND.(AAPP .GT. ROOTSFMIN)) THEN
478:                   AAPP = SNRM2( M, A(1,p), 1 ) * D(p)
479:                ELSE
480:                   T    = ZERO
481:                   AAPP = ZERO
482:                   CALL SLASSQ( M, A(1,p), 1, T, AAPP )
483:                   AAPP = T * SQRT(AAPP) * D(p)
484:                END IF
485:                SVA(p) = AAPP
486:             END IF
487: *
488:          ELSE
489: *        A(:,p) and A(:,q) already numerically orthogonal
490:             IF ( ir1 .EQ. 0 ) NOTROT   = NOTROT + 1
491:             PSKIPPED = PSKIPPED + 1
492:          END IF
493:       ELSE
494: *        A(:,q) is zero column
495:          IF ( ir1. EQ. 0 ) NOTROT = NOTROT + 1
496:          PSKIPPED = PSKIPPED + 1
497:       END IF
498: *
499:       IF ( ( i .LE. SWBAND ) .AND. ( PSKIPPED .GT. ROWSKIP ) ) THEN
500:          IF ( ir1 .EQ. 0 ) AAPP = - AAPP
501:          NOTROT = 0
502:          GO TO 2103
503:       END IF
504: *
505:  2002 CONTINUE
506: *     END q-LOOP
507: *
508:  2103 CONTINUE
509: *     bailed out of q-loop
510: 
511:       SVA(p) = AAPP
512: 
513:       ELSE
514:          SVA(p) = AAPP
515:          IF ( ( ir1 .EQ. 0 ) .AND. (AAPP .EQ. ZERO) )
516:      &        NOTROT=NOTROT+MIN0(igl+KBL-1,N)-p
517:       END IF
518: *
519:  2001 CONTINUE
520: *     end of the p-loop
521: *     end of doing the block ( ibr, ibr )
522:  1002 CONTINUE
523: *     end of ir1-loop
524: *
525: *........................................................
526: * ... go to the off diagonal blocks
527: *
528:       igl = ( ibr - 1 ) * KBL + 1
529: *
530:       DO 2010 jbc = ibr + 1, NBL
531: *
532:          jgl = ( jbc - 1 ) * KBL + 1
533: *
534: *        doing the block at ( ibr, jbc )
535: *
536:          IJBLSK = 0
537:          DO 2100 p = igl, MIN0( igl + KBL - 1, N )
538: *
539:          AAPP = SVA(p)
540: *
541:          IF ( AAPP .GT. ZERO ) THEN
542: *
543:          PSKIPPED = 0
544: *
545:          DO 2200 q = jgl, MIN0( jgl + KBL - 1, N )
546: *
547:          AAQQ = SVA(q)
548: *
549:          IF ( AAQQ .GT. ZERO ) THEN
550:             AAPP0 = AAPP
551: *
552: *     -#- M x 2 Jacobi SVD -#-
553: *
554: *        -#- Safe Gram matrix computation -#-
555: *
556:          IF ( AAQQ .GE. ONE ) THEN
557:             IF ( AAPP .GE. AAQQ ) THEN
558:                ROTOK = ( SMALL*AAPP ) .LE. AAQQ
559:             ELSE
560:                ROTOK = ( SMALL*AAQQ ) .LE. AAPP
561:             END IF
562:             IF ( AAPP .LT. ( BIG / AAQQ ) ) THEN
563:                AAPQ = ( SDOT(M, A(1,p), 1, A(1,q), 1 ) *
564:      &                  D(p) * D(q) / AAQQ ) / AAPP
565:             ELSE
566:                CALL SCOPY( M, A(1,p), 1, WORK, 1 )
567:                CALL SLASCL( 'G', 0, 0, AAPP, D(p), M,
568:      &              1, WORK, LDA, IERR )
569:                AAPQ = SDOT( M, WORK, 1, A(1,q), 1 ) *
570:      &                D(q) / AAQQ
571:             END IF
572:          ELSE
573:             IF ( AAPP .GE. AAQQ ) THEN
574:                ROTOK = AAPP .LE. ( AAQQ / SMALL )
575:             ELSE
576:                ROTOK = AAQQ .LE. ( AAPP / SMALL )
577:             END IF
578:             IF ( AAPP .GT.  ( SMALL / AAQQ ) ) THEN
579:                AAPQ = ( SDOT( M, A(1,p), 1, A(1,q), 1 ) *
580:      &               D(p) * D(q) / AAQQ ) / AAPP
581:             ELSE
582:                CALL SCOPY( M, A(1,q), 1, WORK, 1 )
583:                CALL SLASCL( 'G', 0, 0, AAQQ, D(q), M, 1,
584:      &              WORK, LDA, IERR )
585:                AAPQ = SDOT(M,WORK,1,A(1,p),1) * D(p) / AAPP
586:             END IF
587:          END IF
588: *
589:          MXAAPQ = AMAX1( MXAAPQ, ABS(AAPQ) )
590: *
591: *        TO rotate or NOT to rotate, THAT is the question ...
592: *
593:          IF ( ABS( AAPQ ) .GT. TOL ) THEN
594:             NOTROT   = 0
595: *           ROTATED  = ROTATED + 1
596:             PSKIPPED = 0
597:             ISWROT   = ISWROT  + 1
598: *
599:             IF ( ROTOK ) THEN
600: *
601:                AQOAP = AAQQ / AAPP
602:                APOAQ = AAPP / AAQQ
603:                THETA = - HALF * ABS( AQOAP - APOAQ ) / AAPQ
604:                IF ( AAQQ .GT. AAPP0 ) THETA = - THETA
605: *
606:                IF ( ABS( THETA ) .GT. BIGTHETA ) THEN
607:                   T = HALF / THETA
608:                   FASTR(3) =  T * D(p) / D(q)
609:                   FASTR(4) = -T * D(q) / D(p)
610:                   CALL SROTM( M,   A(1,p), 1, A(1,q), 1, FASTR )
611:                   IF ( RSVEC )
612:      &            CALL SROTM( MVL, V(1,p), 1, V(1,q), 1, FASTR )
613:                   SVA(q) = AAQQ*SQRT( AMAX1(ZERO,ONE + T*APOAQ*AAPQ) )
614:                   AAPP   = AAPP*SQRT( AMAX1(ZERO,ONE - T*AQOAP*AAPQ) )
615:                   MXSINJ = AMAX1( MXSINJ, ABS(T) )
616:                ELSE
617: *
618: *                 .. choose correct signum for THETA and rotate
619: *
620:                   THSIGN = - SIGN(ONE,AAPQ)
621:                   IF ( AAQQ .GT. AAPP0 ) THSIGN = - THSIGN
622:                   T  = ONE / ( THETA + THSIGN*SQRT(ONE+THETA*THETA) )
623:                   CS = SQRT( ONE / ( ONE + T*T ) )
624:                   SN = T * CS
625:                   MXSINJ = AMAX1( MXSINJ, ABS(SN) )
626:                   SVA(q) = AAQQ*SQRT( AMAX1(ZERO, ONE+T*APOAQ*AAPQ) )
627:                   AAPP   = AAPP*SQRT( ONE - T*AQOAP*AAPQ)
628: *
629:                   APOAQ = D(p) / D(q)
630:                   AQOAP = D(q) / D(p)
631:                   IF ( D(p) .GE. ONE ) THEN
632: *
633:                      IF ( D(q) .GE.  ONE ) THEN
634:                         FASTR(3) =   T * APOAQ
635:                         FASTR(4) = - T * AQOAP
636:                         D(p)  = D(p) * CS
637:                         D(q)  = D(q) * CS
638:                         CALL SROTM( M,   A(1,p),1, A(1,q),1, FASTR )
639:                         IF ( RSVEC )
640:      &                  CALL SROTM( MVL, V(1,p),1, V(1,q),1, FASTR )
641:                      ELSE
642:                         CALL SAXPY( M,    -T*AQOAP, A(1,q),1, A(1,p),1 )
643:                         CALL SAXPY( M, CS*SN*APOAQ, A(1,p),1, A(1,q),1 )
644:                         IF ( RSVEC ) THEN
645:                         CALL SAXPY( MVL, -T*AQOAP,  V(1,q),1, V(1,p),1 )
646:                         CALL SAXPY( MVL,CS*SN*APOAQ,V(1,p),1, V(1,q),1 )
647:                         END IF
648:                         D(p) = D(p) * CS
649:                         D(q) = D(q) / CS
650:                      END IF
651:                   ELSE
652:                      IF ( D(q) .GE. ONE ) THEN
653:                         CALL SAXPY( M,     T*APOAQ, A(1,p),1, A(1,q),1 )
654:                         CALL SAXPY( M,-CS*SN*AQOAP, A(1,q),1, A(1,p),1 )
655:                         IF ( RSVEC ) THEN
656:                         CALL SAXPY(MVL,T*APOAQ,     V(1,p),1, V(1,q),1 )
657:                         CALL SAXPY(MVL,-CS*SN*AQOAP,V(1,q),1, V(1,p),1 )
658:                         END IF
659:                         D(p) = D(p) / CS
660:                         D(q) = D(q) * CS
661:                      ELSE
662:                         IF ( D(p) .GE. D(q) ) THEN
663:                            CALL SAXPY( M,-T*AQOAP,   A(1,q),1,A(1,p),1 )
664:                            CALL SAXPY( M,CS*SN*APOAQ,A(1,p),1,A(1,q),1 )
665:                            D(p) = D(p) * CS
666:                            D(q) = D(q) / CS
667:                            IF ( RSVEC ) THEN
668:                            CALL SAXPY( MVL, -T*AQOAP, V(1,q),1,V(1,p),1)
669:                            CALL SAXPY(MVL,CS*SN*APOAQ,V(1,p),1,V(1,q),1)
670:                            END IF
671:                         ELSE
672:                            CALL SAXPY(M, T*APOAQ,    A(1,p),1,A(1,q),1)
673:                            CALL SAXPY(M,-CS*SN*AQOAP,A(1,q),1,A(1,p),1)
674:                            D(p) = D(p) / CS
675:                            D(q) = D(q) * CS
676:                           IF ( RSVEC ) THEN
677:                           CALL SAXPY(MVL, T*APOAQ,    V(1,p),1,V(1,q),1)
678:                           CALL SAXPY(MVL,-CS*SN*AQOAP,V(1,q),1,V(1,p),1)
679:                           END IF
680:                         END IF
681:                      END IF
682:                   ENDIF
683:                END IF
684: *
685:             ELSE
686:                IF ( AAPP .GT. AAQQ ) THEN
687:                   CALL SCOPY( M, A(1,p), 1, WORK, 1 )
688:                   CALL SLASCL('G',0,0,AAPP,ONE,M,1,WORK,LDA,IERR)
689:                   CALL SLASCL('G',0,0,AAQQ,ONE,M,1,   A(1,q),LDA,IERR)
690:                   TEMP1 = -AAPQ * D(p) / D(q)
691:                   CALL SAXPY(M,TEMP1,WORK,1,A(1,q),1)
692:                   CALL SLASCL('G',0,0,ONE,AAQQ,M,1,A(1,q),LDA,IERR)
693:                   SVA(q) = AAQQ*SQRT(AMAX1(ZERO, ONE - AAPQ*AAPQ))
694:                   MXSINJ = AMAX1( MXSINJ, SFMIN )
695:                ELSE
696:                   CALL SCOPY( M, A(1,q), 1, WORK, 1 )
697:                   CALL SLASCL('G',0,0,AAQQ,ONE,M,1,WORK,LDA,IERR)
698:                   CALL SLASCL('G',0,0,AAPP,ONE,M,1,   A(1,p),LDA,IERR)
699:                   TEMP1 = -AAPQ * D(q) / D(p)
700:                   CALL SAXPY(M,TEMP1,WORK,1,A(1,p),1)
701:                   CALL SLASCL('G',0,0,ONE,AAPP,M,1,A(1,p),LDA,IERR)
702:                   SVA(p) = AAPP*SQRT(AMAX1(ZERO, ONE - AAPQ*AAPQ))
703:                   MXSINJ = AMAX1( MXSINJ, SFMIN )
704:                END IF
705:             END IF
706: *           END IF ROTOK THEN ... ELSE
707: *
708: *           In the case of cancellation in updating SVA(q)
709: *           .. recompute SVA(q)
710:             IF ( (SVA(q) / AAQQ )**2 .LE. ROOTEPS  ) THEN
711:                IF ((AAQQ .LT. ROOTBIG).AND.(AAQQ .GT. ROOTSFMIN)) THEN
712:                   SVA(q) = SNRM2( M, A(1,q), 1 ) * D(q)
713:                ELSE
714:                   T    = ZERO
715:                   AAQQ = ZERO
716:                   CALL SLASSQ( M, A(1,q), 1, T, AAQQ )
717:                   SVA(q) = T * SQRT(AAQQ) * D(q)
718:                END IF
719:             END IF
720:             IF ( (AAPP / AAPP0 )**2 .LE. ROOTEPS  ) THEN
721:                IF ((AAPP .LT. ROOTBIG).AND.(AAPP .GT. ROOTSFMIN)) THEN
722:                   AAPP = SNRM2( M, A(1,p), 1 ) * D(p)
723:                ELSE
724:                   T    = ZERO
725:                   AAPP = ZERO
726:                   CALL SLASSQ( M, A(1,p), 1, T, AAPP )
727:                   AAPP = T * SQRT(AAPP) * D(p)
728:                END IF
729:                SVA(p) = AAPP
730:             END IF
731: *              end of OK rotation
732:          ELSE
733:             NOTROT   = NOTROT   + 1
734:             PSKIPPED = PSKIPPED + 1
735:             IJBLSK   = IJBLSK   + 1
736:          END IF
737:       ELSE
738:          NOTROT   = NOTROT   + 1
739:          PSKIPPED = PSKIPPED + 1
740:          IJBLSK   = IJBLSK   + 1
741:       END IF
742: *
743:       IF ( ( i .LE. SWBAND ) .AND. ( IJBLSK .GE. BLSKIP ) ) THEN
744:          SVA(p) = AAPP
745:          NOTROT = 0
746:          GO TO 2011
747:       END IF
748:       IF ( ( i .LE. SWBAND ) .AND. ( PSKIPPED .GT. ROWSKIP ) ) THEN
749:          AAPP = -AAPP
750:          NOTROT = 0
751:          GO TO 2203
752:       END IF
753: *
754:  2200    CONTINUE
755: *        end of the q-loop
756:  2203    CONTINUE
757: *
758:          SVA(p) = AAPP
759: *
760:       ELSE
761:          IF ( AAPP .EQ. ZERO ) NOTROT=NOTROT+MIN0(jgl+KBL-1,N)-jgl+1
762:          IF ( AAPP .LT. ZERO ) NOTROT = 0
763:       END IF
764: 
765:  2100 CONTINUE
766: *     end of the p-loop
767:  2010 CONTINUE
768: *     end of the jbc-loop
769:  2011 CONTINUE
770: *2011 bailed out of the jbc-loop
771:       DO 2012 p = igl, MIN0( igl + KBL - 1, N )
772:          SVA(p) = ABS(SVA(p))
773:  2012 CONTINUE
774: *
775:  2000 CONTINUE
776: *2000 :: end of the ibr-loop
777: *
778: *     .. update SVA(N)
779:       IF ((SVA(N) .LT. ROOTBIG).AND.(SVA(N) .GT. ROOTSFMIN)) THEN
780:          SVA(N) = SNRM2( M, A(1,N), 1 ) * D(N)
781:       ELSE
782:          T    = ZERO
783:          AAPP = ZERO
784:          CALL SLASSQ( M, A(1,N), 1, T, AAPP )
785:          SVA(N) = T * SQRT(AAPP) * D(N)
786:       END IF
787: *
788: *     Additional steering devices
789: *
790:       IF ( ( i.LT.SWBAND ) .AND. ( ( MXAAPQ.LE.ROOTTOL ) .OR.
791:      &     ( ISWROT .LE. N ) ) )
792:      &   SWBAND = i
793: *
794:       IF ((i.GT.SWBAND+1).AND. (MXAAPQ.LT.FLOAT(N)*TOL).AND.
795:      &   (FLOAT(N)*MXAAPQ*MXSINJ.LT.TOL))THEN
796:         GO TO 1994
797:       END IF
798: *
799:       IF ( NOTROT .GE. EMPTSW ) GO TO 1994
800: 
801:  1993 CONTINUE
802: *     end i=1:NSWEEP loop
803: * #:) Reaching this point means that the procedure has comleted the given
804: *     number of iterations.
805:       INFO = NSWEEP - 1
806:       GO TO 1995
807:  1994 CONTINUE
808: * #:) Reaching this point means that during the i-th sweep all pivots were
809: *     below the given tolerance, causing early exit.
810: *
811:       INFO = 0
812: * #:) INFO = 0 confirms successful iterations.
813:  1995 CONTINUE
814: *
815: *     Sort the vector D.
816:       DO 5991 p = 1, N - 1
817:          q = ISAMAX( N-p+1, SVA(p), 1 ) + p - 1
818:          IF ( p .NE. q ) THEN
819:             TEMP1  = SVA(p)
820:             SVA(p) = SVA(q)
821:             SVA(q) = TEMP1
822:             TEMP1   = D(p)
823:             D(p) = D(q)
824:             D(q) = TEMP1
825:             CALL SSWAP( M, A(1,p), 1, A(1,q), 1 )
826:             IF ( RSVEC ) CALL SSWAP( MVL, V(1,p), 1, V(1,q), 1 )
827:          END IF
828:  5991 CONTINUE
829: *
830:       RETURN
831: *     ..
832: *     .. END OF SGSVJ0
833: *     ..
834:       END
835: *
836: