From 03a20b6f5ae6557918bbc40b18fbbc264eb33f9c Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 6 Feb 2024 09:26:11 +1300 Subject: [PATCH 1/4] Allow MOI.ModelLike as the optimizer instead of MOI.AbstractOptimizer --- src/JuMP.jl | 2 +- src/print.jl | 7 ++++++- test/test_model.jl | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/JuMP.jl b/src/JuMP.jl index cb13acbafbb..2b6e5444f51 100644 --- a/src/JuMP.jl +++ b/src/JuMP.jl @@ -84,7 +84,7 @@ value_type(::Type{<:AbstractModel}) = Float64 mutable struct GenericModel{T<:Real} <: AbstractModel # In MANUAL and AUTOMATIC modes, CachingOptimizer. # In DIRECT mode, will hold an AbstractOptimizer. - moi_backend::MOI.AbstractOptimizer + moi_backend::MOI.ModelLike # List of shapes of constraints that are not `ScalarShape` or `VectorShape`. shapes::Dict{MOI.ConstraintIndex,AbstractShape} # List of bridges to add in addition to the ones added in diff --git a/src/print.jl b/src/print.jl index 5847ab3922b..66bedbd4a4e 100644 --- a/src/print.jl +++ b/src/print.jl @@ -273,7 +273,12 @@ function show_backend_summary(io::IO, model::GenericModel) println(io, "CachingOptimizer state: ", MOIU.state(backend(model))) end # The last print shouldn't have a new line - print(io, "Solver name: ", solver_name(model)) + name = try + solver_name(model) + catch + "unknown" + end + print(io, "Solver name: ", name) return end diff --git a/test/test_model.jl b/test/test_model.jl index 57bf1f60266..14ce090b157 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -1216,4 +1216,25 @@ function test_show_variable_not_owned() return end +function test_direct_mps_model() + model = direct_model(MOI.FileFormats.MPS.Model()) + @test occursin("unknown", sprint(show, model)) + @variable(model, x >= 0) + io = IOBuffer() + write(io, backend(model)) + seekstart(io) + data = String(take!(io)) + @test startswith(data, "NAME") + @test endswith(data, "ENDATA") + return +end + +function test_caching_mps_model() + model = Model(MOI.FileFormats.MPS.Model) + @test occursin("unknown", sprint(show, model)) + @variable(model, x >= 0) + @test_throws MethodError optimize!(model) + return +end + end # module TestModels From 1c6327fe390c60a4fc08a85c30c506b8c742f1e5 Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 6 Feb 2024 09:31:59 +1300 Subject: [PATCH 2/4] Fix MethodError --- src/optimizer_interface.jl | 6 ++++++ test/test_model.jl | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/optimizer_interface.jl b/src/optimizer_interface.jl index 474a6819fd8..5be17d31bc8 100644 --- a/src/optimizer_interface.jl +++ b/src/optimizer_interface.jl @@ -444,6 +444,12 @@ function optimize!( if mode(model) != DIRECT && MOIU.state(backend(model)) == MOIU.NO_OPTIMIZER throw(NoOptimizer()) end + if !(unsafe_backend(model) isa MOI.AbstractOptimizer) + error( + "Cannot call `optimize!` because the provided optimizer is not " * + "a subtype of `MOI.AbstractOptimizer`.", + ) + end try MOI.optimize!(backend(model)) catch err diff --git a/test/test_model.jl b/test/test_model.jl index 14ce090b157..d63183dc61b 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -1233,7 +1233,13 @@ function test_caching_mps_model() model = Model(MOI.FileFormats.MPS.Model) @test occursin("unknown", sprint(show, model)) @variable(model, x >= 0) - @test_throws MethodError optimize!(model) + @test_throws( + ErrorException( + "Cannot call `optimize!` because the provided optimizer is not " * + "a subtype of `MOI.AbstractOptimizer`.", + ), + optimize!(model), + ) return end From 533f478386730f70c732a7f2c3f5bc8001e7fcb1 Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 6 Feb 2024 09:36:01 +1300 Subject: [PATCH 3/4] Update --- src/optimizer_interface.jl | 6 ++++-- test/test_model.jl | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/optimizer_interface.jl b/src/optimizer_interface.jl index 5be17d31bc8..d2a6a5f809e 100644 --- a/src/optimizer_interface.jl +++ b/src/optimizer_interface.jl @@ -444,10 +444,12 @@ function optimize!( if mode(model) != DIRECT && MOIU.state(backend(model)) == MOIU.NO_OPTIMIZER throw(NoOptimizer()) end - if !(unsafe_backend(model) isa MOI.AbstractOptimizer) + optimizer = unsafe_backend(model) + if !(optimizer isa MOI.AbstractOptimizer) error( "Cannot call `optimize!` because the provided optimizer is not " * - "a subtype of `MOI.AbstractOptimizer`.", + "a subtype of `MOI.AbstractOptimizer`.\n\nThe optimizer is:\n\n" * + sprint(show, optimizer) * "\n", ) end try diff --git a/test/test_model.jl b/test/test_model.jl index d63183dc61b..45a26858d19 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -1236,7 +1236,8 @@ function test_caching_mps_model() @test_throws( ErrorException( "Cannot call `optimize!` because the provided optimizer is not " * - "a subtype of `MOI.AbstractOptimizer`.", + "a subtype of `MOI.AbstractOptimizer`.\n\nThe optimizer is:\n\n" * + "A Mathematical Programming System (MPS) model\n", ), optimize!(model), ) From 661dc0aed2777839982a0a36b3533dc6c99623b6 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Tue, 6 Feb 2024 09:57:33 +1300 Subject: [PATCH 4/4] Apply suggestions from code review --- src/optimizer_interface.jl | 3 ++- test/test_model.jl | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/optimizer_interface.jl b/src/optimizer_interface.jl index d2a6a5f809e..533b4ed0c5b 100644 --- a/src/optimizer_interface.jl +++ b/src/optimizer_interface.jl @@ -449,7 +449,8 @@ function optimize!( error( "Cannot call `optimize!` because the provided optimizer is not " * "a subtype of `MOI.AbstractOptimizer`.\n\nThe optimizer is:\n\n" * - sprint(show, optimizer) * "\n", + sprint(show, optimizer) * + "\n", ) end try diff --git a/test/test_model.jl b/test/test_model.jl index 45a26858d19..20bcb345d6e 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -1225,7 +1225,7 @@ function test_direct_mps_model() seekstart(io) data = String(take!(io)) @test startswith(data, "NAME") - @test endswith(data, "ENDATA") + @test endswith(data, "ENDATA\n") return end