120
121
122
123
124
125
126 CHARACTER UPLO
127 INTEGER INFO, LDA, N, NB
128
129
130 INTEGER IPIV( * )
131 REAL A( LDA, * ), WORK( N+NB+1,* )
132
133
134
135
136
137 REAL ONE, ZERO
138 parameter( one = 1.0e+0, zero = 0.0e+0 )
139
140
141 LOGICAL UPPER
142 INTEGER I, IINFO, IP, K, CUT, NNB
143 INTEGER COUNT
144 INTEGER J, U11, INVD
145
146 REAL AK, AKKP1, AKP1, D, T
147 REAL U01_I_J, U01_IP1_J
148 REAL U11_I_J, U11_IP1_J
149
150
151 LOGICAL LSAME
153
154
157
158
159 INTRINSIC max
160
161
162
163
164
165 info = 0
166 upper =
lsame( uplo,
'U' )
167 IF( .NOT.upper .AND. .NOT.
lsame( uplo,
'L' ) )
THEN
168 info = -1
169 ELSE IF( n.LT.0 ) THEN
170 info = -2
171 ELSE IF( lda.LT.max( 1, n ) ) THEN
172 info = -4
173 END IF
174
175
176
177
178 IF( info.NE.0 ) THEN
179 CALL xerbla(
'SSYTRI2X', -info )
180 RETURN
181 END IF
182 IF( n.EQ.0 )
183 $ RETURN
184
185
186
187
188 CALL ssyconv( uplo,
'C', n, a, lda, ipiv, work, iinfo )
189
190
191
192 IF( upper ) THEN
193
194
195
196 DO info = n, 1, -1
197 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
198 $ RETURN
199 END DO
200 ELSE
201
202
203
204 DO info = 1, n
205 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
206 $ RETURN
207 END DO
208 END IF
209 info = 0
210
211
212
213
214
215
216 u11 = n
217
218
219 invd = nb+2
220
221 IF( upper ) THEN
222
223
224
225 CALL strtri( uplo,
'U', n, a, lda, info )
226
227
228
229 k=1
230 DO WHILE ( k .LE. n )
231 IF( ipiv( k ).GT.0 ) THEN
232
233 work(k,invd) = one / a( k, k )
234 work(k,invd+1) = 0
235 k=k+1
236 ELSE
237
238 t = work(k+1,1)
239 ak = a( k, k ) / t
240 akp1 = a( k+1, k+1 ) / t
241 akkp1 = work(k+1,1) / t
242 d = t*( ak*akp1-one )
243 work(k,invd) = akp1 / d
244 work(k+1,invd+1) = ak / d
245 work(k,invd+1) = -akkp1 / d
246 work(k+1,invd) = -akkp1 / d
247 k=k+2
248 END IF
249 END DO
250
251
252
253
254
255 cut=n
256 DO WHILE (cut .GT. 0)
257 nnb=nb
258 IF (cut .LE. nnb) THEN
259 nnb=cut
260 ELSE
261 count = 0
262
263 DO i=cut+1-nnb,cut
264 IF (ipiv(i) .LT. 0) count=count+1
265 END DO
266
267 IF (mod(count,2) .EQ. 1) nnb=nnb+1
268 END IF
269
270 cut=cut-nnb
271
272
273
274 DO i=1,cut
275 DO j=1,nnb
276 work(i,j)=a(i,cut+j)
277 END DO
278 END DO
279
280
281
282 DO i=1,nnb
283 work(u11+i,i)=one
284 DO j=1,i-1
285 work(u11+i,j)=zero
286 END DO
287 DO j=i+1,nnb
288 work(u11+i,j)=a(cut+i,cut+j)
289 END DO
290 END DO
291
292
293
294 i=1
295 DO WHILE (i .LE. cut)
296 IF (ipiv(i) > 0) THEN
297 DO j=1,nnb
298 work(i,j)=work(i,invd)*work(i,j)
299 END DO
300 i=i+1
301 ELSE
302 DO j=1,nnb
303 u01_i_j = work(i,j)
304 u01_ip1_j = work(i+1,j)
305 work(i,j)=work(i,invd)*u01_i_j+
306 $ work(i,invd+1)*u01_ip1_j
307 work(i+1,j)=work(i+1,invd)*u01_i_j+
308 $ work(i+1,invd+1)*u01_ip1_j
309 END DO
310 i=i+2
311 END IF
312 END DO
313
314
315
316 i=1
317 DO WHILE (i .LE. nnb)
318 IF (ipiv(cut+i) > 0) THEN
319 DO j=i,nnb
320 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j)
321 END DO
322 i=i+1
323 ELSE
324 DO j=i,nnb
325 u11_i_j = work(u11+i,j)
326 u11_ip1_j = work(u11+i+1,j)
327 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j) +
328 $ work(cut+i,invd+1)*work(u11+i+1,j)
329 work(u11+i+1,j)=work(cut+i+1,invd)*u11_i_j+
330 $ work(cut+i+1,invd+1)*u11_ip1_j
331 END DO
332 i=i+2
333 END IF
334 END DO
335
336
337
338 CALL strmm(
'L',
'U',
'T',
'U',nnb, nnb,
339 $ one,a(cut+1,cut+1),lda,work(u11+1,1),n+nb+1)
340
341 DO i=1,nnb
342 DO j=i,nnb
343 a(cut+i,cut+j)=work(u11+i,j)
344 END DO
345 END DO
346
347
348
349 CALL sgemm(
'T',
'N',nnb,nnb,cut,one,a(1,cut+1),lda,
350 $ work,n+nb+1, zero, work(u11+1,1), n+nb+1)
351
352
353
354 DO i=1,nnb
355 DO j=i,nnb
356 a(cut+i,cut+j)=a(cut+i,cut+j)+work(u11+i,j)
357 END DO
358 END DO
359
360
361
362 CALL strmm(
'L',uplo,
'T',
'U',cut, nnb,
363 $ one,a,lda,work,n+nb+1)
364
365
366
367
368 DO i=1,cut
369 DO j=1,nnb
370 a(i,cut+j)=work(i,j)
371 END DO
372 END DO
373
374
375
376 END DO
377
378
379
380 i=1
381 DO WHILE ( i .LE. n )
382 IF( ipiv(i) .GT. 0 ) THEN
383 ip=ipiv(i)
384 IF (i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,ip )
385 IF (i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,i )
386 ELSE
387 ip=-ipiv(i)
388 i=i+1
389 IF ( (i-1) .LT. ip)
390 $
CALL ssyswapr( uplo, n, a, lda, i-1 ,ip )
391 IF ( (i-1) .GT. ip)
392 $
CALL ssyswapr( uplo, n, a, lda, ip ,i-1 )
393 ENDIF
394 i=i+1
395 END DO
396 ELSE
397
398
399
400
401
402 CALL strtri( uplo,
'U', n, a, lda, info )
403
404
405
406 k=n
407 DO WHILE ( k .GE. 1 )
408 IF( ipiv( k ).GT.0 ) THEN
409
410 work(k,invd) = one / a( k, k )
411 work(k,invd+1) = 0
412 k=k-1
413 ELSE
414
415 t = work(k-1,1)
416 ak = a( k-1, k-1 ) / t
417 akp1 = a( k, k ) / t
418 akkp1 = work(k-1,1) / t
419 d = t*( ak*akp1-one )
420 work(k-1,invd) = akp1 / d
421 work(k,invd) = ak / d
422 work(k,invd+1) = -akkp1 / d
423 work(k-1,invd+1) = -akkp1 / d
424 k=k-2
425 END IF
426 END DO
427
428
429
430
431
432 cut=0
433 DO WHILE (cut .LT. n)
434 nnb=nb
435 IF (cut + nnb .GT. n) THEN
436 nnb=n-cut
437 ELSE
438 count = 0
439
440 DO i=cut+1,cut+nnb
441 IF (ipiv(i) .LT. 0) count=count+1
442 END DO
443
444 IF (mod(count,2) .EQ. 1) nnb=nnb+1
445 END IF
446
447 DO i=1,n-cut-nnb
448 DO j=1,nnb
449 work(i,j)=a(cut+nnb+i,cut+j)
450 END DO
451 END DO
452
453 DO i=1,nnb
454 work(u11+i,i)=one
455 DO j=i+1,nnb
456 work(u11+i,j)=zero
457 END DO
458 DO j=1,i-1
459 work(u11+i,j)=a(cut+i,cut+j)
460 END DO
461 END DO
462
463
464
465 i=n-cut-nnb
466 DO WHILE (i .GE. 1)
467 IF (ipiv(cut+nnb+i) > 0) THEN
468 DO j=1,nnb
469 work(i,j)=work(cut+nnb+i,invd)*work(i,j)
470 END DO
471 i=i-1
472 ELSE
473 DO j=1,nnb
474 u01_i_j = work(i,j)
475 u01_ip1_j = work(i-1,j)
476 work(i,j)=work(cut+nnb+i,invd)*u01_i_j+
477 $ work(cut+nnb+i,invd+1)*u01_ip1_j
478 work(i-1,j)=work(cut+nnb+i-1,invd+1)*u01_i_j+
479 $ work(cut+nnb+i-1,invd)*u01_ip1_j
480 END DO
481 i=i-2
482 END IF
483 END DO
484
485
486
487 i=nnb
488 DO WHILE (i .GE. 1)
489 IF (ipiv(cut+i) > 0) THEN
490 DO j=1,nnb
491 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j)
492 END DO
493 i=i-1
494 ELSE
495 DO j=1,nnb
496 u11_i_j = work(u11+i,j)
497 u11_ip1_j = work(u11+i-1,j)
498 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j) +
499 $ work(cut+i,invd+1)*u11_ip1_j
500 work(u11+i-1,j)=work(cut+i-1,invd+1)*u11_i_j+
501 $ work(cut+i-1,invd)*u11_ip1_j
502 END DO
503 i=i-2
504 END IF
505 END DO
506
507
508
509 CALL strmm(
'L',uplo,
'T',
'U',nnb, nnb,
510 $ one,a(cut+1,cut+1),lda,work(u11+1,1),n+nb+1)
511
512
513 DO i=1,nnb
514 DO j=1,i
515 a(cut+i,cut+j)=work(u11+i,j)
516 END DO
517 END DO
518
519 IF ( (cut+nnb) .LT. n ) THEN
520
521
522
523 CALL sgemm(
'T',
'N',nnb,nnb,n-nnb-cut,one,a(cut+nnb+1,cut+1)
524 $ ,lda,work,n+nb+1, zero, work(u11+1,1), n+nb+1)
525
526
527
528
529 DO i=1,nnb
530 DO j=1,i
531 a(cut+i,cut+j)=a(cut+i,cut+j)+work(u11+i,j)
532 END DO
533 END DO
534
535
536
537 CALL strmm(
'L',uplo,
'T',
'U', n-nnb-cut, nnb,
538 $ one,a(cut+nnb+1,cut+nnb+1),lda,work,n+nb+1)
539
540
541
542 DO i=1,n-cut-nnb
543 DO j=1,nnb
544 a(cut+nnb+i,cut+j)=work(i,j)
545 END DO
546 END DO
547
548 ELSE
549
550
551
552 DO i=1,nnb
553 DO j=1,i
554 a(cut+i,cut+j)=work(u11+i,j)
555 END DO
556 END DO
557 END IF
558
559
560
561 cut=cut+nnb
562 END DO
563
564
565
566 i=n
567 DO WHILE ( i .GE. 1 )
568 IF( ipiv(i) .GT. 0 ) THEN
569 ip=ipiv(i)
570 IF (i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,ip )
571 IF (i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,i )
572 ELSE
573 ip=-ipiv(i)
574 IF ( i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,ip )
575 IF ( i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,i )
576 i=i-1
577 ENDIF
578 i=i-1
579 END DO
580 END IF
581
582 RETURN
583
584
585
subroutine xerbla(srname, info)
subroutine sgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
SGEMM
subroutine ssyswapr(uplo, n, a, lda, i1, i2)
SSYSWAPR applies an elementary permutation on the rows and columns of a symmetric matrix.
logical function lsame(ca, cb)
LSAME
subroutine ssyconv(uplo, way, n, a, lda, ipiv, e, info)
SSYCONV
subroutine strmm(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb)
STRMM
subroutine strtri(uplo, diag, n, a, lda, info)
STRTRI