4141* > with respect to the columns of
4242* > Q = [ Q1 ] .
4343* > [ Q2 ]
44- * > The columns of Q must be orthonormal.
44+ * > The Euclidean norm of X must be one and the columns of Q must be
45+ * > orthonormal. The orthogonalized vector will be zero if and only if it
46+ * > lies entirely in the range of Q.
4547* >
46- * > If the projection is zero according to Kahan's "twice is enough"
47- * > criterion, then the zero vector is returned.
48+ * > The projection is computed with at most two iterations of the
49+ * > classical Gram-Schmidt algorithm, see
50+ * > * L. Giraud, J. Langou, M. Rozložník. "On the round-off error
51+ * > analysis of the Gram-Schmidt algorithm with reorthogonalization."
52+ * > 2002. CERFACS Technical Report No. TR/PA/02/33. URL:
53+ * > https://www.cerfacs.fr/algor/reports/2002/TR_PA_02_33.pdf
4854* >
4955* >\endverbatim
5056*
@@ -167,16 +173,19 @@ SUBROUTINE ZUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
167173* =====================================================================
168174*
169175* .. Parameters ..
170- DOUBLE PRECISION ALPHASQ , REALONE, REALZERO
171- PARAMETER ( ALPHASQ = 0.01D0 , REALONE = 1.0D0 ,
176+ DOUBLE PRECISION ALPHA , REALONE, REALZERO
177+ PARAMETER ( ALPHA = 0.01D0 , REALONE = 1.0D0 ,
172178 $ REALZERO = 0.0D0 )
173179 COMPLEX * 16 NEGONE, ONE, ZERO
174180 PARAMETER ( NEGONE = (- 1.0D0 ,0.0D0 ), ONE = (1.0D0 ,0.0D0 ),
175181 $ ZERO = (0.0D0 ,0.0D0 ) )
176182* ..
177183* .. Local Scalars ..
178- INTEGER I
179- DOUBLE PRECISION NORMSQ1, NORMSQ2, SCL1, SCL2, SSQ1, SSQ2
184+ INTEGER I, IX
185+ DOUBLE PRECISION EPS, NORM, NORM_NEW, SCL, SSQ
186+ * ..
187+ * .. External Functions ..
188+ REAL DLAMCH
180189* ..
181190* .. External Subroutines ..
182191 EXTERNAL ZGEMV, ZLASSQ, XERBLA
@@ -211,17 +220,17 @@ SUBROUTINE ZUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
211220 CALL XERBLA( ' ZUNBDB6' , - INFO )
212221 RETURN
213222 END IF
223+ *
224+ EPS = DLAMCH( ' Precision' )
214225*
215226* First, project X onto the orthogonal complement of Q's column
216227* space
217228*
218- SCL1 = REALZERO
219- SSQ1 = REALONE
220- CALL ZLASSQ( M1, X1, INCX1, SCL1, SSQ1 )
221- SCL2 = REALZERO
222- SSQ2 = REALONE
223- CALL ZLASSQ( M2, X2, INCX2, SCL2, SSQ2 )
224- NORMSQ1 = SCL1** 2 * SSQ1 + SCL2** 2 * SSQ2
229+ * Christoph Conrads: In debugging mode the norm should be computed
230+ * and an assertion added comparing the norm with one. Alas, Fortran
231+ * never made it into 1989 when assert() was introduced into the C
232+ * programming language.
233+ NORM = REALONE
225234*
226235 IF ( M1 .EQ. 0 ) THEN
227236 DO I = 1 , N
@@ -239,27 +248,31 @@ SUBROUTINE ZUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
239248 CALL ZGEMV( ' N' , M2, N, NEGONE, Q2, LDQ2, WORK, 1 , ONE, X2,
240249 $ INCX2 )
241250*
242- SCL1 = REALZERO
243- SSQ1 = REALONE
244- CALL ZLASSQ( M1, X1, INCX1, SCL1, SSQ1 )
245- SCL2 = REALZERO
246- SSQ2 = REALONE
247- CALL ZLASSQ( M2, X2, INCX2, SCL2, SSQ2 )
248- NORMSQ2 = SCL1** 2 * SSQ1 + SCL2** 2 * SSQ2
251+ SCL = REALZERO
252+ SSQ = REALZERO
253+ CALL ZLASSQ( M1, X1, INCX1, SCL, SSQ )
254+ CALL ZLASSQ( M2, X2, INCX2, SCL, SSQ )
255+ NORM_NEW = SCL * SQRT (SSQ)
249256*
250257* If projection is sufficiently large in norm, then stop.
251258* If projection is zero, then stop.
252259* Otherwise, project again.
253260*
254- IF ( NORMSQ2 .GE. ALPHASQ * NORMSQ1 ) THEN
261+ IF ( NORM_NEW .GE. ALPHA * NORM ) THEN
255262 RETURN
256263 END IF
257264*
258- IF ( NORMSQ2 .EQ. ZERO ) THEN
265+ IF ( NORMSQ2 .LE. N * EPS * NORM ) THEN
266+ DO IX = 1 , 1 + (M1-1 )* INCX1, INCX1
267+ X1( IX ) = ZERO
268+ END DO
269+ DO IX = 1 , 1 + (M2-1 )* INCX2, INCX2
270+ X2( IX ) = ZERO
271+ END DO
259272 RETURN
260273 END IF
261274*
262- NORMSQ1 = NORMSQ2
275+ NORM = NORM_NEW
263276*
264277 DO I = 1 , N
265278 WORK(I) = ZERO
@@ -281,24 +294,22 @@ SUBROUTINE ZUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
281294 CALL ZGEMV( ' N' , M2, N, NEGONE, Q2, LDQ2, WORK, 1 , ONE, X2,
282295 $ INCX2 )
283296*
284- SCL1 = REALZERO
285- SSQ1 = REALONE
286- CALL ZLASSQ( M1, X1, INCX1, SCL1, SSQ1 )
287- SCL2 = REALZERO
288- SSQ2 = REALONE
289- CALL ZLASSQ( M1, X1, INCX1, SCL1, SSQ1 )
290- NORMSQ2 = SCL1** 2 * SSQ1 + SCL2** 2 * SSQ2
297+ SCL = REALZERO
298+ SSQ = REALZERO
299+ CALL ZLASSQ( M1, X1, INCX1, SCL, SSQ )
300+ CALL ZLASSQ( M2, X2, INCX2, SCL, SSQ )
301+ NORM_NEW = SCL * SQRT (SSQ)
291302*
292303* If second projection is sufficiently large in norm, then do
293304* nothing more. Alternatively, if it shrunk significantly, then
294305* truncate it to zero.
295306*
296- IF ( NORMSQ2 .LT. ALPHASQ * NORMSQ1 ) THEN
297- DO I = 1 , M1
298- X1(I ) = ZERO
307+ IF ( NORM_NEW .LT. ALPHA * NORM ) THEN
308+ DO IX = 1 , 1 + (M1 -1 ) * INCX1, INCX1
309+ X1(IX ) = ZERO
299310 END DO
300- DO I = 1 , M2
301- X2(I ) = ZERO
311+ DO IX = 1 , 1 + (M2 -1 ) * INCX2, INCX2
312+ X2(IX ) = ZERO
302313 END DO
303314 END IF
304315*
@@ -307,4 +318,3 @@ SUBROUTINE ZUNBDB6( M1, M2, N, X1, INCX1, X2, INCX2, Q1, LDQ1, Q2,
307318* End of ZUNBDB6
308319*
309320 END
310-
0 commit comments