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. Also note that no balancing is performed.
23%
24% For solving generalised Sylvestter equations of the form
25% A*X*B^T + C*X*D^T = E
26% see bartelsStewart.m.
27%
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
31%
32% [U, T] = schur(A, 'complex');
33% V = U * lyap(T, U'*C*U) * U';
34%
35% and V = lyap(A, B, C) as
36%
37% [UA, TA] = schur(A, 'complex');
38% [UB, TB] = schur(B, 'complex');
39% V = UA * lyap(TA, TB, UA'*C*UB) * UB';
40%
41% See also SCHUR, BARTELSSTEWART.
42
43% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
44
45% TODO: Balancing?
46
47if ( nargin == 2 )
48 % A*X + X*A' + B = 0
49 X = sylv(A, [], B);
50 if ( isreal(A) && isreal(B) )
51 X = real(X);
52 end
53
54elseif ( nargin == 3 )
55 % A*X + X*B + C = 0
56 X = sylv(A, B, C);
57 if ( isreal(A) && isreal(B) && isreal(C) )
58 X = real(X);
59 end
60
61else
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) )
66 X = real(X);
67 end
68
69end
70
71end
72
73function X = sylv(A, B, C)
74%SYLV Solve Sylvester matrix equation.
75% SYLV(A, B, C) solves the Sylvester matrix equation
76% A*X + X*B + C = 0.
77% SYLV(A, [], C) solves the Lyapunov matrix equation
78% A*X + X*A' + C = 0.
79
80% Nick Hale, Nov 2014. (nick.p.hale@gmail.com)
81
82% Get sizes:
83[m, n] = size(C);
84
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 = [].)
91 TB = TA';
92 n = size(A, 2);
93 solve_direction = 'backward';
94elseif ( isequal(A, B.') ) % <-- We _should_ here as no way to specify.
95 ZB = conj(ZA);
96 TB = TA.';
97 solve_direction = 'backward';
98else
99 % We must also compute the schur factorization of B and forward solve;
100 [ZB, TB] = schur(B, 'complex');
101 solve_direction = 'forward';
102end
103
104% Transform the righthand side.
105F = ZA' * C * ZB;
106
107% Symmetric case is trivial!
108if ( isdiag(TA) && isdiag(TB) )
109 L = -1./(diag(TA) + diag(TB).');
110 X = ZA*(L.*F)*ZB';
111 return
112end
113
114% Initialise storage for transformed solution.
115Y = zeros(m, n);
116
117% Diagonal mask (for speed in shifted solves):
118idx = diag(true(m, 1));
119p = diag(TA);
120
121% Forwards or backwards?
122if ( strcmp(solve_direction, 'backward') )
123 kk = n:-1:1;
124else
125 kk = 1:n;
126end
127
128% Do a backwards/forwards substitution to construct the transformed solution.
129for k = kk
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);
134end
135
136% Transform solution back:
137X = ZA * Y * ZB';
138
139end