1function X = lyap(A, B, C, E)
2%LYAP Solve continuous-time Lyapunov equations.
3% LYAP() aims to mirror the functionality and syntax of the LYAP() function in
4% the MATLAB Control Toolbox. It
is written entirely in MATLAB and so
is a
5% little slower than the implementation in the Control Toobox (which
is
6% essentially a wrapper for LAPACK/SLICOT routines). However it
is a little
9% X = LYAP(A,Q) solves the Lyapunov matrix equation:
13% X = LYAP(A,B,C) solves the Sylvester equation:
17% X = LYAP(A,Q,[],E) solves the generalized Lyapunov equation:
19% A*X*E' + E*X*A' + Q = 0.
21% Note that unlike the built-in MATLAB LYAP() routine there
is no need for Q
22% to be symmetric in the final case. Balancing
is performed for the standard
23% and Sylvester cases using MATLAB's BALANCE to improve numerical stability.
25% For solving generalised Sylvestter equations of the form
26% A*X*B^T + C*X*D^T = E
27% see bartelsStewart.m.
29% When solving for multiple righthand sides or with various constant diagonal
30% shifts in A and/or B, it can be beneficial to precompute the Schur
31% factorizations. In particular, V = lyap(A, C) can be computed as
33% [U, T] = schur(A, 'complex');
34% V = U * lyap(T, U'*C*U) * U';
36% and V = lyap(A, B, C) as
38% [UA, TA] = schur(A, 'complex');
39% [UB, TB] = schur(B, 'complex');
40% V = UA * lyap(TA, TB, UA'*C*UB) * UB';
42% See also SCHUR, BARTELSSTEWART.
44% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
48 % Balance A for improved numerical stability
50 Bb = T \ (B / T); % T^{-1} * B * T^{-1}
51 Xb = sylv(Ab, [], Bb);
53 if ( isreal(A) && isreal(B) )
59 % Balance A and B
for improved numerical stability
60 [TA, Ab] = balance(A);
61 [TB, Bb] = balance(B);
62 Cb = TA \ C * TB; % TA^{-1} * C * TB
63 Xb = sylv(Ab, Bb, Cb);
64 X = TA * Xb / TB; % TA * Xb * TB^{-1}
65 if ( isreal(A) && isreal(B) && isreal(C) )
70 % A*X*E
' + E*X*A' + B = 0
71 % Generalized
case: balancing deferred to bartelsStewart
72 X = bartelsStewart(A, E, [], [], -B);
73 if ( isreal(A) && isreal(B) && isreal(E) )
81function X = sylv(A, B, C)
82%SYLV Solve Sylvester matrix equation.
83% SYLV(A, B, C) solves the Sylvester matrix equation
85% SYLV(A, [], C) solves the Lyapunov matrix equation
88% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
93% Compute Schur factorizations. TA will be upper triangular. TB will be upper or
94% lower. If TB is upper triangular then we backward solve; if it's lower
95% triangular then
do forward solve.
96[ZA, TA] = schur(A,
'complex');
97if ( isempty(B) || isequal(A, B
') ) % <-- Should we check for isequal here?
98 ZB = ZA; % (Since user _should_ have passed B = [].)
101 solve_direction =
'backward';
102elseif ( isequal(A, B.
') ) % <-- We _should_ here as no way to specify.
105 solve_direction =
'backward';
107 % We must also compute the schur factorization of B and forward solve;
108 [ZB, TB] = schur(B,
'complex');
109 solve_direction =
'forward';
112% Transform the righthand side.
115% Symmetric case is trivial!
116if ( isdiag(TA) && isdiag(TB) )
117 L = -1./(diag(TA) + diag(TB).');
122% Initialise storage for transformed solution.
125% Diagonal mask (for speed in shifted solves):
126idx = diag(true(m, 1));
129% Forwards or backwards?
130if ( strcmp(solve_direction, 'backward
') )
136% Do a backwards/forwards substitution to construct the transformed solution.
138 rhs = F(:,k) + Y*TB(:,k); % <-- More efficient multiplication.
139 % Find the kth column of the transformed solution.
140 TA(idx) = p + TB(k,k); % <-- Diagonal shift. More efficient this way.
141 Y(:,k) = TA \ (-rhs);
144% Transform solution back: