From 0df5e0160c3c8b94fb475a9ab38baa74ffd8adb4 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Sun, 13 Jul 2025 11:19:40 -0400 Subject: [PATCH 01/13] bench: changing suit tree hierarchy --- .gitignore | 1 + benchmark/benchmarks.jl | 52 ++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 14fe61749..57db912da 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ lcov.info benchmark/Manifest.toml /.benchmarkci /benchmark/*.json +results_ModelPredictiveControl* diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index 345e49a5e..59b65051f 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -26,25 +26,25 @@ nonlinmodel = NonLinModel(f!, h!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing) nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5]) u, d, y = [10, 50], [5], [50, 30] -SUITE["SimModel"]["allocation"] = BenchmarkGroup(["allocation"]) -SUITE["SimModel"]["allocation"]["LinModel_updatestate!"] = @benchmarkable( +SUITE["allocation"]["SimModel"] = BenchmarkGroup(["allocation"]) +SUITE["allocation"]["SimModel"]["LinModel_updatestate!"] = @benchmarkable( updatestate!($linmodel, $u, $d), samples=1 ) -SUITE["SimModel"]["allocation"]["LinModel_evaloutput"] = @benchmarkable( +SUITE["allocation"]["SimModel"]["LinModel_evaloutput"] = @benchmarkable( evaloutput($linmodel, $d), samples=1 ) -SUITE["SimModel"]["allocation"]["NonLinModel_updatestate!"] = @benchmarkable( +SUITE["allocation"]["SimModel"]["NonLinModel_updatestate!"] = @benchmarkable( updatestate!($nonlinmodel, $u, $d), samples=1 ) -SUITE["SimModel"]["allocation"]["NonLinModel_evaloutput"] = @benchmarkable( +SUITE["allocation"]["SimModel"]["NonLinModel_evaloutput"] = @benchmarkable( evaloutput($nonlinmodel, $d), samples=1 ) -SUITE["SimModel"]["allocation"]["NonLinModel_linearize!"] = @benchmarkable( +SUITE["allocation"]["SimModel"]["NonLinModel_linearize!"] = @benchmarkable( linearize!($linmodel, $nonlinmodel), samples=1 ) @@ -53,77 +53,77 @@ SUITE["SimModel"]["allocation"]["NonLinModel_linearize!"] = @benchmarkable( ## ================== StateEstimator benchmarks ===================================== ## ================================================================================== skf = SteadyKalmanFilter(linmodel) -SUITE["StateEstimator"]["allocation"] = BenchmarkGroup(["allocation"]) -SUITE["StateEstimator"]["allocation"]["SteadyKalmanFilter_preparestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"] = BenchmarkGroup(["allocation"]) +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter_preparestate!"] = @benchmarkable( preparestate!($skf, $y, $d), samples=1 ) -SUITE["StateEstimator"]["allocation"]["SteadyKalmanFilter_updatestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter_updatestate!"] = @benchmarkable( updatestate!($skf, $u, $y, $d), setup=preparestate!($skf, $y, $d), samples=1 ) -SUITE["StateEstimator"]["allocation"]["SteadyKalmanFilter_evaloutput"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter_evaloutput"] = @benchmarkable( evaloutput($skf, $d), setup=preparestate!($skf, $y, $d), samples=1 ) kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["StateEstimator"]["allocation"]["KalmanFilter_preparestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["KalmanFilter_preparestate!"] = @benchmarkable( preparestate!($kf, $y, $d), samples=1 ) -SUITE["StateEstimator"]["allocation"]["KalmanFilter_updatestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["KalmanFilter_updatestate!"] = @benchmarkable( updatestate!($kf, $u, $y, $d), setup=preparestate!($kf, $y, $d), samples=1 ) lo = Luenberger(linmodel, nint_u=[1, 1]) -#SUITE["StateEstimator"]["allocation"]["Luenberger_preparestate!"] = @benchmarkable( -# preparestate!($lo, $y, $d), -# samples=1 -#) -SUITE["StateEstimator"]["allocation"]["Luenberger_updatestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["Luenberger_preparestate!"] = @benchmarkable( + preparestate!($lo, $y, $d), + samples=1 +) +SUITE["allocation"]["StateEstimator"]["Luenberger_updatestate!"] = @benchmarkable( updatestate!($lo, $u, $y, $d), setup=preparestate!($lo, $y, $d), samples=1 ) im = InternalModel(nonlinmodel) -SUITE["StateEstimator"]["allocation"]["InternalModel_preparestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["InternalModel_preparestate!"] = @benchmarkable( preparestate!($im, $y, $d), samples=1 ) -SUITE["StateEstimator"]["allocation"]["InternalModel_updatestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["InternalModel_updatestate!"] = @benchmarkable( updatestate!($im, $u, $y, $d), setup=preparestate!($im, $y, $d), samples=1 ) ukf = UnscentedKalmanFilter(nonlinmodel) -SUITE["StateEstimator"]["allocation"]["UnscentedKalmanFilter_preparestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter_preparestate!"] = @benchmarkable( preparestate!($ukf, $y, $d), samples=1 ) -SUITE["StateEstimator"]["allocation"]["UnscentedKalmanFilter_updatestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter_updatestate!"] = @benchmarkable( updatestate!($ukf, $u, $y, $d), setup=preparestate!($ukf, $y, $d), samples=1 ) -SUITE["StateEstimator"]["allocation"]["UnscentedKalmanFilter_evaloutput"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter_evaloutput"] = @benchmarkable( evaloutput($ukf, $d), setup=preparestate!($ukf, $y, $d), samples=1 ) ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["StateEstimator"]["allocation"]["ExtendedKalmanFilter_preparestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter_preparestate!"] = @benchmarkable( preparestate!($ekf, $y, $d), samples=1 ) -SUITE["StateEstimator"]["allocation"]["ExtendedKalmanFilter_updatestate!"] = @benchmarkable( +SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter_updatestate!"] = @benchmarkable( updatestate!($ekf, $u, $y, $d), setup=preparestate!($ekf, $y, $d), samples=1 @@ -133,8 +133,8 @@ SUITE["StateEstimator"]["allocation"]["ExtendedKalmanFilter_updatestate!"] = @be ## ================== PredictiveController benchmarks =============================== ## ================================================================================== empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) -SUITE["PredictiveController"]["allocation"] = BenchmarkGroup(["allocation"]) -SUITE["PredictiveController"]["allocation"]["ExplicitMPC_moveinput!"] = @benchmarkable( +SUITE["allocation"]["PredictiveController"] = BenchmarkGroup(["allocation"]) +SUITE["allocation"]["PredictiveController"]["ExplicitMPC_moveinput!"] = @benchmarkable( moveinput!($empc, $y, $d), setup=preparestate!($empc, $y, $d), samples=1 From 01df330dd1cc307f508297fa51d6a9e56dcd1065 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Mon, 14 Jul 2025 09:15:00 -0400 Subject: [PATCH 02/13] doc: debug interlink --- src/controller/nonlinmpc.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/nonlinmpc.jl b/src/controller/nonlinmpc.jl index d8ebb5841..5b5d2050a 100644 --- a/src/controller/nonlinmpc.jl +++ b/src/controller/nonlinmpc.jl @@ -550,8 +550,8 @@ This method is really intricate and I'm not proud of it. That's because of 3 ele and as efficient as possible. All the function outputs and derivatives are cached and updated in-place if required to use the efficient [`value_and_jacobian!`](@extref DifferentiationInterface DifferentiationInterface.value_and_jacobian!). - The `JuMP` NLP syntax forces splatting for the decision variable, which implies use - of `Vararg{T,N}` (see the (performance tip)[@extref Julia Be-aware-of-when-Julia-avoids-specializing] - ) and memoization to avoid redundant computations. This is already complex, but it's even + of `Vararg{T,N}` (see the [performance tip](@extref Julia Be-aware-of-when-Julia-avoids-specializing)) + and memoization to avoid redundant computations. This is already complex, but it's even worse knowing that most automatic differentiation tools do not support splatting. - The signature of gradient and hessian functions is not the same for univariate (`nZ̃ == 1`) and multivariate (`nZ̃ > 1`) operators in `JuMP`. Both must be defined. From 8ed551415e9d99d198d899b6f5b7c5604aa6f2c7 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Mon, 14 Jul 2025 15:29:33 -0400 Subject: [PATCH 03/13] bench: added CSTR `LinMPC` benchmarks --- benchmark/benchmarks.jl | 263 ++++++++++++++++++++++++++-------------- 1 file changed, 174 insertions(+), 89 deletions(-) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index 59b65051f..4ce1f3064 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -1,11 +1,12 @@ using BenchmarkTools using ModelPredictiveControl, ControlSystemsBase, LinearAlgebra +using JuMP, OSQP, DAQP, Ipopt, MadNLP Ts = 400.0 sys = [ tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]); tf(-0.74,[800.0,1]) tf(0.74,[800.0,1]) tf(-0.74,[800.0,1]) ] -const SUITE = BenchmarkGroup() +const SUITE = BenchmarkGroup(["ModelPredictiveControl"]) ## ================================================================================== ## ================== SimModel benchmarks =========================================== @@ -26,116 +27,200 @@ nonlinmodel = NonLinModel(f!, h!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing) nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5]) u, d, y = [10, 50], [5], [50, 30] -SUITE["allocation"]["SimModel"] = BenchmarkGroup(["allocation"]) -SUITE["allocation"]["SimModel"]["LinModel_updatestate!"] = @benchmarkable( - updatestate!($linmodel, $u, $d), - samples=1 +## ----------------- Runtime benchmarks --------------------------------------------- +# TODO: Add runtime benchmarks for SimModel + + +## ----------------- Allocation benchmarks ------------------------------------------ +samples, evals = 1, 1 +SUITE["allocation"]["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable( + updatestate!($linmodel, $u, $d); samples=samples, evals=evals ) -SUITE["allocation"]["SimModel"]["LinModel_evaloutput"] = @benchmarkable( - evaloutput($linmodel, $d), - samples=1 +SUITE["allocation"]["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable( + evaloutput($linmodel, $d); samples=samples, evals=evals ) -SUITE["allocation"]["SimModel"]["NonLinModel_updatestate!"] = @benchmarkable( - updatestate!($nonlinmodel, $u, $d), - samples=1 +SUITE["allocation"]["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable( + updatestate!($nonlinmodel, $u, $d); samples=samples, evals=evals ) -SUITE["allocation"]["SimModel"]["NonLinModel_evaloutput"] = @benchmarkable( - evaloutput($nonlinmodel, $d), - samples=1 +SUITE["allocation"]["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable( + evaloutput($nonlinmodel, $d); samples=samples, evals=evals ) - -SUITE["allocation"]["SimModel"]["NonLinModel_linearize!"] = @benchmarkable( - linearize!($linmodel, $nonlinmodel), - samples=1 +SUITE["allocation"]["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable( + linearize!($linmodel, $nonlinmodel); samples=samples, evals=evals ) ## ================================================================================== ## ================== StateEstimator benchmarks ===================================== ## ================================================================================== + + +## ----------------- Runtime benchmarks --------------------------------------------- +# TODO: Add runtime benchmarks for StateEstimator + + +## ----------------- Allocation benchmarks ------------------------------------------ +samples, evals = 1, 1 + skf = SteadyKalmanFilter(linmodel) -SUITE["allocation"]["StateEstimator"] = BenchmarkGroup(["allocation"]) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter_preparestate!"] = @benchmarkable( - preparestate!($skf, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter_updatestate!"] = @benchmarkable( - updatestate!($skf, $u, $y, $d), - setup=preparestate!($skf, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter_evaloutput"] = @benchmarkable( - evaloutput($skf, $d), - setup=preparestate!($skf, $y, $d), - samples=1 -) +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($skf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($skf, $u, $y, $d), + setup=preparestate!($skf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = + @benchmarkable( + evaloutput($skf, $d), + setup=preparestate!($skf, $y, $d), + samples=samples, evals=evals + ) kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["allocation"]["StateEstimator"]["KalmanFilter_preparestate!"] = @benchmarkable( - preparestate!($kf, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["KalmanFilter_updatestate!"] = @benchmarkable( - updatestate!($kf, $u, $y, $d), - setup=preparestate!($kf, $y, $d), - samples=1 -) +SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($kf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($kf, $u, $y, $d), + setup=preparestate!($kf, $y, $d), + samples=samples, evals=evals + ) lo = Luenberger(linmodel, nint_u=[1, 1]) -SUITE["allocation"]["StateEstimator"]["Luenberger_preparestate!"] = @benchmarkable( - preparestate!($lo, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["Luenberger_updatestate!"] = @benchmarkable( - updatestate!($lo, $u, $y, $d), - setup=preparestate!($lo, $y, $d), - samples=1 -) +SUITE["allocation"]["StateEstimator"]["Luenberger"]["preparestate!"] = + @benchmarkable( + preparestate!($lo, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["Luenberger"]["updatestate!"] = + @benchmarkable( + updatestate!($lo, $u, $y, $d), + setup=preparestate!($lo, $y, $d), + samples=samples, evals=evals + ) im = InternalModel(nonlinmodel) -SUITE["allocation"]["StateEstimator"]["InternalModel_preparestate!"] = @benchmarkable( - preparestate!($im, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["InternalModel_updatestate!"] = @benchmarkable( - updatestate!($im, $u, $y, $d), - setup=preparestate!($im, $y, $d), - samples=1 -) +SUITE["allocation"]["StateEstimator"]["InternalModel"]["preparestate!"] = + @benchmarkable( + preparestate!($im, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["InternalModel"]["updatestate!"] = + @benchmarkable( + updatestate!($im, $u, $y, $d), + setup=preparestate!($im, $y, $d), + samples=samples, evals=evals + ) ukf = UnscentedKalmanFilter(nonlinmodel) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter_preparestate!"] = @benchmarkable( - preparestate!($ukf, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter_updatestate!"] = @benchmarkable( - updatestate!($ukf, $u, $y, $d), - setup=preparestate!($ukf, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter_evaloutput"] = @benchmarkable( - evaloutput($ukf, $d), - setup=preparestate!($ukf, $y, $d), - samples=1 -) +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($ukf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($ukf, $u, $y, $d), + setup=preparestate!($ukf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = + @benchmarkable( + evaloutput($ukf, $d), + setup=preparestate!($ukf, $y, $d), + samples=samples, evals=evals + ) ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter_preparestate!"] = @benchmarkable( - preparestate!($ekf, $y, $d), - samples=1 -) -SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter_updatestate!"] = @benchmarkable( - updatestate!($ekf, $u, $y, $d), - setup=preparestate!($ekf, $y, $d), - samples=1 -) +SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($ekf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($ekf, $u, $y, $d), + setup=preparestate!($ekf, $y, $d), + samples=samples, evals=evals + ) ## ================================================================================== ## ================== PredictiveController benchmarks =============================== ## ================================================================================== +G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); + tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] +uop, yop = [20, 20], [50, 30] +model = setop!(LinModel(G, 2.0); uop, yop) +function test_mpc(mpc, plant) + plant.x0 .= 0; y = plant() + initstate!(mpc, plant.uop, y) + N = 75; ry = [50, 30]; ul = 0 + U, Y, Ry = zeros(2, N), zeros(2, N), zeros(2, N) + for i = 1:N + i == 26 && (ry = [48, 35]) + i == 51 && (ul = -10) + y = plant() + preparestate!(mpc, y) + u = mpc(ry) + U[:,i], Y[:,i], Ry[:,i] = u, y, ry + updatestate!(mpc, u, y) + updatestate!(plant, u+[0,ul]) + end + return U, Y, Ry +end + +## ----------------- Runtime benchmarks --------------------------------------------- +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) + +transcription = SingleShooting() +mpc_osqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_osqp_ss.optim) + +transcription = MultipleShooting() +mpc_osqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_osqp_ms.optim) + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) + +transcription = SingleShooting() +mpc_daqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) + +transcription = MultipleShooting() +mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) + +samples, evals = 500, 1 +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] = + @benchmarkable(test_mpc($mpc_osqp_ss, $model); + samples=samples, evals=evals +) +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] = + @benchmarkable(test_mpc($mpc_osqp_ms, $model); + samples=samples, evals=evals +) +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] = + @benchmarkable(test_mpc($mpc_daqp_ss, $model); + samples=samples, evals=evals +) +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] = + @benchmarkable(test_mpc($mpc_daqp_ms, $model); + samples=samples, evals=evals +) + + +# ---------------------- Allocation benchmarks ------------------------------------------ empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) -SUITE["allocation"]["PredictiveController"] = BenchmarkGroup(["allocation"]) -SUITE["allocation"]["PredictiveController"]["ExplicitMPC_moveinput!"] = @benchmarkable( - moveinput!($empc, $y, $d), - setup=preparestate!($empc, $y, $d), - samples=1 -) \ No newline at end of file + +samples, evals = 1, 1 +SUITE["allocation"]["PredictiveController"]["ExplicitMPC"]["moveinput!"] = + @benchmarkable( + moveinput!($empc, $y, $d), + setup=preparestate!($empc, $y, $d), + samples=samples, evals=evals + ) From 7f677aaaa8413a9d58d5024ab42bcc9d84daf874 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Mon, 14 Jul 2025 16:04:26 -0400 Subject: [PATCH 04/13] bench: debug CSTR benchmarks --- benchmark/benchmarks.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index 4ce1f3064..00106efa5 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -178,22 +178,24 @@ end ## ----------------- Runtime benchmarks --------------------------------------------- optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) - transcription = SingleShooting() mpc_osqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) JuMP.unset_time_limit_sec(mpc_osqp_ss.optim) +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) transcription = MultipleShooting() mpc_osqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) JuMP.unset_time_limit_sec(mpc_osqp_ms.optim) optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) - transcription = SingleShooting() mpc_daqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) transcription = MultipleShooting() mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +# needed to solve Hessians with eigenvalues at zero, like in MultipleShooting transcription: +JuMP.set_attribute(mpc_daqp_ms.optim, "eps_prox", 1e-6) samples, evals = 500, 1 SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] = From 9774a36b8258a09699c0d4396a9885ddb382a13a Mon Sep 17 00:00:00 2001 From: franckgaga Date: Mon, 14 Jul 2025 16:29:48 -0400 Subject: [PATCH 05/13] bench: restructuring files --- benchmark/0_bench_setup.jl | 14 ++ benchmark/1_bench_sim_model.jl | 26 +++ benchmark/2_bench_state_estim.jl | 96 ++++++++++ benchmark/3_bench_predictive_control.jl | 72 ++++++++ benchmark/benchmarks.jl | 226 +----------------------- 5 files changed, 212 insertions(+), 222 deletions(-) create mode 100644 benchmark/0_bench_setup.jl create mode 100644 benchmark/1_bench_sim_model.jl create mode 100644 benchmark/2_bench_state_estim.jl create mode 100644 benchmark/3_bench_predictive_control.jl diff --git a/benchmark/0_bench_setup.jl b/benchmark/0_bench_setup.jl new file mode 100644 index 000000000..da83fbeb7 --- /dev/null +++ b/benchmark/0_bench_setup.jl @@ -0,0 +1,14 @@ +Ts = 400.0 +sys = [ tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]); + tf(-0.74,[800.0,1]) tf(0.74,[800.0,1]) tf(-0.74,[800.0,1]) ] +function f!(ẋ, x, u, d, p) + mul!(ẋ, p.A, x) + mul!(ẋ, p.Bu, u, 1, 1) + mul!(ẋ, p.Bd, d, 1, 1) + return nothing +end +function h!(y, x, d, p) + mul!(y, p.C, x) + mul!(y, p.Dd, d, 1, 1) + return nothing +end \ No newline at end of file diff --git a/benchmark/1_bench_sim_model.jl b/benchmark/1_bench_sim_model.jl new file mode 100644 index 000000000..ef8db858f --- /dev/null +++ b/benchmark/1_bench_sim_model.jl @@ -0,0 +1,26 @@ +linmodel = setop!(LinModel(sys, Ts, i_d=[3]), uop=[10, 50], yop=[50, 30], dop=[5]) +nonlinmodel = NonLinModel(f!, h!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing) +nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5]) +u, d, y = [10, 50], [5], [50, 30] + +## ----------------- Runtime benchmarks --------------------------------------------- +# TODO: Add runtime benchmarks for SimModel + + +## ----------------- Allocation benchmarks ------------------------------------------ +samples, evals = 1, 1 +SUITE["allocation"]["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable( + updatestate!($linmodel, $u, $d); samples=samples, evals=evals +) +SUITE["allocation"]["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable( + evaloutput($linmodel, $d); samples=samples, evals=evals +) +SUITE["allocation"]["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable( + updatestate!($nonlinmodel, $u, $d); samples=samples, evals=evals +) +SUITE["allocation"]["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable( + evaloutput($nonlinmodel, $d); samples=samples, evals=evals +) +SUITE["allocation"]["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable( + linearize!($linmodel, $nonlinmodel); samples=samples, evals=evals +) diff --git a/benchmark/2_bench_state_estim.jl b/benchmark/2_bench_state_estim.jl new file mode 100644 index 000000000..eb1e63cd4 --- /dev/null +++ b/benchmark/2_bench_state_estim.jl @@ -0,0 +1,96 @@ +## ----------------- Runtime benchmarks --------------------------------------------- +# TODO: Add runtime benchmarks for StateEstimator + + +## ----------------- Allocation benchmarks ------------------------------------------ +samples, evals = 1, 1 + +skf = SteadyKalmanFilter(linmodel) +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($skf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($skf, $u, $y, $d), + setup=preparestate!($skf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = + @benchmarkable( + evaloutput($skf, $d), + setup=preparestate!($skf, $y, $d), + samples=samples, evals=evals + ) + +kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false) +SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($kf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($kf, $u, $y, $d), + setup=preparestate!($kf, $y, $d), + samples=samples, evals=evals + ) + +lo = Luenberger(linmodel, nint_u=[1, 1]) +SUITE["allocation"]["StateEstimator"]["Luenberger"]["preparestate!"] = + @benchmarkable( + preparestate!($lo, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["Luenberger"]["updatestate!"] = + @benchmarkable( + updatestate!($lo, $u, $y, $d), + setup=preparestate!($lo, $y, $d), + samples=samples, evals=evals + ) + +im = InternalModel(nonlinmodel) +SUITE["allocation"]["StateEstimator"]["InternalModel"]["preparestate!"] = + @benchmarkable( + preparestate!($im, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["InternalModel"]["updatestate!"] = + @benchmarkable( + updatestate!($im, $u, $y, $d), + setup=preparestate!($im, $y, $d), + samples=samples, evals=evals + ) + +ukf = UnscentedKalmanFilter(nonlinmodel) +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($ukf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($ukf, $u, $y, $d), + setup=preparestate!($ukf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = + @benchmarkable( + evaloutput($ukf, $d), + setup=preparestate!($ukf, $y, $d), + samples=samples, evals=evals + ) + +ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) +SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] = + @benchmarkable( + preparestate!($ekf, $y, $d), + samples=samples, evals=evals + ) +SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] = + @benchmarkable( + updatestate!($ekf, $u, $y, $d), + setup=preparestate!($ekf, $y, $d), + samples=samples, evals=evals + ) \ No newline at end of file diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl new file mode 100644 index 000000000..3c81e540a --- /dev/null +++ b/benchmark/3_bench_predictive_control.jl @@ -0,0 +1,72 @@ +G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); + tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] +uop, yop = [20, 20], [50, 30] +model = setop!(LinModel(G, 2.0); uop, yop) +function test_mpc(mpc, plant) + plant.x0 .= 0; y = plant() + initstate!(mpc, plant.uop, y) + N = 75; ry = [50, 30]; ul = 0 + U, Y, Ry = zeros(2, N), zeros(2, N), zeros(2, N) + for i = 1:N + i == 26 && (ry = [48, 35]) + i == 51 && (ul = -10) + y = plant() + preparestate!(mpc, y) + u = mpc(ry) + U[:,i], Y[:,i], Ry[:,i] = u, y, ry + updatestate!(mpc, u, y) + updatestate!(plant, u+[0,ul]) + end + return U, Y, Ry +end + +## ----------------- Runtime benchmarks --------------------------------------------- +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +transcription = SingleShooting() +mpc_osqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_osqp_ss.optim) + +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +transcription = MultipleShooting() +mpc_osqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_osqp_ms.optim) + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +transcription = SingleShooting() +mpc_daqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +transcription = MultipleShooting() +mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +# needed to solve Hessians with eigenvalues at zero, like in MultipleShooting transcription: +JuMP.set_attribute(mpc_daqp_ms.optim, "eps_prox", 1e-6) + +samples, evals = 500, 1 +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] = + @benchmarkable(test_mpc($mpc_osqp_ss, $model); + samples=samples, evals=evals +) +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] = + @benchmarkable(test_mpc($mpc_osqp_ms, $model); + samples=samples, evals=evals +) +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] = + @benchmarkable(test_mpc($mpc_daqp_ss, $model); + samples=samples, evals=evals +) +SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] = + @benchmarkable(test_mpc($mpc_daqp_ms, $model); + samples=samples, evals=evals +) + + +# ---------------------- Allocation benchmarks ------------------------------------------ +empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) + +samples, evals = 1, 1 +SUITE["allocation"]["PredictiveController"]["ExplicitMPC"]["moveinput!"] = + @benchmarkable( + moveinput!($empc, $y, $d), + setup=preparestate!($empc, $y, $d), + samples=samples, evals=evals + ) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index 00106efa5..d7e6fe1f2 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -2,227 +2,9 @@ using BenchmarkTools using ModelPredictiveControl, ControlSystemsBase, LinearAlgebra using JuMP, OSQP, DAQP, Ipopt, MadNLP -Ts = 400.0 -sys = [ tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]); - tf(-0.74,[800.0,1]) tf(0.74,[800.0,1]) tf(-0.74,[800.0,1]) ] - const SUITE = BenchmarkGroup(["ModelPredictiveControl"]) -## ================================================================================== -## ================== SimModel benchmarks =========================================== -## ================================================================================== -linmodel = setop!(LinModel(sys, Ts, i_d=[3]), uop=[10, 50], yop=[50, 30], dop=[5]) -function f!(ẋ, x, u, d, p) - mul!(ẋ, p.A, x) - mul!(ẋ, p.Bu, u, 1, 1) - mul!(ẋ, p.Bd, d, 1, 1) - return nothing -end -function h!(y, x, d, p) - mul!(y, p.C, x) - mul!(y, p.Dd, d, 1, 1) - return nothing -end -nonlinmodel = NonLinModel(f!, h!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing) -nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5]) -u, d, y = [10, 50], [5], [50, 30] - -## ----------------- Runtime benchmarks --------------------------------------------- -# TODO: Add runtime benchmarks for SimModel - - -## ----------------- Allocation benchmarks ------------------------------------------ -samples, evals = 1, 1 -SUITE["allocation"]["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable( - updatestate!($linmodel, $u, $d); samples=samples, evals=evals -) -SUITE["allocation"]["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable( - evaloutput($linmodel, $d); samples=samples, evals=evals -) -SUITE["allocation"]["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable( - updatestate!($nonlinmodel, $u, $d); samples=samples, evals=evals -) -SUITE["allocation"]["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable( - evaloutput($nonlinmodel, $d); samples=samples, evals=evals -) -SUITE["allocation"]["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable( - linearize!($linmodel, $nonlinmodel); samples=samples, evals=evals -) - -## ================================================================================== -## ================== StateEstimator benchmarks ===================================== -## ================================================================================== - - -## ----------------- Runtime benchmarks --------------------------------------------- -# TODO: Add runtime benchmarks for StateEstimator - - -## ----------------- Allocation benchmarks ------------------------------------------ -samples, evals = 1, 1 - -skf = SteadyKalmanFilter(linmodel) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] = - @benchmarkable( - preparestate!($skf, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] = - @benchmarkable( - updatestate!($skf, $u, $y, $d), - setup=preparestate!($skf, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = - @benchmarkable( - evaloutput($skf, $d), - setup=preparestate!($skf, $y, $d), - samples=samples, evals=evals - ) - -kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["preparestate!"] = - @benchmarkable( - preparestate!($kf, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["updatestate!"] = - @benchmarkable( - updatestate!($kf, $u, $y, $d), - setup=preparestate!($kf, $y, $d), - samples=samples, evals=evals - ) - -lo = Luenberger(linmodel, nint_u=[1, 1]) -SUITE["allocation"]["StateEstimator"]["Luenberger"]["preparestate!"] = - @benchmarkable( - preparestate!($lo, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["Luenberger"]["updatestate!"] = - @benchmarkable( - updatestate!($lo, $u, $y, $d), - setup=preparestate!($lo, $y, $d), - samples=samples, evals=evals - ) - -im = InternalModel(nonlinmodel) -SUITE["allocation"]["StateEstimator"]["InternalModel"]["preparestate!"] = - @benchmarkable( - preparestate!($im, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["InternalModel"]["updatestate!"] = - @benchmarkable( - updatestate!($im, $u, $y, $d), - setup=preparestate!($im, $y, $d), - samples=samples, evals=evals - ) - -ukf = UnscentedKalmanFilter(nonlinmodel) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] = - @benchmarkable( - preparestate!($ukf, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] = - @benchmarkable( - updatestate!($ukf, $u, $y, $d), - setup=preparestate!($ukf, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = - @benchmarkable( - evaloutput($ukf, $d), - setup=preparestate!($ukf, $y, $d), - samples=samples, evals=evals - ) - -ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] = - @benchmarkable( - preparestate!($ekf, $y, $d), - samples=samples, evals=evals - ) -SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] = - @benchmarkable( - updatestate!($ekf, $u, $y, $d), - setup=preparestate!($ekf, $y, $d), - samples=samples, evals=evals - ) - -## ================================================================================== -## ================== PredictiveController benchmarks =============================== -## ================================================================================== -G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); - tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] -uop, yop = [20, 20], [50, 30] -model = setop!(LinModel(G, 2.0); uop, yop) -function test_mpc(mpc, plant) - plant.x0 .= 0; y = plant() - initstate!(mpc, plant.uop, y) - N = 75; ry = [50, 30]; ul = 0 - U, Y, Ry = zeros(2, N), zeros(2, N), zeros(2, N) - for i = 1:N - i == 26 && (ry = [48, 35]) - i == 51 && (ul = -10) - y = plant() - preparestate!(mpc, y) - u = mpc(ry) - U[:,i], Y[:,i], Ry[:,i] = u, y, ry - updatestate!(mpc, u, y) - updatestate!(plant, u+[0,ul]) - end - return U, Y, Ry -end - -## ----------------- Runtime benchmarks --------------------------------------------- -optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) -transcription = SingleShooting() -mpc_osqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) -JuMP.unset_time_limit_sec(mpc_osqp_ss.optim) - -optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) -transcription = MultipleShooting() -mpc_osqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) -JuMP.unset_time_limit_sec(mpc_osqp_ms.optim) - -optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) -transcription = SingleShooting() -mpc_daqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) - -optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) -transcription = MultipleShooting() -mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) -# needed to solve Hessians with eigenvalues at zero, like in MultipleShooting transcription: -JuMP.set_attribute(mpc_daqp_ms.optim, "eps_prox", 1e-6) - -samples, evals = 500, 1 -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] = - @benchmarkable(test_mpc($mpc_osqp_ss, $model); - samples=samples, evals=evals -) -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] = - @benchmarkable(test_mpc($mpc_osqp_ms, $model); - samples=samples, evals=evals -) -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] = - @benchmarkable(test_mpc($mpc_daqp_ss, $model); - samples=samples, evals=evals -) -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] = - @benchmarkable(test_mpc($mpc_daqp_ms, $model); - samples=samples, evals=evals -) - - -# ---------------------- Allocation benchmarks ------------------------------------------ -empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) - -samples, evals = 1, 1 -SUITE["allocation"]["PredictiveController"]["ExplicitMPC"]["moveinput!"] = - @benchmarkable( - moveinput!($empc, $y, $d), - setup=preparestate!($empc, $y, $d), - samples=samples, evals=evals - ) +include("0_bench_setup.jl") +include("1_bench_sim_model.jl") +include("2_bench_state_estim.jl") +include("3_bench_predictive_control.jl") From adf78e0b87f107ff56e7be0db198537523655e3a Mon Sep 17 00:00:00 2001 From: franckgaga Date: Mon, 14 Jul 2025 17:27:21 -0400 Subject: [PATCH 06/13] bench: added some `NonLinMPC` benchmarks on pendulum --- benchmark/0_bench_setup.jl | 10 ++- benchmark/1_bench_sim_model.jl | 15 ++-- benchmark/2_bench_state_estim.jl | 28 +++---- benchmark/3_bench_predictive_control.jl | 100 ++++++++++++++++++++++-- benchmark/benchmarks.jl | 3 + 5 files changed, 122 insertions(+), 34 deletions(-) diff --git a/benchmark/0_bench_setup.jl b/benchmark/0_bench_setup.jl index da83fbeb7..ac563ffb3 100644 --- a/benchmark/0_bench_setup.jl +++ b/benchmark/0_bench_setup.jl @@ -1,14 +1,18 @@ Ts = 400.0 sys = [ tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]) tf(1.90,[1800.0,1]); tf(-0.74,[800.0,1]) tf(0.74,[800.0,1]) tf(-0.74,[800.0,1]) ] -function f!(ẋ, x, u, d, p) +function f_lin!(ẋ, x, u, d, p) mul!(ẋ, p.A, x) mul!(ẋ, p.Bu, u, 1, 1) mul!(ẋ, p.Bd, d, 1, 1) return nothing end -function h!(y, x, d, p) +function h_lin!(y, x, d, p) mul!(y, p.C, x) mul!(y, p.Dd, d, 1, 1) return nothing -end \ No newline at end of file +end +linmodel = setop!(LinModel(sys, Ts, i_d=[3]), uop=[10, 50], yop=[50, 30], dop=[5]) +nonlinmodel = NonLinModel(f_lin!, h_lin!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing) +nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5]) +u, d, y = [10, 50], [5], [50, 30] \ No newline at end of file diff --git a/benchmark/1_bench_sim_model.jl b/benchmark/1_bench_sim_model.jl index ef8db858f..89d5e1db8 100644 --- a/benchmark/1_bench_sim_model.jl +++ b/benchmark/1_bench_sim_model.jl @@ -1,26 +1,21 @@ -linmodel = setop!(LinModel(sys, Ts, i_d=[3]), uop=[10, 50], yop=[50, 30], dop=[5]) -nonlinmodel = NonLinModel(f!, h!, Ts, 2, 4, 2, 1, p=linmodel, solver=nothing) -nonlinmodel = setop!(nonlinmodel, uop=[10, 50], yop=[50, 30], dop=[5]) -u, d, y = [10, 50], [5], [50, 30] - ## ----------------- Runtime benchmarks --------------------------------------------- # TODO: Add runtime benchmarks for SimModel ## ----------------- Allocation benchmarks ------------------------------------------ samples, evals = 1, 1 -SUITE["allocation"]["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable( +ALLOC["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable( updatestate!($linmodel, $u, $d); samples=samples, evals=evals ) -SUITE["allocation"]["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable( +ALLOC["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable( evaloutput($linmodel, $d); samples=samples, evals=evals ) -SUITE["allocation"]["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable( +ALLOC["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable( updatestate!($nonlinmodel, $u, $d); samples=samples, evals=evals ) -SUITE["allocation"]["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable( +ALLOC["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable( evaloutput($nonlinmodel, $d); samples=samples, evals=evals ) -SUITE["allocation"]["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable( +ALLOC["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable( linearize!($linmodel, $nonlinmodel); samples=samples, evals=evals ) diff --git a/benchmark/2_bench_state_estim.jl b/benchmark/2_bench_state_estim.jl index eb1e63cd4..5a77acadf 100644 --- a/benchmark/2_bench_state_estim.jl +++ b/benchmark/2_bench_state_estim.jl @@ -6,18 +6,18 @@ samples, evals = 1, 1 skf = SteadyKalmanFilter(linmodel) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] = +ALLOC["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($skf, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] = +ALLOC["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($skf, $u, $y, $d), setup=preparestate!($skf, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = +ALLOC["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = @benchmarkable( evaloutput($skf, $d), setup=preparestate!($skf, $y, $d), @@ -25,12 +25,12 @@ SUITE["allocation"]["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = ) kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["preparestate!"] = +ALLOC["StateEstimator"]["KalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($kf, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["updatestate!"] = +ALLOC["StateEstimator"]["KalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($kf, $u, $y, $d), setup=preparestate!($kf, $y, $d), @@ -38,12 +38,12 @@ SUITE["allocation"]["StateEstimator"]["KalmanFilter"]["updatestate!"] = ) lo = Luenberger(linmodel, nint_u=[1, 1]) -SUITE["allocation"]["StateEstimator"]["Luenberger"]["preparestate!"] = +ALLOC["StateEstimator"]["Luenberger"]["preparestate!"] = @benchmarkable( preparestate!($lo, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["Luenberger"]["updatestate!"] = +ALLOC["StateEstimator"]["Luenberger"]["updatestate!"] = @benchmarkable( updatestate!($lo, $u, $y, $d), setup=preparestate!($lo, $y, $d), @@ -51,12 +51,12 @@ SUITE["allocation"]["StateEstimator"]["Luenberger"]["updatestate!"] = ) im = InternalModel(nonlinmodel) -SUITE["allocation"]["StateEstimator"]["InternalModel"]["preparestate!"] = +ALLOC["StateEstimator"]["InternalModel"]["preparestate!"] = @benchmarkable( preparestate!($im, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["InternalModel"]["updatestate!"] = +ALLOC["StateEstimator"]["InternalModel"]["updatestate!"] = @benchmarkable( updatestate!($im, $u, $y, $d), setup=preparestate!($im, $y, $d), @@ -64,18 +64,18 @@ SUITE["allocation"]["StateEstimator"]["InternalModel"]["updatestate!"] = ) ukf = UnscentedKalmanFilter(nonlinmodel) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] = +ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($ukf, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] = +ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($ukf, $u, $y, $d), setup=preparestate!($ukf, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = +ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = @benchmarkable( evaloutput($ukf, $d), setup=preparestate!($ukf, $y, $d), @@ -83,12 +83,12 @@ SUITE["allocation"]["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = ) ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) -SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] = +ALLOC["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($ekf, $y, $d), samples=samples, evals=evals ) -SUITE["allocation"]["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] = +ALLOC["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($ekf, $u, $y, $d), setup=preparestate!($ekf, $y, $d), diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index 3c81e540a..0b000ca7d 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -1,3 +1,4 @@ +## ----------------- Runtime benchmarks : CSTR ---------------------------------------- G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] uop, yop = [20, 20], [50, 30] @@ -20,7 +21,6 @@ function test_mpc(mpc, plant) return U, Y, Ry end -## ----------------- Runtime benchmarks --------------------------------------------- optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) transcription = SingleShooting() mpc_osqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) @@ -38,33 +38,119 @@ mpc_daqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) transcription = MultipleShooting() mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) -# needed to solve Hessians with eigenvalues at zero, like in MultipleShooting transcription: +# needed to solve Hessians with eigenvalues at zero, like with MultipleShooting: JuMP.set_attribute(mpc_daqp_ms.optim, "eps_prox", 1e-6) +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = SingleShooting() +mpc_ipopt_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_ipopt_ss.optim) + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = MultipleShooting() +mpc_ipopt_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_ipopt_ms.optim) + samples, evals = 500, 1 -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] = +RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] = @benchmarkable(test_mpc($mpc_osqp_ss, $model); samples=samples, evals=evals ) -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] = +RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] = @benchmarkable(test_mpc($mpc_osqp_ms, $model); samples=samples, evals=evals ) -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] = +RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] = @benchmarkable(test_mpc($mpc_daqp_ss, $model); samples=samples, evals=evals ) -SUITE["runtime"]["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] = +RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] = @benchmarkable(test_mpc($mpc_daqp_ms, $model); samples=samples, evals=evals ) +RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["Ipopt"]["SingleShooting"] = + @benchmarkable(test_mpc($mpc_ipopt_ss, $model); + samples=samples, evals=evals +) +RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["Ipopt"]["MultipleShooting"] = + @benchmarkable(test_mpc($mpc_ipopt_ms, $model); + samples=samples, evals=evals +) + +# ----------------- Runtime benchmarks : Pendulum --------------------------------------- +function f!(ẋ, x, u, _ , p) + g, L, K, m = p # [m/s²], [m], [kg/s], [kg] + θ, ω = x[1], x[2] # [rad], [rad/s] + τ = u[1] # [Nm] + ẋ[1] = ω + ẋ[2] = -g/L*sin(θ) - K/m*ω + τ/m/L^2 +end +h!(y, x, _ , _ ) = (y[1] = 180/π*x[1]) # [°] +p = [9.8, 0.4, 1.2, 0.3] +nu = 1; nx = 2; ny = 1; Ts = 0.1 +model = NonLinModel(f!, h!, Ts, nu, nx, ny; p) +σQ = [0.1, 1.0]; σR=[5.0]; nint_u=[1]; σQint_u=[0.1] +estim = UnscentedKalmanFilter(model; σQ, σR, nint_u, σQint_u) +p_plant = copy(p); p_plant[3] = 1.25*p[3] +plant = NonLinModel(f!, h!, Ts, nu, nx, ny; p=p_plant) +N = 35; u = [0.5]; + +Hp, Hc, Mwt, Nwt, Cwt = 20, 2, [0.5], [2.5], Inf +umin, umax = [-1.5], [+1.5] +x_0 = [0, 0]; x̂_0 = [0, 0, 0]; ry = [180] + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = SingleShooting() +nmpc_ipopt_ss = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +nmpc_ipopt_ss = setconstraint!(nmpc_ipopt_ss; umin, umax) +JuMP.unset_time_limit_sec(nmpc_ipopt_ss.optim) +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = MultipleShooting() +nmpc_ipopt_ms = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +nmpc_ipopt_ms = setconstraint!(nmpc_ipopt_ms; umin, umax) +JuMP.unset_time_limit_sec(nmpc_ipopt_ms.optim) + +optim = JuMP.Model(MadNLP.Optimizer, add_bridges=false) +transcription = SingleShooting() +nmpc_madnlp_ss = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +nmpc_madnlp_ss = setconstraint!(nmpc_madnlp_ss; umin, umax) +JuMP.unset_time_limit_sec(nmpc_madnlp_ss.optim) + +optim = JuMP.Model(MadNLP.Optimizer, add_bridges=false) +transcription = MultipleShooting() +nmpc_madnlp_ms = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +nmpc_madnlp_ms = setconstraint!(nmpc_madnlp_ms; umin, umax) +JuMP.unset_time_limit_sec(nmpc_madnlp_ms.optim) + +samples, evals, seconds = 50, 1, 15*60 +RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["Ipopt"]["SingleShooting"] = + @benchmarkable( + sim!($nmpc_ipopt_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds + ) +RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["Ipopt"]["MultipleShooting"] = + @benchmarkable( + sim!($nmpc_ipopt_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds + ) +RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["SingleShooting"] = + @benchmarkable( + sim!($nmpc_madnlp_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds + ) +# TODO: does not work with MadNLP and MultipleShooting, figure out why +# RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["MultipleShooting"] = +# @benchmarkable( +# sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), +# samples=samples, evals=evals, seconds=seconds +# ) # ---------------------- Allocation benchmarks ------------------------------------------ empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) samples, evals = 1, 1 -SUITE["allocation"]["PredictiveController"]["ExplicitMPC"]["moveinput!"] = +ALLOC["PredictiveController"]["ExplicitMPC"]["moveinput!"] = @benchmarkable( moveinput!($empc, $y, $d), setup=preparestate!($empc, $y, $d), diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index d7e6fe1f2..e4f6ad4cd 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -4,6 +4,9 @@ using JuMP, OSQP, DAQP, Ipopt, MadNLP const SUITE = BenchmarkGroup(["ModelPredictiveControl"]) +const ALLOC = SUITE["allocation"] = BenchmarkGroup(["allocation-free","no-allocation"]) +const RUNTIME = SUITE["runtime"] = BenchmarkGroup(["performance","speed"]) + include("0_bench_setup.jl") include("1_bench_sim_model.jl") include("2_bench_state_estim.jl") From bd08f4a315bd9be02ceb3077733f1e633a89590f Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 15 Jul 2025 11:33:02 -0400 Subject: [PATCH 07/13] bench: informative single bench with `MadNLP`+`MultipleShooting` The solver is way too slow for now in this case. See the comments in the code. --- benchmark/3_bench_predictive_control.jl | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index 0b000ca7d..f233e326e 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -117,11 +117,18 @@ nmpc_madnlp_ss = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) nmpc_madnlp_ss = setconstraint!(nmpc_madnlp_ss; umin, umax) JuMP.unset_time_limit_sec(nmpc_madnlp_ss.optim) -optim = JuMP.Model(MadNLP.Optimizer, add_bridges=false) +optim = JuMP.Model(MadNLP.Optimizer) transcription = MultipleShooting() nmpc_madnlp_ms = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) nmpc_madnlp_ms = setconstraint!(nmpc_madnlp_ms; umin, umax) JuMP.unset_time_limit_sec(nmpc_madnlp_ms.optim) +# TODO: does not work well with MadNLP and MultipleShooting, figure out why. +# Current theory: MadNLP LBFGS approximation is less robust than Ipopt version. +# Re-test when exact Hessians will be supported in ModelPredictiveControl.jl. +# The following attributes kinda work with the MadNLP LBFGS approximation but super slow: +JuMP.set_attribute(nmpc_madnlp_ms.optim, "hessian_approximation", MadNLP.CompactLBFGS) +MadNLP_QNopt = MadNLP.QuasiNewtonOptions(; max_history=42) +JuMP.set_attribute(nmpc_madnlp_ms.optim, "quasi_newton_options", MadNLP_QNopt) samples, evals, seconds = 50, 1, 15*60 RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["Ipopt"]["SingleShooting"] = @@ -139,12 +146,12 @@ RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["SingleShooti sim!($nmpc_madnlp_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) -# TODO: does not work with MadNLP and MultipleShooting, figure out why -# RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["MultipleShooting"] = -# @benchmarkable( -# sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), -# samples=samples, evals=evals, seconds=seconds -# ) +# TODO: way too slow, samples=1 (just an informative single point), might change this later. +RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["MultipleShooting"] = + @benchmarkable( + sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), + samples=1, evals=evals, seconds=seconds + ) # ---------------------- Allocation benchmarks ------------------------------------------ empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) From 5a933b44a4294b76e84e1bb5f477c10c5adea8fb Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 15 Jul 2025 12:36:38 -0400 Subject: [PATCH 08/13] bench: added CSTR feedforward benchmarks also renamed no-allocation benchmark to unit test benchmarks --- benchmark/1_bench_sim_model.jl | 49 +++++--- benchmark/2_bench_state_estim.jl | 44 +++---- benchmark/3_bench_predictive_control.jl | 146 +++++++++++++++++++----- benchmark/benchmarks.jl | 4 +- 4 files changed, 170 insertions(+), 73 deletions(-) diff --git a/benchmark/1_bench_sim_model.jl b/benchmark/1_bench_sim_model.jl index 89d5e1db8..8411b5579 100644 --- a/benchmark/1_bench_sim_model.jl +++ b/benchmark/1_bench_sim_model.jl @@ -1,21 +1,32 @@ -## ----------------- Runtime benchmarks --------------------------------------------- -# TODO: Add runtime benchmarks for SimModel +## ----------------- Unit tests (no allocation) ------------------------------------- +const UNIT_MODEL = SUITE["unit tests"]["SimModel"] +samples, evals = 10000, 1 +UNIT_MODEL["LinModel"]["updatestate!"] = + @benchmarkable( + updatestate!($linmodel, $u, $d); + samples=samples, evals=evals + ) +UNIT_MODEL["LinModel"]["evaloutput"] = + @benchmarkable( + evaloutput($linmodel, $d); + samples=samples, evals=evals + ) +UNIT_MODEL["NonLinModel"]["updatestate!"] = + @benchmarkable( + updatestate!($nonlinmodel, $u, $d); + samples=samples, evals=evals + ) +UNIT_MODEL["NonLinModel"]["evaloutput"] = + @benchmarkable( + evaloutput($nonlinmodel, $d); + samples=samples, evals=evals + ) +UNIT_MODEL["NonLinModel"]["linearize!"] = + @benchmarkable( + linearize!($linmodel, $nonlinmodel); + samples=samples, evals=evals + ) -## ----------------- Allocation benchmarks ------------------------------------------ -samples, evals = 1, 1 -ALLOC["SimModel"]["LinModel"]["updatestate!"] = @benchmarkable( - updatestate!($linmodel, $u, $d); samples=samples, evals=evals -) -ALLOC["SimModel"]["LinModel"]["evaloutput"] = @benchmarkable( - evaloutput($linmodel, $d); samples=samples, evals=evals -) -ALLOC["SimModel"]["NonLinModel"]["updatestate!"] = @benchmarkable( - updatestate!($nonlinmodel, $u, $d); samples=samples, evals=evals -) -ALLOC["SimModel"]["NonLinModel"]["evaloutput"] = @benchmarkable( - evaloutput($nonlinmodel, $d); samples=samples, evals=evals -) -ALLOC["SimModel"]["NonLinModel"]["linearize!"] = @benchmarkable( - linearize!($linmodel, $nonlinmodel); samples=samples, evals=evals -) +## ----------------- Case studies --------------------------------------------------- +# TODO: Add case study benchmarks for SimModel diff --git a/benchmark/2_bench_state_estim.jl b/benchmark/2_bench_state_estim.jl index 5a77acadf..b26e165f0 100644 --- a/benchmark/2_bench_state_estim.jl +++ b/benchmark/2_bench_state_estim.jl @@ -1,23 +1,20 @@ -## ----------------- Runtime benchmarks --------------------------------------------- -# TODO: Add runtime benchmarks for StateEstimator - - -## ----------------- Allocation benchmarks ------------------------------------------ -samples, evals = 1, 1 +## ----------------- Unit tests (no allocation) ----------------------------------------- +const UNIT_ESTIM = SUITE["unit tests"]["StateEstimator"] +samples, evals = 10000, 1 skf = SteadyKalmanFilter(linmodel) -ALLOC["StateEstimator"]["SteadyKalmanFilter"]["preparestate!"] = +UNIT_ESTIM["SteadyKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($skf, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["SteadyKalmanFilter"]["updatestate!"] = +UNIT_ESTIM["SteadyKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($skf, $u, $y, $d), setup=preparestate!($skf, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = +UNIT_ESTIM["SteadyKalmanFilter"]["evaloutput"] = @benchmarkable( evaloutput($skf, $d), setup=preparestate!($skf, $y, $d), @@ -25,12 +22,12 @@ ALLOC["StateEstimator"]["SteadyKalmanFilter"]["evaloutput"] = ) kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false) -ALLOC["StateEstimator"]["KalmanFilter"]["preparestate!"] = +UNIT_ESTIM["KalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($kf, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["KalmanFilter"]["updatestate!"] = +UNIT_ESTIM["KalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($kf, $u, $y, $d), setup=preparestate!($kf, $y, $d), @@ -38,12 +35,12 @@ ALLOC["StateEstimator"]["KalmanFilter"]["updatestate!"] = ) lo = Luenberger(linmodel, nint_u=[1, 1]) -ALLOC["StateEstimator"]["Luenberger"]["preparestate!"] = +UNIT_ESTIM["Luenberger"]["preparestate!"] = @benchmarkable( preparestate!($lo, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["Luenberger"]["updatestate!"] = +UNIT_ESTIM["Luenberger"]["updatestate!"] = @benchmarkable( updatestate!($lo, $u, $y, $d), setup=preparestate!($lo, $y, $d), @@ -51,12 +48,12 @@ ALLOC["StateEstimator"]["Luenberger"]["updatestate!"] = ) im = InternalModel(nonlinmodel) -ALLOC["StateEstimator"]["InternalModel"]["preparestate!"] = +UNIT_ESTIM["InternalModel"]["preparestate!"] = @benchmarkable( preparestate!($im, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["InternalModel"]["updatestate!"] = +UNIT_ESTIM["InternalModel"]["updatestate!"] = @benchmarkable( updatestate!($im, $u, $y, $d), setup=preparestate!($im, $y, $d), @@ -64,18 +61,18 @@ ALLOC["StateEstimator"]["InternalModel"]["updatestate!"] = ) ukf = UnscentedKalmanFilter(nonlinmodel) -ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["preparestate!"] = +UNIT_ESTIM["UnscentedKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($ukf, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["updatestate!"] = +UNIT_ESTIM["UnscentedKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($ukf, $u, $y, $d), setup=preparestate!($ukf, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = +UNIT_ESTIM["UnscentedKalmanFilter"]["evaloutput"] = @benchmarkable( evaloutput($ukf, $d), setup=preparestate!($ukf, $y, $d), @@ -83,14 +80,19 @@ ALLOC["StateEstimator"]["UnscentedKalmanFilter"]["evaloutput"] = ) ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) -ALLOC["StateEstimator"]["ExtendedKalmanFilter"]["preparestate!"] = +UNIT_ESTIM["ExtendedKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($ekf, $y, $d), samples=samples, evals=evals ) -ALLOC["StateEstimator"]["ExtendedKalmanFilter"]["updatestate!"] = +UNIT_ESTIM["ExtendedKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($ekf, $u, $y, $d), setup=preparestate!($ekf, $y, $d), samples=samples, evals=evals - ) \ No newline at end of file + ) + +## ----------------- Case studies --------------------------------------------------- +# TODO: Add case study benchmarks for StateEstimator + + diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index f233e326e..3e5bc2720 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -1,4 +1,21 @@ -## ----------------- Runtime benchmarks : CSTR ---------------------------------------- +# ---------------------- Unit tests (no allocation) --------------------------------------- +const UNIT_MPC = SUITE["unit tests"]["PredictiveController"] + +empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) + +samples, evals = 10000, 1 +UNIT_MPC["ExplicitMPC"]["moveinput!"] = + @benchmarkable( + moveinput!($empc, $y, $d), + setup=preparestate!($empc, $y, $d), + samples=samples, evals=evals + ) + + +## ---------------------- Case studies ---------------------------------------------------- +const CASE_MPC = SUITE["case studies"]["PredictiveController"] + +## ----------------- Runtime benchmarks : CSTR without feedforward ------------------------ G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] uop, yop = [20, 20], [50, 30] @@ -52,30 +69,107 @@ mpc_ipopt_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -In JuMP.unset_time_limit_sec(mpc_ipopt_ms.optim) samples, evals = 500, 1 -RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["SingleShooting"] = +CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["OSQP"]["SingleShooting"] = @benchmarkable(test_mpc($mpc_osqp_ss, $model); - samples=samples, evals=evals -) -RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["OSQP"]["MultipleShooting"] = + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["OSQP"]["MultipleShooting"] = @benchmarkable(test_mpc($mpc_osqp_ms, $model); - samples=samples, evals=evals -) -RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["SingleShooting"] = + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["DAQP"]["SingleShooting"] = @benchmarkable(test_mpc($mpc_daqp_ss, $model); - samples=samples, evals=evals -) -RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["DAQP"]["MultipleShooting"] = + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["DAQP"]["MultipleShooting"] = @benchmarkable(test_mpc($mpc_daqp_ms, $model); - samples=samples, evals=evals -) -RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["Ipopt"]["SingleShooting"] = + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["Ipopt"]["SingleShooting"] = @benchmarkable(test_mpc($mpc_ipopt_ss, $model); samples=samples, evals=evals ) -RUNTIME["PredictiveController"]["CSTR"]["LinMPC"]["Ipopt"]["MultipleShooting"] = +CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["Ipopt"]["MultipleShooting"] = @benchmarkable(test_mpc($mpc_ipopt_ms, $model); - samples=samples, evals=evals -) + samples=samples, evals=evals + ) + +## ----------------- Runtime benchmarks : CSTR with feedforward ------------------------- +model_d = LinModel([G G[1:2, 2]], 2.0; i_d=[3]) +model_d = setop!(model_d; uop, yop, dop=[20]) +function test_mpc_d(mpc_d, plant) + plant.x0 .= 0; y = plant(); d = [20] + initstate!(mpc_d, plant.uop, y, d) + N = 75; ry = [50, 30]; ul = 0 + U, Y, Ry = zeros(2, N), zeros(2, N), zeros(2, N) + for i = 1:N + i == 26 && (ry = [48, 35]) + i == 51 && (ul = -10) + y, d = plant(), [20+ul] + preparestate!(mpc_d, y, d) + u = mpc_d(ry, d) + U[:,i], Y[:,i], Ry[:,i] = u, y, ry + updatestate!(mpc_d, u, y, d) + updatestate!(plant, u+[0,ul]) + end + return U, Y, Ry +end + +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +transcription = SingleShooting() +mpc_d_osqp_ss = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_d_osqp_ss.optim) + +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +transcription = MultipleShooting() +mpc_d_osqp_ms = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_d_osqp_ms.optim) + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +transcription = SingleShooting() +mpc_d_daqp_ss = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +transcription = MultipleShooting() +mpc_d_daqp_ms = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) +# needed to solve Hessians with eigenvalues at zero, like with MultipleShooting: +JuMP.set_attribute(mpc_d_daqp_ms.optim, "eps_prox", 1e-6) + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = SingleShooting() +mpc_d_ipopt_ss = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_d_ipopt_ss.optim) + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = MultipleShooting() +mpc_d_ipopt_ms = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) +JuMP.unset_time_limit_sec(mpc_d_ipopt_ms.optim) + +samples, evals = 500, 1 +CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["OSQP"]["SingleShooting"] = + @benchmarkable(test_mpc_d($mpc_d_osqp_ss, $model); + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["OSQP"]["MultipleShooting"] = + @benchmarkable(test_mpc_d($mpc_d_osqp_ms, $model); + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["DAQP"]["SingleShooting"] = + @benchmarkable(test_mpc_d($mpc_d_daqp_ss, $model); + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["DAQP"]["MultipleShooting"] = + @benchmarkable(test_mpc_d($mpc_d_daqp_ms, $model); + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["Ipopt"]["SingleShooting"] = + @benchmarkable(test_mpc_d($mpc_d_ipopt_ss, $model); + samples=samples, evals=evals + ) +CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["Ipopt"]["MultipleShooting"] = + @benchmarkable(test_mpc_d($mpc_d_ipopt_ms, $model); + samples=samples, evals=evals + ) # ----------------- Runtime benchmarks : Pendulum --------------------------------------- function f!(ẋ, x, u, _ , p) @@ -131,35 +225,25 @@ MadNLP_QNopt = MadNLP.QuasiNewtonOptions(; max_history=42) JuMP.set_attribute(nmpc_madnlp_ms.optim, "quasi_newton_options", MadNLP_QNopt) samples, evals, seconds = 50, 1, 15*60 -RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["Ipopt"]["SingleShooting"] = +CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["Ipopt"]["SingleShooting"] = @benchmarkable( sim!($nmpc_ipopt_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) -RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["Ipopt"]["MultipleShooting"] = +CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["Ipopt"]["MultipleShooting"] = @benchmarkable( sim!($nmpc_ipopt_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) -RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["SingleShooting"] = +CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["MadNLP"]["SingleShooting"] = @benchmarkable( sim!($nmpc_madnlp_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) # TODO: way too slow, samples=1 (just an informative single point), might change this later. -RUNTIME["PredictiveController"]["Pendulum"]["NonLinMPC"]["MadNLP"]["MultipleShooting"] = +CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["MadNLP"]["MultipleShooting"] = @benchmarkable( sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=1, evals=evals, seconds=seconds ) -# ---------------------- Allocation benchmarks ------------------------------------------ -empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) - -samples, evals = 1, 1 -ALLOC["PredictiveController"]["ExplicitMPC"]["moveinput!"] = - @benchmarkable( - moveinput!($empc, $y, $d), - setup=preparestate!($empc, $y, $d), - samples=samples, evals=evals - ) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index e4f6ad4cd..b0b3b5192 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -4,8 +4,8 @@ using JuMP, OSQP, DAQP, Ipopt, MadNLP const SUITE = BenchmarkGroup(["ModelPredictiveControl"]) -const ALLOC = SUITE["allocation"] = BenchmarkGroup(["allocation-free","no-allocation"]) -const RUNTIME = SUITE["runtime"] = BenchmarkGroup(["performance","speed"]) +SUITE["unit tests"] = BenchmarkGroup(["allocation-free", "no allocation", "single call"]) +SUITE["case studies"] = BenchmarkGroup(["performance", "speed" ,"integration"]) include("0_bench_setup.jl") include("1_bench_sim_model.jl") From 4a817582513be5c7b08754b8f509eedc0544b14e Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 15 Jul 2025 13:05:12 -0400 Subject: [PATCH 09/13] bench: removing `samples` and `evals` kwargs for unit tests --- benchmark/1_bench_sim_model.jl | 6 ------ benchmark/2_bench_state_estim.jl | 15 --------------- benchmark/3_bench_predictive_control.jl | 2 -- 3 files changed, 23 deletions(-) diff --git a/benchmark/1_bench_sim_model.jl b/benchmark/1_bench_sim_model.jl index 8411b5579..e5731d5cc 100644 --- a/benchmark/1_bench_sim_model.jl +++ b/benchmark/1_bench_sim_model.jl @@ -1,31 +1,25 @@ ## ----------------- Unit tests (no allocation) ------------------------------------- const UNIT_MODEL = SUITE["unit tests"]["SimModel"] -samples, evals = 10000, 1 UNIT_MODEL["LinModel"]["updatestate!"] = @benchmarkable( updatestate!($linmodel, $u, $d); - samples=samples, evals=evals ) UNIT_MODEL["LinModel"]["evaloutput"] = @benchmarkable( evaloutput($linmodel, $d); - samples=samples, evals=evals ) UNIT_MODEL["NonLinModel"]["updatestate!"] = @benchmarkable( updatestate!($nonlinmodel, $u, $d); - samples=samples, evals=evals ) UNIT_MODEL["NonLinModel"]["evaloutput"] = @benchmarkable( evaloutput($nonlinmodel, $d); - samples=samples, evals=evals ) UNIT_MODEL["NonLinModel"]["linearize!"] = @benchmarkable( linearize!($linmodel, $nonlinmodel); - samples=samples, evals=evals ) ## ----------------- Case studies --------------------------------------------------- diff --git a/benchmark/2_bench_state_estim.jl b/benchmark/2_bench_state_estim.jl index b26e165f0..5b82976fb 100644 --- a/benchmark/2_bench_state_estim.jl +++ b/benchmark/2_bench_state_estim.jl @@ -1,95 +1,80 @@ ## ----------------- Unit tests (no allocation) ----------------------------------------- const UNIT_ESTIM = SUITE["unit tests"]["StateEstimator"] -samples, evals = 10000, 1 skf = SteadyKalmanFilter(linmodel) UNIT_ESTIM["SteadyKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($skf, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["SteadyKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($skf, $u, $y, $d), setup=preparestate!($skf, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["SteadyKalmanFilter"]["evaloutput"] = @benchmarkable( evaloutput($skf, $d), setup=preparestate!($skf, $y, $d), - samples=samples, evals=evals ) kf = KalmanFilter(linmodel, nint_u=[1, 1], direct=false) UNIT_ESTIM["KalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($kf, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["KalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($kf, $u, $y, $d), setup=preparestate!($kf, $y, $d), - samples=samples, evals=evals ) lo = Luenberger(linmodel, nint_u=[1, 1]) UNIT_ESTIM["Luenberger"]["preparestate!"] = @benchmarkable( preparestate!($lo, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["Luenberger"]["updatestate!"] = @benchmarkable( updatestate!($lo, $u, $y, $d), setup=preparestate!($lo, $y, $d), - samples=samples, evals=evals ) im = InternalModel(nonlinmodel) UNIT_ESTIM["InternalModel"]["preparestate!"] = @benchmarkable( preparestate!($im, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["InternalModel"]["updatestate!"] = @benchmarkable( updatestate!($im, $u, $y, $d), setup=preparestate!($im, $y, $d), - samples=samples, evals=evals ) ukf = UnscentedKalmanFilter(nonlinmodel) UNIT_ESTIM["UnscentedKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($ukf, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["UnscentedKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($ukf, $u, $y, $d), setup=preparestate!($ukf, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["UnscentedKalmanFilter"]["evaloutput"] = @benchmarkable( evaloutput($ukf, $d), setup=preparestate!($ukf, $y, $d), - samples=samples, evals=evals ) ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) UNIT_ESTIM["ExtendedKalmanFilter"]["preparestate!"] = @benchmarkable( preparestate!($ekf, $y, $d), - samples=samples, evals=evals ) UNIT_ESTIM["ExtendedKalmanFilter"]["updatestate!"] = @benchmarkable( updatestate!($ekf, $u, $y, $d), setup=preparestate!($ekf, $y, $d), - samples=samples, evals=evals ) ## ----------------- Case studies --------------------------------------------------- diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index 3e5bc2720..e34c7e82f 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -3,12 +3,10 @@ const UNIT_MPC = SUITE["unit tests"]["PredictiveController"] empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) -samples, evals = 10000, 1 UNIT_MPC["ExplicitMPC"]["moveinput!"] = @benchmarkable( moveinput!($empc, $y, $d), setup=preparestate!($empc, $y, $d), - samples=samples, evals=evals ) From d80f6a4abb9196ec00db54558ade86719fe33b27 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 15 Jul 2025 14:16:07 -0400 Subject: [PATCH 10/13] bench: add EMPC and custom constraints on Pendulum --- benchmark/3_bench_predictive_control.jl | 115 ++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index e34c7e82f..940a7fb25 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -13,7 +13,7 @@ UNIT_MPC["ExplicitMPC"]["moveinput!"] = ## ---------------------- Case studies ---------------------------------------------------- const CASE_MPC = SUITE["case studies"]["PredictiveController"] -## ----------------- Runtime benchmarks : CSTR without feedforward ------------------------ +## ----------------- Case study: CSTR without feedforward ------------------------ G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] uop, yop = [20, 20], [50, 30] @@ -92,7 +92,7 @@ CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["Ipopt"]["MultipleShooting"] = samples=samples, evals=evals ) -## ----------------- Runtime benchmarks : CSTR with feedforward ------------------------- +## ----------------- Case study: CSTR with feedforward ------------------------- model_d = LinModel([G G[1:2, 2]], 2.0; i_d=[3]) model_d = setop!(model_d; uop, yop, dop=[20]) function test_mpc_d(mpc_d, plant) @@ -169,7 +169,7 @@ CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["Ipopt"]["MultipleShooting"] = samples=samples, evals=evals ) -# ----------------- Runtime benchmarks : Pendulum --------------------------------------- +# ----------------- Case study: Pendulum noneconomic ----------------------------- function f!(ẋ, x, u, _ , p) g, L, K, m = p # [m/s²], [m], [kg/s], [kg] θ, ω = x[1], x[2] # [rad], [rad/s] @@ -223,25 +223,122 @@ MadNLP_QNopt = MadNLP.QuasiNewtonOptions(; max_history=42) JuMP.set_attribute(nmpc_madnlp_ms.optim, "quasi_newton_options", MadNLP_QNopt) samples, evals, seconds = 50, 1, 15*60 -CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["Ipopt"]["SingleShooting"] = +CASE_MPC["Pendulum"]["NonLinMPC"]["Noneconomic"]["Ipopt"]["SingleShooting"] = @benchmarkable( sim!($nmpc_ipopt_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) -CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["Ipopt"]["MultipleShooting"] = +CASE_MPC["Pendulum"]["NonLinMPC"]["Noneconomic"]["Ipopt"]["MultipleShooting"] = @benchmarkable( sim!($nmpc_ipopt_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) -CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["MadNLP"]["SingleShooting"] = +CASE_MPC["Pendulum"]["NonLinMPC"]["Noneconomic"]["MadNLP"]["SingleShooting"] = @benchmarkable( sim!($nmpc_madnlp_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) # TODO: way too slow, samples=1 (just an informative single point), might change this later. -CASE_MPC["Pendulum"]["NonLinMPC"]["Tracking"]["MadNLP"]["MultipleShooting"] = +# CASE_MPC["Pendulum"]["NonLinMPC"]["Noneconomic"]["MadNLP"]["MultipleShooting"] = +# @benchmarkable( +# sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), +# samples=1, evals=evals, seconds=seconds +# ) + +# ----------------- Case study: Pendulum economic -------------------------------- +h2!(y, x, _ , _ ) = (y[1] = 180/π*x[1]; y[2]=x[2]) +nu, nx, ny = 1, 2, 2 +model2 = NonLinModel(f!, h2!, Ts, nu, nx, ny; p) +plant2 = NonLinModel(f!, h2!, Ts, nu, nx, ny; p=p_plant) +estim2 = UnscentedKalmanFilter(model2; σQ, σR, nint_u, σQint_u, i_ym=[1]) +function JE(UE, ŶE, _ , p) + Ts = p + τ, ω = @views UE[1:end-1], ŶE[2:2:end-1] + return Ts*dot(τ, ω) +end +p = Ts; Mwt2 = [Mwt; 0.0]; Ewt = 3.5e3 +x_0 = [0, 0]; x̂_0 = [0, 0, 0]; ry = [180; 0] + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = SingleShooting() +empc_ipopt_ss = NonLinMPC(estim2; Hp, Hc, Nwt, Mwt=Mwt2, Cwt, JE, Ewt, optim, transcription, p) +empc_ipopt_ss = setconstraint!(empc_ipopt_ss; umin, umax) +JuMP.unset_time_limit_sec(empc_ipopt_ss.optim) + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = MultipleShooting() +empc_ipopt_ms = NonLinMPC(estim2; Hp, Hc, Nwt, Mwt=Mwt2, Cwt, JE, Ewt, optim, transcription, p) +empc_ipopt_ms = setconstraint!(empc_ipopt_ms; umin, umax) +JuMP.unset_time_limit_sec(empc_ipopt_ms.optim) + +optim = JuMP.Model(MadNLP.Optimizer, add_bridges=false) +transcription = SingleShooting() +empc_madnlp_ss = NonLinMPC(estim2; Hp, Hc, Nwt, Mwt=Mwt2, Cwt, JE, Ewt, optim, transcription, p) +empc_madnlp_ss = setconstraint!(empc_madnlp_ss; umin, umax) +JuMP.unset_time_limit_sec(empc_madnlp_ss.optim) + +# TODO: test EMPC with MadNLP and MultipleShooting, see comment above. + +samples, evals, seconds = 50, 1, 15*60 +CASE_MPC["Pendulum"]["NonLinMPC"]["Economic"]["Ipopt"]["SingleShooting"] = + @benchmarkable( + sim!($empc_ipopt_ss, $N, $ry; plant=$plant2, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds + ) +CASE_MPC["Pendulum"]["NonLinMPC"]["Economic"]["Ipopt"]["MultipleShooting"] = @benchmarkable( - sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), - samples=1, evals=evals, seconds=seconds + sim!($empc_ipopt_ms, $N, $ry; plant=$plant2, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds ) +CASE_MPC["Pendulum"]["NonLinMPC"]["Economic"]["MadNLP"]["SingleShooting"] = + @benchmarkable( + sim!($empc_madnlp_ss, $N, $ry; plant=$plant2, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds + ) + +# -------------- Case study: Pendulum custom constraints -------------------------- +function gc!(LHS, Ue, Ŷe, _, p, ϵ) + Pmax = p + i_τ, i_ω = 1, 2 + for i in eachindex(LHS) + τ, ω = Ue[i_τ], Ŷe[i_ω] + P = τ*ω + LHS[i] = P - Pmax - ϵ + i_τ += 1 + i_ω += 2 + end + return nothing +end +Cwt, Pmax, nc = 1e5, 3, Hp+1 +x_0 = [0, 0]; x̂_0 = [0, 0, 0]; ry = [180; 0] + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = SingleShooting() +nmpc2_ipopt_ss = NonLinMPC(estim2; + Hp, Hc, Nwt=Nwt, Mwt=[0.5, 0], Cwt, gc!, nc, p=Pmax, optim, transcription +) +nmpc2_ipopt_ss = setconstraint!(nmpc2_ipopt_ss; umin, umax) +JuMP.unset_time_limit_sec(nmpc2_ipopt_ss.optim) +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = MultipleShooting() +nmpc2_ipopt_ms = NonLinMPC(estim2; + Hp, Hc, Nwt=Nwt, Mwt=[0.5, 0], Cwt, gc!, nc, p=Pmax, optim, transcription +) +nmpc2_ipopt_ms = setconstraint!(nmpc2_ipopt_ms; umin, umax) +JuMP.unset_time_limit_sec(nmpc2_ipopt_ms.optim) + +# TODO: test custom constraints with MadNLP and SingleShooting, see comment above. +# TODO: test custom constraints with MadNLP and MultipleShooting, see comment above. + +samples, evals, seconds = 50, 1, 15*60 +CASE_MPC["Pendulum"]["NonLinMPC"]["Custom constraints"]["Ipopt"]["SingleShooting"] = + @benchmarkable( + sim!($nmpc2_ipopt_ss, $N, $ry; plant=$plant2, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds + ) +CASE_MPC["Pendulum"]["NonLinMPC"]["Custom constraints"]["Ipopt"]["MultipleShooting"] = + @benchmarkable( + sim!($nmpc2_ipopt_ms, $N, $ry; plant=$plant2, x_0=$x_0, x̂_0=$x̂_0), + samples=samples, evals=evals, seconds=seconds + ) \ No newline at end of file From 505574152d8527436c87149c73f1e197710e1ba9 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 15 Jul 2025 16:35:40 -0400 Subject: [PATCH 11/13] bench: bench `moveinputs` with implicit MPCs --- benchmark/1_bench_sim_model.jl | 4 +- benchmark/2_bench_state_estim.jl | 115 ++++++++++--- benchmark/3_bench_predictive_control.jl | 217 +++++++++++++++++++----- benchmark/benchmarks.jl | 2 +- 4 files changed, 274 insertions(+), 64 deletions(-) diff --git a/benchmark/1_bench_sim_model.jl b/benchmark/1_bench_sim_model.jl index e5731d5cc..25d98631f 100644 --- a/benchmark/1_bench_sim_model.jl +++ b/benchmark/1_bench_sim_model.jl @@ -1,4 +1,4 @@ -## ----------------- Unit tests (no allocation) ------------------------------------- +## ----------------- Unit tests ---------------------------------------------------------- const UNIT_MODEL = SUITE["unit tests"]["SimModel"] UNIT_MODEL["LinModel"]["updatestate!"] = @@ -22,5 +22,5 @@ UNIT_MODEL["NonLinModel"]["linearize!"] = linearize!($linmodel, $nonlinmodel); ) -## ----------------- Case studies --------------------------------------------------- +## ----------------- Case studies --------------------------------------------------------- # TODO: Add case study benchmarks for SimModel diff --git a/benchmark/2_bench_state_estim.jl b/benchmark/2_bench_state_estim.jl index 5b82976fb..3e1711bd4 100644 --- a/benchmark/2_bench_state_estim.jl +++ b/benchmark/2_bench_state_estim.jl @@ -1,4 +1,4 @@ -## ----------------- Unit tests (no allocation) ----------------------------------------- +## ----------------- Unit tests ----------------------------------------------------------- const UNIT_ESTIM = SUITE["unit tests"]["StateEstimator"] skf = SteadyKalmanFilter(linmodel) @@ -27,6 +27,11 @@ UNIT_ESTIM["KalmanFilter"]["updatestate!"] = updatestate!($kf, $u, $y, $d), setup=preparestate!($kf, $y, $d), ) +UNIT_ESTIM["KalmanFilter"]["evaloutput"] = + @benchmarkable( + evaloutput($kf, $d), + setup=preparestate!($kf, $y, $d), + ) lo = Luenberger(linmodel, nint_u=[1, 1]) UNIT_ESTIM["Luenberger"]["preparestate!"] = @@ -38,44 +43,110 @@ UNIT_ESTIM["Luenberger"]["updatestate!"] = updatestate!($lo, $u, $y, $d), setup=preparestate!($lo, $y, $d), ) +UNIT_ESTIM["Luenberger"]["evaloutput"] = + @benchmarkable( + evaloutput($lo, $d), + setup=preparestate!($lo, $y, $d), + ) -im = InternalModel(nonlinmodel) -UNIT_ESTIM["InternalModel"]["preparestate!"] = +im_lin = InternalModel(linmodel) +im_nonlin = InternalModel(nonlinmodel) +UNIT_ESTIM["InternalModel"]["preparestate!"]["LinModel"] = + @benchmarkable( + preparestate!($im_lin, $y, $d), + ) +UNIT_ESTIM["InternalModel"]["updatestate!"]["LinModel"] = @benchmarkable( - preparestate!($im, $y, $d), + updatestate!($im_lin, $u, $y, $d), + setup=preparestate!($im_lin, $y, $d), ) -UNIT_ESTIM["InternalModel"]["updatestate!"] = +UNIT_ESTIM["InternalModel"]["evaloutput"]["LinModel"] = @benchmarkable( - updatestate!($im, $u, $y, $d), - setup=preparestate!($im, $y, $d), + evaloutput($im_lin, $d), + setup=preparestate!($im_lin, $y, $d), + ) +UNIT_ESTIM["InternalModel"]["preparestate!"]["NonLinModel"] = + @benchmarkable( + preparestate!($im_nonlin, $y, $d), + ) +UNIT_ESTIM["InternalModel"]["updatestate!"]["NonLinModel"] = + @benchmarkable( + updatestate!($im_nonlin, $u, $y, $d), + setup=preparestate!($im_nonlin, $y, $d), + ) +UNIT_ESTIM["InternalModel"]["evaloutput"]["NonLinModel"] = + @benchmarkable( + evaloutput($im_nonlin, $d), + setup=preparestate!($im_nonlin, $y, $d), ) -ukf = UnscentedKalmanFilter(nonlinmodel) -UNIT_ESTIM["UnscentedKalmanFilter"]["preparestate!"] = +ukf_lin = UnscentedKalmanFilter(linmodel) +ukf_nonlin = UnscentedKalmanFilter(nonlinmodel) +UNIT_ESTIM["UnscentedKalmanFilter"]["preparestate!"]["LinModel"] = @benchmarkable( - preparestate!($ukf, $y, $d), + preparestate!($ukf_lin, $y, $d), ) -UNIT_ESTIM["UnscentedKalmanFilter"]["updatestate!"] = +UNIT_ESTIM["UnscentedKalmanFilter"]["updatestate!"]["LinModel"] = @benchmarkable( - updatestate!($ukf, $u, $y, $d), - setup=preparestate!($ukf, $y, $d), + updatestate!($ukf_lin, $u, $y, $d), + setup=preparestate!($ukf_lin, $y, $d), ) -UNIT_ESTIM["UnscentedKalmanFilter"]["evaloutput"] = +UNIT_ESTIM["UnscentedKalmanFilter"]["evaloutput"]["LinModel"] = @benchmarkable( - evaloutput($ukf, $d), - setup=preparestate!($ukf, $y, $d), + evaloutput($ukf_lin, $d), + setup=preparestate!($ukf_lin, $y, $d), + ) +UNIT_ESTIM["UnscentedKalmanFilter"]["preparestate!"]["NonLinModel"] = + @benchmarkable( + preparestate!($ukf_nonlin, $y, $d), + ) +UNIT_ESTIM["UnscentedKalmanFilter"]["updatestate!"]["NonLinModel"] = + @benchmarkable( + updatestate!($ukf_nonlin, $u, $y, $d), + setup=preparestate!($ukf_nonlin, $y, $d), + ) +UNIT_ESTIM["UnscentedKalmanFilter"]["evaloutput"]["NonLinModel"] = + @benchmarkable( + evaloutput($ukf_nonlin, $d), + setup=preparestate!($ukf_nonlin, $y, $d), ) -ekf = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) -UNIT_ESTIM["ExtendedKalmanFilter"]["preparestate!"] = +ekf_lin = ExtendedKalmanFilter(linmodel, nint_u=[1, 1], direct=false) +ekf_nonlin = ExtendedKalmanFilter(nonlinmodel, nint_u=[1, 1], direct=false) +UNIT_ESTIM["ExtendedKalmanFilter"]["preparestate!"]["LinModel"] = + @benchmarkable( + preparestate!($ekf_lin, $y, $d), + ) +UNIT_ESTIM["ExtendedKalmanFilter"]["updatestate!"]["LinModel"] = @benchmarkable( - preparestate!($ekf, $y, $d), + updatestate!($ekf_lin, $u, $y, $d), + setup=preparestate!($ekf_lin, $y, $d), ) -UNIT_ESTIM["ExtendedKalmanFilter"]["updatestate!"] = +UNIT_ESTIM["ExtendedKalmanFilter"]["evaloutput"]["LinModel"] = @benchmarkable( - updatestate!($ekf, $u, $y, $d), - setup=preparestate!($ekf, $y, $d), + evaloutput($ekf_lin, $d), + setup=preparestate!($ekf_lin, $y, $d), ) +UNIT_ESTIM["ExtendedKalmanFilter"]["preparestate!"]["NonLinModel"] = + @benchmarkable( + preparestate!($ekf_nonlin, $y, $d), + ) +UNIT_ESTIM["ExtendedKalmanFilter"]["updatestate!"]["NonLinModel"] = + @benchmarkable( + updatestate!($ekf_nonlin, $u, $y, $d), + setup=preparestate!($ekf_nonlin, $y, $d), + ) +UNIT_ESTIM["ExtendedKalmanFilter"]["evaloutput"]["NonLinModel"] = + @benchmarkable( + evaloutput($ekf_nonlin, $d), + setup=preparestate!($ekf_nonlin, $y, $d), + ) + +mhe_lin_direct = MovingHorizonEstimator(linmodel, He=10, direct=true) +mhe_lin_nondirect = MovingHorizonEstimator(linmodel, He=10, direct=false) +mhe_nonlin_direct = MovingHorizonEstimator(nonlinmodel, He=10, direct=true) +mhe_nonlin_nondirect = MovingHorizonEstimator(nonlinmodel, He=10, direct=false) + ## ----------------- Case studies --------------------------------------------------- # TODO: Add case study benchmarks for StateEstimator diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index 940a7fb25..8006c25e3 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -1,7 +1,30 @@ -# ---------------------- Unit tests (no allocation) --------------------------------------- +# ---------------------- Unit tests ------------------------------------------------------- const UNIT_MPC = SUITE["unit tests"]["PredictiveController"] -empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1]) +linmpc_ss = LinMPC( + linmodel, transcription=SingleShooting(), + Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1], Hp=10 +) +linmpc_ms = LinMPC( + linmodel, transcription=MultipleShooting(), + Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1], Hp=10 +) + +samples, evals, seconds = 500, 1, 60 +UNIT_MPC["LinMPC"]["moveinput!"]["SingleShooting"] = + @benchmarkable( + moveinput!($linmpc_ss, $y, $d), + setup=preparestate!($linmpc_ss, $y, $d), + samples=samples, evals=evals, seconds=seconds + ) +UNIT_MPC["LinMPC"]["moveinput!"]["MultipleShooting"] = + @benchmarkable( + moveinput!($linmpc_ms, $y, $d), + setup=preparestate!($linmpc_ms, $y, $d), + samples=samples, evals=evals, seconds=seconds + ) + +empc = ExplicitMPC(linmodel, Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1], Hp=10) UNIT_MPC["ExplicitMPC"]["moveinput!"] = @benchmarkable( @@ -9,6 +32,49 @@ UNIT_MPC["ExplicitMPC"]["moveinput!"] = setup=preparestate!($empc, $y, $d), ) +nmpc_lin_ss = NonLinMPC( + linmodel, transcription=SingleShooting(), + Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1], Hp=10 +) +nmpc_lin_ms = NonLinMPC( + linmodel, transcription=MultipleShooting(), + Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1], Hp=10 +) +nmpc_nonlin_ss = NonLinMPC( + nonlinmodel, transcription=SingleShooting(), + Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1], Hp=10 +) +nmpc_nonlin_ms = NonLinMPC( + nonlinmodel, transcription=MultipleShooting(), + Mwt=[1, 1], Nwt=[0.1, 0.1], Lwt=[0.1, 0.1], Hp=10 +) + +samples, evals, seconds = 500, 1, 60 +UNIT_MPC["NonLinMPC"]["moveinput!"]["LinModel"]["SingleShooting"] = + @benchmarkable( + moveinput!($nmpc_lin_ss, $y, $d), + setup=preparestate!($nmpc_lin_ss, $y, $d), + samples=samples, evals=evals, seconds=seconds + ) +UNIT_MPC["NonLinMPC"]["moveinput!"]["LinModel"]["MultipleShooting"] = + @benchmarkable( + moveinput!($nmpc_lin_ms, $y, $d), + setup=preparestate!($nmpc_lin_ms, $y, $d), + samples=samples, evals=evals, seconds=seconds + ) +UNIT_MPC["NonLinMPC"]["moveinput!"]["NonLinModel"]["SingleShooting"] = + @benchmarkable( + moveinput!($nmpc_nonlin_ss, $y, $d), + setup=preparestate!($nmpc_nonlin_ss, $y, $d), + samples=samples, evals=evals, seconds=seconds + ) +UNIT_MPC["NonLinMPC"]["moveinput!"]["NonLinModel"]["MultipleShooting"] = + @benchmarkable( + moveinput!($nmpc_nonlin_ms, $y, $d), + setup=preparestate!($nmpc_nonlin_ms, $y, $d), + samples=samples, evals=evals, seconds=seconds + ) + ## ---------------------- Case studies ---------------------------------------------------- const CASE_MPC = SUITE["case studies"]["PredictiveController"] @@ -50,11 +116,12 @@ optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) transcription = SingleShooting() mpc_daqp_ss = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) -optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) -transcription = MultipleShooting() -mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) -# needed to solve Hessians with eigenvalues at zero, like with MultipleShooting: -JuMP.set_attribute(mpc_daqp_ms.optim, "eps_prox", 1e-6) +# # Skip DAQP with MultipleShooting, it is not designed for sparse Hessians. Kind of works +# # with "eps_prox" configured to 1e-6, but not worth it. +# optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +# transcription = MultipleShooting() +# mpc_daqp_ms = setconstraint!(LinMPC(model; optim, transcription), ymin=[45, -Inf]) +# JuMP.set_attribute(mpc_daqp_ms.optim, "eps_prox", 1e-6) optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) transcription = SingleShooting() @@ -79,10 +146,6 @@ CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["DAQP"]["SingleShooting"] = @benchmarkable(test_mpc($mpc_daqp_ss, $model); samples=samples, evals=evals ) -CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["DAQP"]["MultipleShooting"] = - @benchmarkable(test_mpc($mpc_daqp_ms, $model); - samples=samples, evals=evals - ) CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["Ipopt"]["SingleShooting"] = @benchmarkable(test_mpc($mpc_ipopt_ss, $model); samples=samples, evals=evals @@ -127,11 +190,12 @@ optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) transcription = SingleShooting() mpc_d_daqp_ss = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) -optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) -transcription = MultipleShooting() -mpc_d_daqp_ms = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) -# needed to solve Hessians with eigenvalues at zero, like with MultipleShooting: -JuMP.set_attribute(mpc_d_daqp_ms.optim, "eps_prox", 1e-6) +# # Skip DAQP with MultipleShooting, it is not designed for sparse Hessians. Kind of works +# # with "eps_prox" configured to 1e-6, but not worth it. +# optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +# transcription = MultipleShooting() +# mpc_d_daqp_ms = setconstraint!(LinMPC(model_d; optim, transcription), ymin=[45, -Inf]) +# JuMP.set_attribute(mpc_d_daqp_ms.optim, "eps_prox", 1e-6) optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) transcription = SingleShooting() @@ -156,10 +220,6 @@ CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["DAQP"]["SingleShooting"] = @benchmarkable(test_mpc_d($mpc_d_daqp_ss, $model); samples=samples, evals=evals ) -CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["DAQP"]["MultipleShooting"] = - @benchmarkable(test_mpc_d($mpc_d_daqp_ms, $model); - samples=samples, evals=evals - ) CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["Ipopt"]["SingleShooting"] = @benchmarkable(test_mpc_d($mpc_d_ipopt_ss, $model); samples=samples, evals=evals @@ -209,18 +269,18 @@ nmpc_madnlp_ss = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) nmpc_madnlp_ss = setconstraint!(nmpc_madnlp_ss; umin, umax) JuMP.unset_time_limit_sec(nmpc_madnlp_ss.optim) -optim = JuMP.Model(MadNLP.Optimizer) -transcription = MultipleShooting() -nmpc_madnlp_ms = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) -nmpc_madnlp_ms = setconstraint!(nmpc_madnlp_ms; umin, umax) -JuMP.unset_time_limit_sec(nmpc_madnlp_ms.optim) -# TODO: does not work well with MadNLP and MultipleShooting, figure out why. -# Current theory: MadNLP LBFGS approximation is less robust than Ipopt version. -# Re-test when exact Hessians will be supported in ModelPredictiveControl.jl. -# The following attributes kinda work with the MadNLP LBFGS approximation but super slow: -JuMP.set_attribute(nmpc_madnlp_ms.optim, "hessian_approximation", MadNLP.CompactLBFGS) -MadNLP_QNopt = MadNLP.QuasiNewtonOptions(; max_history=42) -JuMP.set_attribute(nmpc_madnlp_ms.optim, "quasi_newton_options", MadNLP_QNopt) +# TODO: does not work well with MadNLP and MultipleShooting, figure out why. Current theory: +# MadNLP LBFGS approximation is less robust than Ipopt version. Re-test when exact Hessians +# will be supported in ModelPredictiveControl.jl. The following attributes kinda work with +# the MadNLP LBFGS approximation but super slow (~1000 times slower than Ipopt): +# optim = JuMP.Model(MadNLP.Optimizer) +# transcription = MultipleShooting() +# nmpc_madnlp_ms = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +# nmpc_madnlp_ms = setconstraint!(nmpc_madnlp_ms; umin, umax) +# JuMP.unset_time_limit_sec(nmpc_madnlp_ms.optim) +# JuMP.set_attribute(nmpc_madnlp_ms.optim, "hessian_approximation", MadNLP.CompactLBFGS) +# MadNLP_QNopt = MadNLP.QuasiNewtonOptions(; max_history=42) +# JuMP.set_attribute(nmpc_madnlp_ms.optim, "quasi_newton_options", MadNLP_QNopt) samples, evals, seconds = 50, 1, 15*60 CASE_MPC["Pendulum"]["NonLinMPC"]["Noneconomic"]["Ipopt"]["SingleShooting"] = @@ -238,12 +298,6 @@ CASE_MPC["Pendulum"]["NonLinMPC"]["Noneconomic"]["MadNLP"]["SingleShooting"] = sim!($nmpc_madnlp_ss, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds ) -# TODO: way too slow, samples=1 (just an informative single point), might change this later. -# CASE_MPC["Pendulum"]["NonLinMPC"]["Noneconomic"]["MadNLP"]["MultipleShooting"] = -# @benchmarkable( -# sim!($nmpc_madnlp_ms, $N, $ry; plant=$plant, x_0=$x_0, x̂_0=$x̂_0), -# samples=1, evals=evals, seconds=seconds -# ) # ----------------- Case study: Pendulum economic -------------------------------- h2!(y, x, _ , _ ) = (y[1] = 180/π*x[1]; y[2]=x[2]) @@ -341,4 +395,89 @@ CASE_MPC["Pendulum"]["NonLinMPC"]["Custom constraints"]["Ipopt"]["MultipleShooti @benchmarkable( sim!($nmpc2_ipopt_ms, $N, $ry; plant=$plant2, x_0=$x_0, x̂_0=$x̂_0), samples=samples, evals=evals, seconds=seconds - ) \ No newline at end of file + ) + +# ----------------- Case study: Pendulum successive linearization ------------------------- +linmodel = linearize(model, x=[0, 0], u=[0]) +kf = KalmanFilter(linmodel; σQ, σR, nint_u, σQint_u) +function sim2!(mpc, nlmodel, N, ry, plant, x, 𝕩̂, y_step) + U, Y, Ry = zeros(1, N), zeros(1, N), zeros(1, N) + setstate!(plant, x); setstate!(mpc, 𝕩̂) + initstate!(mpc, [0], plant()) + linmodel = linearize(nlmodel; u=[0], x=𝕩̂[1:2]) + setmodel!(mpc, linmodel) + for i = 1:N + y = plant() + y_step + 𝕩̂ = preparestate!(mpc, y) + u = mpc(ry) + linearize!(linmodel, nlmodel; u, x=𝕩̂[1:2]) + setmodel!(mpc, linmodel) + U[:,i], Y[:,i], Ry[:,i] = u, y, ry + updatestate!(mpc, u, y) + updatestate!(plant, u) + end + U_data, Y_data, Ry_data = U, Y, Ry + return SimResult(mpc, U_data, Y_data; Ry_data) +end +x_0 = [0, 0]; x̂_0 = [0, 0, 0]; ry = [180]; y_step=[0] + +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +transcription = SingleShooting() +mpc3_osqp_ss = LinMPC(kf; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +mpc3_osqp_ss = setconstraint!(mpc3_osqp_ss; umin, umax) +JuMP.unset_time_limit_sec(mpc3_osqp_ss.optim) +JuMP.set_attribute(mpc3_osqp_ss.optim, "polish", true) # needed to +JuMP.set_attribute(mpc3_osqp_ss.optim, "sigma", 1e-9) # needed to + +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +transcription = MultipleShooting() +mpc3_osqp_ms = LinMPC(kf; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +mpc3_osqp_ms = setconstraint!(mpc3_osqp_ms; umin, umax) +JuMP.unset_time_limit_sec(mpc3_osqp_ms.optim) + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +transcription = SingleShooting() +mpc3_daqp_ss = LinMPC(kf; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +mpc3_daqp_ss = setconstraint!(mpc3_daqp_ss; umin, umax) + +# skip DAQP with MultipleShooting, it is not designed for sparse Hessians +# did not found any settings that works well here (always reach the iteration limit). + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = SingleShooting() +mpc3_ipopt_ss = LinMPC(kf; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +mpc3_ipopt_ss = setconstraint!(mpc3_ipopt_ss; umin, umax) +JuMP.unset_time_limit_sec(mpc3_ipopt_ss.optim) + +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +transcription = MultipleShooting() +mpc3_ipopt_ms = LinMPC(kf; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription) +mpc3_ipopt_ms = setconstraint!(mpc3_ipopt_ms; umin, umax) +JuMP.unset_time_limit_sec(mpc3_ipopt_ms.optim) + +samples, evals = 500, 1 +CASE_MPC["Pendulum"]["LinMPC"]["Successive linearization"]["OSQP"]["SingleShooting"] = + @benchmarkable( + sim2!($mpc3_osqp_ss, $model, $N, $ry, $plant, $x_0, $x̂_0, $y_step), + samples=samples, evals=evals + ) +CASE_MPC["Pendulum"]["LinMPC"]["Successive linearization"]["OSQP"]["MultipleShooting"] = + @benchmarkable( + sim2!($mpc3_osqp_ms, $model, $N, $ry, $plant, $x_0, $x̂_0, $y_step), + samples=samples, evals=evals + ) +CASE_MPC["Pendulum"]["LinMPC"]["Successive linearization"]["DAQP"]["SingleShooting"] = + @benchmarkable( + sim2!($mpc3_daqp_ss, $model, $N, $ry, $plant, $x_0, $x̂_0, $y_step), + samples=samples, evals=evals + ) +CASE_MPC["Pendulum"]["LinMPC"]["Successive linearization"]["Ipopt"]["SingleShooting"] = + @benchmarkable( + sim2!($mpc3_ipopt_ss, $model, $N, $ry, $plant, $x_0, $x̂_0, $y_step), + samples=samples, evals=evals + ) +CASE_MPC["Pendulum"]["LinMPC"]["Successive linearization"]["Ipopt"]["MultipleShooting"] = + @benchmarkable( + sim2!($mpc3_ipopt_ms, $model, $N, $ ry, $plant, $x_0, $x̂_0, $y_step), + samples=samples, evals=evals + ) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index b0b3b5192..8407e38b3 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -4,7 +4,7 @@ using JuMP, OSQP, DAQP, Ipopt, MadNLP const SUITE = BenchmarkGroup(["ModelPredictiveControl"]) -SUITE["unit tests"] = BenchmarkGroup(["allocation-free", "no allocation", "single call"]) +SUITE["unit tests"] = BenchmarkGroup(["allocation-free", "allocations", "single call"]) SUITE["case studies"] = BenchmarkGroup(["performance", "speed" ,"integration"]) include("0_bench_setup.jl") From e44297fb25ad1ace1ba73b1cffd4531e807e9105 Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 15 Jul 2025 17:27:00 -0400 Subject: [PATCH 12/13] bench: CSTR study with some plant-model mismatch --- benchmark/3_bench_predictive_control.jl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index 8006c25e3..b3d181565 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -84,6 +84,8 @@ G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] uop, yop = [20, 20], [50, 30] model = setop!(LinModel(G, 2.0); uop, yop) +plant = setop!(LinModel(G, 2.0); uop, yop) +plant.A[diagind(plant.A)] .-= 0.1 # plant-model mismatch function test_mpc(mpc, plant) plant.x0 .= 0; y = plant() initstate!(mpc, plant.uop, y) @@ -135,23 +137,23 @@ JuMP.unset_time_limit_sec(mpc_ipopt_ms.optim) samples, evals = 500, 1 CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["OSQP"]["SingleShooting"] = - @benchmarkable(test_mpc($mpc_osqp_ss, $model); + @benchmarkable(test_mpc($mpc_osqp_ss, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["OSQP"]["MultipleShooting"] = - @benchmarkable(test_mpc($mpc_osqp_ms, $model); + @benchmarkable(test_mpc($mpc_osqp_ms, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["DAQP"]["SingleShooting"] = - @benchmarkable(test_mpc($mpc_daqp_ss, $model); + @benchmarkable(test_mpc($mpc_daqp_ss, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["Ipopt"]["SingleShooting"] = - @benchmarkable(test_mpc($mpc_ipopt_ss, $model); + @benchmarkable(test_mpc($mpc_ipopt_ss, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["Without feedforward"]["Ipopt"]["MultipleShooting"] = - @benchmarkable(test_mpc($mpc_ipopt_ms, $model); + @benchmarkable(test_mpc($mpc_ipopt_ms, $plant); samples=samples, evals=evals ) @@ -209,23 +211,23 @@ JuMP.unset_time_limit_sec(mpc_d_ipopt_ms.optim) samples, evals = 500, 1 CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["OSQP"]["SingleShooting"] = - @benchmarkable(test_mpc_d($mpc_d_osqp_ss, $model); + @benchmarkable(test_mpc_d($mpc_d_osqp_ss, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["OSQP"]["MultipleShooting"] = - @benchmarkable(test_mpc_d($mpc_d_osqp_ms, $model); + @benchmarkable(test_mpc_d($mpc_d_osqp_ms, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["DAQP"]["SingleShooting"] = - @benchmarkable(test_mpc_d($mpc_d_daqp_ss, $model); + @benchmarkable(test_mpc_d($mpc_d_daqp_ss, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["Ipopt"]["SingleShooting"] = - @benchmarkable(test_mpc_d($mpc_d_ipopt_ss, $model); + @benchmarkable(test_mpc_d($mpc_d_ipopt_ss, $plant); samples=samples, evals=evals ) CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["Ipopt"]["MultipleShooting"] = - @benchmarkable(test_mpc_d($mpc_d_ipopt_ms, $model); + @benchmarkable(test_mpc_d($mpc_d_ipopt_ms, $plant); samples=samples, evals=evals ) From bd3a48ed733133475191909e0f1cd01649492c6f Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 15 Jul 2025 17:42:45 -0400 Subject: [PATCH 13/13] bench: add CSTR MHE case study --- benchmark/1_bench_sim_model.jl | 3 +- benchmark/2_bench_state_estim.jl | 141 +++++++++++++++++++++++- benchmark/3_bench_predictive_control.jl | 1 + 3 files changed, 139 insertions(+), 6 deletions(-) diff --git a/benchmark/1_bench_sim_model.jl b/benchmark/1_bench_sim_model.jl index 25d98631f..13f5edd1e 100644 --- a/benchmark/1_bench_sim_model.jl +++ b/benchmark/1_bench_sim_model.jl @@ -23,4 +23,5 @@ UNIT_MODEL["NonLinModel"]["linearize!"] = ) ## ----------------- Case studies --------------------------------------------------------- -# TODO: Add case study benchmarks for SimModel +const CASE_MODEL = SUITE["case studies"]["SimModel"] +# TODO: Add case study benchmarks for SimModel \ No newline at end of file diff --git a/benchmark/2_bench_state_estim.jl b/benchmark/2_bench_state_estim.jl index 3e1711bd4..f86ce9d99 100644 --- a/benchmark/2_bench_state_estim.jl +++ b/benchmark/2_bench_state_estim.jl @@ -142,13 +142,144 @@ UNIT_ESTIM["ExtendedKalmanFilter"]["evaloutput"]["NonLinModel"] = setup=preparestate!($ekf_nonlin, $y, $d), ) -mhe_lin_direct = MovingHorizonEstimator(linmodel, He=10, direct=true) -mhe_lin_nondirect = MovingHorizonEstimator(linmodel, He=10, direct=false) -mhe_nonlin_direct = MovingHorizonEstimator(nonlinmodel, He=10, direct=true) -mhe_nonlin_nondirect = MovingHorizonEstimator(nonlinmodel, He=10, direct=false) +mhe_lin_curr = MovingHorizonEstimator(linmodel, He=10, direct=true) +mhe_lin_pred = MovingHorizonEstimator(linmodel, He=10, direct=false) +mhe_nonlin_curr = MovingHorizonEstimator(nonlinmodel, He=10, direct=true) +mhe_nonlin_pred = MovingHorizonEstimator(nonlinmodel, He=10, direct=false) +samples, evals, seconds = 5000, 1, 60 +UNIT_ESTIM["MovingHorizonEstimator"]["preparestate!"]["LinModel"]["Current form"] = + @benchmarkable( + preparestate!($mhe_lin_curr, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) +UNIT_ESTIM["MovingHorizonEstimator"]["updatestate!"]["LinModel"]["Current form"] = + @benchmarkable( + updatestate!($mhe_lin_curr, $u, $y, $d), + setup=preparestate!($mhe_lin_curr, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) +UNIT_ESTIM["MovingHorizonEstimator"]["preparestate!"]["LinModel"]["Prediction form"] = + @benchmarkable( + preparestate!($mhe_lin_pred, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) +UNIT_ESTIM["MovingHorizonEstimator"]["updatestate!"]["LinModel"]["Prediction form"] = + @benchmarkable( + updatestate!($mhe_lin_pred, $u, $y, $d), + setup=preparestate!($mhe_lin_pred, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) +UNIT_ESTIM["MovingHorizonEstimator"]["preparestate!"]["NonLinModel"]["Current form"] = + @benchmarkable( + preparestate!($mhe_nonlin_curr, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) +UNIT_ESTIM["MovingHorizonEstimator"]["updatestate!"]["NonLinModel"]["Current form"] = + @benchmarkable( + updatestate!($mhe_nonlin_curr, $u, $y, $d), + setup=preparestate!($mhe_nonlin_curr, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) +UNIT_ESTIM["MovingHorizonEstimator"]["preparestate!"]["NonLinModel"]["Prediction form"] = + @benchmarkable( + preparestate!($mhe_nonlin_pred, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) +UNIT_ESTIM["MovingHorizonEstimator"]["updatestate!"]["NonLinModel"]["Prediction form"] = + @benchmarkable( + updatestate!($mhe_nonlin_pred, $u, $y, $d), + setup=preparestate!($mhe_nonlin_pred, $y, $d), + samples=samples, evals=evals, seconds=seconds, + ) ## ----------------- Case studies --------------------------------------------------- -# TODO: Add case study benchmarks for StateEstimator +const CASE_ESTIM = SUITE["case studies"]["StateEstimator"] + +## ----------------- Case study: CSTR ----------------------------------------------------- +G = [ tf(1.90, [18, 1]) tf(1.90, [18, 1]); + tf(-0.74,[8, 1]) tf(0.74, [8, 1]) ] +uop, yop = [20, 20], [50, 30] +model = setop!(LinModel(G, 2.0); uop, yop) +plant = setop!(LinModel(G, 2.0); uop, yop) +plant.A[diagind(plant.A)] .-= 0.1 # plant-model mismatch +function test_mhe(mhe, plant) + plant.x0 .= 0; y = plant() + initstate!(mhe, plant.uop, y) + N = 75; u = [20, 20]; ul = 0 + U, Y, Ŷ = zeros(2, N), zeros(2, N), zeros(2, N) + for i = 1:N + i == 26 && (u = [15, 25]) + i == 51 && (ul = -10) + y = plant() + preparestate!(mhe, y) + ŷ = evaloutput(mhe) + U[:,i], Y[:,i], Ŷ[:,i] = u, y, ŷ + updatestate!(mhe, u, y) + updatestate!(plant, u+[0,ul]) + end + return U, Y, Ŷ +end +He = 10; nint_u = [1, 1]; σQint_u = [1, 2] + +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +direct = true +mhe_cstr_osqp_curr = MovingHorizonEstimator(model; He, nint_u, σQint_u, optim, direct) +mhe_cstr_osqp_curr = setconstraint!(mhe_cstr_osqp_curr, v̂min=[-1, -0.5], v̂max=[+1, +0.5]) +JuMP.unset_time_limit_sec(mhe_cstr_osqp_curr.optim) + +optim = JuMP.Model(OSQP.Optimizer, add_bridges=false) +direct = false +mhe_cstr_osqp_pred = MovingHorizonEstimator(model; He, nint_u, σQint_u, optim, direct) +mhe_cstr_osqp_pred = setconstraint!(mhe_cstr_osqp_pred, v̂min=[-1, -0.5], v̂max=[+1, +0.5]) +JuMP.unset_time_limit_sec(mhe_cstr_osqp_pred.optim) + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +direct = true +mhe_cstr_daqp_curr = MovingHorizonEstimator(model; He, nint_u, σQint_u, optim, direct) +mhe_cstr_daqp_curr = setconstraint!(mhe_cstr_daqp_curr, v̂min=[-1, -0.5], v̂max=[+1, +0.5]) +JuMP.set_attribute(mhe_cstr_daqp_curr.optim, "eps_prox", 1e-6) # needed to support hessians H≥0 + +optim = JuMP.Model(DAQP.Optimizer, add_bridges=false) +direct = false +mhe_cstr_daqp_pred = MovingHorizonEstimator(model; He, nint_u, σQint_u, optim, direct) +mhe_cstr_daqp_pred = setconstraint!(mhe_cstr_daqp_pred, v̂min=[-1, -0.5], v̂max=[+1, +0.5]) +JuMP.set_attribute(mhe_cstr_daqp_pred.optim, "eps_prox", 1e-6) # needed to support hessians H≥0 +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +direct = true +mhe_cstr_ipopt_curr = MovingHorizonEstimator(model; He, nint_u, σQint_u, optim, direct) +mhe_cstr_ipopt_curr = setconstraint!(mhe_cstr_ipopt_curr, v̂min=[-1, -0.5], v̂max=[+1, +0.5]) +JuMP.unset_time_limit_sec(mhe_cstr_ipopt_curr.optim) +optim = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"), add_bridges=false) +direct = false +mhe_cstr_ipopt_pred = MovingHorizonEstimator(model; He, nint_u, σQint_u, optim, direct) +mhe_cstr_ipopt_pred = setconstraint!(mhe_cstr_ipopt_pred, v̂min=[-1, -0.5], v̂max=[+1, +0.5]) +JuMP.unset_time_limit_sec(mhe_cstr_ipopt_pred.optim) + +samples, evals = 500, 1 +CASE_ESTIM["CSTR"]["MovingHorizonEstimator"]["OSQP"]["Current form"] = + @benchmarkable(test_mhe($mhe_cstr_osqp_curr, $plant); + samples=samples, evals=evals + ) +CASE_ESTIM["CSTR"]["MovingHorizonEstimator"]["OSQP"]["Prediction form"] = + @benchmarkable(test_mhe($mhe_cstr_osqp_pred, $plant); + samples=samples, evals=evals + ) +CASE_ESTIM["CSTR"]["MovingHorizonEstimator"]["DAQP"]["Current form"] = + @benchmarkable(test_mhe($mhe_cstr_daqp_curr, $plant); + samples=samples, evals=evals + ) +CASE_ESTIM["CSTR"]["MovingHorizonEstimator"]["DAQP"]["Prediction form"] = + @benchmarkable(test_mhe($mhe_cstr_daqp_pred, $plant); + samples=samples, evals=evals + ) +CASE_ESTIM["CSTR"]["MovingHorizonEstimator"]["Ipopt"]["Current form"] = + @benchmarkable(test_mhe($mhe_cstr_ipopt_curr, $plant); + samples=samples, evals=evals + ) +CASE_ESTIM["CSTR"]["MovingHorizonEstimator"]["Ipopt"]["Prediction form"] = + @benchmarkable(test_mhe($mhe_cstr_ipopt_pred, $plant); + samples=samples, evals=evals + ) \ No newline at end of file diff --git a/benchmark/3_bench_predictive_control.jl b/benchmark/3_bench_predictive_control.jl index b3d181565..3ffd1a86e 100644 --- a/benchmark/3_bench_predictive_control.jl +++ b/benchmark/3_bench_predictive_control.jl @@ -231,6 +231,7 @@ CASE_MPC["CSTR"]["LinMPC"]["With feedforward"]["Ipopt"]["MultipleShooting"] = samples=samples, evals=evals ) + # ----------------- Case study: Pendulum noneconomic ----------------------------- function f!(ẋ, x, u, _ , p) g, L, K, m = p # [m/s²], [m], [kg/s], [kg]