Skip to content

Commit d58be46

Browse files
authored
Merge pull request #727 from JuliaControl/timeout
reduce allocations and compile time in feedback
2 parents 2407165 + eeaa657 commit d58be46

File tree

2 files changed

+58
-32
lines changed

2 files changed

+58
-32
lines changed

src/connections.jl

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ See also `lft`, `starprod`, `sensitivity`, `input_sensitivity`, `output_sensitiv
308308
309309
See Zhou, Doyle, Glover (1996) for similar (somewhat less symmetric) formulas.
310310
"""
311-
@views function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace;
311+
function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace;
312312
U1=:, Y1=:, U2=:, Y2=:, W1=:, Z1=:, W2=Int[], Z2=Int[],
313313
Wperm=:, Zperm=:, pos_feedback::Bool=false)
314314

@@ -328,34 +328,54 @@ See Zhou, Doyle, Glover (1996) for similar (somewhat less symmetric) formulas.
328328

329329
α = pos_feedback ? 1 : -1 # The sign of feedback
330330

331-
s1_B1 = sys1.B[:,W1]
332-
s1_B2 = sys1.B[:,U1]
333-
s1_C1 = sys1.C[Z1,:]
334-
s1_C2 = sys1.C[Y1,:]
331+
@views begin
332+
s1_B2 = U1 isa Colon ? sys1.B : sys1.B[:,U1]
333+
s1_C2 = Y1 isa Colon ? sys1.C : sys1.C[Y1,:]
334+
s1_D12 = Z1 isa Colon && U1 isa Colon ? sys1.D : sys1.D[Z1,U1]
335+
s1_D21 = Y1 isa Colon && W1 isa Colon ? sys1.D : sys1.D[Y1,W1]
336+
s1_D22 = Y1 isa Colon && U1 isa Colon ? sys1.D : sys1.D[Y1,U1]
337+
338+
s2_B2 = sys2.B[:,U2]
339+
s2_C2 = sys2.C[Y2,:]
340+
s2_D22 = sys2.D[Y2,U2]
341+
end
342+
# These are deliberate copies instead of views for two reasons.
343+
# 1) Many of them are overwritten in-place below
344+
# 2) Some that are not overwritten are still copied since it greatly reduces compile time. These are the ones that are by default indexed by an empty array (W2/Z2), implying that the copy will be an empty array as well.
335345
s1_D11 = sys1.D[Z1,W1]
336-
s1_D12 = sys1.D[Z1,U1]
337-
s1_D21 = sys1.D[Y1,W1]
338-
s1_D22 = sys1.D[Y1,U1]
339-
346+
s1_C1 = sys1.C[Z1,:]
347+
s1_B1 = sys1.B[:,W1]
340348
s2_B1 = sys2.B[:,W2]
341-
s2_B2 = sys2.B[:,U2]
342349
s2_C1 = sys2.C[Z2,:]
343-
s2_C2 = sys2.C[Y2,:]
344350
s2_D11 = sys2.D[Z2,W2]
345-
s2_D12 = sys2.D[Z2,U2]
346351
s2_D21 = sys2.D[Y2,W2]
347-
s2_D22 = sys2.D[Y2,U2]
352+
s2_D12 = sys2.D[Z2,U2]
353+
354+
αs2_D12 = α*s2_D12
355+
s2_D22s1_C2 = s2_D22*s1_C2
356+
αs2_B2 = α*s2_B2
357+
s1_D22s2_C2 = s1_D22*s2_C2
358+
s1_D22s2_D21 = s1_D22*s2_D21
348359

349360
if iszero(s1_D22) || iszero(s2_D22)
350-
A = [sys1.A + α*s1_B2*s2_D22*s1_C2 α*s1_B2*s2_C2;
351-
s2_B2*s1_C2 sys2.A + α*s2_B2*s1_D22*s2_C2]
352-
353-
B = [s1_B1 + α*s1_B2*s2_D22*s1_D21 α*s1_B2*s2_D21;
354-
s2_B2*s1_D21 s2_B1 + α*s2_B2*s1_D22*s2_D21]
355-
C = [s1_C1 + α*s1_D12*s2_D22*s1_C2 α*s1_D12*s2_C2;
356-
s2_D12*s1_C2 s2_C1 + α*s2_D12*s1_D22*s2_C2]
357-
D = [s1_D11 + α*s1_D12*s2_D22*s1_D21 α*s1_D12*s2_D21;
358-
s2_D12*s1_D21 s2_D11 + α*s2_D12*s1_D22*s2_D21]
361+
αs1_D12 = α*s1_D12
362+
A11 = mul!(copy(sys1.A), s1_B2, s2_D22s1_C2, α, 1)
363+
A22 = mul!(copy(sys2.A), αs2_B2, s1_D22s2_C2, 1, 1)
364+
C11 = mul!(s1_C1, αs1_D12, s2_D22s1_C2, 1, 1)
365+
C22 = mul!(s2_C1, αs2_D12, s1_D22s2_C2, 1, 1)
366+
B11 = mul!(s1_B1, s1_B2, s2_D22*s1_D21, α, 1)
367+
B22 = mul!(s2_B1, αs2_B2, s1_D22s2_D21, 1, 1)
368+
D22 = mul!(s2_D11, αs2_D12, s1_D22s2_D21, 1, 1)
369+
D11 = mul!(s1_D11, αs1_D12, s2_D22*s1_D21, 1, 1)
370+
A = [A11 ((s1_B2*s2_C2) .*= α);
371+
s2_B2*s1_C2 A22]
372+
373+
B = [B11 ((s1_B2*s2_D21) .*= α);
374+
s2_B2*s1_D21 B22]
375+
C = [C11 αs1_D12*s2_C2;
376+
s2_D12*s1_C2 C22]
377+
D = [D11 αs1_D12*s2_D21;
378+
s2_D12*s1_D21 D22]
359379
else
360380
# inv seems to be better than lu
361381
R1 = try
@@ -370,15 +390,21 @@ See Zhou, Doyle, Glover (1996) for similar (somewhat less symmetric) formulas.
370390
error("Ill-posed feedback interconnection, I - α*s2_D22*s1_D22 or I - α*s2_D22*s1_D22 not invertible")
371391
end
372392

373-
A = [sys1.A + s1_B2*R1*s2_D22*s1_C2 s1_B2*R1*s2_C2;
374-
s2_B2*R2*s1_C2 sys2.A + α*s2_B2*R2*s1_D22*s2_C2]
375-
376-
B = [s1_B1 + s1_B2*R1*s2_D22*s1_D21 s1_B2*R1*s2_D21;
377-
s2_B2*R2*s1_D21 s2_B1 + α*s2_B2*R2*s1_D22*s2_D21]
378-
C = [s1_C1 + s1_D12*R1*s2_D22*s1_C2 s1_D12*R1*s2_C2;
379-
s2_D12*R2*s1_C2 s2_C1 + α*s2_D12*R2*s1_D22*s2_C2]
380-
D = [s1_D11 + s1_D12*R1*s2_D22*s1_D21 s1_D12*R1*s2_D21;
381-
s2_D12*R2*s1_D21 s2_D11 + α*s2_D12*R2*s1_D22*s2_D21]
393+
s2_B2R2 = s2_B2*R2
394+
s1_D12R1 = s1_D12*R1
395+
s1_B2R1 = s1_B2*R1
396+
s2_D22s1_D21 = s2_D22*s1_D21
397+
αs2_D12R2 = αs2_D12*R2
398+
αs2_B2R2 = α*s2_B2R2
399+
A = [sys1.A + s1_B2R1*s2_D22s1_C2 s1_B2R1*s2_C2;
400+
s2_B2R2*s1_C2 sys2.A + αs2_B2R2*s1_D22s2_C2]
401+
402+
B = [s1_B1 + s1_B2R1*s2_D22s1_D21 s1_B2R1*s2_D21;
403+
s2_B2R2*s1_D21 s2_B1 + αs2_B2R2*s1_D22s2_D21]
404+
C = [s1_C1 + s1_D12R1*s2_D22s1_C2 s1_D12R1*s2_C2;
405+
s2_D12*R2*s1_C2 s2_C1 + αs2_D12R2*s1_D22s2_C2]
406+
D = [s1_D11 + s1_D12R1*s2_D22s1_D21 s1_D12R1*s2_D21;
407+
s2_D12*R2*s1_D21 s2_D11 + αs2_D12R2*s1_D22s2_D21]
382408
end
383409

384410
return StateSpace(A, B[:, Wperm], C[Zperm,:], D[Zperm, Wperm], timeevol)

test/test_staticsystems.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ eye, sys2 = promote(1, sys)
135135
promote_type(typeof(StaticStateSpace(ssrand(1,1,1,Ts=0.1))), typeof(1)) == HeteroStateSpace{Discrete{Float64}}
136136

137137
sys = StaticStateSpace(ssrand(1,1,2,proper=false))
138-
@test feedback(sys,sys) == feedback(ss(sys),ss(sys))
138+
@test feedback(sys,sys) feedback(ss(sys),ss(sys))
139139
@inferred feedback(sys,sys)
140140

141141
## Freqresp

0 commit comments

Comments
 (0)