dynare/mex/sources/libslicot/SB10LD.f

439 lines
14 KiB
Fortran

SUBROUTINE SB10LD( N, M, NP, NCON, NMEAS, A, LDA, B, LDB, C, LDC,
$ D, LDD, AK, LDAK, BK, LDBK, CK, LDCK, DK, LDDK,
$ AC, LDAC, BC, LDBC, CC, LDCC, DC, LDDC, IWORK,
$ DWORK, LDWORK, 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 compute the matrices of the closed-loop system
C
C | AC | BC |
C G = |----|----|,
C | CC | DC |
C
C from the matrices of the open-loop system
C
C | A | B |
C P = |---|---|
C | C | D |
C
C and the matrices of the controller
C
C | AK | BK |
C K = |----|----|.
C | CK | DK |
C
C ARGUMENTS
C
C Input/Output Parameters
C
C N (input) INTEGER
C The order of the system. N >= 0.
C
C M (input) INTEGER
C The column size of the matrix B. M >= 0.
C
C NP (input) INTEGER
C The row size of the matrix C. NP >= 0.
C
C NCON (input) INTEGER
C The number of control inputs (M2). M >= NCON >= 0.
C NP-NMEAS >= NCON.
C
C NMEAS (input) INTEGER
C The number of measurements (NP2). NP >= NMEAS >= 0.
C M-NCON >= NMEAS.
C
C A (input) DOUBLE PRECISION array, dimension (LDA,N)
C The leading N-by-N part of this array must contain the
C system state matrix A.
C
C LDA INTEGER
C The leading dimension of the array A. LDA >= max(1,N).
C
C B (input) DOUBLE PRECISION array, dimension (LDB,M)
C The leading N-by-M part of this array must contain the
C system input matrix B.
C
C LDB INTEGER
C The leading dimension of the array B. LDB >= max(1,N).
C
C C (input) DOUBLE PRECISION array, dimension (LDC,N)
C The leading NP-by-N part of this array must contain the
C system output matrix C.
C
C LDC INTEGER
C The leading dimension of the array C. LDC >= max(1,NP).
C
C D (input) DOUBLE PRECISION array, dimension (LDD,M)
C The leading NP-by-M part of this array must contain the
C system input/output matrix D.
C
C LDD INTEGER
C The leading dimension of the array D. LDD >= max(1,NP).
C
C AK (input) DOUBLE PRECISION array, dimension (LDAK,N)
C The leading N-by-N part of this array must contain the
C controller state matrix AK.
C
C LDAK INTEGER
C The leading dimension of the array AK. LDAK >= max(1,N).
C
C BK (input) DOUBLE PRECISION array, dimension (LDBK,NMEAS)
C The leading N-by-NMEAS part of this array must contain the
C controller input matrix BK.
C
C LDBK INTEGER
C The leading dimension of the array BK. LDBK >= max(1,N).
C
C CK (input) DOUBLE PRECISION array, dimension (LDCK,N)
C The leading NCON-by-N part of this array must contain the
C controller output matrix CK.
C
C LDCK INTEGER
C The leading dimension of the array CK.
C LDCK >= max(1,NCON).
C
C DK (input) DOUBLE PRECISION array, dimension (LDDK,NMEAS)
C The leading NCON-by-NMEAS part of this array must contain
C the controller input/output matrix DK.
C
C LDDK INTEGER
C The leading dimension of the array DK.
C LDDK >= max(1,NCON).
C
C AC (output) DOUBLE PRECISION array, dimension (LDAC,2*N)
C The leading 2*N-by-2*N part of this array contains the
C closed-loop system state matrix AC.
C
C LDAC INTEGER
C The leading dimension of the array AC.
C LDAC >= max(1,2*N).
C
C BC (output) DOUBLE PRECISION array, dimension (LDBC,M-NCON)
C The leading 2*N-by-(M-NCON) part of this array contains
C the closed-loop system input matrix BC.
C
C LDBC INTEGER
C The leading dimension of the array BC.
C LDBC >= max(1,2*N).
C
C CC (output) DOUBLE PRECISION array, dimension (LDCC,2*N)
C The leading (NP-NMEAS)-by-2*N part of this array contains
C the closed-loop system output matrix CC.
C
C LDCC INTEGER
C The leading dimension of the array CC.
C LDCC >= max(1,NP-NMEAS).
C
C DC (output) DOUBLE PRECISION array, dimension (LDDC,M-NCON)
C The leading (NP-NMEAS)-by-(M-NCON) part of this array
C contains the closed-loop system input/output matrix DC.
C
C LDDC INTEGER
C The leading dimension of the array DC.
C LDDC >= max(1,NP-NMEAS).
C
C Workspace
C
C IWORK INTEGER array, dimension 2*max(NCON,NMEAS)
C
C DWORK DOUBLE PRECISION array, dimension (LDWORK)
C On exit, if INFO = 0, DWORK(1) contains the optimal
C LDWORK.
C
C LDWORK INTEGER
C The dimension of the array DWORK.
C LDWORK >= 2*M*M+NP*NP+2*M*N+M*NP+2*N*NP.
C For good performance, LDWORK must generally be larger.
C
C Error Indicactor
C
C INFO INTEGER
C = 0: successful exit;
C < 0: if INFO = -i, the i-th argument had an illegal
C value;
C = 1: if the matrix Inp2 - D22*DK is singular to working
C precision;
C = 2: if the matrix Im2 - DK*D22 is singular to working
C precision.
C
C METHOD
C
C The routine implements the formulas given in [1].
C
C REFERENCES
C
C [1] Balas, G.J., Doyle, J.C., Glover, K., Packard, A., and
C Smith, R.
C mu-Analysis and Synthesis Toolbox.
C The MathWorks Inc., Natick, Mass., 1995.
C
C NUMERICAL ASPECTS
C
C The accuracy of the result depends on the condition numbers of the
C matrices Inp2 - D22*DK and Im2 - DK*D22.
C
C CONTRIBUTORS
C
C P.Hr. Petkov, D.W. Gu and M.M. Konstantinov, October 1998.
C
C REVISIONS
C
C V. Sima, Research Institute for Informatics, Bucharest, May 1999.
C A. Markovski, Technical University, Sofia, April, 2003.
C
C KEYWORDS
C
C Closed loop systems, feedback control, robust control.
C
C ******************************************************************
C
C .. Parameters ..
DOUBLE PRECISION ZERO, ONE
PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 )
C
C .. Scalar Arguments ..
INTEGER INFO, LDA, LDAC, LDAK, LDB, LDBC, LDBK, LDC,
$ LDCC, LDCK, LDD, LDDC, LDDK, LDWORK, M, N,
$ NCON, NMEAS, NP
C ..
C .. Array Arguments ..
INTEGER IWORK( * )
DOUBLE PRECISION A( LDA, * ), AC( LDAC, * ), AK( LDAK, * ),
$ B( LDB, * ), BC( LDBC, * ), BK( LDBK, * ),
$ C( LDC, * ), CC( LDCC, * ), CK( LDCK, * ),
$ D( LDD, * ), DC( LDDC, * ), DK( LDDK, * ),
$ DWORK( * )
C ..
C .. Local Scalars ..
INTEGER INFO2, IW2, IW3, IW4, IW5, IW6, IW7, IW8, IWRK,
$ LWAMAX, M1, M2, MINWRK, N2, NP1, NP2
DOUBLE PRECISION ANORM, EPS, RCOND
C ..
C .. External Functions ..
DOUBLE PRECISION DLAMCH, DLANGE
EXTERNAL DLAMCH, DLANGE
C ..
C .. External Subroutines ..
EXTERNAL DGECON, DGEMM, DGETRF, DGETRI, DLACPY, DLASET,
$ XERBLA
C ..
C .. Executable Statements ..
C
C Decode and Test input parameters.
C
N2 = 2*N
M1 = M - NCON
M2 = NCON
NP1 = NP - NMEAS
NP2 = NMEAS
C
INFO = 0
IF( N.LT.0 ) THEN
INFO = -1
ELSE IF( M.LT.0 ) THEN
INFO = -2
ELSE IF( NP.LT.0 ) THEN
INFO = -3
ELSE IF( NCON.LT.0 .OR. M1.LT.0 .OR. M2.GT.NP1 ) THEN
INFO = -4
ELSE IF( NMEAS.LT.0 .OR. NP1.LT.0 .OR. NP2.GT.M1 ) THEN
INFO = -5
ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
INFO = -7
ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
INFO = -9
ELSE IF( LDC.LT.MAX( 1, NP ) ) THEN
INFO = -11
ELSE IF( LDD.LT.MAX( 1, NP ) ) THEN
INFO = -13
ELSE IF( LDAK.LT.MAX( 1, N ) ) THEN
INFO = -15
ELSE IF( LDBK.LT.MAX( 1, N ) ) THEN
INFO = -17
ELSE IF( LDCK.LT.MAX( 1, M2 ) ) THEN
INFO = -19
ELSE IF( LDDK.LT.MAX( 1, M2 ) ) THEN
INFO = -21
ELSE IF( LDAC.LT.MAX( 1, N2 ) ) THEN
INFO = -23
ELSE IF( LDBC.LT.MAX( 1, N2 ) ) THEN
INFO = -25
ELSE IF( LDCC.LT.MAX( 1, NP1 ) ) THEN
INFO = -27
ELSE IF( LDDC.LT.MAX( 1, NP1 ) ) THEN
INFO = -29
ELSE
C
C Compute workspace.
C
MINWRK = 2*M*M + NP*NP + 2*M*N + M*NP + 2*N*NP
IF( LDWORK.LT.MINWRK )
$ INFO = -32
END IF
IF( INFO.NE.0 ) THEN
CALL XERBLA( 'SB10LD', -INFO )
RETURN
END IF
C
C Quick return if possible.
C
IF( N.EQ.0 .OR. M.EQ.0 .OR. NP.EQ.0 .OR. M1.EQ.0 .OR. M2.EQ.0
$ .OR. NP1.EQ.0 .OR. NP2.EQ.0 ) THEN
DWORK( 1 ) = ONE
RETURN
END IF
C
C Get the machine precision.
C
EPS = DLAMCH( 'Epsilon' )
C
C Workspace usage.
C
IW2 = NP2*NP2 + 1
IW3 = IW2 + M2*M2
IW4 = IW3 + NP2*N
IW5 = IW4 + M2*N
IW6 = IW5 + NP2*M1
IW7 = IW6 + M2*M1
IW8 = IW7 + M2*N
IWRK = IW8 + NP2*N
C
C Compute inv(Inp2 - D22*DK) .
C
CALL DLASET( 'Full', NP2, NP2, ZERO, ONE, DWORK, NP2 )
CALL DGEMM( 'N', 'N', NP2, NP2, M2, -ONE, D( NP1+1, M1+1 ),
$ LDD, DK, LDDK, ONE, DWORK, NP2 )
ANORM = DLANGE( '1', NP2, NP2, DWORK, NP2, DWORK( IWRK ) )
CALL DGETRF( NP2, NP2, DWORK, NP2, IWORK, INFO2 )
IF( INFO2.GT.0 ) THEN
INFO = 1
RETURN
END IF
CALL DGECON( '1', NP2, DWORK, NP2, ANORM, RCOND, DWORK( IWRK ),
$ IWORK( NP2+1 ), INFO )
LWAMAX = INT( DWORK( IWRK ) ) + IWRK - 1
C
C Return if the matrix is singular to working precision.
C
IF( RCOND.LT.EPS ) THEN
INFO = 1
RETURN
END IF
CALL DGETRI( NP2, DWORK, NP2, IWORK, DWORK( IWRK ), LDWORK-IWRK+1,
$ INFO2 )
LWAMAX = MAX( INT( DWORK( IWRK ) ) + IWRK - 1, LWAMAX )
C
C Compute inv(Im2 - DK*D22) .
C
CALL DLASET( 'Full', M2, M2, ZERO, ONE, DWORK( IW2 ), M2 )
CALL DGEMM( 'N', 'N', M2, M2, NP2, -ONE, DK, LDDK,
$ D( NP1+1, M1+1 ), LDD, ONE, DWORK( IW2 ), M2 )
ANORM = DLANGE( '1', M2, M2, DWORK( IW2 ), M2, DWORK( IWRK ) )
CALL DGETRF( M2, M2, DWORK( IW2 ), M2, IWORK, INFO2 )
IF( INFO2.GT.0 ) THEN
INFO = 2
RETURN
END IF
CALL DGECON( '1', M2, DWORK( IW2 ), M2, ANORM, RCOND,
$ DWORK( IWRK ), IWORK( M2+1 ), INFO )
LWAMAX = MAX( INT( DWORK( IWRK ) ) + IWRK - 1, LWAMAX )
C
C Return if the matrix is singular to working precision.
C
IF( RCOND.LT.EPS ) THEN
INFO = 2
RETURN
END IF
CALL DGETRI( M2, DWORK( IW2 ), M2, IWORK, DWORK( IWRK ),
$ LDWORK-IWRK+1, INFO2 )
LWAMAX = MAX( INT( DWORK( IWRK ) ) + IWRK - 1, LWAMAX )
C
C Compute inv(Inp2 - D22*DK)*C2 .
C
CALL DGEMM( 'N', 'N', NP2, N, NP2, ONE, DWORK, NP2, C( NP1+1, 1 ),
$ LDC, ZERO, DWORK( IW3 ), NP2 )
C
C Compute DK*inv(Inp2 - D22*DK)*C2 .
C
CALL DGEMM( 'N', 'N', M2, N, NP2, ONE, DK, LDDK, DWORK( IW3 ),
$ NP2, ZERO, DWORK( IW4 ), M2 )
C
C Compute inv(Inp2 - D22*DK)*D21 .
C
CALL DGEMM( 'N', 'N', NP2, M1, NP2, ONE, DWORK, NP2,
$ D( NP1+1, 1 ), LDD, ZERO, DWORK( IW5 ), NP2 )
C
C Compute DK*inv(Inp2 - D22*DK)*D21 .
C
CALL DGEMM( 'N', 'N', M2, M1, NP2, ONE, DK, LDDK, DWORK( IW5 ),
$ NP2, ZERO, DWORK( IW6 ), M2 )
C
C Compute inv(Im2 - DK*D22)*CK .
C
CALL DGEMM( 'N', 'N', M2, N, M2, ONE, DWORK( IW2 ), M2, CK, LDCK,
$ ZERO, DWORK( IW7 ), M2 )
C
C Compute D22*inv(Im2 - DK*D22)*CK .
C
CALL DGEMM( 'N', 'N', NP2, N, M2, ONE, D( NP1+1, M1+1 ), LDD,
$ DWORK( IW7 ), M2, ZERO, DWORK( IW8 ), NP2 )
C
C Compute AC .
C
CALL DLACPY( 'Full', N, N, A, LDA, AC, LDAC )
CALL DGEMM( 'N', 'N', N, N, M2, ONE, B( 1, M1+1 ), LDB,
$ DWORK( IW4 ), M2, ONE, AC, LDAC )
CALL DGEMM( 'N', 'N', N, N, M2, ONE, B( 1, M1+1 ), LDB,
$ DWORK( IW7 ), M2, ZERO, AC( 1, N+1 ), LDAC )
CALL DGEMM( 'N', 'N', N, N, NP2, ONE, BK, LDBK, DWORK( IW3 ), NP2,
$ ZERO, AC( N+1, 1 ), LDAC )
CALL DLACPY( 'Full', N, N, AK, LDAK, AC( N+1, N+1 ), LDAC )
CALL DGEMM( 'N', 'N', N, N, NP2, ONE, BK, LDBK, DWORK( IW8 ), NP2,
$ ONE, AC( N+1, N+1 ), LDAC )
C
C Compute BC .
C
CALL DLACPY( 'Full', N, M1, B, LDB, BC, LDBC )
CALL DGEMM( 'N', 'N', N, M1, M2, ONE, B( 1, M1+1 ), LDB,
$ DWORK( IW6 ), M2, ONE, BC, LDBC )
CALL DGEMM( 'N', 'N', N, M1, NP2, ONE, BK, LDBK, DWORK( IW5 ),
$ NP2, ZERO, BC( N+1, 1 ), LDBC )
C
C Compute CC .
C
CALL DLACPY( 'Full', NP1, N, C, LDC, CC, LDCC )
CALL DGEMM( 'N', 'N', NP1, N, M2, ONE, D( 1, M1+1 ), LDD,
$ DWORK( IW4 ), M2, ONE, CC, LDCC )
CALL DGEMM( 'N', 'N', NP1, N, M2, ONE, D( 1, M1+1 ), LDD,
$ DWORK( IW7 ), M2, ZERO, CC( 1, N+1 ), LDCC )
C
C Compute DC .
C
CALL DLACPY( 'Full', NP1, M1, D, LDD, DC, LDDC )
CALL DGEMM( 'N', 'N', NP1, M1, M2, ONE, D( 1, M1+1 ), LDD,
$ DWORK( IW6 ), M2, ONE, DC, LDDC )
C
RETURN
C *** Last line of SB10LD ***
END