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. Also note that no balancing
is performed.
24% For solving generalised Sylvestter equations of the form
25% A*X*B^T + C*X*D^T = E
26% see bartelsStewart.m.
28% When solving for multiple righthand sides or with various constant diagonal
29% shifts in A and/or B, it can be beneficial to precompute the Schur
30% factorizations. In particular, V = lyap(A, C) can be computed as
32% [U, T] = schur(A, 'complex');
33% V = U * lyap(T, U'*C*U) * U';
35% and V = lyap(A, B, C) as
37% [UA, TA] = schur(A, 'complex');
38% [UB, TB] = schur(B, 'complex');
39% V = UA * lyap(TA, TB, UA'*C*UB) * UB';
41% See also SCHUR, BARTELSSTEWART.
43% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
50 if ( isreal(A) && isreal(B) )
57 if ( isreal(A) && isreal(B) && isreal(C) )
62 % A*X*E' + E*X*A' + B = 0
63% X = bartelsStewart(A, E, E, A, -B);
64 X = bartelsStewart(A, E, [], [], -B);
65 if ( isreal(A) && isreal(B) && isreal(E) )
73function X = sylv(A, B, C)
74%SYLV Solve Sylvester matrix equation.
75% SYLV(A, B, C) solves the Sylvester matrix equation
77% SYLV(A, [], C) solves the Lyapunov matrix equation
80% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
85% Compute Schur factorizations. TA will be upper triangular. TB will be upper or
86% lower. If TB
is upper triangular then we backward solve; if it's lower
87% triangular then do forward solve.
88[ZA, TA] = schur(A, 'complex');
89if ( isempty(B) || isequal(A, B') ) % <-- Should we check for isequal here?
90 ZB = ZA; % (Since user _should_ have passed B = [].)
93 solve_direction = 'backward';
94elseif ( isequal(A, B.') ) % <-- We _should_ here as no way to specify.
97 solve_direction = 'backward';
99 % We must also compute the schur factorization of B and forward solve;
100 [ZB, TB] = schur(B, 'complex');
101 solve_direction = 'forward';
104% Transform the righthand side.
107% Symmetric case
is trivial!
108if ( isdiag(TA) && isdiag(TB) )
109 L = -1./(diag(TA) + diag(TB).');
114% Initialise storage for transformed solution.
117% Diagonal mask (for speed in shifted solves):
118idx = diag(true(m, 1));
121% Forwards or backwards?
122if ( strcmp(solve_direction, 'backward') )
128% Do a backwards/forwards substitution to construct the transformed solution.
130 rhs = F(:,k) + Y*TB(:,k); % <-- More efficient multiplication.
131 % Find the kth column of the transformed solution.
132 TA(idx) = p + TB(k,k); % <-- Diagonal shift. More efficient this way.
133 Y(:,k) = TA \ (-rhs);
136% Transform solution back: