224
225
226
227
228
229
230 CHARACTER JOBZ, RANGE, UPLO
231 INTEGER IL, INFO, IU, LDZ, N, NS
232 REAL VL, VU
233
234
235 INTEGER IWORK( * )
236 REAL D( * ), E( * ), S( * ), WORK( * ),
237 $ Z( LDZ, * )
238
239
240
241
242
243 REAL ZERO, ONE, TEN, HNDRD, MEIGTH
244 parameter( zero = 0.0e0, one = 1.0e0, ten = 10.0e0,
245 $ hndrd = 100.0e0, meigth = -0.1250e0 )
246 REAL FUDGE
247 parameter( fudge = 2.0e0 )
248
249
250 CHARACTER RNGVX
251 LOGICAL ALLSV, INDSV, LOWER, SPLIT, SVEQ0, VALSV, WANTZ
252 INTEGER I, ICOLZ, IDBEG, IDEND, IDTGK, IDPTR, IEPTR,
253 $ IETGK, IIFAIL, IIWORK, ILTGK, IROWU, IROWV,
254 $ IROWZ, ISBEG, ISPLT, ITEMP, IUTGK, J, K,
255 $ NTGK, NRU, NRV, NSL
256 REAL ABSTOL, EPS, EMIN, MU, NRMU, NRMV, ORTOL, SMAX,
257 $ SMIN, SQRT2, THRESH, TOL, ULP,
258 $ VLTGK, VUTGK, ZJTJI
259
260
261 LOGICAL LSAME
262 INTEGER ISAMAX
263 REAL SDOT, SLAMCH, SNRM2
266
267
270
271
272 INTRINSIC abs, real, sign, sqrt
273
274
275
276
277
278 allsv =
lsame( range,
'A' )
279 valsv =
lsame( range,
'V' )
280 indsv =
lsame( range,
'I' )
281 wantz =
lsame( jobz,
'V' )
282 lower =
lsame( uplo,
'L' )
283
284 info = 0
285 IF( .NOT.
lsame( uplo,
'U' ) .AND. .NOT.lower )
THEN
286 info = -1
287 ELSE IF( .NOT.( wantz .OR.
lsame( jobz,
'N' ) ) )
THEN
288 info = -2
289 ELSE IF( .NOT.( allsv .OR. valsv .OR. indsv ) ) THEN
290 info = -3
291 ELSE IF( n.LT.0 ) THEN
292 info = -4
293 ELSE IF( n.GT.0 ) THEN
294 IF( valsv ) THEN
295 IF( vl.LT.zero ) THEN
296 info = -7
297 ELSE IF( vu.LE.vl ) THEN
298 info = -8
299 END IF
300 ELSE IF( indsv ) THEN
301 IF( il.LT.1 .OR. il.GT.max( 1, n ) ) THEN
302 info = -9
303 ELSE IF( iu.LT.min( n, il ) .OR. iu.GT.n ) THEN
304 info = -10
305 END IF
306 END IF
307 END IF
308 IF( info.EQ.0 ) THEN
309 IF( ldz.LT.1 .OR. ( wantz .AND. ldz.LT.n*2 ) ) info = -14
310 END IF
311
312 IF( info.NE.0 ) THEN
313 CALL xerbla(
'SBDSVDX', -info )
314 RETURN
315 END IF
316
317
318
319 ns = 0
320 IF( n.EQ.0 ) RETURN
321
322 IF( n.EQ.1 ) THEN
323 IF( allsv .OR. indsv ) THEN
324 ns = 1
325 s( 1 ) = abs( d( 1 ) )
326 ELSE
327 IF( vl.LT.abs( d( 1 ) ) .AND. vu.GE.abs( d( 1 ) ) ) THEN
328 ns = 1
329 s( 1 ) = abs( d( 1 ) )
330 END IF
331 END IF
332 IF( wantz ) THEN
333 z( 1, 1 ) = sign( one, d( 1 ) )
334 z( 2, 1 ) = one
335 END IF
336 RETURN
337 END IF
338
339 abstol = 2*
slamch(
'Safe Minimum' )
340 ulp =
slamch(
'Precision' )
342 sqrt2 = sqrt( 2.0e0 )
343 ortol = sqrt( ulp )
344
345
346
347
348
349
350 tol = max( ten, min( hndrd, eps**meigth ) )*eps
351
352
353
355 smax = abs( d( i ) )
357 smax = max( smax, abs( e( i ) ) )
358
359
360
361 smin = abs( d( 1 ) )
362 IF( smin.NE.zero ) THEN
363 mu = smin
364 DO i = 2, n
365 mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) )
366 smin = min( smin, mu )
367 IF( smin.EQ.zero ) EXIT
368 END DO
369 END IF
370 smin = smin / sqrt( real( n ) )
371 thresh = tol*smin
372
373
374
375 DO i = 1, n-1
376 IF( abs( d( i ) ).LE.thresh ) d( i ) = zero
377 IF( abs( e( i ) ).LE.thresh ) e( i ) = zero
378 END DO
379 IF( abs( d( n ) ).LE.thresh ) d( n ) = zero
380
381
382
383 idtgk = 1
384 ietgk = idtgk + n*2
385 itemp = ietgk + n*2
386 iifail = 1
387 iiwork = iifail + n*2
388
389
390
391
392
393 iltgk = 0
394 iutgk = 0
395 vltgk = zero
396 vutgk = zero
397
398 IF( allsv ) THEN
399
400
401
402
403
404
405 rngvx = 'I'
406 IF( wantz )
CALL slaset(
'F', n*2, n+1, zero, zero, z, ldz )
407 ELSE IF( valsv ) THEN
408
409
410
411
412
413 rngvx = 'V'
414 vltgk = -vu
415 vutgk = -vl
416 work( idtgk:idtgk+2*n-1 ) = zero
417 CALL scopy( n, d, 1, work( ietgk ), 2 )
418 CALL scopy( n-1, e, 1, work( ietgk+1 ), 2 )
419 CALL sstevx(
'N',
'V', n*2, work( idtgk ), work( ietgk ),
420 $ vltgk, vutgk, iltgk, iltgk, abstol, ns, s,
421 $ z, ldz, work( itemp ), iwork( iiwork ),
422 $ iwork( iifail ), info )
423 IF( ns.EQ.0 ) THEN
424 RETURN
425 ELSE
426 IF( wantz )
CALL slaset(
'F', n*2, ns, zero, zero, z,
427 $ ldz )
428 END IF
429 ELSE IF( indsv ) THEN
430
431
432
433
434
435
436
437
438 iltgk = il
439 iutgk = iu
440 rngvx = 'V'
441 work( idtgk:idtgk+2*n-1 ) = zero
442 CALL scopy( n, d, 1, work( ietgk ), 2 )
443 CALL scopy( n-1, e, 1, work( ietgk+1 ), 2 )
444 CALL sstevx(
'N',
'I', n*2, work( idtgk ), work( ietgk ),
445 $ vltgk, vltgk, iltgk, iltgk, abstol, ns, s,
446 $ z, ldz, work( itemp ), iwork( iiwork ),
447 $ iwork( iifail ), info )
448 vltgk = s( 1 ) - fudge*smax*ulp*real( n )
449 work( idtgk:idtgk+2*n-1 ) = zero
450 CALL scopy( n, d, 1, work( ietgk ), 2 )
451 CALL scopy( n-1, e, 1, work( ietgk+1 ), 2 )
452 CALL sstevx(
'N',
'I', n*2, work( idtgk ), work( ietgk ),
453 $ vutgk, vutgk, iutgk, iutgk, abstol, ns, s,
454 $ z, ldz, work( itemp ), iwork( iiwork ),
455 $ iwork( iifail ), info )
456 vutgk = s( 1 ) + fudge*smax*ulp*real( n )
457 vutgk = min( vutgk, zero )
458
459
460
461
462 IF( vltgk.EQ.vutgk ) vltgk = vltgk - tol
463
464 IF( wantz )
CALL slaset(
'F', n*2, iu-il+1, zero, zero, z,
465 $ ldz)
466 END IF
467
468
469
470
471
472
473
474
475 ns = 0
476 nru = 0
477 nrv = 0
478 idbeg = 1
479 isbeg = 1
480 irowz = 1
481 icolz = 1
482 irowu = 2
483 irowv = 1
484 split = .false.
485 sveq0 = .false.
486
487
488
489 s( 1:n ) = zero
490 work( ietgk+2*n-1 ) = zero
491 work( idtgk:idtgk+2*n-1 ) = zero
492 CALL scopy( n, d, 1, work( ietgk ), 2 )
493 CALL scopy( n-1, e, 1, work( ietgk+1 ), 2 )
494
495
496
497
498
499 DO ieptr = 2, n*2, 2
500 IF( work( ietgk+ieptr-1 ).EQ.zero ) THEN
501
502
503
504
505 isplt = idbeg
506 idend = ieptr - 1
507 DO idptr = idbeg, idend, 2
508 IF( work( ietgk+idptr-1 ).EQ.zero ) THEN
509
510
511
512
513 IF( idptr.EQ.idbeg ) THEN
514
515
516
517 sveq0 = .true.
518 IF( idbeg.EQ.idend) THEN
519 nru = 1
520 nrv = 1
521 END IF
522 ELSE IF( idptr.EQ.idend ) THEN
523
524
525
526 sveq0 = .true.
527 nru = (idend-isplt)/2 + 1
528 nrv = nru
529 IF( isplt.NE.idbeg ) THEN
530 nru = nru + 1
531 END IF
532 ELSE
533 IF( isplt.EQ.idbeg ) THEN
534
535
536
537 nru = (idptr-idbeg)/2
538 nrv = nru + 1
539 ELSE
540
541
542
543 nru = (idptr-isplt)/2 + 1
544 nrv = nru
545 END IF
546 END IF
547 ELSE IF( idptr.EQ.idend ) THEN
548
549
550
551 IF( isplt.EQ.idbeg ) THEN
552
553
554
555 nru = (idend-idbeg)/2 + 1
556 nrv = nru
557 ELSE
558
559
560
561 nrv = (idend-isplt)/2 + 1
562 nru = nrv + 1
563 END IF
564 END IF
565
566 ntgk = nru + nrv
567
568 IF( ntgk.GT.0 ) THEN
569
570
571
572
573
574
575
576 iltgk = 1
577 iutgk = ntgk / 2
578 IF( allsv .OR. vutgk.EQ.zero ) THEN
579 IF( sveq0 .OR.
580 $ smin.LT.eps .OR.
581 $ mod(ntgk,2).GT.0 ) THEN
582
583
584 iutgk = iutgk + 1
585 END IF
586 END IF
587
588
589
590
591
592 CALL sstevx( jobz, rngvx, ntgk,
593 $ work( idtgk+isplt-1 ),
594 $ work( ietgk+isplt-1 ), vltgk, vutgk,
595 $ iltgk, iutgk, abstol, nsl, s( isbeg ),
596 $ z( irowz,icolz ), ldz, work( itemp ),
597 $ iwork( iiwork ), iwork( iifail ),
598 $ info )
599 IF( info.NE.0 ) THEN
600
601 RETURN
602 END IF
603 emin = abs( maxval( s( isbeg:isbeg+nsl-1 ) ) )
604
605 IF( nsl.GT.0 .AND. wantz ) THEN
606
607
608
609
610
611
612
613
614
615 IF( nsl.GT.1 .AND.
616 $ vutgk.EQ.zero .AND.
617 $ mod(ntgk,2).EQ.0 .AND.
618 $ emin.EQ.0 .AND. .NOT.split ) THEN
619
620
621
622
623
624
625 z( irowz:irowz+ntgk-1,icolz+nsl-2 ) =
626 $ z( irowz:irowz+ntgk-1,icolz+nsl-2 ) +
627 $ z( irowz:irowz+ntgk-1,icolz+nsl-1 )
628 z( irowz:irowz+ntgk-1,icolz+nsl-1 ) =
629 $ zero
630
631
632
633
634 END IF
635
636 DO i = 0, min( nsl-1, nru-1 )
637 nrmu =
snrm2( nru, z( irowu, icolz+i ), 2 )
638 IF( nrmu.EQ.zero ) THEN
639 info = n*2 + 1
640 RETURN
641 END IF
642 CALL sscal( nru, one/nrmu,
643 $ z( irowu,icolz+i ), 2 )
644 IF( nrmu.NE.one .AND.
645 $ abs( nrmu-ortol )*sqrt2.GT.one )
646 $ THEN
647 DO j = 0, i-1
648 zjtji = -
sdot( nru, z( irowu,
649 $ icolz+j ),
650 $ 2, z( irowu, icolz+i ), 2 )
651 CALL saxpy( nru, zjtji,
652 $ z( irowu, icolz+j ), 2,
653 $ z( irowu, icolz+i ), 2 )
654 END DO
655 nrmu =
snrm2( nru, z( irowu, icolz+i ),
656 $ 2 )
657 CALL sscal( nru, one/nrmu,
658 $ z( irowu,icolz+i ), 2 )
659 END IF
660 END DO
661 DO i = 0, min( nsl-1, nrv-1 )
662 nrmv =
snrm2( nrv, z( irowv, icolz+i ), 2 )
663 IF( nrmv.EQ.zero ) THEN
664 info = n*2 + 1
665 RETURN
666 END IF
667 CALL sscal( nrv, -one/nrmv,
668 $ z( irowv,icolz+i ), 2 )
669 IF( nrmv.NE.one .AND.
670 $ abs( nrmv-ortol )*sqrt2.GT.one )
671 $ THEN
672 DO j = 0, i-1
673 zjtji = -
sdot( nrv, z( irowv,
674 $ icolz+j ),
675 $ 2, z( irowv, icolz+i ), 2 )
676 CALL saxpy( nru, zjtji,
677 $ z( irowv, icolz+j ), 2,
678 $ z( irowv, icolz+i ), 2 )
679 END DO
680 nrmv =
snrm2( nrv, z( irowv, icolz+i ),
681 $ 2 )
682 CALL sscal( nrv, one/nrmv,
683 $ z( irowv,icolz+i ), 2 )
684 END IF
685 END DO
686 IF( vutgk.EQ.zero .AND.
687 $ idptr.LT.idend .AND.
688 $ mod(ntgk,2).GT.0 ) THEN
689
690
691
692
693
694
695 split = .true.
696 z( irowz:irowz+ntgk-1,n+1 ) =
697 $ z( irowz:irowz+ntgk-1,ns+nsl )
698 z( irowz:irowz+ntgk-1,ns+nsl ) =
699 $ zero
700 END IF
701 END IF
702
703 nsl = min( nsl, nru )
704 sveq0 = .false.
705
706
707
708 DO i = 0, nsl-1
709 s( isbeg+i ) = abs( s( isbeg+i ) )
710 END DO
711
712
713
714 isbeg = isbeg + nsl
715 irowz = irowz + ntgk
716 icolz = icolz + nsl
717 irowu = irowz
718 irowv = irowz + 1
719 isplt = idptr + 1
720 ns = ns + nsl
721 nru = 0
722 nrv = 0
723 END IF
724 IF( irowz.LT.n*2 .AND. wantz ) THEN
725 z( 1:irowz-1, icolz ) = zero
726 END IF
727 END DO
728 IF( split .AND. wantz ) THEN
729
730
731
732
733 z( idbeg:idend-ntgk+1,isbeg-1 ) =
734 $ z( idbeg:idend-ntgk+1,isbeg-1 ) +
735 $ z( idbeg:idend-ntgk+1,n+1 )
736 z( idbeg:idend-ntgk+1,n+1 ) = 0
737 END IF
738 irowv = irowv - 1
739 irowu = irowu + 1
740 idbeg = ieptr + 1
741 sveq0 = .false.
742 split = .false.
743 END IF
744 END DO
745
746
747
748
749 DO i = 1, ns-1
750 k = 1
751 smin = s( 1 )
752 DO j = 2, ns + 1 - i
753 IF( s( j ).LE.smin ) THEN
754 k = j
755 smin = s( j )
756 END IF
757 END DO
758 IF( k.NE.ns+1-i ) THEN
759 s( k ) = s( ns+1-i )
760 s( ns+1-i ) = smin
761 IF( wantz )
CALL sswap( n*2, z( 1,k ), 1, z( 1,ns+1-i ),
762 $ 1 )
763 END IF
764 END DO
765
766
767
768 IF( indsv ) THEN
769 k = iu - il + 1
770 IF( k.LT.ns ) THEN
771 s( k+1:ns ) = zero
772 IF( wantz ) z( 1:n*2,k+1:ns ) = zero
773 ns = k
774 END IF
775 END IF
776
777
778
779
780 IF( wantz ) THEN
781 DO i = 1, ns
782 CALL scopy( n*2, z( 1,i ), 1, work, 1 )
783 IF( lower ) THEN
784 CALL scopy( n, work( 2 ), 2, z( n+1,i ), 1 )
785 CALL scopy( n, work( 1 ), 2, z( 1 ,i ), 1 )
786 ELSE
787 CALL scopy( n, work( 2 ), 2, z( 1 ,i ), 1 )
788 CALL scopy( n, work( 1 ), 2, z( n+1,i ), 1 )
789 END IF
790 END DO
791 END IF
792
793 RETURN
794
795
796
subroutine xerbla(srname, info)
subroutine saxpy(n, sa, sx, incx, sy, incy)
SAXPY
subroutine scopy(n, sx, incx, sy, incy)
SCOPY
real function sdot(n, sx, incx, sy, incy)
SDOT
integer function isamax(n, sx, incx)
ISAMAX
real function slamch(cmach)
SLAMCH
subroutine slaset(uplo, m, n, alpha, beta, a, lda)
SLASET initializes the off-diagonal elements and the diagonal elements of a matrix to given values.
logical function lsame(ca, cb)
LSAME
real(wp) function snrm2(n, x, incx)
SNRM2
subroutine sscal(n, sa, sx, incx)
SSCAL
subroutine sstevx(jobz, range, n, d, e, vl, vu, il, iu, abstol, m, w, z, ldz, work, iwork, ifail, info)
SSTEVX computes the eigenvalues and, optionally, the left and/or right eigenvectors for OTHER matrice...
subroutine sswap(n, sx, incx, sy, incy)
SSWAP