From 8808d9ae8794ca8e8a070645999c2865abf5ec23 Mon Sep 17 00:00:00 2001 From: Johnathan Rhyne Date: Thu, 10 Sep 2026 14:24:21 -0600 Subject: [PATCH 1/2] adding a recursiving lauum while keeping the blocked variant around. lauum is a dispatch to the varint of choice. We are defaulting to recursive, but could be blocked as well --- SRC/CMakeLists.txt | 8 +- SRC/Makefile | 8 +- SRC/clauum.f | 61 +-------- SRC/clauum_blocked.f | 220 ++++++++++++++++++++++++++++++++ SRC/clauum_recursive.f | 281 +++++++++++++++++++++++++++++++++++++++++ SRC/dlauum.f | 61 +-------- SRC/dlauum_blocked.f | 216 +++++++++++++++++++++++++++++++ SRC/dlauum_recursive.f | 281 +++++++++++++++++++++++++++++++++++++++++ SRC/slauum.f | 59 +-------- SRC/slauum_blocked.f | 216 +++++++++++++++++++++++++++++++ SRC/slauum_recursive.f | 281 +++++++++++++++++++++++++++++++++++++++++ SRC/zlauum.f | 61 +-------- SRC/zlauum_blocked.f | 220 ++++++++++++++++++++++++++++++++ SRC/zlauum_recursive.f | 281 +++++++++++++++++++++++++++++++++++++++++ 14 files changed, 2029 insertions(+), 225 deletions(-) create mode 100644 SRC/clauum_blocked.f create mode 100644 SRC/clauum_recursive.f create mode 100644 SRC/dlauum_blocked.f create mode 100644 SRC/dlauum_recursive.f create mode 100644 SRC/slauum_blocked.f create mode 100644 SRC/slauum_recursive.f create mode 100644 SRC/zlauum_blocked.f create mode 100644 SRC/zlauum_recursive.f diff --git a/SRC/CMakeLists.txt b/SRC/CMakeLists.txt index 1a1813c1d..2d2edb73c 100644 --- a/SRC/CMakeLists.txt +++ b/SRC/CMakeLists.txt @@ -113,7 +113,7 @@ set(SLASRC slarz.f slarzb.f slarzt.f slasy2.f slasyf.f slasyf_rook.f slasyf_rk.f slasyf_aa.f slatbs.f slatdf.f slatps.f slatrd.f slatrs.f slatrs3.f slatrz.f - slauu2.f slauum.f sopgtr.f sopmtr.f sorg2l.f sorg2r.f + slauu2.f slauum.f slauum_blocked.f slauum_recursive.f sopgtr.f sopmtr.f sorg2l.f sorg2r.f sorgbr.f sorghr.f sorgl2.f sorglq.f sorgql.f sorgqr.f sorgr2.f sorgrq.f sorgtr.f sorgtsqr.f sorgtsqr_row.f sorm2l.f sorm2r.f sorm22.f sormbr.f sormhr.f sorml2.f sormlq.f sormql.f sormqr.f sormr2.f @@ -225,7 +225,7 @@ set(CLASRC clarz.f clarzb.f clarzt.f clascl.f claset.f clasr.f classq.f90 claswp.f clasyf.f clasyf_rook.f clasyf_rk.f clasyf_aa.f clatbs.f clatdf.f clatps.f clatrd.f clatrs.f clatrs3.f clatrz.f - clauu2.f clauum.f cpbcon.f cpbequ.f cpbrfs.f cpbstf.f cpbsv.f + clauu2.f clauum.f clauum_blocked.f clauum_recursive.f cpbcon.f cpbequ.f cpbrfs.f cpbstf.f cpbsv.f cpbsvx.f cpbtf2.f cpbtrf.f cpbtrs.f cpocon.f cpoequ.f cporfs.f cposv.f cposvx.f cpotf2.f cpotrf2.f cpotri.f cpstrf.f cpstf2.f cppcon.f cppequ.f cpprfs.f cppsv.f cppsvx.f cpptrf.f cpptri.f cpptrs.f @@ -314,7 +314,7 @@ set(DLASRC dlarz.f dlarzb.f dlarzt.f dlaswp.f dlasy2.f dlasyf.f dlasyf_rook.f dlasyf_rk.f dlasyf_aa.f dlatbs.f dlatdf.f dlatps.f dlatrd.f dlatrs.f dlatrs3.f dlatrz.f dlauu2.f - dlauum.f dopgtr.f dopmtr.f dorg2l.f dorg2r.f + dlauum.f dlauum_blocked.f dlauum_recursive.f dopgtr.f dopmtr.f dorg2l.f dorg2r.f dorgbr.f dorghr.f dorgl2.f dorglq.f dorgql.f dorgqr.f dorgr2.f dorgrq.f dorgtr.f dorgtsqr.f dorgtsqr_row.f dorm2l.f dorm2r.f dorm22.f dormbr.f dormhr.f dorml2.f dormlq.f dormql.f dormqr.f dormr2.f @@ -426,7 +426,7 @@ set(ZLASRC zlarz.f zlarzb.f zlarzt.f zlascl.f zlaset.f zlasr.f zlassq.f90 zlaswp.f zlasyf.f zlasyf_rook.f zlasyf_rk.f zlasyf_aa.f zlatbs.f zlatdf.f zlatps.f zlatrd.f zlatrs.f zlatrs3.f zlatrz.f zlauu2.f - zlauum.f zpbcon.f zpbequ.f zpbrfs.f zpbstf.f zpbsv.f + zlauum.f zlauum_blocked.f zlauum_recursive.f zpbcon.f zpbequ.f zpbrfs.f zpbstf.f zpbsv.f zpbsvx.f zpbtf2.f zpbtrf.f zpbtrs.f zpocon.f zpoequ.f zporfs.f zposv.f zposvx.f zpotf2.f zpotrf.f zpotrf2.f zpotri.f zpotrs.f zpstrf.f zpstf2.f zppcon.f zppequ.f zpprfs.f zppsv.f zppsvx.f zpptrf.f zpptri.f zpptrs.f diff --git a/SRC/Makefile b/SRC/Makefile index 39d4a0c07..f3e0ca01e 100644 --- a/SRC/Makefile +++ b/SRC/Makefile @@ -142,7 +142,7 @@ SLASRC = \ slarz.o slarzb.o slarzt.o slaswp.o slasy2.o slasyf.o slasyf_rook.o \ slasyf_rk.o \ slatbs.o slatdf.o slatps.o slatrd.o slatrs.o slatrs3.o slatrz.o \ - slauu2.o slauum.o sopgtr.o sopmtr.o sorg2l.o sorg2r.o \ + slauu2.o slauum.o slauum_blocked.o slauum_recursive.o sopgtr.o sopmtr.o sorg2l.o sorg2r.o \ sorgbr.o sorghr.o sorgl2.o sorglq.o sorgql.o sorgqr.o sorgr2.o \ sorgrq.o sorgtr.o sorgtsqr.o sorgtsqr_row.o sorm2l.o sorm2r.o sorm22.o \ sormbr.o sormhr.o sorml2.o sormlq.o sormql.o sormqr.o sormr2.o \ @@ -254,7 +254,7 @@ CLASRC = \ clarz.o clarzb.o clarzt.o clascl.o claset.o clasr.o classq.o \ claswp.o clasyf.o clasyf_rook.o clasyf_rk.o clasyf_aa.o \ clatbs.o clatdf.o clatps.o clatrd.o clatrs.o clatrs3.o clatrz.o \ - clauu2.o clauum.o cpbcon.o cpbequ.o cpbrfs.o cpbstf.o cpbsv.o \ + clauu2.o clauum.o clauum_blocked.o clauum_recursive.o cpbcon.o cpbequ.o cpbrfs.o cpbstf.o cpbsv.o \ cpbsvx.o cpbtf2.o cpbtrf.o cpbtrs.o cpocon.o cpoequ.o cporfs.o \ cposv.o cposvx.o cpotf2.o cpotri.o cpstrf.o cpstf2.o \ cppcon.o cppequ.o cpprfs.o cppsv.o cppsvx.o cpptrf.o cpptri.o cpptrs.o \ @@ -344,7 +344,7 @@ DLASRC = \ dlarz.o dlarzb.o dlarzt.o dlaswp.o dlasy2.o \ dlasyf.o dlasyf_rook.o dlasyf_rk.o \ dlatbs.o dlatdf.o dlatps.o dlatrd.o dlatrs.o dlatrs3.o dlatrz.o dlauu2.o \ - dlauum.o dopgtr.o dopmtr.o dorg2l.o dorg2r.o \ + dlauum.o dlauum_blocked.o dlauum_recursive.o dlauum_recursive.o dopgtr.o dopmtr.o dorg2l.o dorg2r.o \ dorgbr.o dorghr.o dorgl2.o dorglq.o dorgql.o dorgqr.o dorgr2.o \ dorgrq.o dorgtr.o dorgtsqr.o dorgtsqr_row.o dorm2l.o dorm2r.o dorm22.o \ dormbr.o dormhr.o dorml2.o dormlq.o dormql.o dormqr.o dormr2.o \ @@ -459,7 +459,7 @@ ZLASRC = \ zlarz.o zlarzb.o zlarzt.o zlascl.o zlaset.o zlasr.o \ zlassq.o zlaswp.o zlasyf.o zlasyf_rook.o zlasyf_rk.o zlasyf_aa.o \ zlatbs.o zlatdf.o zlatps.o zlatrd.o zlatrs.o zlatrs3.o zlatrz.o zlauu2.o \ - zlauum.o zpbcon.o zpbequ.o zpbrfs.o zpbstf.o zpbsv.o \ + zlauum.o zlauum_blocked.o zlauum_recursive.o zpbcon.o zpbequ.o zpbrfs.o zpbstf.o zpbsv.o \ zpbsvx.o zpbtf2.o zpbtrf.o zpbtrs.o zpocon.o zpoequ.o zporfs.o \ zposv.o zposvx.o zpotf2.o zpotrf.o zpotri.o zpotrs.o zpstrf.o zpstf2.o \ zppcon.o zppequ.o zpprfs.o zppsv.o zppsvx.o zpptrf.o zpptri.o zpptrs.o \ diff --git a/SRC/clauum.f b/SRC/clauum.f index 49f4410c5..336a6f458 100644 --- a/SRC/clauum.f +++ b/SRC/clauum.f @@ -157,62 +157,13 @@ SUBROUTINE CLAUUM( UPLO, N, A, LDA, INFO ) IF( N.EQ.0 ) $ RETURN * -* Determine the block size for this environment. -* - NB = ILAENV( 1, 'CLAUUM', UPLO, N, -1, -1, -1 ) -* - IF( NB.LE.1 .OR. NB.GE.N ) THEN -* -* Use unblocked code -* - CALL CLAUU2( UPLO, N, A, LDA, INFO ) - ELSE -* -* Use blocked code -* - IF( UPPER ) THEN -* -* Compute the product U * U**H. -* - DO 10 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL CTRMM( 'Right', 'Upper', 'Conjugate transpose', - $ 'Non-unit', I-1, IB, CONE, A( I, I ), LDA, - $ A( 1, I ), LDA ) - CALL CLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL CGEMM( 'No transpose', 'Conjugate transpose', - $ I-1, IB, N-I-IB+1, CONE, A( 1, I+IB ), - $ LDA, A( I, I+IB ), LDA, CONE, A( 1, I ), - $ LDA ) - CALL CHERK( 'Upper', 'No transpose', IB, N-I-IB+1, - $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), - $ LDA ) - END IF - 10 CONTINUE - ELSE -* -* Compute the product L**H * L. -* - DO 20 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL CTRMM( 'Left', 'Lower', 'Conjugate transpose', - $ 'Non-unit', IB, I-1, CONE, A( I, I ), LDA, - $ A( I, 1 ), LDA ) - CALL CLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL CGEMM( 'Conjugate transpose', 'No transpose', - $ IB, - $ I-1, N-I-IB+1, CONE, A( I+IB, I ), LDA, - $ A( I+IB, 1 ), LDA, CONE, A( I, 1 ), LDA ) - CALL CHERK( 'Lower', 'Conjugate transpose', IB, - $ N-I-IB+1, ONE, A( I+IB, I ), LDA, ONE, - $ A( I, I ), LDA ) - END IF - 20 CONTINUE - END IF - END IF +* Here we dispatch to whatever is more efficient in a particular environment +* We are defaulting to recursive, but if you want to use the blocked variant +* Comment out the line starting with `CALL CLAUUM_RECURSIVE...` +* and uncomment the line starting with `CALL CLAUUM_BLOCKED...` * + CALL CLAUUM_RECURSIVE(UPLO, N, A, LDA, INFO) +* CALL CLAUUM_BLOCKED(UPLO, N, A, LDA, INFO) RETURN * * End of CLAUUM diff --git a/SRC/clauum_blocked.f b/SRC/clauum_blocked.f new file mode 100644 index 000000000..80f3cb85d --- /dev/null +++ b/SRC/clauum_blocked.f @@ -0,0 +1,220 @@ +*> \brief \b CLAUUM_BLOCKED computes the product UUH or LHL, where U and L are upper or lower triangular matrices (blocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download CLAUUM_BLOCKED + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE CLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* COMPLEX A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> CLAUUM_BLOCKED computes the product U * U**H or L**H * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is COMPLEX array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**H; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**H * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE CLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + COMPLEX A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + REAL ONE + PARAMETER ( ONE = 1.0E+0 ) + COMPLEX CONE + PARAMETER ( CONE = ( 1.0E+0, 0.0E+0 ) ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER I, IB, NB +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL CGEMM, CHERK, CLAUU2, CTRMM, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'CLAUUM_BLOCKED', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine the block size for this environment. +* + NB = ILAENV( 1, 'CLAUUM_BLOCKED', UPLO, N, -1, -1, -1 ) +* + IF( NB.LE.1 .OR. NB.GE.N ) THEN +* +* Use unblocked code +* + CALL CLAUU2( UPLO, N, A, LDA, INFO ) + ELSE +* +* Use blocked code +* + IF( UPPER ) THEN +* +* Compute the product U * U**H. +* + DO 10 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL CTRMM( 'Right', 'Upper', 'Conjugate transpose', + $ 'Non-unit', I-1, IB, CONE, A( I, I ), LDA, + $ A( 1, I ), LDA ) + CALL CLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL CGEMM( 'No transpose', 'Conjugate transpose', + $ I-1, IB, N-I-IB+1, CONE, A( 1, I+IB ), + $ LDA, A( I, I+IB ), LDA, CONE, A( 1, I ), + $ LDA ) + CALL CHERK( 'Upper', 'No transpose', IB, N-I-IB+1, + $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), + $ LDA ) + END IF + 10 CONTINUE + ELSE +* +* Compute the product L**H * L. +* + DO 20 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL CTRMM( 'Left', 'Lower', 'Conjugate transpose', + $ 'Non-unit', IB, I-1, CONE, A( I, I ), LDA, + $ A( I, 1 ), LDA ) + CALL CLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL CGEMM( 'Conjugate transpose', 'No transpose', + $ IB, + $ I-1, N-I-IB+1, CONE, A( I+IB, I ), LDA, + $ A( I+IB, 1 ), LDA, CONE, A( I, 1 ), LDA ) + CALL CHERK( 'Lower', 'Conjugate transpose', IB, + $ N-I-IB+1, ONE, A( I+IB, I ), LDA, ONE, + $ A( I, I ), LDA ) + END IF + 20 CONTINUE + END IF + END IF +* + RETURN +* +* End of CLAUUM_BLOCKED +* + END diff --git a/SRC/clauum_recursive.f b/SRC/clauum_recursive.f new file mode 100644 index 000000000..2e819e910 --- /dev/null +++ b/SRC/clauum_recursive.f @@ -0,0 +1,281 @@ +*> \brief \b CLAUUM_RECURSIVE computes the product UUH or LHL, where U and L are upper or lower triangular matrices (recursive algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download CLAUUM_RECURSIVE + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE CLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* COMPLEX A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> CLAUUM_RECURSIVE computes the product U * U**T or L**T * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is COMPLEX array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**T; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**T * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE CLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + COMPLEX A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + COMPLEX ONE + PARAMETER ( ONE = 1.0E+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER K, NX +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL CHERK, CTRMM, CLAUU2 +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DLAUUM_RECURSIVE', -INFO ) + RETURN + END IF +* +* Early termination criteria +* + IF( N.EQ.0 ) THEN + RETURN + END IF +* +* Base Case +* + IF( N.EQ.1 ) THEN + A(1,1) = A(1,1) * A(1,1) + RETURN + END IF +* +* Determine crossover point for when to bail to level2 +* + NX = ILAENV(3, "DLAUUM_RECURSIVE", UPLO, N, -1, -1, -1) + IF( K.LT.NX ) THEN + CALL CLAUU2(UPLO, N, A, LDA, INFO) + RETURN + END IF +* +* Beginning of executable statements for the recursive case +* + K = N/2 + IF( UPPER ) THEN +* +* We are computing A = ut(U*U**H). +* +* Break apart U as follows +* |-----------------| +* U = | U_{11} U_{12} | +* | 0 U_{22} | +* |-----------------| +* +* Where +* U_{11}\in\R^{k\times k} U_{12}\in\R^{ k\times n-k} +* U_{22}\in\R^{n-k\times n-k} +* +* and U_{11},U_{22} are upper triangular and U_{12} is rectangular +* +* This gives us our operations as +* |--------------------| |------------------------| +* ut(U * U**H) = | U_{11} U_{12} | | U_{11}**H 0 | +* | 0 U_{22} | | U_{12}**H U_{22}**H | +* |--------------------| |------------------------| +* +* Thus we get +* +* U_{11} = U_{11}U_{11}**H + U_{12}U_{12}**H +* U_{12} = U_{12}U_{22}**H +* +* U_{22} = U_{22}U_{22}**H +* +* We break these operations apart as follows +* +* U_{11} = U_{11}U_{11}**H (This subroutine) +* U_{11} = U_{12}U_{12}**H + U_{11} (SYRK) +* +* U_{12} = U_{12}U_{22}**H (TRMM) +* +* U_{22} = U_{22}U_{22}**H (This subroutine) +* +* +* Compute U_{11} +* + CALL CLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL CHERK('Upper', 'No Transpose', K, N-K, + $ ONE, A(1,K+1), LDA, ONE, A, LDA) +* +* Compute U_{12} +* + CALL CTRMM('Right', 'Upper', 'Conjugate', 'Non-unit', + $ K, N-K, ONE, A(K+1,K+1), LDA, A(1,K+1), LDA) +* +* Compute U_{22} +* + CALL CLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + ELSE +* +* We are computing A = lt(L**H*L). +* +* Break apart L as follows +* |-----------------| +* L = | L_{11} 0 | +* | L_{21} L_{22} | +* |-----------------| +* +* Where +* L_{11}\in\R^{ k\times k} +* L_{21}\in\R^{n-k\times k} l_{22}\in\R^{n-k\times n-k} +* +* and L_{11},L_{22} are lower triangular and L_{21} is rectangular +* +* This gives us our operations as +* |--------------------------| |-----------------| +* lt(L**H * L) = | L_{11}**H L_{21}**H | | L_{11} 0 | +* | 0 L_{22}**H | | L_{21} L_{22} | +* |--------------------------| |-----------------| +* +* Thus we get +* +* L_{11} = L_{11}**H L_{11} + L_{21}**H L_{21} +* L_{21} = L_{22}**H L_{21} +* +* L_{22} = L_{22}**H L_{22} +* +* We break these operations apart as follows +* +* L_{11} = L_{11}**H L_{11} (This subroutine) +* L_{11} = L_{21}**H L_{21} + L_{11} (SYRK) +* +* L_{21} = L_{22}**H L_{21} (TRMM) +* +* L_{22} = L_{22}**H L_{22} (This subroutine) +* +* +* Compute L_{11} +* + CALL CLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL CHERK('Lower', 'Conjugate', K, N-K, + $ ONE, A(K+1,1), LDA, ONE, A, LDA) +* +* Compute L_{21} +* + CALL CTRMM('Left', 'Lower', 'Conjugate', 'Non-Unit', + $ N-K, K, ONE, A(K+1,K+1), LDA, A(K+1,1), LDA) +* +* Compute L_{22} +* + CALL CLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + END IF + END SUBROUTINE diff --git a/SRC/dlauum.f b/SRC/dlauum.f index 2321f238f..014358d8f 100644 --- a/SRC/dlauum.f +++ b/SRC/dlauum.f @@ -127,7 +127,7 @@ SUBROUTINE DLAUUM( UPLO, N, A, LDA, INFO ) EXTERNAL LSAME, ILAENV * .. * .. External Subroutines .. - EXTERNAL DGEMM, DLAUU2, DSYRK, DTRMM, XERBLA + EXTERNAL DLAUUM_BLOCKED, DLAUUM_RECURSIVE * .. * .. Intrinsic Functions .. INTRINSIC MAX, MIN @@ -155,60 +155,13 @@ SUBROUTINE DLAUUM( UPLO, N, A, LDA, INFO ) IF( N.EQ.0 ) $ RETURN * -* Determine the block size for this environment. -* - NB = ILAENV( 1, 'DLAUUM', UPLO, N, -1, -1, -1 ) -* - IF( NB.LE.1 .OR. NB.GE.N ) THEN -* -* Use unblocked code -* - CALL DLAUU2( UPLO, N, A, LDA, INFO ) - ELSE -* -* Use blocked code -* - IF( UPPER ) THEN -* -* Compute the product U * U**T. -* - DO 10 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL DTRMM( 'Right', 'Upper', 'Transpose', 'Non-unit', - $ I-1, IB, ONE, A( I, I ), LDA, A( 1, I ), - $ LDA ) - CALL DLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL DGEMM( 'No transpose', 'Transpose', I-1, IB, - $ N-I-IB+1, ONE, A( 1, I+IB ), LDA, - $ A( I, I+IB ), LDA, ONE, A( 1, I ), LDA ) - CALL DSYRK( 'Upper', 'No transpose', IB, N-I-IB+1, - $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), - $ LDA ) - END IF - 10 CONTINUE - ELSE -* -* Compute the product L**T * L. -* - DO 20 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL DTRMM( 'Left', 'Lower', 'Transpose', 'Non-unit', - $ IB, - $ I-1, ONE, A( I, I ), LDA, A( I, 1 ), LDA ) - CALL DLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL DGEMM( 'Transpose', 'No transpose', IB, I-1, - $ N-I-IB+1, ONE, A( I+IB, I ), LDA, - $ A( I+IB, 1 ), LDA, ONE, A( I, 1 ), LDA ) - CALL DSYRK( 'Lower', 'Transpose', IB, N-I-IB+1, - $ ONE, - $ A( I+IB, I ), LDA, ONE, A( I, I ), LDA ) - END IF - 20 CONTINUE - END IF - END IF +* Here we dispatch to whatever is more efficient in a particular environment +* We are defaulting to recursive, but if you want to use the blocked variant +* Comment out the line starting with `CALL DLAUUM_RECURSIVE...` +* and uncomment the line starting with `CALL DLAUUM_BLOCKED...` * + CALL DLAUUM_RECURSIVE(UPLO, N, A, LDA, INFO) +* CALL DLAUUM_BLOCKED(UPLO, N, A, LDA, INFO) RETURN * * End of DLAUUM diff --git a/SRC/dlauum_blocked.f b/SRC/dlauum_blocked.f new file mode 100644 index 000000000..7a97c3652 --- /dev/null +++ b/SRC/dlauum_blocked.f @@ -0,0 +1,216 @@ +*> \brief \b DLAUUM_BLOCKED computes the product UUH or LHL, where U and L are upper or lower triangular matrices (blocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download DLAUUM_BLOCKED + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE DLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DLAUUM_BLOCKED computes the product U * U**T or L**T * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**T; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**T * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE DLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER I, IB, NB +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL DGEMM, DLAUU2, DSYRK, DTRMM, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DLAUUM_BLOCKED', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine the block size for this environment. +* + NB = ILAENV( 1, 'DLAUUM_BLOCKED', UPLO, N, -1, -1, -1 ) +* + IF( NB.LE.1 .OR. NB.GE.N ) THEN +* +* Use unblocked code +* + CALL DLAUU2( UPLO, N, A, LDA, INFO ) + ELSE +* +* Use blocked code +* + IF( UPPER ) THEN +* +* Compute the product U * U**T. +* + DO 10 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL DTRMM( 'Right', 'Upper', 'Transpose', 'Non-unit', + $ I-1, IB, ONE, A( I, I ), LDA, A( 1, I ), + $ LDA ) + CALL DLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL DGEMM( 'No transpose', 'Transpose', I-1, IB, + $ N-I-IB+1, ONE, A( 1, I+IB ), LDA, + $ A( I, I+IB ), LDA, ONE, A( 1, I ), LDA ) + CALL DSYRK( 'Upper', 'No transpose', IB, N-I-IB+1, + $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), + $ LDA ) + END IF + 10 CONTINUE + ELSE +* +* Compute the product L**T * L. +* + DO 20 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL DTRMM( 'Left', 'Lower', 'Transpose', 'Non-unit', + $ IB, + $ I-1, ONE, A( I, I ), LDA, A( I, 1 ), LDA ) + CALL DLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL DGEMM( 'Transpose', 'No transpose', IB, I-1, + $ N-I-IB+1, ONE, A( I+IB, I ), LDA, + $ A( I+IB, 1 ), LDA, ONE, A( I, 1 ), LDA ) + CALL DSYRK( 'Lower', 'Transpose', IB, N-I-IB+1, + $ ONE, + $ A( I+IB, I ), LDA, ONE, A( I, I ), LDA ) + END IF + 20 CONTINUE + END IF + END IF +* + RETURN +* +* End of DLAUUM_BLOCKED +* + END diff --git a/SRC/dlauum_recursive.f b/SRC/dlauum_recursive.f new file mode 100644 index 000000000..80cca24a2 --- /dev/null +++ b/SRC/dlauum_recursive.f @@ -0,0 +1,281 @@ +*> \brief \b DLAUUM_RECURSIVE computes the product UUH or LHL, where U and L are upper or lower triangular matrices (recursive algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download DLAUUM_RECURSIVE + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE DLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DLAUUM_RECURSIVE computes the product U * U**T or L**T * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**T; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**T * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE DLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER K, NX +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL DSYRK, DTRMM, DLAUU2 +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DLAUUM_RECURSIVE', -INFO ) + RETURN + END IF +* +* Early termination criteria +* + IF( N.EQ.0 ) THEN + RETURN + END IF +* +* Base Case +* + IF( N.EQ.1 ) THEN + A(1,1) = A(1,1) * A(1,1) + RETURN + END IF +* +* Determine crossover point for when to bail to level2 +* + NX = ILAENV(3, "DLAUUM_RECURSIVE", UPLO, N, -1, -1, -1) + IF( K.LT.NX ) THEN + CALL DLAUU2(UPLO, N, A, LDA, INFO) + RETURN + END IF +* +* Beginning of executable statements for the recursive case +* + K = N/2 + IF( UPPER ) THEN +* +* We are computing A = ut(U*U**H). +* +* Break apart U as follows +* |-----------------| +* U = | U_{11} U_{12} | +* | 0 U_{22} | +* |-----------------| +* +* Where +* U_{11}\in\R^{k\times k} U_{12}\in\R^{ k\times n-k} +* U_{22}\in\R^{n-k\times n-k} +* +* and U_{11},U_{22} are upper triangular and U_{12} is rectangular +* +* This gives us our operations as +* |--------------------| |------------------------| +* ut(U * U**H) = | U_{11} U_{12} | | U_{11}**H 0 | +* | 0 U_{22} | | U_{12}**H U_{22}**H | +* |--------------------| |------------------------| +* +* Thus we get +* +* U_{11} = U_{11}U_{11}**H + U_{12}U_{12}**H +* U_{12} = U_{12}U_{22}**H +* +* U_{22} = U_{22}U_{22}**H +* +* We break these operations apart as follows +* +* U_{11} = U_{11}U_{11}**H (This subroutine) +* U_{11} = U_{12}U_{12}**H + U_{11} (SYRK) +* +* U_{12} = U_{12}U_{22}**H (TRMM) +* +* U_{22} = U_{22}U_{22}**H (This subroutine) +* +* +* Compute U_{11} +* + CALL DLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL DSYRK('Upper', 'No Transpose', K, N-K, + $ ONE, A(1,K+1), LDA, ONE, A, LDA) +* +* Compute U_{12} +* + CALL DTRMM('Right', 'Upper', 'Transpose', 'Non-unit', + $ K, N-K, ONE, A(K+1,K+1), LDA, A(1,K+1), LDA) +* +* Compute U_{22} +* + CALL DLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + ELSE +* +* We are computing A = lt(L**H*L). +* +* Break apart L as follows +* |-----------------| +* L = | L_{11} 0 | +* | L_{21} L_{22} | +* |-----------------| +* +* Where +* L_{11}\in\R^{ k\times k} +* L_{21}\in\R^{n-k\times k} l_{22}\in\R^{n-k\times n-k} +* +* and L_{11},L_{22} are lower triangular and L_{21} is rectangular +* +* This gives us our operations as +* |--------------------------| |-----------------| +* lt(L**H * L) = | L_{11}**H L_{21}**H | | L_{11} 0 | +* | 0 L_{22}**H | | L_{21} L_{22} | +* |--------------------------| |-----------------| +* +* Thus we get +* +* L_{11} = L_{11}**H L_{11} + L_{21}**H L_{21} +* L_{21} = L_{22}**H L_{21} +* +* L_{22} = L_{22}**H L_{22} +* +* We break these operations apart as follows +* +* L_{11} = L_{11}**H L_{11} (This subroutine) +* L_{11} = L_{21}**H L_{21} + L_{11} (SYRK) +* +* L_{21} = L_{22}**H L_{21} (TRMM) +* +* L_{22} = L_{22}**H L_{22} (This subroutine) +* +* +* Compute L_{11} +* + CALL DLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL DSYRK('Lower', 'Transpose', K, N-K, + $ ONE, A(K+1,1), LDA, ONE, A, LDA) +* +* Compute L_{21} +* + CALL DTRMM('Left', 'Lower', 'Transpose', 'Non-Unit', + $ N-K, K, ONE, A(K+1,K+1), LDA, A(K+1,1), LDA) +* +* Compute L_{22} +* + CALL DLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + END IF + END SUBROUTINE diff --git a/SRC/slauum.f b/SRC/slauum.f index f4e1d9df6..d92c68c3d 100644 --- a/SRC/slauum.f +++ b/SRC/slauum.f @@ -155,60 +155,13 @@ SUBROUTINE SLAUUM( UPLO, N, A, LDA, INFO ) IF( N.EQ.0 ) $ RETURN * -* Determine the block size for this environment. -* - NB = ILAENV( 1, 'SLAUUM', UPLO, N, -1, -1, -1 ) -* - IF( NB.LE.1 .OR. NB.GE.N ) THEN -* -* Use unblocked code -* - CALL SLAUU2( UPLO, N, A, LDA, INFO ) - ELSE -* -* Use blocked code -* - IF( UPPER ) THEN -* -* Compute the product U * U**T. -* - DO 10 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL STRMM( 'Right', 'Upper', 'Transpose', 'Non-unit', - $ I-1, IB, ONE, A( I, I ), LDA, A( 1, I ), - $ LDA ) - CALL SLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL SGEMM( 'No transpose', 'Transpose', I-1, IB, - $ N-I-IB+1, ONE, A( 1, I+IB ), LDA, - $ A( I, I+IB ), LDA, ONE, A( 1, I ), LDA ) - CALL SSYRK( 'Upper', 'No transpose', IB, N-I-IB+1, - $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), - $ LDA ) - END IF - 10 CONTINUE - ELSE -* -* Compute the product L**T * L. -* - DO 20 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL STRMM( 'Left', 'Lower', 'Transpose', 'Non-unit', - $ IB, - $ I-1, ONE, A( I, I ), LDA, A( I, 1 ), LDA ) - CALL SLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL SGEMM( 'Transpose', 'No transpose', IB, I-1, - $ N-I-IB+1, ONE, A( I+IB, I ), LDA, - $ A( I+IB, 1 ), LDA, ONE, A( I, 1 ), LDA ) - CALL SSYRK( 'Lower', 'Transpose', IB, N-I-IB+1, - $ ONE, - $ A( I+IB, I ), LDA, ONE, A( I, I ), LDA ) - END IF - 20 CONTINUE - END IF - END IF +* Here we dispatch to whatever is more efficient in a particular environment +* We are defaulting to recursive, but if you want to use the blocked variant +* Comment out the line starting with `CALL SLAUUM_RECURSIVE...` +* and uncomment the line starting with `CALL SLAUUM_BLOCKED...` * + CALL SLAUUM_RECURSIVE(UPLO, N, A, LDA, INFO) +* CALL SLAUUM_BLOCKED(UPLO, N, A, LDA, INFO) RETURN * * End of SLAUUM diff --git a/SRC/slauum_blocked.f b/SRC/slauum_blocked.f new file mode 100644 index 000000000..a66a3d0dd --- /dev/null +++ b/SRC/slauum_blocked.f @@ -0,0 +1,216 @@ +*> \brief \b SLAUUM_BLOCKED computes the product UUH or LHL, where U and L are upper or lower triangular matrices (blocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download SLAUUM_BLOCKED + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE SLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* REAL A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> SLAUUM_BLOCKED computes the product U * U**T or L**T * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is REAL array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**T; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**T * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE SLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + REAL A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + REAL ONE + PARAMETER ( ONE = 1.0E+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER I, IB, NB +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL SGEMM, SLAUU2, SSYRK, STRMM, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'SLAUUM_BLOCKED', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine the block size for this environment. +* + NB = ILAENV( 1, 'SLAUUM_BLOCKED', UPLO, N, -1, -1, -1 ) +* + IF( NB.LE.1 .OR. NB.GE.N ) THEN +* +* Use unblocked code +* + CALL SLAUU2( UPLO, N, A, LDA, INFO ) + ELSE +* +* Use blocked code +* + IF( UPPER ) THEN +* +* Compute the product U * U**T. +* + DO 10 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL STRMM( 'Right', 'Upper', 'Transpose', 'Non-unit', + $ I-1, IB, ONE, A( I, I ), LDA, A( 1, I ), + $ LDA ) + CALL SLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL SGEMM( 'No transpose', 'Transpose', I-1, IB, + $ N-I-IB+1, ONE, A( 1, I+IB ), LDA, + $ A( I, I+IB ), LDA, ONE, A( 1, I ), LDA ) + CALL SSYRK( 'Upper', 'No transpose', IB, N-I-IB+1, + $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), + $ LDA ) + END IF + 10 CONTINUE + ELSE +* +* Compute the product L**T * L. +* + DO 20 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL STRMM( 'Left', 'Lower', 'Transpose', 'Non-unit', + $ IB, + $ I-1, ONE, A( I, I ), LDA, A( I, 1 ), LDA ) + CALL SLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL SGEMM( 'Transpose', 'No transpose', IB, I-1, + $ N-I-IB+1, ONE, A( I+IB, I ), LDA, + $ A( I+IB, 1 ), LDA, ONE, A( I, 1 ), LDA ) + CALL SSYRK( 'Lower', 'Transpose', IB, N-I-IB+1, + $ ONE, + $ A( I+IB, I ), LDA, ONE, A( I, I ), LDA ) + END IF + 20 CONTINUE + END IF + END IF +* + RETURN +* +* End of SLAUUM_BLOCKED +* + END diff --git a/SRC/slauum_recursive.f b/SRC/slauum_recursive.f new file mode 100644 index 000000000..6ac7e218b --- /dev/null +++ b/SRC/slauum_recursive.f @@ -0,0 +1,281 @@ +*> \brief \b SLAUUM_RECURSIVE computes the product UUH or LHL, where U and L are upper or lower triangular matrices (recursive algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download SLAUUM_RECURSIVE + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE SLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* REAL A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> SLAUUM_RECURSIVE computes the product U * U**T or L**T * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is REAL array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**T; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**T * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE SLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + REAL A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + REAL ONE + PARAMETER ( ONE = 1.0E+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER K, NX +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL SSYRK, STRMM, SLAUU2 +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DLAUUM_RECURSIVE', -INFO ) + RETURN + END IF +* +* Early termination criteria +* + IF( N.EQ.0 ) THEN + RETURN + END IF +* +* Base Case +* + IF( N.EQ.1 ) THEN + A(1,1) = A(1,1) * A(1,1) + RETURN + END IF +* +* Determine crossover point for when to bail to level2 +* + NX = ILAENV(3, "DLAUUM_RECURSIVE", UPLO, N, -1, -1, -1) + IF( K.LT.NX ) THEN + CALL SLAUU2(UPLO, N, A, LDA, INFO) + RETURN + END IF +* +* Beginning of executable statements for the recursive case +* + K = N/2 + IF( UPPER ) THEN +* +* We are computing A = ut(U*U**H). +* +* Break apart U as follows +* |-----------------| +* U = | U_{11} U_{12} | +* | 0 U_{22} | +* |-----------------| +* +* Where +* U_{11}\in\R^{k\times k} U_{12}\in\R^{ k\times n-k} +* U_{22}\in\R^{n-k\times n-k} +* +* and U_{11},U_{22} are upper triangular and U_{12} is rectangular +* +* This gives us our operations as +* |--------------------| |------------------------| +* ut(U * U**H) = | U_{11} U_{12} | | U_{11}**H 0 | +* | 0 U_{22} | | U_{12}**H U_{22}**H | +* |--------------------| |------------------------| +* +* Thus we get +* +* U_{11} = U_{11}U_{11}**H + U_{12}U_{12}**H +* U_{12} = U_{12}U_{22}**H +* +* U_{22} = U_{22}U_{22}**H +* +* We break these operations apart as follows +* +* U_{11} = U_{11}U_{11}**H (This subroutine) +* U_{11} = U_{12}U_{12}**H + U_{11} (SYRK) +* +* U_{12} = U_{12}U_{22}**H (TRMM) +* +* U_{22} = U_{22}U_{22}**H (This subroutine) +* +* +* Compute U_{11} +* + CALL SLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL SSYRK('Upper', 'No Transpose', K, N-K, + $ ONE, A(1,K+1), LDA, ONE, A, LDA) +* +* Compute U_{12} +* + CALL STRMM('Right', 'Upper', 'Transpose', 'Non-unit', + $ K, N-K, ONE, A(K+1,K+1), LDA, A(1,K+1), LDA) +* +* Compute U_{22} +* + CALL SLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + ELSE +* +* We are computing A = lt(L**H*L). +* +* Break apart L as follows +* |-----------------| +* L = | L_{11} 0 | +* | L_{21} L_{22} | +* |-----------------| +* +* Where +* L_{11}\in\R^{ k\times k} +* L_{21}\in\R^{n-k\times k} l_{22}\in\R^{n-k\times n-k} +* +* and L_{11},L_{22} are lower triangular and L_{21} is rectangular +* +* This gives us our operations as +* |--------------------------| |-----------------| +* lt(L**H * L) = | L_{11}**H L_{21}**H | | L_{11} 0 | +* | 0 L_{22}**H | | L_{21} L_{22} | +* |--------------------------| |-----------------| +* +* Thus we get +* +* L_{11} = L_{11}**H L_{11} + L_{21}**H L_{21} +* L_{21} = L_{22}**H L_{21} +* +* L_{22} = L_{22}**H L_{22} +* +* We break these operations apart as follows +* +* L_{11} = L_{11}**H L_{11} (This subroutine) +* L_{11} = L_{21}**H L_{21} + L_{11} (SYRK) +* +* L_{21} = L_{22}**H L_{21} (TRMM) +* +* L_{22} = L_{22}**H L_{22} (This subroutine) +* +* +* Compute L_{11} +* + CALL SLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL SSYRK('Lower', 'Transpose', K, N-K, + $ ONE, A(K+1,1), LDA, ONE, A, LDA) +* +* Compute L_{21} +* + CALL STRMM('Left', 'Lower', 'Transpose', 'Non-Unit', + $ N-K, K, ONE, A(K+1,K+1), LDA, A(K+1,1), LDA) +* +* Compute L_{22} +* + CALL SLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + END IF + END SUBROUTINE diff --git a/SRC/zlauum.f b/SRC/zlauum.f index d7c13fc37..6eeab4ef5 100644 --- a/SRC/zlauum.f +++ b/SRC/zlauum.f @@ -157,62 +157,13 @@ SUBROUTINE ZLAUUM( UPLO, N, A, LDA, INFO ) IF( N.EQ.0 ) $ RETURN * -* Determine the block size for this environment. -* - NB = ILAENV( 1, 'ZLAUUM', UPLO, N, -1, -1, -1 ) -* - IF( NB.LE.1 .OR. NB.GE.N ) THEN -* -* Use unblocked code -* - CALL ZLAUU2( UPLO, N, A, LDA, INFO ) - ELSE -* -* Use blocked code -* - IF( UPPER ) THEN -* -* Compute the product U * U**H. -* - DO 10 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL ZTRMM( 'Right', 'Upper', 'Conjugate transpose', - $ 'Non-unit', I-1, IB, CONE, A( I, I ), LDA, - $ A( 1, I ), LDA ) - CALL ZLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL ZGEMM( 'No transpose', 'Conjugate transpose', - $ I-1, IB, N-I-IB+1, CONE, A( 1, I+IB ), - $ LDA, A( I, I+IB ), LDA, CONE, A( 1, I ), - $ LDA ) - CALL ZHERK( 'Upper', 'No transpose', IB, N-I-IB+1, - $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), - $ LDA ) - END IF - 10 CONTINUE - ELSE -* -* Compute the product L**H * L. -* - DO 20 I = 1, N, NB - IB = MIN( NB, N-I+1 ) - CALL ZTRMM( 'Left', 'Lower', 'Conjugate transpose', - $ 'Non-unit', IB, I-1, CONE, A( I, I ), LDA, - $ A( I, 1 ), LDA ) - CALL ZLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) - IF( I+IB.LE.N ) THEN - CALL ZGEMM( 'Conjugate transpose', 'No transpose', - $ IB, - $ I-1, N-I-IB+1, CONE, A( I+IB, I ), LDA, - $ A( I+IB, 1 ), LDA, CONE, A( I, 1 ), LDA ) - CALL ZHERK( 'Lower', 'Conjugate transpose', IB, - $ N-I-IB+1, ONE, A( I+IB, I ), LDA, ONE, - $ A( I, I ), LDA ) - END IF - 20 CONTINUE - END IF - END IF +* Here we dispatch to whatever is more efficient in a particular environment +* We are defaulting to recursive, but if you want to use the blocked variant +* Comment out the line starting with `CALL ZLAUUM_RECURSIVE...` +* and uncomment the line starting with `CALL ZLAUUM_BLOCKED...` * + CALL ZLAUUM_RECURSIVE(UPLO, N, A, LDA, INFO) +* CALL ZLAUUM_BLOCKED(UPLO, N, A, LDA, INFO) RETURN * * End of ZLAUUM diff --git a/SRC/zlauum_blocked.f b/SRC/zlauum_blocked.f new file mode 100644 index 000000000..28fa7cbb5 --- /dev/null +++ b/SRC/zlauum_blocked.f @@ -0,0 +1,220 @@ +*> \brief \b ZLAUUM_BLOCKED computes the product UUH or LHL, where U and L are upper or lower triangular matrices (blocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download ZLAUUM_BLOCKED + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE ZLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* COMPLEX*16 A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> ZLAUUM_BLOCKED computes the product U * U**H or L**H * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is COMPLEX*16 array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**H; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**H * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE ZLAUUM_BLOCKED( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + COMPLEX*16 A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) + COMPLEX*16 CONE + PARAMETER ( CONE = ( 1.0D+0, 0.0D+0 ) ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER I, IB, NB +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL XERBLA, ZGEMM, ZHERK, ZLAUU2, ZTRMM +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'ZLAUUM_BLOCKED', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine the block size for this environment. +* + NB = ILAENV( 1, 'ZLAUUM_BLOCKED', UPLO, N, -1, -1, -1 ) +* + IF( NB.LE.1 .OR. NB.GE.N ) THEN +* +* Use unblocked code +* + CALL ZLAUU2( UPLO, N, A, LDA, INFO ) + ELSE +* +* Use blocked code +* + IF( UPPER ) THEN +* +* Compute the product U * U**H. +* + DO 10 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL ZTRMM( 'Right', 'Upper', 'Conjugate transpose', + $ 'Non-unit', I-1, IB, CONE, A( I, I ), LDA, + $ A( 1, I ), LDA ) + CALL ZLAUU2( 'Upper', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL ZGEMM( 'No transpose', 'Conjugate transpose', + $ I-1, IB, N-I-IB+1, CONE, A( 1, I+IB ), + $ LDA, A( I, I+IB ), LDA, CONE, A( 1, I ), + $ LDA ) + CALL ZHERK( 'Upper', 'No transpose', IB, N-I-IB+1, + $ ONE, A( I, I+IB ), LDA, ONE, A( I, I ), + $ LDA ) + END IF + 10 CONTINUE + ELSE +* +* Compute the product L**H * L. +* + DO 20 I = 1, N, NB + IB = MIN( NB, N-I+1 ) + CALL ZTRMM( 'Left', 'Lower', 'Conjugate transpose', + $ 'Non-unit', IB, I-1, CONE, A( I, I ), LDA, + $ A( I, 1 ), LDA ) + CALL ZLAUU2( 'Lower', IB, A( I, I ), LDA, INFO ) + IF( I+IB.LE.N ) THEN + CALL ZGEMM( 'Conjugate transpose', 'No transpose', + $ IB, + $ I-1, N-I-IB+1, CONE, A( I+IB, I ), LDA, + $ A( I+IB, 1 ), LDA, CONE, A( I, 1 ), LDA ) + CALL ZHERK( 'Lower', 'Conjugate transpose', IB, + $ N-I-IB+1, ONE, A( I+IB, I ), LDA, ONE, + $ A( I, I ), LDA ) + END IF + 20 CONTINUE + END IF + END IF +* + RETURN +* +* End of ZLAUUM_BLOCKED +* + END diff --git a/SRC/zlauum_recursive.f b/SRC/zlauum_recursive.f new file mode 100644 index 000000000..e3d58295f --- /dev/null +++ b/SRC/zlauum_recursive.f @@ -0,0 +1,281 @@ +*> \brief \b ZLAUUM_RECURSIVE computes the product UUH or LHL, where U and L are upper or lower triangular matrices (recursive algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> Download ZLAUUM_RECURSIVE + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +* +* Definition: +* =========== +* +* SUBROUTINE ZLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* COMPLEX*16 A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> ZLAUUM_RECURSIVE computes the product U * U**T or L**T * L, where the triangular +*> factor U or L is stored in the upper or lower triangular part of +*> the array A. +*> +*> If UPLO = 'U' or 'u' then the upper triangle of the result is stored, +*> overwriting the factor U in A. +*> If UPLO = 'L' or 'l' then the lower triangle of the result is stored, +*> overwriting the factor L in A. +*> +*> This is the blocked form of the algorithm, calling Level 3 BLAS. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the triangular factor stored in the array A +*> is upper or lower triangular: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the triangular factor U or L. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is COMPLEX*16 array, dimension (LDA,N) +*> On entry, the triangular factor U or L. +*> On exit, if UPLO = 'U', the upper triangle of A is +*> overwritten with the upper triangle of the product U * U**T; +*> if UPLO = 'L', the lower triangle of A is overwritten with +*> the lower triangle of the product L**T * L. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -k, the k-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lauum +* +* ===================================================================== + SUBROUTINE ZLAUUM_RECURSIVE( UPLO, N, A, LDA, INFO ) + IMPLICIT NONE +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + COMPLEX*16 A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + COMPLEX*16 ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER K, NX +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL ZHERK, ZTRMM, ZLAUU2 +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DLAUUM_RECURSIVE', -INFO ) + RETURN + END IF +* +* Early termination criteria +* + IF( N.EQ.0 ) THEN + RETURN + END IF +* +* Base Case +* + IF( N.EQ.1 ) THEN + A(1,1) = A(1,1) * A(1,1) + RETURN + END IF +* +* Determine crossover point for when to bail to level2 +* + NX = ILAENV(3, "DLAUUM_RECURSIVE", UPLO, N, -1, -1, -1) + IF( K.LT.NX ) THEN + CALL ZLAUU2(UPLO, N, A, LDA, INFO) + RETURN + END IF +* +* Beginning of executable statements for the recursive case +* + K = N/2 + IF( UPPER ) THEN +* +* We are computing A = ut(U*U**H). +* +* Break apart U as follows +* |-----------------| +* U = | U_{11} U_{12} | +* | 0 U_{22} | +* |-----------------| +* +* Where +* U_{11}\in\R^{k\times k} U_{12}\in\R^{ k\times n-k} +* U_{22}\in\R^{n-k\times n-k} +* +* and U_{11},U_{22} are upper triangular and U_{12} is rectangular +* +* This gives us our operations as +* |--------------------| |------------------------| +* ut(U * U**H) = | U_{11} U_{12} | | U_{11}**H 0 | +* | 0 U_{22} | | U_{12}**H U_{22}**H | +* |--------------------| |------------------------| +* +* Thus we get +* +* U_{11} = U_{11}U_{11}**H + U_{12}U_{12}**H +* U_{12} = U_{12}U_{22}**H +* +* U_{22} = U_{22}U_{22}**H +* +* We break these operations apart as follows +* +* U_{11} = U_{11}U_{11}**H (This subroutine) +* U_{11} = U_{12}U_{12}**H + U_{11} (SYRK) +* +* U_{12} = U_{12}U_{22}**H (TRMM) +* +* U_{22} = U_{22}U_{22}**H (This subroutine) +* +* +* Compute U_{11} +* + CALL ZLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL ZHERK('Upper', 'No Transpose', K, N-K, + $ ONE, A(1,K+1), LDA, ONE, A, LDA) +* +* Compute U_{12} +* + CALL ZTRMM('Right', 'Upper', 'Conjugate', 'Non-unit', + $ K, N-K, ONE, A(K+1,K+1), LDA, A(1,K+1), LDA) +* +* Compute U_{22} +* + CALL ZLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + ELSE +* +* We are computing A = lt(L**H*L). +* +* Break apart L as follows +* |-----------------| +* L = | L_{11} 0 | +* | L_{21} L_{22} | +* |-----------------| +* +* Where +* L_{11}\in\R^{ k\times k} +* L_{21}\in\R^{n-k\times k} l_{22}\in\R^{n-k\times n-k} +* +* and L_{11},L_{22} are lower triangular and L_{21} is rectangular +* +* This gives us our operations as +* |--------------------------| |-----------------| +* lt(L**H * L) = | L_{11}**H L_{21}**H | | L_{11} 0 | +* | 0 L_{22}**H | | L_{21} L_{22} | +* |--------------------------| |-----------------| +* +* Thus we get +* +* L_{11} = L_{11}**H L_{11} + L_{21}**H L_{21} +* L_{21} = L_{22}**H L_{21} +* +* L_{22} = L_{22}**H L_{22} +* +* We break these operations apart as follows +* +* L_{11} = L_{11}**H L_{11} (This subroutine) +* L_{11} = L_{21}**H L_{21} + L_{11} (SYRK) +* +* L_{21} = L_{22}**H L_{21} (TRMM) +* +* L_{22} = L_{22}**H L_{22} (This subroutine) +* +* +* Compute L_{11} +* + CALL ZLAUUM_RECURSIVE(UPLO, K, A, LDA, INFO) + CALL ZHERK('Lower', 'Conjugate', K, N-K, + $ ONE, A(K+1,1), LDA, ONE, A, LDA) +* +* Compute L_{21} +* + CALL ZTRMM('Left', 'Lower', 'Conjugate', 'Non-Unit', + $ N-K, K, ONE, A(K+1,K+1), LDA, A(K+1,1), LDA) +* +* Compute L_{22} +* + CALL ZLAUUM_RECURSIVE(UPLO, N-K, A(K+1,K+1), LDA, INFO) + END IF + END SUBROUTINE From 5e9701febff9a6301bdabcf2479cc7e59cb40e05 Mon Sep 17 00:00:00 2001 From: Johnathan Rhyne Date: Thu, 10 Sep 2026 14:31:45 -0600 Subject: [PATCH 2/2] updating ILAENV to have a nx computation for lauum_recursive. Due to how ilaenv parses names, any lauum routine that queries for nx will return the same value. --- SRC/ilaenv.f | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SRC/ilaenv.f b/SRC/ilaenv.f index c0371c0b0..2622d44cc 100644 --- a/SRC/ilaenv.f +++ b/SRC/ilaenv.f @@ -679,6 +679,12 @@ INTEGER FUNCTION ILAENV( ISPEC, NAME, OPTS, N1, N2, N3, N4 ) ELSE IF( C2.EQ.'LA' ) THEN IF( C3.EQ.'RFT' ) THEN NX = 64 + ELSE IF( C3.EQ.'UUM' ) THEN +* +* Note that this matches on *lauum_recursive, which is the +* only place we currently use this +* + NX = 64 END IF END IF ILAENV = NX