From e5d3eaa1f56346d53a5ef8f895743ab3e89ff38c Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 18 Jan 2024 14:02:58 +1300 Subject: [PATCH] Update to latest JuMP syntax (#29) --- Project.toml | 21 +---------- README.md | 11 ++++-- test/Project.toml | 21 +++++++++++ test/runtests.jl | 95 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 test/Project.toml diff --git a/Project.toml b/Project.toml index 39dd6cb..4830088 100644 --- a/Project.toml +++ b/Project.toml @@ -9,24 +9,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" [compat] -Ipopt = "1" -JuMP = "1.2" -LinearAlgebra = "<0.0.1, 1.6" -MathOptInterface = "1.4" -PowerModels = "0.19" -Random = "<0.0.1, 1.6" -Symbolics = "4, 5" +MathOptInterface = "1.25" SparseArrays = "<0.0.1, 1.6" -Test = "<0.0.1, 1.6" +Symbolics = "4, 5" julia = "1.6" - -[extras] -Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" -JuMP = "4076af6c-e467-56ae-b986-b466b2749572" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[targets] -test = ["Ipopt", "JuMP", "LinearAlgebra", "PowerModels", "Random", "Test"] diff --git a/README.md b/README.md index 4d0ee9d..3479d83 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,13 @@ import Ipopt import MathOptSymbolicAD model = Model(Ipopt.Optimizer) @variable(model, x[1:2]) -@NLobjective(model, Min, (1 - x[1])^2 + 100 * (x[2] - x[1]^2)^2) -optimize!(model; _differentiation_backend = MathOptSymbolicAD.DefaultBackend()) +@objective(model, Min, (1 - x[1])^2 + 100 * (x[2] - x[1]^2)^2) +set_attribute( + model, + MOI.AutomaticDifferentiationBackend(), + MathOptSymbolicAD.DefaultBackend(), +) +optimize!(model) ``` ## Background @@ -52,7 +57,7 @@ large with few unique constraints. For example, a model like: ```julia model = Model() @variable(model, 0 <= x[1:10_000] <= 1) -@NLconstraint(model, [i=1:10_000], sin(x[i]) <= 1) +@constraint(model, [i=1:10_000], sin(x[i]) <= 1) @objective(model, Max, sum(x)) ``` is ideal, because although the Jacobian matrix has 10,000 rows, we can compute diff --git a/test/Project.toml b/test/Project.toml new file mode 100644 index 0000000..d765aab --- /dev/null +++ b/test/Project.toml @@ -0,0 +1,21 @@ +[deps] +Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" +JuMP = "4076af6c-e467-56ae-b986-b466b2749572" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MathOptSymbolicAD = "309f4015-3481-4d63-a8f9-aeb13adfe8eb" +PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Ipopt = "1" +JuMP = "1.2" +LinearAlgebra = "<0.0.1, 1.6" +PowerModels = "0.19, 0.20" +Random = "<0.0.1, 1.6" +SparseArrays = "<0.0.1, 1.6" +SpecialFunctions = "2" +Test = "<0.0.1, 1.6" + diff --git a/test/runtests.jl b/test/runtests.jl index 1c5c99d..ce4bb22 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,10 +9,11 @@ using JuMP import Ipopt import LinearAlgebra +import MathOptSymbolicAD import PowerModels import Random import SparseArrays -import MathOptSymbolicAD +import SpecialFunctions import Test function runtests() @@ -270,6 +271,44 @@ function test_optimizer_clnlbeam(; N::Int = 10) return end +function test_optimizer_clnlbeam_expr(; N::Int = 10) + h = 1 / N + model = Model(Ipopt.Optimizer) + @variable(model, -1 <= t[1:(N+1)] <= 1) + @variable(model, -0.05 <= x[1:(N+1)] <= 0.05) + @variable(model, u[1:(N+1)]) + @objective( + model, + Min, + sum( + h / 2 * (u[i+1]^2 + u[i]^2) + + 350 * h / 2 * (cos(t[i+1]) + cos(t[i])) for i in 1:N + ), + ) + for i in 1:N + @constraint(model, x[i+1] - x[i] == h / 2 * (sin(t[i+1]) + sin(t[i]))) + @constraint(model, t[i+1] - t[i] == h / 2 * (u[i+1] - u[i])) + end + set_attribute( + model, + MOI.AutomaticDifferentiationBackend(), + MathOptSymbolicAD.DefaultBackend(), + ) + optimize!(model) + Test.@test isapprox(objective_value(model), 350; atol = 1e-6) + t_sol = value.(t) + u_sol = value.(u) + Test.@test isapprox( + sum( + h / 2 * (u_sol[i+1]^2 + u_sol[i]^2) + + 350 * h / 2 * (cos(t_sol[i+1]) + cos(t_sol[i])) for i in 1:N + ), + 350.0; + atol = 1e-6, + ) + return +end + function test_optimizer_case5_pjm() model = power_model("pglib_opf_case5_pjm.m") set_optimizer(model, Ipopt.Optimizer) @@ -297,6 +336,26 @@ function test_user_defined_functions() return end +function test_user_defined_functions_expr() + model = Model(Ipopt.Optimizer) + @variable(model, 0.5 <= x <= 1.0) + @operator(model, mysin, 1, a -> sin(a)) + @operator(model, pow, 2, (a, b) -> a^b) + @objective( + model, + Max, + mysin(x) + log(x) + SpecialFunctions.dawson(x) - pow(x, 2), + ) + set_attribute( + model, + MOI.AutomaticDifferentiationBackend(), + MathOptSymbolicAD.DefaultBackend(), + ) + optimize!(model) + Test.@test termination_status(model) == LOCALLY_SOLVED + return +end + function test_nested_subexpressions() model = Model(Ipopt.Optimizer) @variable(model, 0.5 <= x <= 1.0) @@ -312,6 +371,23 @@ function test_nested_subexpressions() return end +function test_nested_subexpressions_expr() + model = Model(Ipopt.Optimizer) + @variable(model, 0.5 <= x <= 1.0) + @expression(model, my_expr1, x - 1) + @expression(model, my_expr2, my_expr1^2) + @objective(model, Min, my_expr2) + set_attribute( + model, + MOI.AutomaticDifferentiationBackend(), + MathOptSymbolicAD.DefaultBackend(), + ) + optimize!(model) + Test.@test termination_status(model) == LOCALLY_SOLVED + Test.@test ≈(value(x), 1.0; atol = 1e-3) + return +end + function test_constant_subexpressions() model = Model(Ipopt.Optimizer) @variable(model, 0.5 <= x <= 1.0) @@ -327,6 +403,23 @@ function test_constant_subexpressions() return end +function test_constant_subexpressions_expr() + model = Model(Ipopt.Optimizer) + @variable(model, 0.5 <= x <= 1.0) + @expression(model, my_expr1, 1.0) + @expression(model, my_expr2, x) + @objective(model, Min, (my_expr2 - my_expr1)^2) + set_attribute( + model, + MOI.AutomaticDifferentiationBackend(), + MathOptSymbolicAD.DefaultBackend(), + ) + optimize!(model) + Test.@test termination_status(model) == LOCALLY_SOLVED + Test.@test ≈(value(x), 1.0; atol = 1e-3) + return +end + end # module RunTests.runtests()