From 2492ac5fd33291e82cc12f0cd23fb0e536496244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Tue, 8 Oct 2024 10:11:32 +0200 Subject: [PATCH 1/3] node limit --- docs/src/manual/models.md | 1 + docs/src/reference/models.md | 1 + docs/src/tutorials/implementing.md | 1 + src/Test/test_attribute.jl | 26 ++++++++++++++++++++++++++ src/attributes.jl | 23 +++++++++++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/docs/src/manual/models.md b/docs/src/manual/models.md index d17e0f27f5..42e1415242 100644 --- a/docs/src/manual/models.md +++ b/docs/src/manual/models.md @@ -105,4 +105,5 @@ The following attributes are available: * [`TimeLimitSec`](@ref) * [`ObjectiveLimit`](@ref) * [`SolutionLimit`](@ref) + * [`NodeLimit`](@ref) * [`AutomaticDifferentiationBackend`](@ref) diff --git a/docs/src/reference/models.md b/docs/src/reference/models.md index 349130fbb2..884edc2baf 100644 --- a/docs/src/reference/models.md +++ b/docs/src/reference/models.md @@ -81,6 +81,7 @@ Silent TimeLimitSec ObjectiveLimit SolutionLimit +NodeLimit RawOptimizerAttribute NumberOfThreads RawSolver diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index 4ca2443e73..1a53e2512b 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -335,6 +335,7 @@ method for each attribute. | [`TimeLimitSec`](@ref) | Yes | Yes | Yes | | [`ObjectiveLimit`](@ref) | Yes | Yes | Yes | | [`SolutionLimit`](@ref) | Yes | Yes | Yes | +| [`NodeLimit`](@ref) | Yes | Yes | Yes | | [`RawOptimizerAttribute`](@ref) | Yes | Yes | Yes | | [`NumberOfThreads`](@ref) | Yes | Yes | Yes | | [`AbsoluteGapTolerance`](@ref) | Yes | Yes | Yes | diff --git a/src/Test/test_attribute.jl b/src/Test/test_attribute.jl index 6b83ff858f..7d567fb738 100644 --- a/src/Test/test_attribute.jl +++ b/src/Test/test_attribute.jl @@ -252,6 +252,32 @@ function setup_test( return end +function test_attribute_NodeLimit(model::MOI.AbstractOptimizer, ::Config) + @requires MOI.supports(model, MOI.NodeLimit()) + # Get the current value to restore it at the end of the test + value = MOI.get(model, MOI.NodeLimit()) + MOI.set(model, MOI.NodeLimit(), 3) + @test MOI.get(model, MOI.NodeLimit()) == 3 + MOI.set(model, MOI.NodeLimit(), nothing) + @test MOI.get(model, MOI.NodeLimit()) === nothing + MOI.set(model, MOI.NodeLimit(), 1) + @test MOI.get(model, MOI.NodeLimit()) == 1 + MOI.set(model, MOI.NodeLimit(), value) + _test_attribute_value_type(model, MOI.NodeLimit()) + return +end + +test_attribute_NodeLimit(::MOI.ModelLike, ::Config) = nothing + +function setup_test( + ::typeof(test_attribute_NodeLimit), + model::MOIU.MockOptimizer, + ::Config, +) + MOI.set(model, MOI.NodeLimit(), nothing) + return +end + """ test_attribute_AbsoluteGapTolerance(model::MOI.AbstractOptimizer, config::Config) diff --git a/src/attributes.jl b/src/attributes.jl index a7fba17b31..da7d3f767f 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -899,6 +899,29 @@ struct SolutionLimit <: AbstractOptimizerAttribute end attribute_value_type(::SolutionLimit) = Union{Nothing,Int} +""" + NodeLimit() + +An optimizer attribute for setting a limit on the number of branch-and-bound nodes explored by a MIP solver. + +## Default values + +The provided limit must be a `Union{Nothing,Int}`. + +When `set` to `nothing`, the limit reverts to the solver's default. + +The default value is `nothing`. + +## Termination criteria + +The solver may stop when the [`NodeCount`](@ref) is larger than or equal to +the `NodeLimit`. If stopped because of this attribute, the +[`TerminationStatus`](@ref) must be `NODE_LIMIT`. +""" +struct NodeLimit <: AbstractOptimizerAttribute end + +attribute_value_type(::NodeLimit) = Union{Nothing,Int} + """ RawOptimizerAttribute(name::String) From a365a15c8d91df8eb4298a0b76abb27dc2528bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Tue, 8 Oct 2024 15:52:01 +0200 Subject: [PATCH 2/3] Update src/attributes.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: BenoƮt Legat --- src/attributes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes.jl b/src/attributes.jl index da7d3f767f..a0d297d5af 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -902,7 +902,7 @@ attribute_value_type(::SolutionLimit) = Union{Nothing,Int} """ NodeLimit() -An optimizer attribute for setting a limit on the number of branch-and-bound nodes explored by a MIP solver. +An optimizer attribute for setting a limit on the number of branch-and-bound nodes explored by a mixed-integer program (MIP) solver. ## Default values From 5ead689086996ff43a3d578dd6dc1f84f6de6ded Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 9 Oct 2024 09:43:08 +1300 Subject: [PATCH 3/3] Apply suggestions from code review --- docs/src/tutorials/implementing.md | 2 +- src/attributes.jl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index 1a53e2512b..7fb6877a1b 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -335,7 +335,7 @@ method for each attribute. | [`TimeLimitSec`](@ref) | Yes | Yes | Yes | | [`ObjectiveLimit`](@ref) | Yes | Yes | Yes | | [`SolutionLimit`](@ref) | Yes | Yes | Yes | -| [`NodeLimit`](@ref) | Yes | Yes | Yes | +| [`NodeLimit`](@ref) | Yes | Yes | Yes | | [`RawOptimizerAttribute`](@ref) | Yes | Yes | Yes | | [`NumberOfThreads`](@ref) | Yes | Yes | Yes | | [`AbsoluteGapTolerance`](@ref) | Yes | Yes | Yes | diff --git a/src/attributes.jl b/src/attributes.jl index a0d297d5af..c6c3d4c930 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -902,7 +902,8 @@ attribute_value_type(::SolutionLimit) = Union{Nothing,Int} """ NodeLimit() -An optimizer attribute for setting a limit on the number of branch-and-bound nodes explored by a mixed-integer program (MIP) solver. +An optimizer attribute for setting a limit on the number of branch-and-bound +nodes explored by a mixed-integer program (MIP) solver. ## Default values