1*> \brief \b DEBCHVXX
2*
3*  =========== DOCUMENTATION ===========
4*
5* Online html documentation available at
6*            http://www.netlib.org/lapack/explore-html/
7*
8*  Definition:
9*  ===========
10*
11*     SUBROUTINE DEBCHVXX( THRESH, PATH )
12*
13*     .. Scalar Arguments ..
14*      DOUBLE PRECISION  THRESH
15*      CHARACTER*3       PATH
16*       ..
17*
18*
19*> \par Purpose:
20*  =============
21*>
22*> \verbatim
23*>
24*>  DEBCHVXX will run D**SVXX on a series of Hilbert matrices and then
25*>  compare the error bounds returned by D**SVXX to see if the returned
26*>  answer indeed falls within those bounds.
27*>
28*>  Eight test ratios will be computed.  The tests will pass if they are .LT.
29*>  THRESH.  There are two cases that are determined by 1 / (SQRT( N ) * EPS).
30*>  If that value is .LE. to the component wise reciprocal condition number,
31*>  it uses the guaranteed case, other wise it uses the unguaranteed case.
32*>
33*>  Test ratios:
34*>     Let Xc be X_computed and Xt be X_truth.
35*>     The norm used is the infinity norm.
36*>
37*>     Let A be the guaranteed case and B be the unguaranteed case.
38*>
39*>       1. Normwise guaranteed forward error bound.
40*>       A: norm ( abs( Xc - Xt ) / norm ( Xt ) .LE. ERRBND( *, nwise_i, bnd_i ) and
41*>          ERRBND( *, nwise_i, bnd_i ) .LE. MAX(SQRT(N),10) * EPS.
42*>          If these conditions are met, the test ratio is set to be
43*>          ERRBND( *, nwise_i, bnd_i ) / MAX(SQRT(N), 10).  Otherwise it is 1/EPS.
44*>       B: For this case, CGESVXX should just return 1.  If it is less than
45*>          one, treat it the same as in 1A.  Otherwise it fails. (Set test
46*>          ratio to ERRBND( *, nwise_i, bnd_i ) * THRESH?)
47*>
48*>       2. Componentwise guaranteed forward error bound.
49*>       A: norm ( abs( Xc(j) - Xt(j) ) ) / norm (Xt(j)) .LE. ERRBND( *, cwise_i, bnd_i )
50*>          for all j .AND. ERRBND( *, cwise_i, bnd_i ) .LE. MAX(SQRT(N), 10) * EPS.
51*>          If these conditions are met, the test ratio is set to be
52*>          ERRBND( *, cwise_i, bnd_i ) / MAX(SQRT(N), 10).  Otherwise it is 1/EPS.
53*>       B: Same as normwise test ratio.
54*>
55*>       3. Backwards error.
56*>       A: The test ratio is set to BERR/EPS.
57*>       B: Same test ratio.
58*>
59*>       4. Reciprocal condition number.
60*>       A: A condition number is computed with Xt and compared with the one
61*>          returned from CGESVXX.  Let RCONDc be the RCOND returned by D**SVXX
62*>          and RCONDt be the RCOND from the truth value.  Test ratio is set to
63*>          MAX(RCONDc/RCONDt, RCONDt/RCONDc).
64*>       B: Test ratio is set to 1 / (EPS * RCONDc).
65*>
66*>       5. Reciprocal normwise condition number.
67*>       A: The test ratio is set to
68*>          MAX(ERRBND( *, nwise_i, cond_i ) / NCOND, NCOND / ERRBND( *, nwise_i, cond_i )).
69*>       B: Test ratio is set to 1 / (EPS * ERRBND( *, nwise_i, cond_i )).
70*>
71*>       6. Reciprocal componentwise condition number.
72*>       A: Test ratio is set to
73*>          MAX(ERRBND( *, cwise_i, cond_i ) / CCOND, CCOND / ERRBND( *, cwise_i, cond_i )).
74*>       B: Test ratio is set to 1 / (EPS * ERRBND( *, cwise_i, cond_i )).
75*>
76*>     .. Parameters ..
77*>     NMAX is determined by the largest number in the inverse of the hilbert
78*>     matrix.  Precision is exhausted when the largest entry in it is greater
79*>     than 2 to the power of the number of bits in the fraction of the data
80*>     type used plus one, which is 24 for single precision.
81*>     NMAX should be 6 for single and 11 for double.
82*> \endverbatim
83*
84*  Authors:
85*  ========
86*
87*> \author Univ. of Tennessee
88*> \author Univ. of California Berkeley
89*> \author Univ. of Colorado Denver
90*> \author NAG Ltd.
91*
92*> \ingroup double_lin
93*
94*  =====================================================================
95      SUBROUTINE DEBCHVXX( THRESH, PATH )
96      IMPLICIT NONE
97*     .. Scalar Arguments ..
98      DOUBLE PRECISION  THRESH
99      CHARACTER*3       PATH
100
101      INTEGER            NMAX, NPARAMS, NERRBND, NTESTS, KL, KU
102      PARAMETER          (NMAX = 10, NPARAMS = 2, NERRBND = 3,
103     $                    NTESTS = 6)
104
105*     .. Local Scalars ..
106      INTEGER            N, NRHS, INFO, I ,J, k, NFAIL, LDA,
107     $                   N_AUX_TESTS, LDAB, LDAFB
108      CHARACTER          FACT, TRANS, UPLO, EQUED
109      CHARACTER*2        C2
110      CHARACTER(3)       NGUAR, CGUAR
111      LOGICAL            printed_guide
112      DOUBLE PRECISION   NCOND, CCOND, M, NORMDIF, NORMT, RCOND,
113     $                   RNORM, RINORM, SUMR, SUMRI, EPS,
114     $                   BERR(NMAX), RPVGRW, ORCOND,
115     $                   CWISE_ERR, NWISE_ERR, CWISE_BND, NWISE_BND,
116     $                   CWISE_RCOND, NWISE_RCOND,
117     $                   CONDTHRESH, ERRTHRESH
118
119*     .. Local Arrays ..
120      DOUBLE PRECISION   TSTRAT(NTESTS), RINV(NMAX), PARAMS(NPARAMS),
121     $                   S(NMAX),R(NMAX),C(NMAX), DIFF(NMAX, NMAX),
122     $                   ERRBND_N(NMAX*3), ERRBND_C(NMAX*3),
123     $                   A(NMAX,NMAX),INVHILB(NMAX,NMAX),X(NMAX,NMAX),
124     $                   AB( (NMAX-1)+(NMAX-1)+1, NMAX ),
125     $                   ABCOPY( (NMAX-1)+(NMAX-1)+1, NMAX ),
126     $                   AFB( 2*(NMAX-1)+(NMAX-1)+1, NMAX ),
127     $                   WORK(NMAX*3*5), AF(NMAX, NMAX),B(NMAX, NMAX),
128     $                   ACOPY(NMAX, NMAX)
129      INTEGER            IPIV(NMAX), IWORK(3*NMAX)
130
131*     .. External Functions ..
132      DOUBLE PRECISION   DLAMCH
133
134*     .. External Subroutines ..
135      EXTERNAL           DLAHILB, DGESVXX, DPOSVXX, DSYSVXX,
136     $                   DGBSVXX, DLACPY, LSAMEN
137      LOGICAL            LSAMEN
138
139*     .. Intrinsic Functions ..
140      INTRINSIC          SQRT, MAX, ABS, DBLE
141
142*     .. Parameters ..
143      INTEGER            NWISE_I, CWISE_I
144      PARAMETER          (NWISE_I = 1, CWISE_I = 1)
145      INTEGER            BND_I, COND_I
146      PARAMETER          (BND_I = 2, COND_I = 3)
147
148*  Create the loop to test out the Hilbert matrices
149
150      FACT = 'E'
151      UPLO = 'U'
152      TRANS = 'N'
153      EQUED = 'N'
154      EPS = DLAMCH('Epsilon')
155      NFAIL = 0
156      N_AUX_TESTS = 0
157      LDA = NMAX
158      LDAB = (NMAX-1)+(NMAX-1)+1
159      LDAFB = 2*(NMAX-1)+(NMAX-1)+1
160      C2 = PATH( 2: 3 )
161
162*     Main loop to test the different Hilbert Matrices.
163
164      printed_guide = .false.
165
166      DO N = 1 , NMAX
167         PARAMS(1) = -1
168         PARAMS(2) = -1
169
170         KL = N-1
171         KU = N-1
172         NRHS = n
173         M = MAX(SQRT(DBLE(N)), 10.0D+0)
174
175*        Generate the Hilbert matrix, its inverse, and the
176*        right hand side, all scaled by the LCM(1,..,2N-1).
177         CALL DLAHILB(N, N, A, LDA, INVHILB, LDA, B, LDA, WORK, INFO)
178
179*        Copy A into ACOPY.
180         CALL DLACPY('ALL', N, N, A, NMAX, ACOPY, NMAX)
181
182*        Store A in band format for GB tests
183         DO J = 1, N
184            DO I = 1, KL+KU+1
185               AB( I, J ) = 0.0D+0
186            END DO
187         END DO
188         DO J = 1, N
189            DO I = MAX( 1, J-KU ), MIN( N, J+KL )
190               AB( KU+1+I-J, J ) = A( I, J )
191            END DO
192         END DO
193
194*        Copy AB into ABCOPY.
195         DO J = 1, N
196            DO I = 1, KL+KU+1
197               ABCOPY( I, J ) = 0.0D+0
198            END DO
199         END DO
200         CALL DLACPY('ALL', KL+KU+1, N, AB, LDAB, ABCOPY, LDAB)
201
202*        Call D**SVXX with default PARAMS and N_ERR_BND = 3.
203         IF ( LSAMEN( 2, C2, 'SY' ) ) THEN
204            CALL DSYSVXX(FACT, UPLO, N, NRHS, ACOPY, LDA, AF, LDA,
205     $           IPIV, EQUED, S, B, LDA, X, LDA, ORCOND,
206     $           RPVGRW, BERR, NERRBND, ERRBND_N, ERRBND_C, NPARAMS,
207     $           PARAMS, WORK, IWORK, INFO)
208         ELSE IF ( LSAMEN( 2, C2, 'PO' ) ) THEN
209            CALL DPOSVXX(FACT, UPLO, N, NRHS, ACOPY, LDA, AF, LDA,
210     $           EQUED, S, B, LDA, X, LDA, ORCOND,
211     $           RPVGRW, BERR, NERRBND, ERRBND_N, ERRBND_C, NPARAMS,
212     $           PARAMS, WORK, IWORK, INFO)
213         ELSE IF ( LSAMEN( 2, C2, 'GB' ) ) THEN
214            CALL DGBSVXX(FACT, TRANS, N, KL, KU, NRHS, ABCOPY,
215     $           LDAB, AFB, LDAFB, IPIV, EQUED, R, C, B,
216     $           LDA, X, LDA, ORCOND, RPVGRW, BERR, NERRBND,
217     $           ERRBND_N, ERRBND_C, NPARAMS, PARAMS, WORK, IWORK,
218     $           INFO)
219         ELSE
220            CALL DGESVXX(FACT, TRANS, N, NRHS, ACOPY, LDA, AF, LDA,
221     $           IPIV, EQUED, R, C, B, LDA, X, LDA, ORCOND,
222     $           RPVGRW, BERR, NERRBND, ERRBND_N, ERRBND_C, NPARAMS,
223     $           PARAMS, WORK, IWORK, INFO)
224         END IF
225
226         N_AUX_TESTS = N_AUX_TESTS + 1
227         IF (ORCOND .LT. EPS) THEN
228!        Either factorization failed or the matrix is flagged, and 1 <=
229!        INFO <= N+1. We don't decide based on rcond anymore.
230!            IF (INFO .EQ. 0 .OR. INFO .GT. N+1) THEN
231!               NFAIL = NFAIL + 1
232!               WRITE (*, FMT=8000) N, INFO, ORCOND, RCOND
233!            END IF
234         ELSE
235!        Either everything succeeded (INFO == 0) or some solution failed
236!        to converge (INFO > N+1).
237            IF (INFO .GT. 0 .AND. INFO .LE. N+1) THEN
238               NFAIL = NFAIL + 1
239               WRITE (*, FMT=8000) C2, N, INFO, ORCOND, RCOND
240            END IF
241         END IF
242
243*        Calculating the difference between D**SVXX's X and the true X.
244         DO I = 1,N
245            DO J =1,NRHS
246               DIFF(I,J) = X(I,J) - INVHILB(I,J)
247            END DO
248         END DO
249
250*        Calculating the RCOND
251         RNORM = 0.0D+0
252         RINORM = 0.0D+0
253         IF ( LSAMEN( 2, C2, 'PO' ) .OR. LSAMEN( 2, C2, 'SY' ) ) THEN
254            DO I = 1, N
255               SUMR = 0.0D+0
256               SUMRI = 0.0D+0
257               DO J = 1, N
258                  SUMR = SUMR + S(I) * ABS(A(I,J)) * S(J)
259                  SUMRI = SUMRI + ABS(INVHILB(I, J)) / (S(J) * S(I))
260
261               END DO
262               RNORM = MAX(RNORM,SUMR)
263               RINORM = MAX(RINORM,SUMRI)
264            END DO
265         ELSE IF ( LSAMEN( 2, C2, 'GE' ) .OR. LSAMEN( 2, C2, 'GB' ) )
266     $           THEN
267            DO I = 1, N
268               SUMR = 0.0D+0
269               SUMRI = 0.0D+0
270               DO J = 1, N
271                  SUMR = SUMR + R(I) * ABS(A(I,J)) * C(J)
272                  SUMRI = SUMRI + ABS(INVHILB(I, J)) / (R(J) * C(I))
273               END DO
274               RNORM = MAX(RNORM,SUMR)
275               RINORM = MAX(RINORM,SUMRI)
276            END DO
277         END IF
278
279         RNORM = RNORM / ABS(A(1, 1))
280         RCOND = 1.0D+0/(RNORM * RINORM)
281
282*        Calculating the R for normwise rcond.
283         DO I = 1, N
284            RINV(I) = 0.0D+0
285         END DO
286         DO J = 1, N
287            DO I = 1, N
288               RINV(I) = RINV(I) + ABS(A(I,J))
289            END DO
290         END DO
291
292*        Calculating the Normwise rcond.
293         RINORM = 0.0D+0
294         DO I = 1, N
295            SUMRI = 0.0D+0
296            DO J = 1, N
297               SUMRI = SUMRI + ABS(INVHILB(I,J) * RINV(J))
298            END DO
299            RINORM = MAX(RINORM, SUMRI)
300         END DO
301
302!        invhilb is the inverse *unscaled* Hilbert matrix, so scale its norm
303!        by 1/A(1,1) to make the scaling match A (the scaled Hilbert matrix)
304         NCOND = ABS(A(1,1)) / RINORM
305
306         CONDTHRESH = M * EPS
307         ERRTHRESH = M * EPS
308
309         DO K = 1, NRHS
310            NORMT = 0.0D+0
311            NORMDIF = 0.0D+0
312            CWISE_ERR = 0.0D+0
313            DO I = 1, N
314               NORMT = MAX(ABS(INVHILB(I, K)), NORMT)
315               NORMDIF = MAX(ABS(X(I,K) - INVHILB(I,K)), NORMDIF)
316               IF (INVHILB(I,K) .NE. 0.0D+0) THEN
317                  CWISE_ERR = MAX(ABS(X(I,K) - INVHILB(I,K))
318     $                            /ABS(INVHILB(I,K)), CWISE_ERR)
319               ELSE IF (X(I, K) .NE. 0.0D+0) THEN
320                  CWISE_ERR = DLAMCH('OVERFLOW')
321               END IF
322            END DO
323            IF (NORMT .NE. 0.0D+0) THEN
324               NWISE_ERR = NORMDIF / NORMT
325            ELSE IF (NORMDIF .NE. 0.0D+0) THEN
326               NWISE_ERR = DLAMCH('OVERFLOW')
327            ELSE
328               NWISE_ERR = 0.0D+0
329            ENDIF
330
331            DO I = 1, N
332               RINV(I) = 0.0D+0
333            END DO
334            DO J = 1, N
335               DO I = 1, N
336                  RINV(I) = RINV(I) + ABS(A(I, J) * INVHILB(J, K))
337               END DO
338            END DO
339            RINORM = 0.0D+0
340            DO I = 1, N
341               SUMRI = 0.0D+0
342               DO J = 1, N
343                  SUMRI = SUMRI
344     $                 + ABS(INVHILB(I, J) * RINV(J) / INVHILB(I, K))
345               END DO
346               RINORM = MAX(RINORM, SUMRI)
347            END DO
348!        invhilb is the inverse *unscaled* Hilbert matrix, so scale its norm
349!        by 1/A(1,1) to make the scaling match A (the scaled Hilbert matrix)
350            CCOND = ABS(A(1,1))/RINORM
351
352!        Forward error bound tests
353            NWISE_BND = ERRBND_N(K + (BND_I-1)*NRHS)
354            CWISE_BND = ERRBND_C(K + (BND_I-1)*NRHS)
355            NWISE_RCOND = ERRBND_N(K + (COND_I-1)*NRHS)
356            CWISE_RCOND = ERRBND_C(K + (COND_I-1)*NRHS)
357!            write (*,*) 'nwise : ', n, k, ncond, nwise_rcond,
358!     $           condthresh, ncond.ge.condthresh
359!            write (*,*) 'nwise2: ', k, nwise_bnd, nwise_err, errthresh
360            IF (NCOND .GE. CONDTHRESH) THEN
361               NGUAR = 'YES'
362               IF (NWISE_BND .GT. ERRTHRESH) THEN
363                  TSTRAT(1) = 1/(2.0D+0*EPS)
364               ELSE
365                  IF (NWISE_BND .NE. 0.0D+0) THEN
366                     TSTRAT(1) = NWISE_ERR / NWISE_BND
367                  ELSE IF (NWISE_ERR .NE. 0.0D+0) THEN
368                     TSTRAT(1) = 1/(16.0*EPS)
369                  ELSE
370                     TSTRAT(1) = 0.0D+0
371                  END IF
372                  IF (TSTRAT(1) .GT. 1.0D+0) THEN
373                     TSTRAT(1) = 1/(4.0D+0*EPS)
374                  END IF
375               END IF
376            ELSE
377               NGUAR = 'NO'
378               IF (NWISE_BND .LT. 1.0D+0) THEN
379                  TSTRAT(1) = 1/(8.0D+0*EPS)
380               ELSE
381                  TSTRAT(1) = 1.0D+0
382               END IF
383            END IF
384!            write (*,*) 'cwise : ', n, k, ccond, cwise_rcond,
385!     $           condthresh, ccond.ge.condthresh
386!            write (*,*) 'cwise2: ', k, cwise_bnd, cwise_err, errthresh
387            IF (CCOND .GE. CONDTHRESH) THEN
388               CGUAR = 'YES'
389               IF (CWISE_BND .GT. ERRTHRESH) THEN
390                  TSTRAT(2) = 1/(2.0D+0*EPS)
391               ELSE
392                  IF (CWISE_BND .NE. 0.0D+0) THEN
393                     TSTRAT(2) = CWISE_ERR / CWISE_BND
394                  ELSE IF (CWISE_ERR .NE. 0.0D+0) THEN
395                     TSTRAT(2) = 1/(16.0D+0*EPS)
396                  ELSE
397                     TSTRAT(2) = 0.0D+0
398                  END IF
399                  IF (TSTRAT(2) .GT. 1.0D+0) TSTRAT(2) = 1/(4.0D+0*EPS)
400               END IF
401            ELSE
402               CGUAR = 'NO'
403               IF (CWISE_BND .LT. 1.0D+0) THEN
404                  TSTRAT(2) = 1/(8.0D+0*EPS)
405               ELSE
406                  TSTRAT(2) = 1.0D+0
407               END IF
408            END IF
409
410!     Backwards error test
411            TSTRAT(3) = BERR(K)/EPS
412
413!     Condition number tests
414            TSTRAT(4) = RCOND / ORCOND
415            IF (RCOND .GE. CONDTHRESH .AND. TSTRAT(4) .LT. 1.0D+0)
416     $         TSTRAT(4) = 1.0D+0 / TSTRAT(4)
417
418            TSTRAT(5) = NCOND / NWISE_RCOND
419            IF (NCOND .GE. CONDTHRESH .AND. TSTRAT(5) .LT. 1.0D+0)
420     $         TSTRAT(5) = 1.0D+0 / TSTRAT(5)
421
422            TSTRAT(6) = CCOND / NWISE_RCOND
423            IF (CCOND .GE. CONDTHRESH .AND. TSTRAT(6) .LT. 1.0D+0)
424     $         TSTRAT(6) = 1.0D+0 / TSTRAT(6)
425
426            DO I = 1, NTESTS
427               IF (TSTRAT(I) .GT. THRESH) THEN
428                  IF (.NOT.PRINTED_GUIDE) THEN
429                     WRITE(*,*)
430                     WRITE( *, 9996) 1
431                     WRITE( *, 9995) 2
432                     WRITE( *, 9994) 3
433                     WRITE( *, 9993) 4
434                     WRITE( *, 9992) 5
435                     WRITE( *, 9991) 6
436                     WRITE( *, 9990) 7
437                     WRITE( *, 9989) 8
438                     WRITE(*,*)
439                     PRINTED_GUIDE = .TRUE.
440                  END IF
441                  WRITE( *, 9999) C2, N, K, NGUAR, CGUAR, I, TSTRAT(I)
442                  NFAIL = NFAIL + 1
443               END IF
444            END DO
445      END DO
446
447c$$$         WRITE(*,*)
448c$$$         WRITE(*,*) 'Normwise Error Bounds'
449c$$$         WRITE(*,*) 'Guaranteed error bound: ',ERRBND(NRHS,nwise_i,bnd_i)
450c$$$         WRITE(*,*) 'Reciprocal condition number: ',ERRBND(NRHS,nwise_i,cond_i)
451c$$$         WRITE(*,*) 'Raw error estimate: ',ERRBND(NRHS,nwise_i,rawbnd_i)
452c$$$         WRITE(*,*)
453c$$$         WRITE(*,*) 'Componentwise Error Bounds'
454c$$$         WRITE(*,*) 'Guaranteed error bound: ',ERRBND(NRHS,cwise_i,bnd_i)
455c$$$         WRITE(*,*) 'Reciprocal condition number: ',ERRBND(NRHS,cwise_i,cond_i)
456c$$$         WRITE(*,*) 'Raw error estimate: ',ERRBND(NRHS,cwise_i,rawbnd_i)
457c$$$         print *, 'Info: ', info
458c$$$         WRITE(*,*)
459*         WRITE(*,*) 'TSTRAT: ',TSTRAT
460
461      END DO
462
463      WRITE(*,*)
464      IF( NFAIL .GT. 0 ) THEN
465         WRITE(*,9998) C2, NFAIL, NTESTS*N+N_AUX_TESTS
466      ELSE
467         WRITE(*,9997) C2
468      END IF
469 9999 FORMAT( ' D', A2, 'SVXX: N =', I2, ', RHS = ', I2,
470     $     ', NWISE GUAR. = ', A, ', CWISE GUAR. = ', A,
471     $     ' test(',I1,') =', G12.5 )
472 9998 FORMAT( ' D', A2, 'SVXX: ', I6, ' out of ', I6,
473     $     ' tests failed to pass the threshold' )
474 9997 FORMAT( ' D', A2, 'SVXX passed the tests of error bounds' )
475*     Test ratios.
476 9996 FORMAT( 3X, I2, ': Normwise guaranteed forward error', / 5X,
477     $     'Guaranteed case: if norm ( abs( Xc - Xt )',
478     $     ' / norm ( Xt ) .LE. ERRBND( *, nwise_i, bnd_i ), then',
479     $     / 5X,
480     $     'ERRBND( *, nwise_i, bnd_i ) .LE. MAX(SQRT(N), 10) * EPS')
481 9995 FORMAT( 3X, I2, ': Componentwise guaranteed forward error' )
482 9994 FORMAT( 3X, I2, ': Backwards error' )
483 9993 FORMAT( 3X, I2, ': Reciprocal condition number' )
484 9992 FORMAT( 3X, I2, ': Reciprocal normwise condition number' )
485 9991 FORMAT( 3X, I2, ': Raw normwise error estimate' )
486 9990 FORMAT( 3X, I2, ': Reciprocal componentwise condition number' )
487 9989 FORMAT( 3X, I2, ': Raw componentwise error estimate' )
488
489 8000 FORMAT( ' D', A2, 'SVXX: N =', I2, ', INFO = ', I3,
490     $     ', ORCOND = ', G12.5, ', real RCOND = ', G12.5 )
491*
492*     End of DEBCHVXX
493*
494      END
495