diff --git a/README.md b/README.md index 68c6eef..35bf1c4 100644 --- a/README.md +++ b/README.md @@ -1490,10 +1490,9 @@ A subsequent solve uses the time limit in its own search parameters. Native improvement-rate stopping is available through search parameters: ```ruby -search_parameters.improvement_limit_parameters = { - improvement_rate_coefficient: 0.01, - improvement_rate_solutions_distance: 5 -} +limits = search_parameters.improvement_limit_parameters +limits.improvement_rate_coefficient = 0.01 +limits.improvement_rate_solutions_distance = 5 ``` Piecewise linear costs can be applied to dimension cumul variables: diff --git a/ext/or-tools/routing.cpp b/ext/or-tools/routing.cpp index de960d8..73ec71d 100644 --- a/ext/or-tools/routing.cpp +++ b/ext/or-tools/routing.cpp @@ -354,6 +354,12 @@ void init_routing(Rice::Module& m) { m.define_singleton_function("default_routing_search_parameters", &DefaultRoutingSearchParameters); + Rice::define_class_under(rb_cRoutingSearchParameters, "ImprovementSearchLimitParameters") + .define_method("improvement_rate_coefficient", &RoutingSearchParameters::ImprovementSearchLimitParameters::improvement_rate_coefficient) + .define_method("improvement_rate_coefficient=", &RoutingSearchParameters::ImprovementSearchLimitParameters::set_improvement_rate_coefficient) + .define_method("improvement_rate_solutions_distance", &RoutingSearchParameters::ImprovementSearchLimitParameters::improvement_rate_solutions_distance) + .define_method("improvement_rate_solutions_distance=", &RoutingSearchParameters::ImprovementSearchLimitParameters::set_improvement_rate_solutions_distance); + rb_cRoutingSearchParameters .define_method("christofides_use_minimum_matching", &RoutingSearchParameters::christofides_use_minimum_matching) .define_method("christofides_use_minimum_matching=", &RoutingSearchParameters::set_christofides_use_minimum_matching) @@ -475,6 +481,7 @@ void init_routing(Rice::Module& m) { return self.set_local_search_metaheuristic(v); }) + .define_method("improvement_limit_parameters", &RoutingSearchParameters::mutable_improvement_limit_parameters, Rice::Return().keepAlive()) .define_method( "time_limit=", [](RoutingSearchParameters& self, int64_t value) { @@ -484,32 +491,6 @@ void init_routing(Rice::Module& m) { "lns_time_limit=", [](RoutingSearchParameters& self, int64_t value) { self.mutable_lns_time_limit()->set_seconds(value); - }) - .define_method( - "improvement_limit_parameters", - [](RoutingSearchParameters& self) -> Object { - if (!self.has_improvement_limit_parameters()) { - return Object(Qnil); - } - - const auto& parameters = self.improvement_limit_parameters(); - Hash result; - result[Symbol("improvement_rate_coefficient")] = - parameters.improvement_rate_coefficient(); - result[Symbol("improvement_rate_solutions_distance")] = - parameters.improvement_rate_solutions_distance(); - return result; - }) - .define_method( - "improvement_limit_parameters=", - [](RoutingSearchParameters& self, Hash value) { - const double coefficient = - value.get(Symbol("improvement_rate_coefficient")); - const int distance = - value.get(Symbol("improvement_rate_solutions_distance")); - auto* parameters = self.mutable_improvement_limit_parameters(); - parameters->set_improvement_rate_coefficient(coefficient); - parameters->set_improvement_rate_solutions_distance(distance); }); Rice::define_class_under(m, "RoutingIndexManager") diff --git a/test/routing_test.rb b/test/routing_test.rb index 9a7074e..94431ad 100644 --- a/test/routing_test.rb +++ b/test/routing_test.rb @@ -1,4 +1,5 @@ require_relative "test_helper" +require "weakref" class RoutingTest < Minitest::Test # https://developers.google.com/optimization/routing/tsp @@ -907,20 +908,28 @@ def test_search_parameters search_parameters.first_solution_strategy = :path_cheapest_arc search_parameters.local_search_metaheuristic = :guided_local_search search_parameters.log_search = true - assert_nil search_parameters.improvement_limit_parameters - - search_parameters.improvement_limit_parameters = { - improvement_rate_coefficient: 0.01, - improvement_rate_solutions_distance: 5 - } - - assert_equal( - { - improvement_rate_coefficient: 0.01, - improvement_rate_solutions_distance: 5 - }, - search_parameters.improvement_limit_parameters - ) + + assert_equal 0, search_parameters.improvement_limit_parameters.improvement_rate_coefficient + search_parameters.improvement_limit_parameters.improvement_rate_coefficient = 0.5 + assert_equal 0.5, search_parameters.improvement_limit_parameters.improvement_rate_coefficient + + assert_equal 0, search_parameters.improvement_limit_parameters.improvement_rate_solutions_distance + search_parameters.improvement_limit_parameters.improvement_rate_solutions_distance = 1 + assert_equal 1, search_parameters.improvement_limit_parameters.improvement_rate_solutions_distance + end + + def test_improvement_parameters_retain_search_parameters + search_parameters = ORTools.default_routing_search_parameters + parent = WeakRef.new(search_parameters) + limits = search_parameters.improvement_limit_parameters + search_parameters = nil + 3.times { GC.start } + + assert parent.weakref_alive? + limits.improvement_rate_coefficient = 0.5 + limits.improvement_rate_solutions_distance = 1 + assert_equal 0.5, limits.improvement_rate_coefficient + assert_equal 1, limits.improvement_rate_solutions_distance end def test_set_allowed_vehicles_for_index