LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
lyap.m
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
7% more flexible.
8%
9% X = LYAP(A,Q) solves the Lyapunov matrix equation:
10%
11% A*X + X*A' + Q = 0
12%
13% X = LYAP(A,B,C) solves the Sylvester equation:
14%
15% A*X + X*B + C = 0
16%
17% X = LYAP(A,Q,[],E) solves the generalized Lyapunov equation:
18%
19% A*X*E' + E*X*A' + Q = 0.
20%
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.
24%
25% For solving generalised Sylvestter equations of the form
26% A*X*B^T + C*X*D^T = E
27% see bartelsStewart.m.
28%
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
32%
33% [U, T] = schur(A, 'complex');
34% V = U * lyap(T, U'*C*U) * U';
35%
36% and V = lyap(A, B, C) as
37%
38% [UA, TA] = schur(A, 'complex');
39% [UB, TB] = schur(B, 'complex');
40% V = UA * lyap(TA, TB, UA'*C*UB) * UB';
41%
42% See also SCHUR, BARTELSSTEWART.
43
44% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
45
46if ( nargin == 2 )
47 % A*X + X*A' + B = 0
48 % Balance A for improved numerical stability
49 [T, Ab] = balance(A);
50 Bb = T \ (B / T); % T^{-1} * B * T^{-1}
51 Xb = sylv(Ab, [], Bb);
52 X = T * Xb * T;
53 if ( isreal(A) && isreal(B) )
54 X = real(X);
55 end
56
57elseif ( nargin == 3 )
58 % A*X + X*B + C = 0
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) )
66 X = real(X);
67 end
68
69else
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) )
74 X = real(X);
75 end
76
77end
78
79end
80
81function X = sylv(A, B, C)
82%SYLV Solve Sylvester matrix equation.
83% SYLV(A, B, C) solves the Sylvester matrix equation
84% A*X + X*B + C = 0.
85% SYLV(A, [], C) solves the Lyapunov matrix equation
86% A*X + X*A' + C = 0.
87
88% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
89
90% Get sizes:
91[m, n] = size(C);
92
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 = [].)
99 TB = TA';
100 n = size(A, 2);
101 solve_direction = 'backward';
102elseif ( isequal(A, B.') ) % <-- We _should_ here as no way to specify.
103 ZB = conj(ZA);
104 TB = TA.';
105 solve_direction = 'backward';
106else
107 % We must also compute the schur factorization of B and forward solve;
108 [ZB, TB] = schur(B, 'complex');
109 solve_direction = 'forward';
110end
111
112% Transform the righthand side.
113F = ZA' * C * ZB;
114
115% Symmetric case is trivial!
116if ( isdiag(TA) && isdiag(TB) )
117 L = -1./(diag(TA) + diag(TB).');
118 X = ZA*(L.*F)*ZB';
119 return
120end
121
122% Initialise storage for transformed solution.
123Y = zeros(m, n);
124
125% Diagonal mask (for speed in shifted solves):
126idx = diag(true(m, 1));
127p = diag(TA);
128
129% Forwards or backwards?
130if ( strcmp(solve_direction, 'backward') )
131 kk = n:-1:1;
132else
133 kk = 1:n;
134end
135
136% Do a backwards/forwards substitution to construct the transformed solution.
137for k = kk
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);
142end
143
144% Transform solution back:
145X = ZA * Y * ZB';
146
147end