@@ -276,7 +276,7 @@ function tzeros(A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, D::Abst
276276 tzeros (A2, B2, C2, D2)
277277end
278278
279- function tzeros (A:: AbstractMatrix{T} , B:: AbstractMatrix{T} , C:: AbstractMatrix{T} , D:: AbstractMatrix{T} ; extra:: Val{E} = Val {false} (), balance= true , kwargs... ) where {T <: BlasFloat , E}
279+ function tzeros (A:: AbstractMatrix{T} , B:: AbstractMatrix{T} , C:: AbstractMatrix{T} , D:: AbstractMatrix{T} ; extra:: Val{E} = Val {false} (), balance= true , kwargs... ) where {T, E}
280280 if balance
281281 A, B, C = balance_statespace (A, B, C)
282282 end
@@ -289,110 +289,110 @@ function tzeros(A::AbstractMatrix{T}, B::AbstractMatrix{T}, C::AbstractMatrix{T}
289289 end
290290end
291291
292- function tzeros (A:: AbstractMatrix{T} , B:: AbstractMatrix{T} , C:: AbstractMatrix{T} , D:: AbstractMatrix{T} ; extra:: Val{E} = Val {false} (), kwargs... ) where {T <: Union{AbstractFloat,Complex{<:AbstractFloat}} , E}
293- isempty (A) && return complex (T)[]
294-
295- # Balance the system
296- A, B, C = balance_statespace (A, B, C; verbose= false )
297-
298- # Compute a good tolerance
299- meps = 10 * eps (real (T))* norm ([A B; C D])
300-
301- # Step 1:
302- A_r, B_r, C_r, D_r = reduce_sys (A, B, C, D, meps)
303-
304- # Step 2: (conjugate transpose should be avoided since single complex zeros get conjugated)
305- A_rc, B_rc, C_rc, D_rc = reduce_sys (copy (transpose (A_r)), copy (transpose (C_r)), copy (transpose (B_r)), copy (transpose (D_r)), meps)
306-
307- # Step 3:
308- # Compress cols of [C D] to [0 Df]
309- mat = [C_rc D_rc]
310- Wr = qr (mat' ). Q * I
311- W = reverse (Wr, dims= 2 )
312- mat = mat* W
313- if fastrank (mat' , meps) > 0
314- nf = size (A_rc, 1 )
315- m = size (D_rc, 2 )
316- Af = ([A_rc B_rc] * W)[1 : nf, 1 : nf]
317- Bf = ([Matrix {T} (I, nf, nf) zeros (nf, m)] * W)[1 : nf, 1 : nf]
318- Z = schur (complex .(Af), complex .(Bf)) # Schur instead of eigvals to handle BigFloat
319- zs = Z. values
320- ControlSystemsBase. _fix_conjugate_pairs! (zs) # Generalized eigvals does not return exact conj. pairs
321- else
322- zs = complex (T)[]
323- end
324- return zs
325- end
326-
327- """
328- reduce_sys(A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, D::AbstractMatrix, meps::AbstractFloat)
329- Implements REDUCE in the Emami-Naeini & Van Dooren paper. Returns transformed
330- A, B, C, D matrices. These are empty if there are no zeros.
331- """
332- function reduce_sys (A:: AbstractMatrix , B:: AbstractMatrix , C:: AbstractMatrix , D:: AbstractMatrix , meps:: AbstractFloat )
333- T = promote_type (eltype (A), eltype (B), eltype (C), eltype (D))
334- Cbar, Dbar = C, D
335- if isempty (A)
336- return A, B, C, D
337- end
338- while true
339- # Compress rows of D
340- U = qr (D). Q
341- D = U' D
342- C = U' C
343- sigma = fastrank (D, meps)
344- Cbar = C[1 : sigma, :]
345- Dbar = D[1 : sigma, :]
346- Ctilde = C[(1 + sigma): end , :]
347- if sigma == size (D, 1 )
348- break
349- end
350-
351- # Compress columns of Ctilde
352- V = reverse (qr (Ctilde' ). Q * I, dims= 2 )
353- Sj = Ctilde* V
354- rho = fastrank (Sj' , meps)
355- nu = size (Sj, 2 ) - rho
356-
357- if rho == 0
358- break
359- elseif nu == 0
360- # System has no zeros, return empty matrices
361- A = B = Cbar = Dbar = Matrix {T} (undef, 0 ,0 )
362- break
363- end
364- # Update System
365- n, m = size (B)
366- Vm = [V zeros (T, n, m); zeros (T, m, n) Matrix {T} (I, m, m)] # I(m) is not used for type stability reasons (as of julia v1.7)
367- if sigma > 0
368- M = [A B; Cbar Dbar]
369- Vs = [copy (V' ) zeros (T, n, sigma) ; zeros (T, sigma, n) Matrix {T} (I, sigma, sigma)]
370- else
371- M = [A B]
372- Vs = copy (V' )
373- end
374- sigma, rho, nu
375- M = Vs * M * Vm
376- A = M[1 : nu, 1 : nu]
377- B = M[1 : nu, (nu + rho + 1 ): end ]
378- C = M[(nu + 1 ): end , 1 : nu]
379- D = M[(nu + 1 ): end , (nu + rho + 1 ): end ]
380- end
381- return A, B, Cbar, Dbar
382- end
383-
384- # Determine the number of non-zero rows, with meps as a tolerance. For an
385- # upper-triangular matrix, this is a good proxy for determining the row-rank.
386- function fastrank (A:: AbstractMatrix , meps:: Real )
387- n, m = size (A)
388- if n* m == 0 return 0 end
389- norms = Vector {real(eltype(A))} (undef, n)
390- for i = 1 : n
391- norms[i] = norm (A[i, :])
392- end
393- mrank = sum (norms .> meps)
394- return mrank
395- end
292+ # function tzeros(A::AbstractMatrix{T}, B::AbstractMatrix{T}, C::AbstractMatrix{T}, D::AbstractMatrix{T}; extra::Val{E} = Val{false}(), kwargs...) where {T <: Union{AbstractFloat,Complex{<:AbstractFloat}}, E}
293+ # isempty(A) && return complex(T)[]
294+
295+ # # Balance the system
296+ # A, B, C = balance_statespace(A, B, C; verbose=false)
297+
298+ # # Compute a good tolerance
299+ # meps = 10*eps(real(T))*norm([A B; C D])
300+
301+ # # Step 1:
302+ # A_r, B_r, C_r, D_r = reduce_sys(A, B, C, D, meps)
303+
304+ # # Step 2: (conjugate transpose should be avoided since single complex zeros get conjugated)
305+ # A_rc, B_rc, C_rc, D_rc = reduce_sys(copy(transpose(A_r)), copy(transpose(C_r)), copy(transpose(B_r)), copy(transpose(D_r)), meps)
306+
307+ # # Step 3:
308+ # # Compress cols of [C D] to [0 Df]
309+ # mat = [C_rc D_rc]
310+ # Wr = qr(mat').Q * I
311+ # W = reverse(Wr, dims=2)
312+ # mat = mat*W
313+ # if fastrank(mat', meps) > 0
314+ # nf = size(A_rc, 1)
315+ # m = size(D_rc, 2)
316+ # Af = ([A_rc B_rc] * W)[1:nf, 1:nf]
317+ # Bf = ([Matrix{T}(I, nf, nf) zeros(nf, m)] * W)[1:nf, 1:nf]
318+ # Z = schur(complex.(Af), complex.(Bf)) # Schur instead of eigvals to handle BigFloat
319+ # zs = Z.values
320+ # ControlSystemsBase._fix_conjugate_pairs!(zs) # Generalized eigvals does not return exact conj. pairs
321+ # else
322+ # zs = complex(T)[]
323+ # end
324+ # return zs
325+ # end
326+
327+ # """
328+ # reduce_sys(A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, D::AbstractMatrix, meps::AbstractFloat)
329+ # Implements REDUCE in the Emami-Naeini & Van Dooren paper. Returns transformed
330+ # A, B, C, D matrices. These are empty if there are no zeros.
331+ # """
332+ # function reduce_sys(A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, D::AbstractMatrix, meps::AbstractFloat)
333+ # T = promote_type(eltype(A), eltype(B), eltype(C), eltype(D))
334+ # Cbar, Dbar = C, D
335+ # if isempty(A)
336+ # return A, B, C, D
337+ # end
338+ # while true
339+ # # Compress rows of D
340+ # U = qr(D).Q
341+ # D = U'D
342+ # C = U'C
343+ # sigma = fastrank(D, meps)
344+ # Cbar = C[1:sigma, :]
345+ # Dbar = D[1:sigma, :]
346+ # Ctilde = C[(1 + sigma):end, :]
347+ # if sigma == size(D, 1)
348+ # break
349+ # end
350+
351+ # # Compress columns of Ctilde
352+ # V = reverse(qr(Ctilde').Q * I, dims=2)
353+ # Sj = Ctilde*V
354+ # rho = fastrank(Sj', meps)
355+ # nu = size(Sj, 2) - rho
356+
357+ # if rho == 0
358+ # break
359+ # elseif nu == 0
360+ # # System has no zeros, return empty matrices
361+ # A = B = Cbar = Dbar = Matrix{T}(undef, 0,0)
362+ # break
363+ # end
364+ # # Update System
365+ # n, m = size(B)
366+ # Vm = [V zeros(T, n, m); zeros(T, m, n) Matrix{T}(I, m, m)] # I(m) is not used for type stability reasons (as of julia v1.7)
367+ # if sigma > 0
368+ # M = [A B; Cbar Dbar]
369+ # Vs = [copy(V') zeros(T, n, sigma) ; zeros(T, sigma, n) Matrix{T}(I, sigma, sigma)]
370+ # else
371+ # M = [A B]
372+ # Vs = copy(V')
373+ # end
374+ # sigma, rho, nu
375+ # M = Vs * M * Vm
376+ # A = M[1:nu, 1:nu]
377+ # B = M[1:nu, (nu + rho + 1):end]
378+ # C = M[(nu + 1):end, 1:nu]
379+ # D = M[(nu + 1):end, (nu + rho + 1):end]
380+ # end
381+ # return A, B, Cbar, Dbar
382+ # end
383+
384+ # # Determine the number of non-zero rows, with meps as a tolerance. For an
385+ # # upper-triangular matrix, this is a good proxy for determining the row-rank.
386+ # function fastrank(A::AbstractMatrix, meps::Real)
387+ # n, m = size(A)
388+ # if n*m == 0 return 0 end
389+ # norms = Vector{real(eltype(A))}(undef, n)
390+ # for i = 1:n
391+ # norms[i] = norm(A[i, :])
392+ # end
393+ # mrank = sum(norms .> meps)
394+ # return mrank
395+ # end
396396
397397"""
398398 relative_gain_array(G, w::AbstractVector)
0 commit comments