dynare/mex/sources/libslicot/SB04PY.f

1112 lines
40 KiB
Fortran

SUBROUTINE SB04PY( TRANA, TRANB, ISGN, M, N, A, LDA, B, LDB, C,
$ LDC, SCALE, DWORK, INFO )
C
C SLICOT RELEASE 5.0.
C
C Copyright (c) 2002-2009 NICONET e.V.
C
C This program is free software: you can redistribute it and/or
C modify it under the terms of the GNU General Public License as
C published by the Free Software Foundation, either version 2 of
C the License, or (at your option) any later version.
C
C This program is distributed in the hope that it will be useful,
C but WITHOUT ANY WARRANTY; without even the implied warranty of
C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
C GNU General Public License for more details.
C
C You should have received a copy of the GNU General Public License
C along with this program. If not, see
C <http://www.gnu.org/licenses/>.
C
C PURPOSE
C
C To solve for X the discrete-time Sylvester equation
C
C op(A)*X*op(B) + ISGN*X = scale*C,
C
C where op(A) = A or A**T, A and B are both upper quasi-triangular,
C and ISGN = 1 or -1. A is M-by-M and B is N-by-N; the right hand
C side C and the solution X are M-by-N; and scale is an output scale
C factor, set less than or equal to 1 to avoid overflow in X. The
C solution matrix X is overwritten onto C.
C
C A and B must be in Schur canonical form (as returned by LAPACK
C Library routine DHSEQR), that is, block upper triangular with
C 1-by-1 and 2-by-2 diagonal blocks; each 2-by-2 diagonal block has
C its diagonal elements equal and its off-diagonal elements of
C opposite sign.
C
C ARGUMENTS
C
C Mode Parameters
C
C TRANA CHARACTER*1
C Specifies the form of op(A) to be used, as follows:
C = 'N': op(A) = A (No transpose);
C = 'T': op(A) = A**T (Transpose);
C = 'C': op(A) = A**T (Conjugate transpose = Transpose).
C
C TRANB CHARACTER*1
C Specifies the form of op(B) to be used, as follows:
C = 'N': op(B) = B (No transpose);
C = 'T': op(B) = B**T (Transpose);
C = 'C': op(B) = B**T (Conjugate transpose = Transpose).
C
C ISGN INTEGER
C Specifies the sign of the equation as described before.
C ISGN may only be 1 or -1.
C
C Input/Output Parameters
C
C M (input) INTEGER
C The order of the matrix A, and the number of rows in the
C matrices X and C. M >= 0.
C
C N (input) INTEGER
C The order of the matrix B, and the number of columns in
C the matrices X and C. N >= 0.
C
C A (input) DOUBLE PRECISION array, dimension (LDA,M)
C The leading M-by-M part of this array must contain the
C upper quasi-triangular matrix A, in Schur canonical form.
C The part of A below the first sub-diagonal is not
C referenced.
C
C LDA INTEGER
C The leading dimension of array A. LDA >= MAX(1,M).
C
C B (input) DOUBLE PRECISION array, dimension (LDB,N)
C The leading N-by-N part of this array must contain the
C upper quasi-triangular matrix B, in Schur canonical form.
C The part of B below the first sub-diagonal is not
C referenced.
C
C LDB (input) INTEGER
C The leading dimension of the array B. LDB >= max(1,N).
C
C C (input/output) DOUBLE PRECISION array, dimension (LDC,N)
C On entry, the leading M-by-N part of this array must
C contain the right hand side matrix C.
C On exit, if INFO >= 0, the leading M-by-N part of this
C array contains the solution matrix X.
C
C LDC INTEGER
C The leading dimension of array C. LDC >= MAX(1,M).
C
C SCALE (output) DOUBLE PRECISION
C The scale factor, scale, set less than or equal to 1 to
C prevent the solution overflowing.
C
C Workspace
C
C DWORK DOUBLE PRECISION array, dimension (2*M)
C
C Error Indicator
C
C INFO INTEGER
C = 0: successful exit;
C < 0: if INFO = -i, the i-th argument had an illegal
C value;
C = 1: A and -ISGN*B have almost reciprocal eigenvalues;
C perturbed values were used to solve the equation
C (but the matrices A and B are unchanged).
C
C METHOD
C
C The solution matrix X is computed column-wise via a back
C substitution scheme, an extension and refinement of the algorithm
C in [1], similar to that used in [2] for continuous-time Sylvester
C equations. A set of equivalent linear algebraic systems of
C equations of order at most four are formed and solved using
C Gaussian elimination with complete pivoting.
C
C REFERENCES
C
C [1] Bartels, R.H. and Stewart, G.W. T
C Solution of the matrix equation A X + XB = C.
C Comm. A.C.M., 15, pp. 820-826, 1972.
C
C [2] Anderson, E., Bai, Z., Bischof, C., Demmel, J., Dongarra, J.,
C Du Croz, J., Greenbaum, A., Hammarling, S., McKenney, A.,
C Ostrouchov, S., and Sorensen, D.
C LAPACK Users' Guide: Second Edition.
C SIAM, Philadelphia, 1995.
C
C NUMERICAL ASPECTS
C
C The algorithm is stable and reliable, since Gaussian elimination
C with complete pivoting is used.
C
C CONTRIBUTORS
C
C A. Varga, German Aerospace Center, Oberpfaffenhofen, March 2000.
C D. Sima, University of Bucharest, April 2000.
C V. Sima, Research Institute for Informatics, Bucharest, Apr. 2000.
C Partly based on the routine SYLSV, A. Varga, 1992.
C
C REVISIONS
C
C -
C
C KEYWORDS
C
C Discrete-time system, matrix algebra, Sylvester equation.
C
C ******************************************************************
C
C .. Parameters ..
DOUBLE PRECISION ZERO, ONE
PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 )
C ..
C .. Scalar Arguments ..
CHARACTER TRANA, TRANB
INTEGER INFO, ISGN, LDA, LDB, LDC, M, N
DOUBLE PRECISION SCALE
C ..
C .. Array Arguments ..
DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( LDC, * ),
$ DWORK( * )
C ..
C .. Local Scalars ..
LOGICAL NOTRNA, NOTRNB
INTEGER IERR, J, K, K1, K2, KNEXT, L, L1, L2, LNEXT,
$ MNK1, MNK2, MNL1, MNL2
DOUBLE PRECISION A11, BIGNUM, DA11, DB, EPS, P11, P12, P21, P22,
$ SCALOC, SGN, SMIN, SMLNUM, SUMR, XNORM
C ..
C .. Local Arrays ..
DOUBLE PRECISION DUM( 1 ), VEC( 2, 2 ), X( 2, 2 )
C ..
C .. External Functions ..
LOGICAL LSAME
DOUBLE PRECISION DDOT, DLAMCH, DLANGE
EXTERNAL DDOT, DLAMCH, DLANGE, LSAME
C ..
C .. External Subroutines ..
EXTERNAL DLABAD, DLALN2, DSCAL, SB04PX, XERBLA
C ..
C .. Intrinsic Functions ..
INTRINSIC ABS, DBLE, MAX, MIN
C ..
C .. Executable Statements ..
C
C Decode and Test input parameters
C
NOTRNA = LSAME( TRANA, 'N' )
NOTRNB = LSAME( TRANB, 'N' )
C
INFO = 0
IF( .NOT.NOTRNA .AND. .NOT.LSAME( TRANA, 'T' ) .AND.
$ .NOT.LSAME( TRANA, 'C' ) ) THEN
INFO = -1
ELSE IF( .NOT.NOTRNB .AND. .NOT.LSAME( TRANB, 'T' ) .AND.
$ .NOT.LSAME( TRANB, 'C' ) ) THEN
INFO = -2
ELSE IF( ISGN.NE.1 .AND. ISGN.NE.-1 ) THEN
INFO = -3
ELSE IF( M.LT.0 ) THEN
INFO = -4
ELSE IF( N.LT.0 ) THEN
INFO = -5
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
INFO = -7
ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
INFO = -9
ELSE IF( LDC.LT.MAX( 1, M ) ) THEN
INFO = -11
END IF
IF( INFO.NE.0 ) THEN
CALL XERBLA( 'SB04PY', -INFO )
RETURN
END IF
C
C Quick return if possible.
C
SCALE = ONE
IF( M.EQ.0 .OR. N.EQ.0 )
$ RETURN
C
C Set constants to control overflow.
C
EPS = DLAMCH( 'Precision' )
SMLNUM = DLAMCH( 'Safe minimum' )
BIGNUM = ONE / SMLNUM
CALL DLABAD( SMLNUM, BIGNUM )
SMLNUM = SMLNUM*DBLE( M*N ) / EPS
BIGNUM = ONE / SMLNUM
C
SMIN = MAX( SMLNUM, EPS*DLANGE( 'M', M, M, A, LDA, DUM ),
$ EPS*DLANGE( 'M', N, N, B, LDB, DUM ) )
C
SGN = ISGN
C
IF( NOTRNA .AND. NOTRNB ) THEN
C
C Solve A*X*B + ISGN*X = scale*C.
C
C The (K,L)th block of X is determined starting from
C bottom-left corner column by column by
C
C A(K,K)*X(K,L)*B(L,L) + ISGN*X(K,L) = C(K,L) - R(K,L)
C
C where
C M
C R(K,L) = { SUM [A(K,J)*X(J,L)] } * B(L,L) +
C J=K+1
C M L-1
C SUM { A(K,J) * SUM [X(J,I)*B(I,L)] }.
C J=K I=1
C
C Start column loop (index = L)
C L1 (L2) : column index of the first (last) row of X(K,L).
C
LNEXT = 1
C
DO 60 L = 1, N
IF( L.LT.LNEXT )
$ GO TO 60
L1 = L
IF( L.EQ.N ) THEN
L2 = L
ELSE
IF( B( L+1, L ).NE.ZERO ) THEN
L2 = L + 1
ELSE
L2 = L
END IF
LNEXT = L2 + 1
END IF
C
C Start row loop (index = K)
C K1 (K2): row index of the first (last) row of X(K,L).
C
KNEXT = M
C
DO 50 K = M, 1, -1
IF( K.GT.KNEXT )
$ GO TO 50
K2 = K
IF( K.EQ.1 ) THEN
K1 = K
ELSE
IF( A( K, K-1 ).NE.ZERO ) THEN
K1 = K - 1
ELSE
K1 = K
END IF
KNEXT = K1 - 1
END IF
C
MNK1 = MIN( K1+1, M )
MNK2 = MIN( K2+1, M )
P11 = DDOT( M-K2, A( K1, MNK2 ), LDA, C( MNK2, L1 ), 1 )
DWORK( K1 ) = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ),
$ 1 )
C
IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
C
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
SCALOC = ONE
C
A11 = A( K1, K1 )*B( L1, L1 ) + SGN
DA11 = ABS( A11 )
IF( DA11.LE.SMIN ) THEN
A11 = SMIN
DA11 = SMIN
INFO = 1
END IF
DB = ABS( VEC( 1, 1 ) )
IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
IF( DB.GT.BIGNUM*DA11 )
$ SCALOC = ONE / DB
END IF
X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
C
IF( SCALOC.NE.ONE ) THEN
C
DO 10 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
10 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C
ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( M-K2, A( K2, MNK2 ), LDA, C( MNK2, L1 ),
$ 1 )
DWORK( K2 ) = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L1 ),
$ 1 )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
C
SUMR = DDOT( M-K1+1, A( K2, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) )
C
CALL DLALN2( .FALSE., 2, 1, SMIN, B( L1, L1 ),
$ A( K1, K1 ), LDA, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 20 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
20 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K2, L1 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
C
P12 = DDOT( M-K1, A( K1, MNK1 ), LDA, C( MNK1, L2 ),
$ 1 )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L2, L1 ) )
C
DWORK( K1+M ) = DDOT( L1-1, C( K1, 1 ), LDC,
$ B( 1, L2 ), 1 )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1+M ),
$ 1 )
VEC( 2, 1 ) = C( K1, L2 ) - ( SUMR + P11*B( L1, L2 ) +
$ P12*B( L2, L2 ) )
C
CALL DLALN2( .TRUE., 2, 1, SMIN, A( K1, K1 ),
$ B( L1, L1 ), LDB, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 30 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
30 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1+M ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( M-K2, A( K2, MNK2 ), LDA, C( MNK2, L1 ),
$ 1 )
P12 = DDOT( M-K2, A( K1, MNK2 ), LDA, C( MNK2, L2 ),
$ 1 )
P22 = DDOT( M-K2, A( K2, MNK2 ), LDA, C( MNK2, L2 ),
$ 1 )
C
DWORK( K2 ) = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L1 ),
$ 1 )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L2, L1 ) )
C
DWORK( K1+M ) = DDOT( L1-1, C( K1, 1 ), LDC,
$ B( 1, L2 ), 1 )
DWORK( K2+M ) = DDOT( L1-1, C( K2, 1 ), LDC,
$ B( 1, L2 ), 1 )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1+M ),
$ 1 )
VEC( 1, 2 ) = C( K1, L2 ) - ( SUMR + P11*B( L1, L2 ) +
$ P12*B( L2, L2 ) )
C
SUMR = DDOT( M-K1+1, A( K2, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) +
$ P22*B( L2, L1 ) )
C
SUMR = DDOT( M-K1+1, A( K2, K1 ), LDA, DWORK( K1+M ),
$ 1 )
VEC( 2, 2 ) = C( K2, L2 ) - ( SUMR + P21*B( L1, L2 ) +
$ P22*B( L2, L2 ) )
C
CALL SB04PX( .FALSE., .FALSE., ISGN, 2, 2,
$ A( K1, K1 ), LDA, B( L1, L1 ), LDB, VEC,
$ 2, SCALOC, X, 2, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 40 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
40 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1+M ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 1, 2 )
C( K2, L1 ) = X( 2, 1 )
C( K2, L2 ) = X( 2, 2 )
END IF
C
50 CONTINUE
C
60 CONTINUE
C
ELSE IF( .NOT.NOTRNA .AND. NOTRNB ) THEN
C
C Solve A'*X*B + ISGN*X = scale*C.
C
C The (K,L)th block of X is determined starting from
C upper-left corner column by column by
C
C A(K,K)'*X(K,L)*B(L,L) + ISGN*X(K,L) = C(K,L) - R(K,L)
C
C where
C K-1
C R(K,L) = { SUM [A(J,K)'*X(J,L)] } * B(L,L) +
C J=1
C K L-1
C SUM A(J,K)' * { SUM [X(J,I)*B(I,L)] }.
C J=1 I=1
C
C Start column loop (index = L)
C L1 (L2): column index of the first (last) row of X(K,L).
C
LNEXT = 1
C
DO 120 L = 1, N
IF( L.LT.LNEXT )
$ GO TO 120
L1 = L
IF( L.EQ.N ) THEN
L2 = L
ELSE
IF( B( L+1, L ).NE.ZERO ) THEN
L2 = L + 1
ELSE
L2 = L
END IF
LNEXT = L2 + 1
END IF
C
C Start row loop (index = K)
C K1 (K2): row index of the first (last) row of X(K,L).
C
KNEXT = 1
C
DO 110 K = 1, M
IF( K.LT.KNEXT )
$ GO TO 110
K1 = K
IF( K.EQ.M ) THEN
K2 = K
ELSE
IF( A( K+1, K ).NE.ZERO ) THEN
K2 = K + 1
ELSE
K2 = K
END IF
KNEXT = K2 + 1
END IF
C
P11 = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
DWORK( K1 ) = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1),
$ 1 )
C
IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
C
SUMR = DDOT( K1, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
SCALOC = ONE
C
A11 = A( K1, K1 )*B( L1, L1 ) + SGN
DA11 = ABS( A11 )
IF( DA11.LE.SMIN ) THEN
A11 = SMIN
DA11 = SMIN
INFO = 1
END IF
DB = ABS( VEC( 1, 1 ) )
IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
IF( DB.GT.BIGNUM*DA11 )
$ SCALOC = ONE / DB
END IF
X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
C
IF( SCALOC.NE.ONE ) THEN
C
DO 70 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
70 CONTINUE
C
CALL DSCAL( K1, SCALOC, DWORK, 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C
ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
DWORK( K2 ) = DDOT( L1-1, C( K2, 1 ), LDC,
$ B( 1, L1), 1 )
SUMR = DDOT( K2, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
C
SUMR = DDOT( K2, A( 1, K2 ), 1, DWORK, 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) )
C
CALL DLALN2( .TRUE., 2, 1, SMIN, B( L1, L1 ),
$ A( K1, K1 ), LDA, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 80 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
80 CONTINUE
C
CALL DSCAL( K2, SCALOC, DWORK, 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K2, L1 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
C
P12 = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
SUMR = DDOT( K1, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L2, L1 ) )
C
DWORK( K1+M ) = DDOT( L1-1, C( K1, 1 ), LDC,
$ B( 1, L2 ), 1 )
SUMR = DDOT( K1, A( 1, K1 ), 1, DWORK( M+1 ), 1 )
VEC( 2, 1 ) = C( K1, L2 ) - ( SUMR + P11*B( L1, L2 ) +
$ P12*B( L2, L2 ) )
C
CALL DLALN2( .TRUE., 2, 1, SMIN, A( K1, K1 ),
$ B( L1, L1 ), LDB, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 90 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
90 CONTINUE
C
CALL DSCAL( K1, SCALOC, DWORK, 1 )
CALL DSCAL( K1, SCALOC, DWORK( M+1 ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
P12 = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
P22 = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L2 ), 1 )
C
DWORK( K2 ) = DDOT( L1-1, C( K2, 1 ), LDC,
$ B( 1, L1), 1 )
SUMR = DDOT( K2, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L2, L1 ) )
C
SUMR = DDOT( K2, A( 1, K2 ), 1, DWORK, 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) +
$ P22*B( L2, L1 ) )
C
DWORK( K1+M ) = DDOT( L1-1, C( K1, 1 ), LDC,
$ B( 1, L2 ), 1 )
DWORK( K2+M ) = DDOT( L1-1, C( K2, 1 ), LDC,
$ B( 1, L2 ), 1 )
SUMR = DDOT( K2, A( 1, K1 ), 1, DWORK( M+1 ), 1 )
VEC( 1, 2 ) = C( K1, L2 ) - ( SUMR + P11*B( L1, L2 ) +
$ P12*B( L2, L2 ) )
C
SUMR = DDOT( K2, A( 1, K2 ), 1, DWORK( M+1 ), 1 )
VEC( 2, 2 ) = C( K2, L2 ) - ( SUMR + P21*B( L1, L2 ) +
$ P22*B( L2, L2 ) )
C
CALL SB04PX( .TRUE., .FALSE., ISGN, 2, 2, A( K1, K1 ),
$ LDA, B( L1, L1 ), LDB, VEC, 2, SCALOC, X,
$ 2, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 100 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
100 CONTINUE
C
CALL DSCAL( K2, SCALOC, DWORK, 1 )
CALL DSCAL( K2, SCALOC, DWORK( M+1 ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 1, 2 )
C( K2, L1 ) = X( 2, 1 )
C( K2, L2 ) = X( 2, 2 )
END IF
C
110 CONTINUE
C
120 CONTINUE
C
ELSE IF( .NOT.NOTRNA .AND. .NOT.NOTRNB ) THEN
C
C Solve A'*X*B' + ISGN*X = scale*C.
C
C The (K,L)th block of X is determined starting from
C top-right corner column by column by
C
C A(K,K)'*X(K,L)*B(L,L)' + ISGN*X(K,L) = C(K,L) - R(K,L)
C
C where
C K-1
C R(K,L) = { SUM [A(J,K)'*X(J,L)] } * B(L,L)' +
C J=1
C K N
C SUM A(J,K)' * { SUM [X(J,I)*B(L,I)'] }.
C J=1 I=L+1
C
C Start column loop (index = L)
C L1 (L2): column index of the first (last) row of X(K,L).
C
LNEXT = N
C
DO 180 L = N, 1, -1
IF( L.GT.LNEXT )
$ GO TO 180
L2 = L
IF( L.EQ.1 ) THEN
L1 = L
ELSE
IF( B( L, L-1 ).NE.ZERO ) THEN
L1 = L - 1
ELSE
L1 = L
END IF
LNEXT = L1 - 1
END IF
C
C Start row loop (index = K)
C K1 (K2): row index of the first (last) row of X(K,L).
C
KNEXT = 1
C
DO 170 K = 1, M
IF( K.LT.KNEXT )
$ GO TO 170
K1 = K
IF( K.EQ.M ) THEN
K2 = K
ELSE
IF( A( K+1, K ).NE.ZERO ) THEN
K2 = K + 1
ELSE
K2 = K
END IF
KNEXT = K2 + 1
END IF
C
MNL1 = MIN( L1+1, N )
MNL2 = MIN( L2+1, N )
P11 = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
DWORK( K1 ) = DDOT( N-L2, C( K1, MNL2 ), LDC,
$ B( L1, MNL2 ), LDB )
C
IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
SUMR = DDOT( K1, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
SCALOC = ONE
C
A11 = A( K1, K1 )*B( L1, L1 ) + SGN
DA11 = ABS( A11 )
IF( DA11.LE.SMIN ) THEN
A11 = SMIN
DA11 = SMIN
INFO = 1
END IF
DB = ABS( VEC( 1, 1 ) )
IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
IF( DB.GT.BIGNUM*DA11 )
$ SCALOC = ONE / DB
END IF
X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
C
IF( SCALOC.NE.ONE ) THEN
C
DO 130 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
130 CONTINUE
C
CALL DSCAL( K1, SCALOC, DWORK, 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C
ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
DWORK( K2 ) = DDOT( N-L1, C( K2, MNL1 ), LDC,
$ B( L1, MNL1 ), LDB )
SUMR = DDOT( K2, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
C
SUMR = DDOT( K2, A( 1, K2 ), 1, DWORK, 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) )
C
CALL DLALN2( .TRUE., 2, 1, SMIN, B( L1, L1 ),
$ A( K1, K1 ), LDA, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 140 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
140 CONTINUE
C
CALL DSCAL( K2, SCALOC, DWORK, 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K2, L1 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
C
P12 = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
SUMR = DDOT( K1, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L1, L2 ) )
C
DWORK( K1+M ) = DDOT( N-L2, C( K1, MNL2 ), LDC,
$ B( L2, MNL2 ), LDB )
SUMR = DDOT( K1, A( 1, K1 ), 1, DWORK( M+1 ), 1 )
VEC( 2, 1 ) = C( K1, L2 ) - ( SUMR + P11*B( L2, L1 ) +
$ P12*B( L2, L2 ) )
C
CALL DLALN2( .FALSE., 2, 1, SMIN, A( K1, K1 ),
$ B( L1, L1 ), LDB, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 150 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
150 CONTINUE
C
CALL DSCAL( K1, SCALOC, DWORK, 1 )
CALL DSCAL( K1, SCALOC, DWORK(M+1), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
P12 = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
P22 = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L2 ), 1 )
C
DWORK( K2 ) = DDOT( N-L2, C( K2, MNL2 ), LDC,
$ B( L1, MNL2 ), LDB )
SUMR = DDOT( K2, A( 1, K1 ), 1, DWORK, 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L1, L2 ) )
C
SUMR = DDOT( K2, A( 1, K2 ), 1, DWORK, 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) +
$ P22*B( L1, L2 ) )
C
DWORK( K1+M ) = DDOT( N-L2, C( K1, MNL2 ), LDC,
$ B( L2, MNL2 ), LDB )
DWORK( K2+M ) = DDOT( N-L2, C( K2, MNL2 ), LDC,
$ B( L2, MNL2 ), LDB )
SUMR = DDOT( K2, A( 1, K1 ), 1, DWORK( M+1 ), 1 )
VEC( 1, 2 ) = C( K1, L2 ) - ( SUMR + P11*B( L2, L1 ) +
$ P12*B( L2, L2 ) )
C
SUMR = DDOT( K2, A( 1, K2 ), 1, DWORK( M+1 ), 1 )
VEC( 2, 2 ) = C( K2, L2 ) - ( SUMR + P21*B( L2, L1 ) +
$ P22*B( L2, L2 ) )
C
CALL SB04PX( .TRUE., .TRUE., ISGN, 2, 2, A( K1, K1 ),
$ LDA, B( L1, L1 ), LDB, VEC, 2, SCALOC, X,
$ 2, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 160 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
160 CONTINUE
C
CALL DSCAL( K2, SCALOC, DWORK, 1 )
CALL DSCAL( K2, SCALOC, DWORK(M+1), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 1, 2 )
C( K2, L1 ) = X( 2, 1 )
C( K2, L2 ) = X( 2, 2 )
END IF
C
170 CONTINUE
C
180 CONTINUE
C
ELSE
C
C Solve A*X*B' + ISGN*X = scale*C.
C
C The (K,L)th block of X is determined starting from
C bottom-right corner column by column by
C
C A(K,K)*X(K,L)*B(L,L)' + ISGN*X(K,L) = C(K,L) - R(K,L)
C
C where
C M
C R(K,L) = { SUM [A(K,J)*X(J,L)] } * B(L,L)' +
C J=K+1
C M N
C SUM { A(K,J) * SUM [X(J,I)*B(L,I)'] }.
C J=K I=L+1
C
C Start column loop (index = L)
C L1 (L2): column index of the first (last) row of X(K,L).
C
LNEXT = N
C
DO 240 L = N, 1, -1
IF( L.GT.LNEXT )
$ GO TO 240
L2 = L
IF( L.EQ.1 ) THEN
L1 = L
ELSE
IF( B( L, L-1 ).NE.ZERO ) THEN
L1 = L - 1
ELSE
L1 = L
END IF
LNEXT = L1 - 1
END IF
C
C Start row loop (index = K)
C K1 (K2): row index of the first (last) row of X(K,L).
C
KNEXT = M
C
DO 230 K = M, 1, -1
IF( K.GT.KNEXT )
$ GO TO 230
K2 = K
IF( K.EQ.1 ) THEN
K1 = K
ELSE
IF( A( K, K-1 ).NE.ZERO ) THEN
K1 = K - 1
ELSE
K1 = K
END IF
KNEXT = K1 - 1
END IF
C
MNK1 = MIN( K1+1, M )
MNK2 = MIN( K2+1, M )
MNL1 = MIN( L1+1, N )
MNL2 = MIN( L2+1, N )
P11 = DDOT( M-K2, A( K1, MNK2 ), LDA, C( MNK2, L1 ), 1 )
DWORK( K1 ) = DDOT( N-L2, C( K1, MNL2 ), LDC,
$ B( L1, MNL2 ), LDB )
C
IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
C
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
SCALOC = ONE
C
A11 = A( K1, K1 )*B( L1, L1 ) + SGN
DA11 = ABS( A11 )
IF( DA11.LE.SMIN ) THEN
A11 = SMIN
DA11 = SMIN
INFO = 1
END IF
DB = ABS( VEC( 1, 1 ) )
IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
IF( DB.GT.BIGNUM*DA11 )
$ SCALOC = ONE / DB
END IF
X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
C
IF( SCALOC.NE.ONE ) THEN
C
DO 190 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
190 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C
ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( M-K2, A( K2, MNK2 ), LDA, C( MNK2, L1 ),
$ 1 )
DWORK( K2 ) = DDOT( N-L1, C( K2, MNL1 ), LDC,
$ B( L1, MNL1 ), LDB )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) )
C
SUMR = DDOT( M-K1+1, A( K2, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) )
C
CALL DLALN2( .FALSE., 2, 1, SMIN, B( L1, L1 ),
$ A( K1, K1 ), LDA, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 200 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
200 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K2, L1 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
C
P12 = DDOT( M-K1, A( K1, MNK1 ), LDA, C( MNK1, L2 ),
$ 1 )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L1, L2 ) )
C
DWORK( K1+M ) = DDOT( N-L2, C( K1, MNL2 ), LDC,
$ B( L2, MNL2 ), LDB )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1+M ),
$ 1 )
VEC( 2, 1 ) = C( K1, L2 ) - ( SUMR + P11*B( L2, L1 ) +
$ P12*B( L2, L2 ) )
C
CALL DLALN2( .FALSE., 2, 1, SMIN, A( K1, K1 ),
$ B( L1, L1 ), LDB, ONE, ONE, VEC, 2, -SGN,
$ ZERO, X, 2, SCALOC, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 210 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
210 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1+M ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 2, 1 )
C
ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
C
P21 = DDOT( M-K2, A( K2, MNK2 ), LDA, C( MNK2, L1 ),
$ 1 )
P12 = DDOT( M-K2, A( K1, MNK2 ), LDA, C( MNK2, L2 ),
$ 1 )
P22 = DDOT( M-K2, A( K2, MNK2 ), LDA, C( MNK2, L2 ),
$ 1 )
C
DWORK( K2 ) = DDOT( N-L2, C( K2, MNL2 ), LDC,
$ B( L1, MNL2 ), LDB )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 1, 1 ) = C( K1, L1 ) - ( SUMR + P11*B( L1, L1 ) +
$ P12*B( L1, L2 ) )
C
SUMR = DDOT( M-K1+1, A( K2, K1 ), LDA, DWORK( K1 ),
$ 1 )
VEC( 2, 1 ) = C( K2, L1 ) - ( SUMR + P21*B( L1, L1 ) +
$ P22*B( L1, L2 ) )
C
DWORK( K1+M ) = DDOT( N-L2, C( K1, MNL2 ), LDC,
$ B( L2, MNL2 ), LDB )
DWORK( K2+M ) = DDOT( N-L2, C( K2, MNL2 ), LDC,
$ B( L2, MNL2 ), LDB )
SUMR = DDOT( M-K1+1, A( K1, K1 ), LDA, DWORK( K1+M ),
$ 1 )
VEC( 1, 2 ) = C( K1, L2 ) - ( SUMR + P11*B( L2, L1 ) +
$ P12*B( L2, L2 ) )
C
SUMR = DDOT( M-K1+1, A( K2, K1 ), LDA, DWORK( K1+M ),
$ 1 )
VEC( 2, 2 ) = C( K2, L2 ) - ( SUMR + P21*B( L2, L1 ) +
$ P22*B( L2, L2 ) )
C
CALL SB04PX( .FALSE., .TRUE., ISGN, 2, 2, A( K1, K1 ),
$ LDA, B( L1, L1 ), LDB, VEC, 2, SCALOC, X,
$ 2, XNORM, IERR )
IF( IERR.NE.0 )
$ INFO = 1
C
IF( SCALOC.NE.ONE ) THEN
C
DO 220 J = 1, N
CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
220 CONTINUE
C
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1 ), 1 )
CALL DSCAL( M-K1+1, SCALOC, DWORK( K1+M ), 1 )
SCALE = SCALE*SCALOC
END IF
C( K1, L1 ) = X( 1, 1 )
C( K1, L2 ) = X( 1, 2 )
C( K2, L1 ) = X( 2, 1 )
C( K2, L2 ) = X( 2, 2 )
END IF
C
230 CONTINUE
C
240 CONTINUE
C
END IF
C
RETURN
C *** Last line of SB04PY ***
END