Skip to content

Commit eb4e945

Browse files
author
olof3
committed
Added naive method for generic inputs.
1 parent 7781ff9 commit eb4e945

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

src/LyapTest.jl

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ end
8080
LinearAlgebra.schur(A::AbstractMatrix{T}) where T = schur!(LinearAlgebra.copy_oftype(A, LinearAlgebra.eigtype(T)))
8181

8282

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))
8485
sylvdsoltype(A, B, C) = Base.promote_op(sylvd, eltype(A), eltype(B), eltype(C))
8586

8687
"""
@@ -236,6 +237,10 @@ function lyapc(A, Q)
236237

237238
_check_lyap_inputs(A, Q)
238239

240+
if !hasmethod(schur!, (typeof(A),))
241+
return lyapc(A, Q, Val(:naive))
242+
end
243+
239244
At2, U = schur(A')
240245

241246
Q2 = U'*Q*U
@@ -244,6 +249,57 @@ function lyapc(A, Q)
244249

245250
X = mul!(Y, U, Y*U')
246251
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+
247303
"""
248304
X = lyapd(A, Q) -> X
249305
@@ -316,6 +372,10 @@ function _sylvc_schur!(A::Matrix, B::Matrix, C::Matrix, alg::Union{Val{:sylv},Va
316372

317373
@inbounds for j=1:nblocksb
318374
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+
319379
for i=i0:nblocksa
320380
if schurtype === Val(:complex)
321381
if i > 1; C[i,j] -= sum(A[i, k] * C[k, j] for k=1:i-1); end

test/test_matrix_equations.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ Cherm = [1.0 2+im; 2-im 1]
7676
@test LyapTest.lyapd(A, C) sylvd_diag(a, a, -C)
7777
@test LyapTest.lyapd(Ac, Cherm) sylvd_diag(ac, conj(ac), -Cherm)
7878

79+
# A few tests for the naive version, should have more
80+
@test LyapTest.sylvc(A, B, C, Val(:naive)) sylvc_diag(a, a, -C)
81+
@test LyapTest.lyapc(A, C, Val(:naive)) sylvc_diag(a, a, -C)
7982

8083

8184

0 commit comments

Comments
 (0)