diff --git a/README.md b/README.md index d9e7633..f884fdd 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ the solution process. * `MOA.ObjectivePriority(index::Int)` * `MOA.ObjectiveRelativeTolerance(index::Int)` * `MOA.ObjectiveWeight(index::Int)` + * `MOA.SilentInner()` * `MOA.SolutionLimit()` * `MOI.TimeLimitSec()` diff --git a/src/MultiObjectiveAlgorithms.jl b/src/MultiObjectiveAlgorithms.jl index fdbad5d..0a7f39c 100644 --- a/src/MultiObjectiveAlgorithms.jl +++ b/src/MultiObjectiveAlgorithms.jl @@ -178,9 +178,13 @@ MOI.instantiate(optimizer_factory; with_cache_type = Float64) ## Example ```julia -import MultiObjectiveAlgorithms as MOA -import HiGHS -optimizer = () -> MOA.Optimizer(HiGHS.Optimizer) +julia> using JuMP + +julia> import MultiObjectiveAlgorithms as MOA + +julia> import HiGHS + +julia> model = Model(() -> MOA.Optimizer(HiGHS.Optimizer)) ``` """ mutable struct Optimizer <: MOI.AbstractOptimizer @@ -202,6 +206,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer function Optimizer(optimizer_factory) inner = MOI.instantiate(optimizer_factory; with_cache_type = Float64) if MOI.supports(inner, MOI.Silent()) + # Make the default for `SilentInner` true. MOI.set(inner, MOI.Silent(), true) end return new( @@ -261,6 +266,33 @@ function MOI.set(model::Optimizer, ::MOI.Silent, value::Bool) return end +### SilentInner + +""" + SilentInner() <: MOI.AbstractOptimizerAttribute + +An optimizer attribute that controls whether the inner optimizer's `MOI.Silent` +attribute. + +By default, this attribute is set to `true`. Set it to `false` to enable logging +of the inner solver. In most cases, this will result in a large amount of output +that is hard to interpret, but it may be helpful when debugging failed solves. +""" +struct SilentInner <: MOI.AbstractOptimizerAttribute end + +function MOI.supports(model::Optimizer, ::SilentInner) + return MOI.supports(model.inner, MOI.Silent()) +end + +function MOI.get(model::Optimizer, ::SilentInner) + return MOI.get(model.inner, MOI.Silent()) +end + +function MOI.set(model::Optimizer, ::SilentInner, value::Bool) + MOI.set(model.inner, MOI.Silent(), value) + return +end + ### TimeLimitSec function MOI.supports(model::Optimizer, attr::MOI.TimeLimitSec) diff --git a/test/test_model.jl b/test/test_model.jl index 6cadedf..0c35f8d 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -271,6 +271,32 @@ function test_printing() return end +function test_printing_silent_inner() + model = MOA.Optimizer(HiGHS.Optimizer) + @test MOI.supports(model, MOA.SilentInner()) + @test MOI.get(model, MOA.SilentInner()) == true + MOI.set(model, MOA.SilentInner(), false) + @test MOI.get(model, MOA.SilentInner()) == false + MOI.set(model, MOI.Silent(), true) + MOI.set(model, MOA.Algorithm(), MOA.KirlikSayin()) + x = MOI.add_variables(model, 2) + MOI.add_constraint.(model, x, MOI.GreaterThan(0.0)) + MOI.add_constraint(model, x[2], MOI.LessThan(3.0)) + MOI.add_constraint(model, 3.0 * x[1] - 1.0 * x[2], MOI.LessThan(6.0)) + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + f = MOI.Utilities.vectorize([3.0 * x[1] + x[2], -1.0 * x[1] - 2.0 * x[2]]) + MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) + dir = mktempdir() + open(joinpath(dir, "log.txt"), "w") do io + redirect_stdout(() -> MOI.optimize!(model), io) + return + end + contents = read(joinpath(dir, "log.txt"), String) + @test occursin("HiGHS", contents) + @test !occursin("MultiObjectiveAlgorithms.jl", contents) + return +end + end # module TestModel.run_tests()