80
80
LinearAlgebra. schur (A:: AbstractMatrix{T} ) where T = schur! (LinearAlgebra. copy_oftype (A, LinearAlgebra. eigtype (T)))
81
81
82
82
83
- sylvcsoltype (A, B, C) = Base. promote_op (sylvc, eltype (A), eltype (B), eltype (C))
83
+ sylvcsoltype (A, B, C) = Base. promote_op ((a,b,c) -> c / (a + b), eltype (A), eltype (B), eltype (C))
84
+ # sylvcsoltype(A, B, C) = Base.promote_op(sylvc, eltype(A), eltype(B), eltype(C))
84
85
sylvdsoltype (A, B, C) = Base. promote_op (sylvd, eltype (A), eltype (B), eltype (C))
85
86
86
87
"""
@@ -236,6 +237,10 @@ function lyapc(A, Q)
236
237
237
238
_check_lyap_inputs (A, Q)
238
239
240
+ if ! hasmethod (schur!, (typeof (A),))
241
+ return lyapc (A, Q, Val (:naive ))
242
+ end
243
+
239
244
At2, U = schur (A' )
240
245
241
246
Q2 = U' * Q* U
@@ -244,6 +249,57 @@ function lyapc(A, Q)
244
249
245
250
X = mul! (Y, U, Y* U' )
246
251
end
252
+
253
+
254
+ function sylvc (A, B, C, :: Val{:naive} )
255
+ Xv = kron (I (size (B,1 )), A) + kron (transpose (B), I (size (A,1 ))) \ C[:]
256
+ return reshape (Xv, size (C))
257
+ end
258
+
259
+ # Mapping from Cartesian index into vector represenentation of Symmetric matrix
260
+ @inline sub2triidx (i,j) = (j >= i ? (j* (j- 1 ))>>> 1 + i : (i* (i- 1 ))>>> 1 + j)
261
+
262
+ function lyapc (A, Q, :: Val{:naive} ) # Only works for real matrices A
263
+ # Sets up and solves a system of equations for the upper triangular part of X
264
+ # and solves that equation. This gives an n(n+1)/2 system instead of n^2
265
+ # ONLY WORKS FOR REAL A!
266
+ # Should be able to to base the discrete time version on this as well
267
+ _check_lyap_inputs (A, Q)
268
+
269
+ if ! isreal (A); error (" Only works for real A matrices" ); end # Should call sylvc
270
+
271
+ n = size (Q, 1 )
272
+ nR = (n* (n+ 1 )) >>> 1 # Ssize of the system to be solved
273
+
274
+ R = zeros (eltype (A), nR, nR)
275
+ minusQv = Vector {eltype(Q)} (undef, nR)
276
+
277
+ for j= 1 : n
278
+ for i= 1 : j
279
+ m = sub2triidx (i,j) # Set up equation for X[i,j]
280
+ minusQv[m] = - Q[i,j]
281
+ # (AX + XA')[i,j] = sum(A[i,k]*X[k,j]) + sum(X[i,k]*A'[k,j])
282
+ # the r = trinum[i]+r gives the kth element in the upper traingle
283
+ # which correpsonds to X[i,j]
284
+ for k= 1 : n
285
+ R[m, sub2triidx (k,j)] += A[i,k]
286
+ R[m, sub2triidx (i,k)] += A[j,k]
287
+ end
288
+ end
289
+ end
290
+
291
+ Xv = R \ minusQv
292
+
293
+ # Fill the upper traingle of X from Xv
294
+ X = [Xv[sub2triidx (i,j)] for i= 1 : n, j= 1 : n]
295
+
296
+ return X
297
+ end
298
+
299
+
300
+
301
+
302
+
247
303
"""
248
304
X = lyapd(A, Q) -> X
249
305
@@ -316,6 +372,10 @@ function _sylvc_schur!(A::Matrix, B::Matrix, C::Matrix, alg::Union{Val{:sylv},Va
316
372
317
373
@inbounds for j= 1 : nblocksb
318
374
i0 = (alg === Val (:lyap ) ? j : 1 )
375
+
376
+ # if j > 1; mul!(C[i0:nblocksa,j], C[i0:nblocksa, 1:j-1], B[1:j-1, j], 1, -1); end # Could move this out?
377
+ # figure out the row indexing
378
+
319
379
for i= i0: nblocksa
320
380
if schurtype === Val (:complex )
321
381
if i > 1 ; C[i,j] -= sum (A[i, k] * C[k, j] for k= 1 : i- 1 ); end
0 commit comments