1*> \brief \b SLA_PORFSX_EXTENDED improves the computed solution to a system of linear equations for symmetric or Hermitian positive-definite matrices by performing extra-precise iterative refinement and provides error bounds and backward error estimates for the solution.
2*
3*  =========== DOCUMENTATION ===========
4*
5* Online html documentation available at
6*            http://www.netlib.org/lapack/explore-html/
7*
8*> \htmlonly
9*> Download SLA_PORFSX_EXTENDED + dependencies
10*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/sla_porfsx_extended.f">
11*> [TGZ]</a>
12*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/sla_porfsx_extended.f">
13*> [ZIP]</a>
14*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/sla_porfsx_extended.f">
15*> [TXT]</a>
16*> \endhtmlonly
17*
18*  Definition:
19*  ===========
20*
21*       SUBROUTINE SLA_PORFSX_EXTENDED( PREC_TYPE, UPLO, N, NRHS, A, LDA,
22*                                       AF, LDAF, COLEQU, C, B, LDB, Y,
23*                                       LDY, BERR_OUT, N_NORMS,
24*                                       ERR_BNDS_NORM, ERR_BNDS_COMP, RES,
25*                                       AYB, DY, Y_TAIL, RCOND, ITHRESH,
26*                                       RTHRESH, DZ_UB, IGNORE_CWISE,
27*                                       INFO )
28*
29*       .. Scalar Arguments ..
30*       INTEGER            INFO, LDA, LDAF, LDB, LDY, N, NRHS, PREC_TYPE,
31*      $                   N_NORMS, ITHRESH
32*       CHARACTER          UPLO
33*       LOGICAL            COLEQU, IGNORE_CWISE
34*       REAL               RTHRESH, DZ_UB
35*       ..
36*       .. Array Arguments ..
37*       REAL               A( LDA, * ), AF( LDAF, * ), B( LDB, * ),
38*      $                   Y( LDY, * ), RES( * ), DY( * ), Y_TAIL( * )
39*       REAL               C( * ), AYB(*), RCOND, BERR_OUT( * ),
40*      $                   ERR_BNDS_NORM( NRHS, * ),
41*      $                   ERR_BNDS_COMP( NRHS, * )
42*       ..
43*
44*
45*> \par Purpose:
46*  =============
47*>
48*> \verbatim
49*>
50*> SLA_PORFSX_EXTENDED improves the computed solution to a system of
51*> linear equations by performing extra-precise iterative refinement
52*> and provides error bounds and backward error estimates for the solution.
53*> This subroutine is called by SPORFSX to perform iterative refinement.
54*> In addition to normwise error bound, the code provides maximum
55*> componentwise error bound if possible. See comments for ERR_BNDS_NORM
56*> and ERR_BNDS_COMP for details of the error bounds. Note that this
57*> subroutine is only resonsible for setting the second fields of
58*> ERR_BNDS_NORM and ERR_BNDS_COMP.
59*> \endverbatim
60*
61*  Arguments:
62*  ==========
63*
64*> \param[in] PREC_TYPE
65*> \verbatim
66*>          PREC_TYPE is INTEGER
67*>     Specifies the intermediate precision to be used in refinement.
68*>     The value is defined by ILAPREC(P) where P is a CHARACTER and
69*>     P    = 'S':  Single
70*>          = 'D':  Double
71*>          = 'I':  Indigenous
72*>          = 'X', 'E':  Extra
73*> \endverbatim
74*>
75*> \param[in] UPLO
76*> \verbatim
77*>          UPLO is CHARACTER*1
78*>       = 'U':  Upper triangle of A is stored;
79*>       = 'L':  Lower triangle of A is stored.
80*> \endverbatim
81*>
82*> \param[in] N
83*> \verbatim
84*>          N is INTEGER
85*>     The number of linear equations, i.e., the order of the
86*>     matrix A.  N >= 0.
87*> \endverbatim
88*>
89*> \param[in] NRHS
90*> \verbatim
91*>          NRHS is INTEGER
92*>     The number of right-hand-sides, i.e., the number of columns of the
93*>     matrix B.
94*> \endverbatim
95*>
96*> \param[in] A
97*> \verbatim
98*>          A is REAL array, dimension (LDA,N)
99*>     On entry, the N-by-N matrix A.
100*> \endverbatim
101*>
102*> \param[in] LDA
103*> \verbatim
104*>          LDA is INTEGER
105*>     The leading dimension of the array A.  LDA >= max(1,N).
106*> \endverbatim
107*>
108*> \param[in] AF
109*> \verbatim
110*>          AF is REAL array, dimension (LDAF,N)
111*>     The triangular factor U or L from the Cholesky factorization
112*>     A = U**T*U or A = L*L**T, as computed by SPOTRF.
113*> \endverbatim
114*>
115*> \param[in] LDAF
116*> \verbatim
117*>          LDAF is INTEGER
118*>     The leading dimension of the array AF.  LDAF >= max(1,N).
119*> \endverbatim
120*>
121*> \param[in] COLEQU
122*> \verbatim
123*>          COLEQU is LOGICAL
124*>     If .TRUE. then column equilibration was done to A before calling
125*>     this routine. This is needed to compute the solution and error
126*>     bounds correctly.
127*> \endverbatim
128*>
129*> \param[in] C
130*> \verbatim
131*>          C is REAL array, dimension (N)
132*>     The column scale factors for A. If COLEQU = .FALSE., C
133*>     is not accessed. If C is input, each element of C should be a power
134*>     of the radix to ensure a reliable solution and error estimates.
135*>     Scaling by powers of the radix does not cause rounding errors unless
136*>     the result underflows or overflows. Rounding errors during scaling
137*>     lead to refining with a matrix that is not equivalent to the
138*>     input matrix, producing error estimates that may not be
139*>     reliable.
140*> \endverbatim
141*>
142*> \param[in] B
143*> \verbatim
144*>          B is REAL array, dimension (LDB,NRHS)
145*>     The right-hand-side matrix B.
146*> \endverbatim
147*>
148*> \param[in] LDB
149*> \verbatim
150*>          LDB is INTEGER
151*>     The leading dimension of the array B.  LDB >= max(1,N).
152*> \endverbatim
153*>
154*> \param[in,out] Y
155*> \verbatim
156*>          Y is REAL array, dimension (LDY,NRHS)
157*>     On entry, the solution matrix X, as computed by SPOTRS.
158*>     On exit, the improved solution matrix Y.
159*> \endverbatim
160*>
161*> \param[in] LDY
162*> \verbatim
163*>          LDY is INTEGER
164*>     The leading dimension of the array Y.  LDY >= max(1,N).
165*> \endverbatim
166*>
167*> \param[out] BERR_OUT
168*> \verbatim
169*>          BERR_OUT is REAL array, dimension (NRHS)
170*>     On exit, BERR_OUT(j) contains the componentwise relative backward
171*>     error for right-hand-side j from the formula
172*>         max(i) ( abs(RES(i)) / ( abs(op(A_s))*abs(Y) + abs(B_s) )(i) )
173*>     where abs(Z) is the componentwise absolute value of the matrix
174*>     or vector Z. This is computed by SLA_LIN_BERR.
175*> \endverbatim
176*>
177*> \param[in] N_NORMS
178*> \verbatim
179*>          N_NORMS is INTEGER
180*>     Determines which error bounds to return (see ERR_BNDS_NORM
181*>     and ERR_BNDS_COMP).
182*>     If N_NORMS >= 1 return normwise error bounds.
183*>     If N_NORMS >= 2 return componentwise error bounds.
184*> \endverbatim
185*>
186*> \param[in,out] ERR_BNDS_NORM
187*> \verbatim
188*>          ERR_BNDS_NORM is REAL array, dimension (NRHS, N_ERR_BNDS)
189*>     For each right-hand side, this array contains information about
190*>     various error bounds and condition numbers corresponding to the
191*>     normwise relative error, which is defined as follows:
192*>
193*>     Normwise relative error in the ith solution vector:
194*>             max_j (abs(XTRUE(j,i) - X(j,i)))
195*>            ------------------------------
196*>                  max_j abs(X(j,i))
197*>
198*>     The array is indexed by the type of error information as described
199*>     below. There currently are up to three pieces of information
200*>     returned.
201*>
202*>     The first index in ERR_BNDS_NORM(i,:) corresponds to the ith
203*>     right-hand side.
204*>
205*>     The second index in ERR_BNDS_NORM(:,err) contains the following
206*>     three fields:
207*>     err = 1 "Trust/don't trust" boolean. Trust the answer if the
208*>              reciprocal condition number is less than the threshold
209*>              sqrt(n) * slamch('Epsilon').
210*>
211*>     err = 2 "Guaranteed" error bound: The estimated forward error,
212*>              almost certainly within a factor of 10 of the true error
213*>              so long as the next entry is greater than the threshold
214*>              sqrt(n) * slamch('Epsilon'). This error bound should only
215*>              be trusted if the previous boolean is true.
216*>
217*>     err = 3  Reciprocal condition number: Estimated normwise
218*>              reciprocal condition number.  Compared with the threshold
219*>              sqrt(n) * slamch('Epsilon') to determine if the error
220*>              estimate is "guaranteed". These reciprocal condition
221*>              numbers are 1 / (norm(Z^{-1},inf) * norm(Z,inf)) for some
222*>              appropriately scaled matrix Z.
223*>              Let Z = S*A, where S scales each row by a power of the
224*>              radix so all absolute row sums of Z are approximately 1.
225*>
226*>     This subroutine is only responsible for setting the second field
227*>     above.
228*>     See Lapack Working Note 165 for further details and extra
229*>     cautions.
230*> \endverbatim
231*>
232*> \param[in,out] ERR_BNDS_COMP
233*> \verbatim
234*>          ERR_BNDS_COMP is REAL array, dimension (NRHS, N_ERR_BNDS)
235*>     For each right-hand side, this array contains information about
236*>     various error bounds and condition numbers corresponding to the
237*>     componentwise relative error, which is defined as follows:
238*>
239*>     Componentwise relative error in the ith solution vector:
240*>                    abs(XTRUE(j,i) - X(j,i))
241*>             max_j ----------------------
242*>                         abs(X(j,i))
243*>
244*>     The array is indexed by the right-hand side i (on which the
245*>     componentwise relative error depends), and the type of error
246*>     information as described below. There currently are up to three
247*>     pieces of information returned for each right-hand side. If
248*>     componentwise accuracy is not requested (PARAMS(3) = 0.0), then
249*>     ERR_BNDS_COMP is not accessed.  If N_ERR_BNDS .LT. 3, then at most
250*>     the first (:,N_ERR_BNDS) entries are returned.
251*>
252*>     The first index in ERR_BNDS_COMP(i,:) corresponds to the ith
253*>     right-hand side.
254*>
255*>     The second index in ERR_BNDS_COMP(:,err) contains the following
256*>     three fields:
257*>     err = 1 "Trust/don't trust" boolean. Trust the answer if the
258*>              reciprocal condition number is less than the threshold
259*>              sqrt(n) * slamch('Epsilon').
260*>
261*>     err = 2 "Guaranteed" error bound: The estimated forward error,
262*>              almost certainly within a factor of 10 of the true error
263*>              so long as the next entry is greater than the threshold
264*>              sqrt(n) * slamch('Epsilon'). This error bound should only
265*>              be trusted if the previous boolean is true.
266*>
267*>     err = 3  Reciprocal condition number: Estimated componentwise
268*>              reciprocal condition number.  Compared with the threshold
269*>              sqrt(n) * slamch('Epsilon') to determine if the error
270*>              estimate is "guaranteed". These reciprocal condition
271*>              numbers are 1 / (norm(Z^{-1},inf) * norm(Z,inf)) for some
272*>              appropriately scaled matrix Z.
273*>              Let Z = S*(A*diag(x)), where x is the solution for the
274*>              current right-hand side and S scales each row of
275*>              A*diag(x) by a power of the radix so all absolute row
276*>              sums of Z are approximately 1.
277*>
278*>     This subroutine is only responsible for setting the second field
279*>     above.
280*>     See Lapack Working Note 165 for further details and extra
281*>     cautions.
282*> \endverbatim
283*>
284*> \param[in] RES
285*> \verbatim
286*>          RES is REAL array, dimension (N)
287*>     Workspace to hold the intermediate residual.
288*> \endverbatim
289*>
290*> \param[in] AYB
291*> \verbatim
292*>          AYB is REAL array, dimension (N)
293*>     Workspace. This can be the same workspace passed for Y_TAIL.
294*> \endverbatim
295*>
296*> \param[in] DY
297*> \verbatim
298*>          DY is REAL array, dimension (N)
299*>     Workspace to hold the intermediate solution.
300*> \endverbatim
301*>
302*> \param[in] Y_TAIL
303*> \verbatim
304*>          Y_TAIL is REAL array, dimension (N)
305*>     Workspace to hold the trailing bits of the intermediate solution.
306*> \endverbatim
307*>
308*> \param[in] RCOND
309*> \verbatim
310*>          RCOND is REAL
311*>     Reciprocal scaled condition number.  This is an estimate of the
312*>     reciprocal Skeel condition number of the matrix A after
313*>     equilibration (if done).  If this is less than the machine
314*>     precision (in particular, if it is zero), the matrix is singular
315*>     to working precision.  Note that the error may still be small even
316*>     if this number is very small and the matrix appears ill-
317*>     conditioned.
318*> \endverbatim
319*>
320*> \param[in] ITHRESH
321*> \verbatim
322*>          ITHRESH is INTEGER
323*>     The maximum number of residual computations allowed for
324*>     refinement. The default is 10. For 'aggressive' set to 100 to
325*>     permit convergence using approximate factorizations or
326*>     factorizations other than LU. If the factorization uses a
327*>     technique other than Gaussian elimination, the guarantees in
328*>     ERR_BNDS_NORM and ERR_BNDS_COMP may no longer be trustworthy.
329*> \endverbatim
330*>
331*> \param[in] RTHRESH
332*> \verbatim
333*>          RTHRESH is REAL
334*>     Determines when to stop refinement if the error estimate stops
335*>     decreasing. Refinement will stop when the next solution no longer
336*>     satisfies norm(dx_{i+1}) < RTHRESH * norm(dx_i) where norm(Z) is
337*>     the infinity norm of Z. RTHRESH satisfies 0 < RTHRESH <= 1. The
338*>     default value is 0.5. For 'aggressive' set to 0.9 to permit
339*>     convergence on extremely ill-conditioned matrices. See LAWN 165
340*>     for more details.
341*> \endverbatim
342*>
343*> \param[in] DZ_UB
344*> \verbatim
345*>          DZ_UB is REAL
346*>     Determines when to start considering componentwise convergence.
347*>     Componentwise convergence is only considered after each component
348*>     of the solution Y is stable, which we definte as the relative
349*>     change in each component being less than DZ_UB. The default value
350*>     is 0.25, requiring the first bit to be stable. See LAWN 165 for
351*>     more details.
352*> \endverbatim
353*>
354*> \param[in] IGNORE_CWISE
355*> \verbatim
356*>          IGNORE_CWISE is LOGICAL
357*>     If .TRUE. then ignore componentwise convergence. Default value
358*>     is .FALSE..
359*> \endverbatim
360*>
361*> \param[out] INFO
362*> \verbatim
363*>          INFO is INTEGER
364*>       = 0:  Successful exit.
365*>       < 0:  if INFO = -i, the ith argument to SPOTRS had an illegal
366*>             value
367*> \endverbatim
368*
369*  Authors:
370*  ========
371*
372*> \author Univ. of Tennessee
373*> \author Univ. of California Berkeley
374*> \author Univ. of Colorado Denver
375*> \author NAG Ltd.
376*
377*> \date September 2012
378*
379*> \ingroup realPOcomputational
380*
381*  =====================================================================
382      SUBROUTINE SLA_PORFSX_EXTENDED( PREC_TYPE, UPLO, N, NRHS, A, LDA,
383     $                                AF, LDAF, COLEQU, C, B, LDB, Y,
384     $                                LDY, BERR_OUT, N_NORMS,
385     $                                ERR_BNDS_NORM, ERR_BNDS_COMP, RES,
386     $                                AYB, DY, Y_TAIL, RCOND, ITHRESH,
387     $                                RTHRESH, DZ_UB, IGNORE_CWISE,
388     $                                INFO )
389*
390*  -- LAPACK computational routine (version 3.4.2) --
391*  -- LAPACK is a software package provided by Univ. of Tennessee,    --
392*  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
393*     September 2012
394*
395*     .. Scalar Arguments ..
396      INTEGER            INFO, LDA, LDAF, LDB, LDY, N, NRHS, PREC_TYPE,
397     $                   N_NORMS, ITHRESH
398      CHARACTER          UPLO
399      LOGICAL            COLEQU, IGNORE_CWISE
400      REAL               RTHRESH, DZ_UB
401*     ..
402*     .. Array Arguments ..
403      REAL               A( LDA, * ), AF( LDAF, * ), B( LDB, * ),
404     $                   Y( LDY, * ), RES( * ), DY( * ), Y_TAIL( * )
405      REAL               C( * ), AYB(*), RCOND, BERR_OUT( * ),
406     $                   ERR_BNDS_NORM( NRHS, * ),
407     $                   ERR_BNDS_COMP( NRHS, * )
408*     ..
409*
410*  =====================================================================
411*
412*     .. Local Scalars ..
413      INTEGER            UPLO2, CNT, I, J, X_STATE, Z_STATE
414      REAL               YK, DYK, YMIN, NORMY, NORMX, NORMDX, DXRAT,
415     $                   DZRAT, PREVNORMDX, PREV_DZ_Z, DXRATMAX,
416     $                   DZRATMAX, DX_X, DZ_Z, FINAL_DX_X, FINAL_DZ_Z,
417     $                   EPS, HUGEVAL, INCR_THRESH
418      LOGICAL            INCR_PREC
419*     ..
420*     .. Parameters ..
421      INTEGER           UNSTABLE_STATE, WORKING_STATE, CONV_STATE,
422     $                  NOPROG_STATE, Y_PREC_STATE, BASE_RESIDUAL,
423     $                  EXTRA_RESIDUAL, EXTRA_Y
424      PARAMETER         ( UNSTABLE_STATE = 0, WORKING_STATE = 1,
425     $                  CONV_STATE = 2, NOPROG_STATE = 3 )
426      PARAMETER         ( BASE_RESIDUAL = 0, EXTRA_RESIDUAL = 1,
427     $                  EXTRA_Y = 2 )
428      INTEGER            FINAL_NRM_ERR_I, FINAL_CMP_ERR_I, BERR_I
429      INTEGER            RCOND_I, NRM_RCOND_I, NRM_ERR_I, CMP_RCOND_I
430      INTEGER            CMP_ERR_I, PIV_GROWTH_I
431      PARAMETER          ( FINAL_NRM_ERR_I = 1, FINAL_CMP_ERR_I = 2,
432     $                   BERR_I = 3 )
433      PARAMETER          ( RCOND_I = 4, NRM_RCOND_I = 5, NRM_ERR_I = 6 )
434      PARAMETER          ( CMP_RCOND_I = 7, CMP_ERR_I = 8,
435     $                   PIV_GROWTH_I = 9 )
436      INTEGER            LA_LINRX_ITREF_I, LA_LINRX_ITHRESH_I,
437     $                   LA_LINRX_CWISE_I
438      PARAMETER          ( LA_LINRX_ITREF_I = 1,
439     $                   LA_LINRX_ITHRESH_I = 2 )
440      PARAMETER          ( LA_LINRX_CWISE_I = 3 )
441      INTEGER            LA_LINRX_TRUST_I, LA_LINRX_ERR_I,
442     $                   LA_LINRX_RCOND_I
443      PARAMETER          ( LA_LINRX_TRUST_I = 1, LA_LINRX_ERR_I = 2 )
444      PARAMETER          ( LA_LINRX_RCOND_I = 3 )
445*     ..
446*     .. External Functions ..
447      LOGICAL            LSAME
448      EXTERNAL           ILAUPLO
449      INTEGER            ILAUPLO
450*     ..
451*     .. External Subroutines ..
452      EXTERNAL          SAXPY, SCOPY, SPOTRS, SSYMV, BLAS_SSYMV_X,
453     $                  BLAS_SSYMV2_X, SLA_SYAMV, SLA_WWADDW,
454     $                  SLA_LIN_BERR
455      REAL              SLAMCH
456*     ..
457*     .. Intrinsic Functions ..
458      INTRINSIC         ABS, MAX, MIN
459*     ..
460*     .. Executable Statements ..
461*
462      IF (INFO.NE.0) RETURN
463      EPS = SLAMCH( 'Epsilon' )
464      HUGEVAL = SLAMCH( 'Overflow' )
465*     Force HUGEVAL to Inf
466      HUGEVAL = HUGEVAL * HUGEVAL
467*     Using HUGEVAL may lead to spurious underflows.
468      INCR_THRESH = REAL( N ) * EPS
469
470      IF ( LSAME ( UPLO, 'L' ) ) THEN
471         UPLO2 = ILAUPLO( 'L' )
472      ELSE
473         UPLO2 = ILAUPLO( 'U' )
474      ENDIF
475
476      DO J = 1, NRHS
477         Y_PREC_STATE = EXTRA_RESIDUAL
478         IF ( Y_PREC_STATE .EQ. EXTRA_Y ) THEN
479            DO I = 1, N
480               Y_TAIL( I ) = 0.0
481            END DO
482         END IF
483
484         DXRAT = 0.0
485         DXRATMAX = 0.0
486         DZRAT = 0.0
487         DZRATMAX = 0.0
488         FINAL_DX_X = HUGEVAL
489         FINAL_DZ_Z = HUGEVAL
490         PREVNORMDX = HUGEVAL
491         PREV_DZ_Z = HUGEVAL
492         DZ_Z = HUGEVAL
493         DX_X = HUGEVAL
494
495         X_STATE = WORKING_STATE
496         Z_STATE = UNSTABLE_STATE
497         INCR_PREC = .FALSE.
498
499         DO CNT = 1, ITHRESH
500*
501*         Compute residual RES = B_s - op(A_s) * Y,
502*             op(A) = A, A**T, or A**H depending on TRANS (and type).
503*
504            CALL SCOPY( N, B( 1, J ), 1, RES, 1 )
505            IF ( Y_PREC_STATE .EQ. BASE_RESIDUAL ) THEN
506               CALL SSYMV( UPLO, N, -1.0, A, LDA, Y(1,J), 1,
507     $              1.0, RES, 1 )
508            ELSE IF ( Y_PREC_STATE .EQ. EXTRA_RESIDUAL ) THEN
509               CALL BLAS_SSYMV_X( UPLO2, N, -1.0, A, LDA,
510     $              Y( 1, J ), 1, 1.0, RES, 1, PREC_TYPE )
511            ELSE
512               CALL BLAS_SSYMV2_X(UPLO2, N, -1.0, A, LDA,
513     $              Y(1, J), Y_TAIL, 1, 1.0, RES, 1, PREC_TYPE)
514            END IF
515
516!         XXX: RES is no longer needed.
517            CALL SCOPY( N, RES, 1, DY, 1 )
518            CALL SPOTRS( UPLO, N, 1, AF, LDAF, DY, N, INFO )
519*
520*         Calculate relative changes DX_X, DZ_Z and ratios DXRAT, DZRAT.
521*
522            NORMX = 0.0
523            NORMY = 0.0
524            NORMDX = 0.0
525            DZ_Z = 0.0
526            YMIN = HUGEVAL
527
528            DO I = 1, N
529               YK = ABS( Y( I, J ) )
530               DYK = ABS( DY( I ) )
531
532               IF ( YK .NE. 0.0 ) THEN
533                  DZ_Z = MAX( DZ_Z, DYK / YK )
534               ELSE IF ( DYK .NE. 0.0 ) THEN
535                  DZ_Z = HUGEVAL
536               END IF
537
538               YMIN = MIN( YMIN, YK )
539
540               NORMY = MAX( NORMY, YK )
541
542               IF ( COLEQU ) THEN
543                  NORMX = MAX( NORMX, YK * C( I ) )
544                  NORMDX = MAX( NORMDX, DYK * C( I ) )
545               ELSE
546                  NORMX = NORMY
547                  NORMDX = MAX( NORMDX, DYK )
548               END IF
549            END DO
550
551            IF ( NORMX .NE. 0.0 ) THEN
552               DX_X = NORMDX / NORMX
553            ELSE IF ( NORMDX .EQ. 0.0 ) THEN
554               DX_X = 0.0
555            ELSE
556               DX_X = HUGEVAL
557            END IF
558
559            DXRAT = NORMDX / PREVNORMDX
560            DZRAT = DZ_Z / PREV_DZ_Z
561*
562*         Check termination criteria.
563*
564            IF ( YMIN*RCOND .LT. INCR_THRESH*NORMY
565     $           .AND. Y_PREC_STATE .LT. EXTRA_Y )
566     $           INCR_PREC = .TRUE.
567
568            IF ( X_STATE .EQ. NOPROG_STATE .AND. DXRAT .LE. RTHRESH )
569     $           X_STATE = WORKING_STATE
570            IF ( X_STATE .EQ. WORKING_STATE ) THEN
571               IF ( DX_X .LE. EPS ) THEN
572                  X_STATE = CONV_STATE
573               ELSE IF ( DXRAT .GT. RTHRESH ) THEN
574                  IF ( Y_PREC_STATE .NE. EXTRA_Y ) THEN
575                     INCR_PREC = .TRUE.
576                  ELSE
577                     X_STATE = NOPROG_STATE
578                  END IF
579               ELSE
580                  IF ( DXRAT .GT. DXRATMAX ) DXRATMAX = DXRAT
581               END IF
582               IF ( X_STATE .GT. WORKING_STATE ) FINAL_DX_X = DX_X
583            END IF
584
585            IF ( Z_STATE .EQ. UNSTABLE_STATE .AND. DZ_Z .LE. DZ_UB )
586     $           Z_STATE = WORKING_STATE
587            IF ( Z_STATE .EQ. NOPROG_STATE .AND. DZRAT .LE. RTHRESH )
588     $           Z_STATE = WORKING_STATE
589            IF ( Z_STATE .EQ. WORKING_STATE ) THEN
590               IF ( DZ_Z .LE. EPS ) THEN
591                  Z_STATE = CONV_STATE
592               ELSE IF ( DZ_Z .GT. DZ_UB ) THEN
593                  Z_STATE = UNSTABLE_STATE
594                  DZRATMAX = 0.0
595                  FINAL_DZ_Z = HUGEVAL
596               ELSE IF ( DZRAT .GT. RTHRESH ) THEN
597                  IF ( Y_PREC_STATE .NE. EXTRA_Y ) THEN
598                     INCR_PREC = .TRUE.
599                  ELSE
600                     Z_STATE = NOPROG_STATE
601                  END IF
602               ELSE
603                  IF ( DZRAT .GT. DZRATMAX ) DZRATMAX = DZRAT
604               END IF
605               IF ( Z_STATE .GT. WORKING_STATE ) FINAL_DZ_Z = DZ_Z
606            END IF
607
608            IF ( X_STATE.NE.WORKING_STATE.AND.
609     $           ( IGNORE_CWISE.OR.Z_STATE.NE.WORKING_STATE ) )
610     $           GOTO 666
611
612            IF ( INCR_PREC ) THEN
613               INCR_PREC = .FALSE.
614               Y_PREC_STATE = Y_PREC_STATE + 1
615               DO I = 1, N
616                  Y_TAIL( I ) = 0.0
617               END DO
618            END IF
619
620            PREVNORMDX = NORMDX
621            PREV_DZ_Z = DZ_Z
622*
623*           Update soluton.
624*
625            IF (Y_PREC_STATE .LT. EXTRA_Y) THEN
626               CALL SAXPY( N, 1.0, DY, 1, Y(1,J), 1 )
627            ELSE
628               CALL SLA_WWADDW( N, Y( 1, J ), Y_TAIL, DY )
629            END IF
630
631         END DO
632*        Target of "IF (Z_STOP .AND. X_STOP)".  Sun's f77 won't EXIT.
633 666     CONTINUE
634*
635*     Set final_* when cnt hits ithresh.
636*
637         IF ( X_STATE .EQ. WORKING_STATE ) FINAL_DX_X = DX_X
638         IF ( Z_STATE .EQ. WORKING_STATE ) FINAL_DZ_Z = DZ_Z
639*
640*     Compute error bounds.
641*
642         IF ( N_NORMS .GE. 1 ) THEN
643            ERR_BNDS_NORM( J, LA_LINRX_ERR_I ) =
644     $           FINAL_DX_X / (1 - DXRATMAX)
645         END IF
646         IF ( N_NORMS .GE. 2 ) THEN
647            ERR_BNDS_COMP( J, LA_LINRX_ERR_I ) =
648     $           FINAL_DZ_Z / (1 - DZRATMAX)
649         END IF
650*
651*     Compute componentwise relative backward error from formula
652*         max(i) ( abs(R(i)) / ( abs(op(A_s))*abs(Y) + abs(B_s) )(i) )
653*     where abs(Z) is the componentwise absolute value of the matrix
654*     or vector Z.
655*
656*        Compute residual RES = B_s - op(A_s) * Y,
657*            op(A) = A, A**T, or A**H depending on TRANS (and type).
658*
659         CALL SCOPY( N, B( 1, J ), 1, RES, 1 )
660         CALL SSYMV( UPLO, N, -1.0, A, LDA, Y(1,J), 1, 1.0, RES, 1 )
661
662         DO I = 1, N
663            AYB( I ) = ABS( B( I, J ) )
664         END DO
665*
666*     Compute abs(op(A_s))*abs(Y) + abs(B_s).
667*
668         CALL SLA_SYAMV( UPLO2, N, 1.0,
669     $        A, LDA, Y(1, J), 1, 1.0, AYB, 1 )
670
671         CALL SLA_LIN_BERR( N, N, 1, RES, AYB, BERR_OUT( J ) )
672*
673*     End of loop for each RHS.
674*
675      END DO
676*
677      RETURN
678      END
679