Skip to content

Commit

Permalink
Make vector orthogonalization more reliable (Reference-LAPACK PR 930)
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-frbg authored Nov 12, 2023
1 parent d58c88c commit 3d38da2
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 113 deletions.
7 changes: 4 additions & 3 deletions lapack-netlib/SRC/clarfgp.f
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
*> \author Univ. of Colorado Denver
*> \author NAG Ltd.
*
*> \ingroup complexOTHERauxiliary
*> \ingroup larfgp
*
* =====================================================================
SUBROUTINE CLARFGP( N, ALPHA, X, INCX, TAU )
Expand All @@ -122,7 +122,7 @@ SUBROUTINE CLARFGP( N, ALPHA, X, INCX, TAU )
* ..
* .. Local Scalars ..
INTEGER J, KNT
REAL ALPHI, ALPHR, BETA, BIGNUM, SMLNUM, XNORM
REAL ALPHI, ALPHR, BETA, BIGNUM, EPS, SMLNUM, XNORM
COMPLEX SAVEALPHA
* ..
* .. External Functions ..
Expand All @@ -143,11 +143,12 @@ SUBROUTINE CLARFGP( N, ALPHA, X, INCX, TAU )
RETURN
END IF
*
EPS = SLAMCH( 'Precision' )
XNORM = SCNRM2( N-1, X, INCX )
ALPHR = REAL( ALPHA )
ALPHI = AIMAG( ALPHA )
*
IF( XNORM.EQ.ZERO ) THEN
IF( XNORM.LE.EPS*ABS(ALPHA) ) THEN
*
* H = [1-alpha/abs(alpha) 0; 0 I], sign chosen so ALPHA >= 0.
*
Expand Down
50 changes: 35 additions & 15 deletions lapack-netlib/SRC/cunbdb5.f
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
*> \author Univ. of Colorado Denver
*> \author NAG Ltd.
*
*> \ingroup complexOTHERcomputational
*> \ingroup unbdb5
*
* =====================================================================
SUBROUTINE CUNBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
Expand All @@ -169,18 +169,21 @@ SUBROUTINE CUNBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
* =====================================================================
*
* .. Parameters ..
REAL REALZERO
PARAMETER ( REALZERO = 0.0E0 )
COMPLEX ONE, ZERO
PARAMETER ( ONE = (1.0E0,0.0E0), ZERO = (0.0E0,0.0E0) )
* ..
* .. Local Scalars ..
INTEGER CHILDINFO, I, J
REAL EPS, NORM, SCL, SSQ
* ..
* .. External Subroutines ..
EXTERNAL CUNBDB6, XERBLA
EXTERNAL CLASSQ, CUNBDB6, CSCAL, XERBLA
* ..
* .. External Functions ..
REAL SCNRM2
EXTERNAL SCNRM2
REAL SLAMCH, SCNRM2
EXTERNAL SLAMCH, SCNRM2
* ..
* .. Intrinsic Function ..
INTRINSIC MAX
Expand Down Expand Up @@ -213,16 +216,33 @@ SUBROUTINE CUNBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
RETURN
END IF
*
* Project X onto the orthogonal complement of Q
EPS = SLAMCH( 'Precision' )
*
CALL CUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2, LDQ2,
$ WORK, LWORK, CHILDINFO )
* Project X onto the orthogonal complement of Q if X is nonzero
*
* If the projection is nonzero, then return
SCL = REALZERO
SSQ = REALZERO
CALL CLASSQ( M1, X1, INCX1, SCL, SSQ )
CALL CLASSQ( M2, X2, INCX2, SCL, SSQ )
NORM = SCL * SQRT( SSQ )
*
IF( SCNRM2(M1,X1,INCX1) .NE. ZERO
$ .OR. SCNRM2(M2,X2,INCX2) .NE. ZERO ) THEN
RETURN
IF( NORM .GT. N * EPS ) THEN
* Scale vector to unit norm to avoid problems in the caller code.
* Computing the reciprocal is undesirable but
* * xLASCL cannot be used because of the vector increments and
* * the round-off error has a negligible impact on
* orthogonalization.
CALL CSCAL( M1, ONE / NORM, X1, INCX1 )
CALL CSCAL( M2, ONE / NORM, X2, INCX2 )
CALL CUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
$ LDQ2, WORK, LWORK, CHILDINFO )
*
* If the projection is nonzero, then return
*
IF( SCNRM2(M1,X1,INCX1) .NE. REALZERO
$ .OR. SCNRM2(M2,X2,INCX2) .NE. REALZERO ) THEN
RETURN
END IF
END IF
*
* Project each standard basis vector e_1,...,e_M1 in turn, stopping
Expand All @@ -238,8 +258,8 @@ SUBROUTINE CUNBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
END DO
CALL CUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
$ LDQ2, WORK, LWORK, CHILDINFO )
IF( SCNRM2(M1,X1,INCX1) .NE. ZERO
$ .OR. SCNRM2(M2,X2,INCX2) .NE. ZERO ) THEN
IF( SCNRM2(M1,X1,INCX1) .NE. REALZERO
$ .OR. SCNRM2(M2,X2,INCX2) .NE. REALZERO ) THEN
RETURN
END IF
END DO
Expand All @@ -257,8 +277,8 @@ SUBROUTINE CUNBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
X2(I) = ONE
CALL CUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
$ LDQ2, WORK, LWORK, CHILDINFO )
IF( SCNRM2(M1,X1,INCX1) .NE. ZERO
$ .OR. SCNRM2(M2,X2,INCX2) .NE. ZERO ) THEN
IF( SCNRM2(M1,X1,INCX1) .NE. REALZERO
$ .OR. SCNRM2(M2,X2,INCX2) .NE. REALZERO ) THEN
RETURN
END IF
END DO
Expand Down
21 changes: 11 additions & 10 deletions lapack-netlib/SRC/cunbdb6.f
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@
*> with respect to the columns of
*> Q = [ Q1 ] .
*> [ Q2 ]
*> The Euclidean norm of X must be one and the columns of Q must be
*> orthonormal. The orthogonalized vector will be zero if and only if it
*> lies entirely in the range of Q.
*> The columns of Q must be orthonormal. The orthogonalized vector will
*> be zero if and only if it lies entirely in the range of Q.
*>
*> The projection is computed with at most two iterations of the
*> classical Gram-Schmidt algorithm, see
Expand Down Expand Up @@ -174,7 +173,7 @@ SUBROUTINE CUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
*
* .. Parameters ..
REAL ALPHA, REALONE, REALZERO
PARAMETER ( ALPHA = 0.1E0, REALONE = 1.0E0,
PARAMETER ( ALPHA = 0.83E0, REALONE = 1.0E0,
$ REALZERO = 0.0E0 )
COMPLEX NEGONE, ONE, ZERO
PARAMETER ( NEGONE = (-1.0E0,0.0E0), ONE = (1.0E0,0.0E0),
Expand Down Expand Up @@ -223,14 +222,16 @@ SUBROUTINE CUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
*
EPS = SLAMCH( 'Precision' )
*
* Compute the Euclidean norm of X
*
SCL = REALZERO
SSQ = REALZERO
CALL CLASSQ( M1, X1, INCX1, SCL, SSQ )
CALL CLASSQ( M2, X2, INCX2, SCL, SSQ )
NORM = SCL * SQRT( SSQ )
*
* First, project X onto the orthogonal complement of Q's column
* space
*
* Christoph Conrads: In debugging mode the norm should be computed
* and an assertion added comparing the norm with one. Alas, Fortran
* never made it into 1989 when assert() was introduced into the C
* programming language.
NORM = REALONE
*
IF( M1 .EQ. 0 ) THEN
DO I = 1, N
Expand Down
9 changes: 5 additions & 4 deletions lapack-netlib/SRC/dlarfgp.f
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
*> \author Univ. of Colorado Denver
*> \author NAG Ltd.
*
*> \ingroup doubleOTHERauxiliary
*> \ingroup larfgp
*
* =====================================================================
SUBROUTINE DLARFGP( N, ALPHA, X, INCX, TAU )
Expand All @@ -122,7 +122,7 @@ SUBROUTINE DLARFGP( N, ALPHA, X, INCX, TAU )
* ..
* .. Local Scalars ..
INTEGER J, KNT
DOUBLE PRECISION BETA, BIGNUM, SAVEALPHA, SMLNUM, XNORM
DOUBLE PRECISION BETA, BIGNUM, EPS, SAVEALPHA, SMLNUM, XNORM
* ..
* .. External Functions ..
DOUBLE PRECISION DLAMCH, DLAPY2, DNRM2
Expand All @@ -141,11 +141,12 @@ SUBROUTINE DLARFGP( N, ALPHA, X, INCX, TAU )
RETURN
END IF
*
EPS = DLAMCH( 'Precision' )
XNORM = DNRM2( N-1, X, INCX )
*
IF( XNORM.EQ.ZERO ) THEN
IF( XNORM.LE.EPS*ABS(ALPHA) ) THEN
*
* H = [+/-1, 0; I], sign chosen so ALPHA >= 0
* H = [+/-1, 0; I], sign chosen so ALPHA >= 0.
*
IF( ALPHA.GE.ZERO ) THEN
* When TAU.eq.ZERO, the vector is special-cased to be
Expand Down
50 changes: 35 additions & 15 deletions lapack-netlib/SRC/dorbdb5.f
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
*> \author Univ. of Colorado Denver
*> \author NAG Ltd.
*
*> \ingroup doubleOTHERcomputational
*> \ingroup unbdb5
*
* =====================================================================
SUBROUTINE DORBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
Expand All @@ -169,18 +169,21 @@ SUBROUTINE DORBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
* =====================================================================
*
* .. Parameters ..
DOUBLE PRECISION REALZERO
PARAMETER ( REALZERO = 0.0D0 )
DOUBLE PRECISION ONE, ZERO
PARAMETER ( ONE = 1.0D0, ZERO = 0.0D0 )
* ..
* .. Local Scalars ..
INTEGER CHILDINFO, I, J
DOUBLE PRECISION EPS, NORM, SCL, SSQ
* ..
* .. External Subroutines ..
EXTERNAL DORBDB6, XERBLA
EXTERNAL DLASSQ, DORBDB6, DSCAL, XERBLA
* ..
* .. External Functions ..
DOUBLE PRECISION DNRM2
EXTERNAL DNRM2
DOUBLE PRECISION DLAMCH, DNRM2
EXTERNAL DLAMCH, DNRM2
* ..
* .. Intrinsic Function ..
INTRINSIC MAX
Expand Down Expand Up @@ -213,16 +216,33 @@ SUBROUTINE DORBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
RETURN
END IF
*
* Project X onto the orthogonal complement of Q
EPS = DLAMCH( 'Precision' )
*
CALL DORBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2, LDQ2,
$ WORK, LWORK, CHILDINFO )
* Project X onto the orthogonal complement of Q if X is nonzero
*
* If the projection is nonzero, then return
SCL = REALZERO
SSQ = REALZERO
CALL DLASSQ( M1, X1, INCX1, SCL, SSQ )
CALL DLASSQ( M2, X2, INCX2, SCL, SSQ )
NORM = SCL * SQRT( SSQ )
*
IF( DNRM2(M1,X1,INCX1) .NE. ZERO
$ .OR. DNRM2(M2,X2,INCX2) .NE. ZERO ) THEN
RETURN
IF( NORM .GT. N * EPS ) THEN
* Scale vector to unit norm to avoid problems in the caller code.
* Computing the reciprocal is undesirable but
* * xLASCL cannot be used because of the vector increments and
* * the round-off error has a negligible impact on
* orthogonalization.
CALL DSCAL( M1, ONE / NORM, X1, INCX1 )
CALL DSCAL( M2, ONE / NORM, X2, INCX2 )
CALL DORBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
$ LDQ2, WORK, LWORK, CHILDINFO )
*
* If the projection is nonzero, then return
*
IF( DNRM2(M1,X1,INCX1) .NE. REALZERO
$ .OR. DNRM2(M2,X2,INCX2) .NE. REALZERO ) THEN
RETURN
END IF
END IF
*
* Project each standard basis vector e_1,...,e_M1 in turn, stopping
Expand All @@ -238,8 +258,8 @@ SUBROUTINE DORBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
END DO
CALL DORBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
$ LDQ2, WORK, LWORK, CHILDINFO )
IF( DNRM2(M1,X1,INCX1) .NE. ZERO
$ .OR. DNRM2(M2,X2,INCX2) .NE. ZERO ) THEN
IF( DNRM2(M1,X1,INCX1) .NE. REALZERO
$ .OR. DNRM2(M2,X2,INCX2) .NE. REALZERO ) THEN
RETURN
END IF
END DO
Expand All @@ -257,8 +277,8 @@ SUBROUTINE DORBDB5( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
X2(I) = ONE
CALL DORBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
$ LDQ2, WORK, LWORK, CHILDINFO )
IF( DNRM2(M1,X1,INCX1) .NE. ZERO
$ .OR. DNRM2(M2,X2,INCX2) .NE. ZERO ) THEN
IF( DNRM2(M1,X1,INCX1) .NE. REALZERO
$ .OR. DNRM2(M2,X2,INCX2) .NE. REALZERO ) THEN
RETURN
END IF
END DO
Expand Down
21 changes: 11 additions & 10 deletions lapack-netlib/SRC/dorbdb6.f
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@
*> with respect to the columns of
*> Q = [ Q1 ] .
*> [ Q2 ]
*> The Euclidean norm of X must be one and the columns of Q must be
*> orthonormal. The orthogonalized vector will be zero if and only if it
*> lies entirely in the range of Q.
*> The columns of Q must be orthonormal. The orthogonalized vector will
*> be zero if and only if it lies entirely in the range of Q.
*>
*> The projection is computed with at most two iterations of the
*> classical Gram-Schmidt algorithm, see
Expand Down Expand Up @@ -174,7 +173,7 @@ SUBROUTINE DORBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
*
* .. Parameters ..
DOUBLE PRECISION ALPHA, REALONE, REALZERO
PARAMETER ( ALPHA = 0.1D0, REALONE = 1.0D0,
PARAMETER ( ALPHA = 0.83D0, REALONE = 1.0D0,
$ REALZERO = 0.0D0 )
DOUBLE PRECISION NEGONE, ONE, ZERO
PARAMETER ( NEGONE = -1.0D0, ONE = 1.0D0, ZERO = 0.0D0 )
Expand Down Expand Up @@ -222,14 +221,16 @@ SUBROUTINE DORBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
*
EPS = DLAMCH( 'Precision' )
*
* Compute the Euclidean norm of X
*
SCL = REALZERO
SSQ = REALZERO
CALL DLASSQ( M1, X1, INCX1, SCL, SSQ )
CALL DLASSQ( M2, X2, INCX2, SCL, SSQ )
NORM = SCL * SQRT( SSQ )
*
* First, project X onto the orthogonal complement of Q's column
* space
*
* Christoph Conrads: In debugging mode the norm should be computed
* and an assertion added comparing the norm with one. Alas, Fortran
* never made it into 1989 when assert() was introduced into the C
* programming language.
NORM = REALONE
*
IF( M1 .EQ. 0 ) THEN
DO I = 1, N
Expand Down
7 changes: 4 additions & 3 deletions lapack-netlib/SRC/slarfgp.f
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
*> \author Univ. of Colorado Denver
*> \author NAG Ltd.
*
*> \ingroup realOTHERauxiliary
*> \ingroup larfgp
*
* =====================================================================
SUBROUTINE SLARFGP( N, ALPHA, X, INCX, TAU )
Expand All @@ -122,7 +122,7 @@ SUBROUTINE SLARFGP( N, ALPHA, X, INCX, TAU )
* ..
* .. Local Scalars ..
INTEGER J, KNT
REAL BETA, BIGNUM, SAVEALPHA, SMLNUM, XNORM
REAL BETA, BIGNUM, EPS, SAVEALPHA, SMLNUM, XNORM
* ..
* .. External Functions ..
REAL SLAMCH, SLAPY2, SNRM2
Expand All @@ -141,9 +141,10 @@ SUBROUTINE SLARFGP( N, ALPHA, X, INCX, TAU )
RETURN
END IF
*
EPS = SLAMCH( 'Precision' )
XNORM = SNRM2( N-1, X, INCX )
*
IF( XNORM.EQ.ZERO ) THEN
IF( XNORM.LE.EPS*ABS(ALPHA) ) THEN
*
* H = [+/-1, 0; I], sign chosen so ALPHA >= 0.
*
Expand Down
Loading

0 comments on commit 3d38da2

Please sign in to comment.