3
4
5
6
7
8
9
10 CHARACTER TRANSA, TRANSE, TRANSW
11 INTEGER N
12
13
14 INTEGER DESCA( * ), DESCE( * ), DESCW( * )
15 DOUBLE PRECISION RESULT( 2 ), RWORK( * )
16 COMPLEX*16 A( * ), E( * ), W( * ), WORK( * )
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 INTEGER BLOCK_CYCLIC_2D, DLEN_, DTYPE_, CTXT_, M_, N_,
94 $ MB_, NB_, RSRC_, CSRC_, LLD_
95 parameter( block_cyclic_2d = 1, dlen_ = 9, dtype_ = 1,
96 $ ctxt_ = 2, m_ = 3, n_ = 4, mb_ = 5, nb_ = 6,
97 $ rsrc_ = 7, csrc_ = 8, lld_ = 9 )
98 DOUBLE PRECISION ZERO, ONE
99 parameter( zero = 0.0d+0, one = 1.0d+0 )
100 COMPLEX*16 CZERO, CONE
101 parameter( czero = ( 0.0d+0, 0.0d+0 ),
102 $ cone = ( 1.0d+0, 0.0d+0 ) )
103
104
105 CHARACTER NORMA, NORME
106 INTEGER ICOL, II, IROW, ITRNSE, ITRNSW, J, JCOL, JJ,
107 $ JROW, JVEC, LDA, LDE, LDW, MB, MYCOL, MYROW,
108 $ NB, NPCOL, NPROW, CONTXT, CA, CSRC, RA, RSRC
109 DOUBLE PRECISION ANORM, ENORM, ENRMAX, ENRMIN, ERRNRM, TEMP1,
110 $ ULP, UNFL
111 COMPLEX*16 CDUM, WTEMP
112
113
114 LOGICAL LSAME
115 DOUBLE PRECISION PDLAMCH, PZLANGE
117
118
119 EXTERNAL blacs_gridinfo, dgamn2d, dgamx2d,
infog2l,
121
122
123 INTRINSIC abs, dble, dconjg, dimag,
max,
min
124
125
126 DOUBLE PRECISION CABS1
127
128
129 cabs1( cdum ) = abs( dble( cdum ) ) + abs( dimag( cdum ) )
130
131
132
133
134
135 result( 1 ) = zero
136 result( 2 ) = zero
137 IF( n.LE.0 )
138 $ RETURN
139
140 contxt = desca( ctxt_ )
141 rsrc = desca( rsrc_ )
142 csrc = desca( csrc_ )
143 nb = desca( nb_ )
144 mb = desca( mb_ )
145 lda = desca( lld_ )
146 lde = desce( lld_ )
147 ldw = descw( lld_ )
148 CALL blacs_gridinfo( contxt, nprow, npcol, myrow, mycol )
149
150 unfl =
pdlamch( contxt,
'Safe minimum' )
151 ulp =
pdlamch( contxt,
'Precision' )
152
153 itrnse = 0
154 itrnsw = 0
155 norma = 'O'
156 norme = 'O'
157
158 IF(
lsame( transa,
'T' ) .OR.
lsame( transa,
'C' ) )
THEN
159 norma = 'I'
160 END IF
161
162 IF(
lsame( transe,
'T' ) )
THEN
163 itrnse = 1
164 norme = 'I'
165 ELSE IF(
lsame( transe,
'C' ) )
THEN
166 itrnse = 2
167 norme = 'I'
168 END IF
169
170 IF(
lsame( transw,
'C' ) )
THEN
171 itrnsw = 1
172 END IF
173
174
175
176 enrmin = one / ulp
177 enrmax = zero
178 IF( itrnse.EQ.0 ) THEN
179 DO 20 jvec = 1, n
180 temp1 = zero
181 DO 10 j = 1, n
182 CALL infog2l( j, jvec, desce, nprow, npcol, myrow, mycol,
183 $ irow, icol, ii, jj )
184 IF( ( myrow.EQ.ii ) .AND. ( mycol.EQ.jj ) ) THEN
185 temp1 =
max( temp1, cabs1( e( ( icol-1 )*lde+
186 $ irow ) ) )
187 END IF
188 10 CONTINUE
189 IF( mycol.EQ.jj ) THEN
190 CALL dgamx2d( contxt, 'Col', ' ', 1, 1, temp1, 1, ra, ca,
191 $ -1, -1, -1 )
192 enrmin =
min( enrmin, temp1 )
193 enrmax =
max( enrmax, temp1 )
194 END IF
195 20 CONTINUE
196 CALL dgamx2d( contxt, 'Row', ' ', 1, 1, enrmax, 1, ra, ca, -1,
197 $ -1, -1 )
198 CALL dgamn2d( contxt, 'Row', ' ', 1, 1, enrmin, 1, ra, ca, -1,
199 $ -1, -1 )
200 ELSE
201 DO 40 j = 1, n
202 temp1 = zero
203 DO 30 jvec = 1, n
204 CALL infog2l( j, jvec, desce, nprow, npcol, myrow, mycol,
205 $ irow, icol, ii, jj )
206 IF( ( myrow.EQ.ii ) .AND. ( mycol.EQ.jj ) ) THEN
207 temp1 =
max( temp1, cabs1( e( ( icol-1 )*lde+
208 $ irow ) ) )
209 END IF
210 30 CONTINUE
211 IF( myrow.EQ.ii ) THEN
212 CALL dgamx2d( contxt, 'Row', ' ', 1, 1, temp1, 1, ra, ca,
213 $ -1, -1, -1 )
214 enrmin =
min( enrmin, temp1 )
215 enrmax =
max( enrmax, temp1 )
216 END IF
217 40 CONTINUE
218 CALL dgamx2d( contxt, 'Row', ' ', 1, 1, enrmax, 1, ra, ca, -1,
219 $ -1, -1 )
220 CALL dgamn2d( contxt, 'Row', ' ', 1, 1, enrmin, 1, ra, ca, -1,
221 $ -1, -1 )
222 END IF
223
224
225
226 anorm =
max(
pzlange( norma, n, n, a, 1, 1, desca, rwork ), unfl )
227
228
229
230 enorm =
max(
pzlange( norme, n, n, e, 1, 1, desce, rwork ), ulp )
231
232
233
234
235
236 CALL pzlaset(
'Full', n, n, czero, czero, work, 1, 1, descw )
237
238 DO 60 jcol = 1, n
239 IF( itrnsw.EQ.0 ) THEN
240 wtemp = w( jcol )
241 ELSE
242 wtemp = dconjg( w( jcol ) )
243 END IF
244
245 IF( itrnse.EQ.0 ) THEN
246 CALL pzaxpy( n, wtemp, e, 1, jcol, desce, 1, work, 1, jcol,
247 $ descw, 1 )
248 ELSE IF( itrnse.EQ.1 ) THEN
249 CALL pzaxpy( n, wtemp, e, jcol, 1, desce, n, work, 1, jcol,
250 $ descw, 1 )
251 ELSE
252 CALL pzaxpy( n, dconjg( wtemp ), e, jcol, 1, desce, n, work,
253 $ 1, jcol, descw, 1 )
254 DO 50 jrow = 1, n
255 CALL infog2l( jrow, jcol, descw, nprow, npcol, myrow,
256 $ mycol, irow, icol, ii, jj )
257 IF( ( myrow.EQ.ii ) .AND. ( mycol.EQ.jj ) ) THEN
258 work( ( jcol-1 )*ldw+jrow )
259 $ = dconjg( work( ( jcol-1 )*ldw+jrow ) )
260 END IF
261 50 CONTINUE
262 END IF
263 60 CONTINUE
264
265 CALL pzgemm( transa, transe, n, n, n, cone, a, 1, 1, desca, e, 1,
266 $ 1, desce, -cone, work, 1, 1, descw )
267
268 errnrm =
pzlange(
'One', n, n, work, 1, 1, descw, rwork ) / enorm
269
270
271
272 IF( anorm.GT.errnrm ) THEN
273 result( 1 ) = ( errnrm / anorm ) / ulp
274 ELSE
275 IF( anorm.LT.one ) THEN
276 result( 1 ) = (
min( errnrm, anorm ) / anorm ) / ulp
277 ELSE
278 result( 1 ) =
min( errnrm / anorm, one ) / ulp
279 END IF
280 END IF
281
282
283
284 result( 2 ) =
max( abs( enrmax-one ), abs( enrmin-one ) ) /
285 $ ( dble( n )*ulp )
286
287 RETURN
288
289
290
subroutine infog2l(grindx, gcindx, desc, nprow, npcol, myrow, mycol, lrindx, lcindx, rsrc, csrc)
double precision function pdlamch(ictxt, cmach)
subroutine pzlaset(uplo, m, n, alpha, beta, a, ia, ja, desca)
double precision function pzlange(norm, m, n, a, ia, ja, desca, work)