From fabd6bddd27bc6ab17e7fefcb422a39282c8d152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 12 Dec 2024 18:01:49 +0100 Subject: [PATCH 1/2] added node limit --- src/callbacks.jl | 4 ++++ src/custom_bonobo.jl | 4 ++-- src/interface.jl | 4 ++++ src/problem.jl | 1 + src/utilities.jl | 2 +- test/interface_test.jl | 6 ++++++ 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/callbacks.jl b/src/callbacks.jl index 67d9062b8..a7aee6d32 100644 --- a/src/callbacks.jl +++ b/src/callbacks.jl @@ -201,6 +201,10 @@ function build_bnb_callback( end end + if iteration > tree.root.options[:node_limit] + tree.root.problem.solving_stage = NODE_LIMIT_REACHED + end + fw_time = Dates.value(node.fw_time) fw_iter = if !isempty(fw_iterations) fw_iterations[end] diff --git a/src/custom_bonobo.jl b/src/custom_bonobo.jl index d50b3b24b..b1966ec54 100644 --- a/src/custom_bonobo.jl +++ b/src/custom_bonobo.jl @@ -139,9 +139,9 @@ function Bonobo.get_solution( ) where {N,R,V,S<:FrankWolfeSolution{N,V}} if isempty(tree.solutions) @warn "There is no solution in the tree. This behaviour can happen if you have supplied - \na custom domain oracle. In that case, try to increase the time limit. If you have not specified a + \na custom domain oracle. In that case, try to increase the time or node limit. If you have not specified a \ndomain oracle, please report!" - @assert tree.root.problem.solving_stage == TIME_LIMIT_REACHED + @assert tree.root.problem.solving_stage in (TIME_LIMIT_REACHED, NODE_LIMIT_REACHED) return nothing end return tree.solutions[result].solution diff --git a/src/interface.jl b/src/interface.jl index e08054c92..92e161ea9 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -87,6 +87,7 @@ function solve( dual_gap=1e-6, rel_dual_gap=1.0e-2, time_limit=Inf, + node_limit=Inf, print_iter=100, dual_gap_decay_factor=0.8, max_fw_iter=10000, @@ -225,6 +226,7 @@ function solve( :sharpness_constant => sharpness_constant, :sharpness_exponent => sharpness_exponent, :time_limit => time_limit, + :node_limit => node_limit, :usePostsolve => use_postsolve, :variant => variant, :use_shadow_set => use_shadow_set, @@ -361,6 +363,8 @@ function postsolve(tree, result, time_ref, verbose, max_iteration_post) tree.root.problem.solving_stage = OPT_TREE_EMPTY elseif tree.root.problem.solving_stage == TIME_LIMIT_REACHED status_string = "Time limit reached" + elseif tree.root.problem.solving_stage == NODE_LIMIT_REACHED + status_string = "Node limit reached" else status_string = "Optimal (tolerance reached)" tree.root.problem.solving_stage = OPT_GAP_REACHED diff --git a/src/problem.jl b/src/problem.jl index 10fd0cba9..0ece4bcb9 100644 --- a/src/problem.jl +++ b/src/problem.jl @@ -6,6 +6,7 @@ Enum for the solving stage OPT_GAP_REACHED = 1 OPT_TREE_EMPTY = 2 TIME_LIMIT_REACHED = 3 + NODE_LIMIT_REACHED = 4 end """ diff --git a/src/utilities.jl b/src/utilities.jl index afc7dafab..0bb0041bb 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -270,7 +270,7 @@ Checks if the branch and bound can be stopped. By default (in Bonobo) stops then the priority queue is empty. """ function Bonobo.terminated(tree::Bonobo.BnBTree{<:FrankWolfeNode}) - if tree.root.problem.solving_stage == TIME_LIMIT_REACHED + if tree.root.problem.solving_stage in (TIME_LIMIT_REACHED, NODE_LIMIT_REACHED) return true end absgap = tree.incumbent - tree.lb diff --git a/test/interface_test.jl b/test/interface_test.jl index cbd812c13..dc10750aa 100644 --- a/test/interface_test.jl +++ b/test/interface_test.jl @@ -396,6 +396,12 @@ end @test sum(isapprox.(x_adaptive, x_monotonic, atol=1e-6, rtol=1e-3)) == n @test sum(isapprox.(x_agnostic, x_monotonic, atol=1e-6, rtol=1e-3)) == n @test sum(isapprox.(x_adaptive, x_agnostic, atol=1e-6, rtol=1e-3)) == n + + x_monotonic, _, result_monotonic_node_limit = + Boscia.solve(f, grad!, lmo, verbose=true, line_search=line_search, node_limit=2, print_iter=1) + + @test result_monotonic_node_limit[:list_ub] <= 3 + @test result_monotonic_node_limit[:status] == "Node limit reached" end n = 20 From f2f33d8b9164e03ed2fdbe445a787116d87fe823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Wed, 18 Dec 2024 17:19:24 +0100 Subject: [PATCH 2/2] fix test --- test/interface_test.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/interface_test.jl b/test/interface_test.jl index dc10750aa..a59ad7274 100644 --- a/test/interface_test.jl +++ b/test/interface_test.jl @@ -400,7 +400,7 @@ end x_monotonic, _, result_monotonic_node_limit = Boscia.solve(f, grad!, lmo, verbose=true, line_search=line_search, node_limit=2, print_iter=1) - @test result_monotonic_node_limit[:list_ub] <= 3 + @test length(result_monotonic_node_limit[:list_ub]) <= 3 @test result_monotonic_node_limit[:status] == "Node limit reached" end