From c7515ba6cd04a73bc700737c54840ffb9202138d Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 26 Oct 2026 06:52:12 +0000 Subject: [PATCH 1/3] Improve constant propagation for compiled control analyses --- lib/ControlSystemsBase/src/analysis.jl | 2 +- lib/ControlSystemsBase/src/connections.jl | 6 +++--- lib/ControlSystemsBase/src/freqresp.jl | 2 +- lib/ControlSystemsBase/src/types/conversion.jl | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/ControlSystemsBase/src/analysis.jl b/lib/ControlSystemsBase/src/analysis.jl index 3d3616f65..248b8e551 100644 --- a/lib/ControlSystemsBase/src/analysis.jl +++ b/lib/ControlSystemsBase/src/analysis.jl @@ -759,7 +759,7 @@ Given a transfer function describing the plant `P` and a transfer function descr If `minimal=true`, [`minreal`](@ref) will be applied to all transfer functions. """ -function gangoffour(P::LTISystem, C::LTISystem; minimal=true) +Base.@inline function gangoffour(P::LTISystem, C::LTISystem; minimal=true) minfun = minimal ? robust_minreal : identity S = feedback(I(noutputs(P)), P*C) |> minfun PS = feedback(P, C) |> minfun diff --git a/lib/ControlSystemsBase/src/connections.jl b/lib/ControlSystemsBase/src/connections.jl index 63970aa93..d1f36fec4 100644 --- a/lib/ControlSystemsBase/src/connections.jl +++ b/lib/ControlSystemsBase/src/connections.jl @@ -350,7 +350,7 @@ The manual section [From block diagrams to code](https://juliacontrol.github.io/ See Zhou, Doyle, Glover (1996) for similar (somewhat less symmetric) formulas. """ -function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace; +Base.@inline Base.@constprop :aggressive function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace; U1=:, Y1=:, U2=:, Y2=:, W1=:, Z1=:, W2=Int[], Z2=Int[], Wperm=:, Zperm=:, pos_feedback::Bool=false) @@ -371,10 +371,10 @@ function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace; Z2 isa Number && (Z2 = [Z2]) if (U1 isa Colon ? size(sys1, 2) : length(U1)) != (Y2 isa Colon ? size(sys2, 1) : length(Y2)) - error("Lengths of U1 ($U1) and Y2 ($Y2) must be equal") + error("Lengths of U1 and Y2 must be equal") end if (U2 isa Colon ? size(sys2, 2) : length(U2)) != (Y1 isa Colon ? size(sys1, 1) : length(Y1)) - error("Lengths of U2 ($U2) and Y1 ($Y1) must be equal") + error("Lengths of U2 and Y1 must be equal") end α = pos_feedback ? 1 : -1 # The sign of feedback diff --git a/lib/ControlSystemsBase/src/freqresp.jl b/lib/ControlSystemsBase/src/freqresp.jl index ff53fb5a0..85f53d7bd 100644 --- a/lib/ControlSystemsBase/src/freqresp.jl +++ b/lib/ControlSystemsBase/src/freqresp.jl @@ -31,7 +31,7 @@ end BodemagWorkspace(sys::LTISystem, ω::AbstractVector) = BodemagWorkspace(sys, length(ω)) -function freqresp(sys::LTISystem, w::Real; balance=true) +Base.@inline function freqresp(sys::LTISystem, w::Real; balance=true) sys = _balance(sys, balance) # Create imaginary freq vector s if iscontinuous(sys) diff --git a/lib/ControlSystemsBase/src/types/conversion.jl b/lib/ControlSystemsBase/src/types/conversion.jl index 4c9c75ce1..56438a030 100644 --- a/lib/ControlSystemsBase/src/types/conversion.jl +++ b/lib/ControlSystemsBase/src/types/conversion.jl @@ -247,7 +247,7 @@ for which balancing improves the numerical conditioning without changing the res a no-op for system representations that have no state-space realization to balance, such as transfer functions. """ -_balance(sys, balance::Bool) = balance ? balance_statespace(sys)[1] : sys +Base.@inline _balance(sys, balance::Bool) = balance ? balance_statespace(sys)[1] : sys """ `T = balance_transform{R}(A::AbstractArray, B::AbstractArray, C::AbstractArray, perm::Bool=false)` From 470edd07cced4474b00ad06e366e9b407a87b4b7 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 26 Oct 2026 07:09:18 +0000 Subject: [PATCH 2/3] Replace forced inlining with index specialization and constant propagation --- lib/ControlSystemsBase/src/analysis.jl | 2 +- lib/ControlSystemsBase/src/connections.jl | 7 ++++--- lib/ControlSystemsBase/src/freqresp.jl | 2 +- lib/ControlSystemsBase/src/types/conversion.jl | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/ControlSystemsBase/src/analysis.jl b/lib/ControlSystemsBase/src/analysis.jl index 248b8e551..3d3616f65 100644 --- a/lib/ControlSystemsBase/src/analysis.jl +++ b/lib/ControlSystemsBase/src/analysis.jl @@ -759,7 +759,7 @@ Given a transfer function describing the plant `P` and a transfer function descr If `minimal=true`, [`minreal`](@ref) will be applied to all transfer functions. """ -Base.@inline function gangoffour(P::LTISystem, C::LTISystem; minimal=true) +function gangoffour(P::LTISystem, C::LTISystem; minimal=true) minfun = minimal ? robust_minreal : identity S = feedback(I(noutputs(P)), P*C) |> minfun PS = feedback(P, C) |> minfun diff --git a/lib/ControlSystemsBase/src/connections.jl b/lib/ControlSystemsBase/src/connections.jl index d1f36fec4..18488cae8 100644 --- a/lib/ControlSystemsBase/src/connections.jl +++ b/lib/ControlSystemsBase/src/connections.jl @@ -350,9 +350,10 @@ The manual section [From block diagrams to code](https://juliacontrol.github.io/ See Zhou, Doyle, Glover (1996) for similar (somewhat less symmetric) formulas. """ -Base.@inline Base.@constprop :aggressive function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace; - U1=:, Y1=:, U2=:, Y2=:, W1=:, Z1=:, W2=Int[], Z2=Int[], - Wperm=:, Zperm=:, pos_feedback::Bool=false) +function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace; + U1::TU1=:, Y1::TY1=:, U2::TU2=:, Y2::TY2=:, W1::TW1=:, Z1::TZ1=:, + W2::TW2=Int[], Z2::TZ2=Int[], Wperm::TWperm=:, Zperm::TZperm=:, + pos_feedback::Bool=false) where {TU1, TY1, TU2, TY2, TW1, TZ1, TW2, TZ2, TWperm, TZperm} timeevol = common_timeevol(sys1,sys2) T = Base.promote_type(numeric_type(sys1), numeric_type(sys2)) diff --git a/lib/ControlSystemsBase/src/freqresp.jl b/lib/ControlSystemsBase/src/freqresp.jl index 85f53d7bd..af82fd965 100644 --- a/lib/ControlSystemsBase/src/freqresp.jl +++ b/lib/ControlSystemsBase/src/freqresp.jl @@ -31,7 +31,7 @@ end BodemagWorkspace(sys::LTISystem, ω::AbstractVector) = BodemagWorkspace(sys, length(ω)) -Base.@inline function freqresp(sys::LTISystem, w::Real; balance=true) +Base.@constprop :aggressive function freqresp(sys::LTISystem, w::Real; balance=true) sys = _balance(sys, balance) # Create imaginary freq vector s if iscontinuous(sys) diff --git a/lib/ControlSystemsBase/src/types/conversion.jl b/lib/ControlSystemsBase/src/types/conversion.jl index 56438a030..4c9c75ce1 100644 --- a/lib/ControlSystemsBase/src/types/conversion.jl +++ b/lib/ControlSystemsBase/src/types/conversion.jl @@ -247,7 +247,7 @@ for which balancing improves the numerical conditioning without changing the res a no-op for system representations that have no state-space realization to balance, such as transfer functions. """ -Base.@inline _balance(sys, balance::Bool) = balance ? balance_statespace(sys)[1] : sys +_balance(sys, balance::Bool) = balance ? balance_statespace(sys)[1] : sys """ `T = balance_transform{R}(A::AbstractArray, B::AbstractArray, C::AbstractArray, perm::Bool=false)` From 836140f953dd1c6ee0c13476f968c192dd11d79a Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 26 Oct 2026 07:13:31 +0000 Subject: [PATCH 3/3] Limit the proposal to feedback index specialization --- lib/ControlSystemsBase/src/freqresp.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ControlSystemsBase/src/freqresp.jl b/lib/ControlSystemsBase/src/freqresp.jl index af82fd965..ff53fb5a0 100644 --- a/lib/ControlSystemsBase/src/freqresp.jl +++ b/lib/ControlSystemsBase/src/freqresp.jl @@ -31,7 +31,7 @@ end BodemagWorkspace(sys::LTISystem, ω::AbstractVector) = BodemagWorkspace(sys, length(ω)) -Base.@constprop :aggressive function freqresp(sys::LTISystem, w::Real; balance=true) +function freqresp(sys::LTISystem, w::Real; balance=true) sys = _balance(sys, balance) # Create imaginary freq vector s if iscontinuous(sys)