2525#include < optional>
2626#include < random>
2727#include < string>
28+ #include < string_view>
2829#include < thread>
2930#include < utility>
3031#include < vector>
4647#include " absl/strings/str_format.h"
4748#include " absl/strings/str_join.h"
4849#include " absl/strings/string_view.h"
50+ #include " absl/strings/strip.h"
4951#include " absl/synchronization/mutex.h"
5052#include " absl/types/span.h"
5153#include " google/protobuf/arena.h"
@@ -1293,14 +1295,14 @@ class FeasibilityPumpSolver : public SubSolver {
12931295class LnsSolver : public SubSolver {
12941296 public:
12951297 LnsSolver (std::unique_ptr<NeighborhoodGenerator> generator,
1296- const SatParameters& lns_parameters ,
1297- NeighborhoodGeneratorHelper* helper, SharedClasses* shared ,
1298- int preferred_linearization_level = 0 )
1298+ const SatParameters& lns_parameters_base ,
1299+ const SatParameters& lns_parameters_stalling ,
1300+ NeighborhoodGeneratorHelper* helper, SharedClasses* shared )
12991301 : SubSolver(generator->name (), INCOMPLETE),
1300- preferred_linearization_level_(preferred_linearization_level),
13011302 generator_(std::move(generator)),
13021303 helper_(helper),
1303- lns_parameters_(lns_parameters),
1304+ lns_parameters_base_(lns_parameters_base),
1305+ lns_parameters_stalling_(lns_parameters_stalling),
13041306 shared_(shared) {}
13051307
13061308 ~LnsSolver () override {
@@ -1328,7 +1330,7 @@ class LnsSolver : public SubSolver {
13281330 // change the LNS behavior.
13291331 const int32_t low = static_cast <int32_t >(task_id);
13301332 const int32_t high = static_cast <int32_t >(task_id >> 32 );
1331- std::seed_seq seed{low, high, lns_parameters_ .random_seed ()};
1333+ std::seed_seq seed{low, high, lns_parameters_base_ .random_seed ()};
13321334 random_engine_t random (seed);
13331335
13341336 NeighborhoodGenerator::SolveData data;
@@ -1372,26 +1374,22 @@ class LnsSolver : public SubSolver {
13721374
13731375 if (!neighborhood.is_generated ) return ;
13741376
1375- SatParameters local_params (lns_parameters_);
1376- local_params.set_max_deterministic_time (data.deterministic_limit );
1377+ SatParameters local_params;
13771378
1378- // TODO(user): Tune these.
13791379 // TODO(user): This could be a good candidate for bandits.
13801380 const int64_t stall = generator_->num_consecutive_non_improving_calls ();
1381- std::string search_info;
13821381 const int search_index = stall < 10 ? 0 : task_id % 2 ;
13831382 switch (search_index) {
13841383 case 0 :
1385- local_params.set_search_branching (SatParameters::AUTOMATIC_SEARCH);
1386- local_params.set_linearization_level (preferred_linearization_level_);
1387- search_info = absl::StrCat (" auto_l" , preferred_linearization_level_);
1384+ local_params = lns_parameters_base_;
13881385 break ;
13891386 default :
1390- local_params.set_search_branching (SatParameters::PORTFOLIO_SEARCH);
1391- local_params.set_search_random_variable_pool_size (5 );
1392- search_info = " folio_rnd" ;
1387+ local_params = lns_parameters_stalling_;
13931388 break ;
13941389 }
1390+ const std::string_view search_info =
1391+ absl::StripPrefix (std::string_view (local_params.name ()), " lns_" );
1392+ local_params.set_max_deterministic_time (data.deterministic_limit );
13951393
13961394 std::string source_info =
13971395 neighborhood.source_info .empty () ? name () : neighborhood.source_info ;
@@ -1486,7 +1484,7 @@ class LnsSolver : public SubSolver {
14861484 }
14871485 }
14881486 bool hint_feasible_before_presolve = false ;
1489- if (lns_parameters_ .debug_crash_if_presolve_breaks_hint ()) {
1487+ if (lns_parameters_base_ .debug_crash_if_presolve_breaks_hint ()) {
14901488 hint_feasible_before_presolve =
14911489 SolutionHintIsCompleteAndFeasible (lns_fragment, /* logger=*/ nullptr );
14921490 }
@@ -1525,7 +1523,7 @@ class LnsSolver : public SubSolver {
15251523 context.reset (nullptr );
15261524 neighborhood.delta .Clear ();
15271525
1528- if (lns_parameters_ .debug_crash_if_presolve_breaks_hint () &&
1526+ if (lns_parameters_base_ .debug_crash_if_presolve_breaks_hint () &&
15291527 hint_feasible_before_presolve &&
15301528 !SolutionHintIsCompleteAndFeasible (lns_fragment,
15311529 /* logger=*/ nullptr )) {
@@ -1720,10 +1718,10 @@ class LnsSolver : public SubSolver {
17201718 }
17211719
17221720 private:
1723- int preferred_linearization_level_ = 0 ;
17241721 std::unique_ptr<NeighborhoodGenerator> generator_;
17251722 NeighborhoodGeneratorHelper* helper_;
1726- const SatParameters lns_parameters_;
1723+ const SatParameters lns_parameters_base_;
1724+ const SatParameters lns_parameters_stalling_;
17271725 SharedClasses* shared_;
17281726 // This is a optimization to allocate the arena for the LNS fragment already
17291727 // at roughly the right size. We will update it with the last size of the
@@ -1780,7 +1778,9 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
17801778 }));
17811779
17821780 const auto name_to_params = GetNamedParameters (params);
1783- const SatParameters& lns_params = name_to_params.at (" lns" );
1781+ const SatParameters& lns_params_base = name_to_params.at (" lns_base" );
1782+ const SatParameters& lns_params_stalling = name_to_params.at (" lns_stalling" );
1783+ const SatParameters& lns_params_routing = name_to_params.at (" lns_routing" );
17841784
17851785 // Add the NeighborhoodGeneratorHelper as a special subsolver so that its
17861786 // Synchronize() is called before any LNS neighborhood solvers.
@@ -1854,7 +1854,7 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
18541854 std::make_unique<RelaxationInducedNeighborhoodGenerator>(
18551855 helper, shared->response , shared->lp_solutions .get (),
18561856 shared->incomplete_solutions .get (), name_filter.LastName ()),
1857- lns_params , helper, shared));
1857+ lns_params_base, lns_params_stalling , helper, shared));
18581858 }
18591859
18601860 // Add incomplete subsolvers that require an objective.
@@ -1870,45 +1870,45 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
18701870 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
18711871 std::make_unique<RelaxRandomVariablesGenerator>(
18721872 helper, name_filter.LastName ()),
1873- lns_params , helper, shared));
1873+ lns_params_base, lns_params_stalling , helper, shared));
18741874 }
18751875 if (name_filter.Keep (" rnd_cst_lns" )) {
18761876 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
18771877 std::make_unique<RelaxRandomConstraintsGenerator>(
18781878 helper, name_filter.LastName ()),
1879- lns_params , helper, shared));
1879+ lns_params_base, lns_params_stalling , helper, shared));
18801880 }
18811881 if (name_filter.Keep (" graph_var_lns" )) {
18821882 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
18831883 std::make_unique<VariableGraphNeighborhoodGenerator>(
18841884 helper, name_filter.LastName ()),
1885- lns_params , helper, shared));
1885+ lns_params_base, lns_params_stalling , helper, shared));
18861886 }
18871887 if (name_filter.Keep (" graph_arc_lns" )) {
18881888 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
18891889 std::make_unique<ArcGraphNeighborhoodGenerator>(
18901890 helper, name_filter.LastName ()),
1891- lns_params , helper, shared));
1891+ lns_params_base, lns_params_stalling , helper, shared));
18921892 }
18931893 if (name_filter.Keep (" graph_cst_lns" )) {
18941894 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
18951895 std::make_unique<ConstraintGraphNeighborhoodGenerator>(
18961896 helper, name_filter.LastName ()),
1897- lns_params , helper, shared));
1897+ lns_params_base, lns_params_stalling , helper, shared));
18981898 }
18991899 if (name_filter.Keep (" graph_dec_lns" )) {
19001900 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19011901 std::make_unique<DecompositionGraphNeighborhoodGenerator>(
19021902 helper, name_filter.LastName ()),
1903- lns_params , helper, shared));
1903+ lns_params_base, lns_params_stalling , helper, shared));
19041904 }
19051905 if (params.use_lb_relax_lns () &&
19061906 params.num_workers () >= params.lb_relax_num_workers_threshold () &&
19071907 name_filter.Keep (" lb_relax_lns" )) {
19081908 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19091909 std::make_unique<LocalBranchingLpBasedNeighborhoodGenerator>(
19101910 helper, name_filter.LastName (), shared->time_limit , shared),
1911- lns_params , helper, shared));
1911+ lns_params_base, lns_params_stalling , helper, shared));
19121912 }
19131913
19141914 const bool has_no_overlap_or_cumulative =
@@ -1921,13 +1921,13 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
19211921 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19221922 std::make_unique<RandomIntervalSchedulingNeighborhoodGenerator>(
19231923 helper, name_filter.LastName ()),
1924- lns_params , helper, shared));
1924+ lns_params_base, lns_params_stalling , helper, shared));
19251925 }
19261926 if (name_filter.Keep (" scheduling_time_window_lns" )) {
19271927 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19281928 std::make_unique<SchedulingTimeWindowNeighborhoodGenerator>(
19291929 helper, name_filter.LastName ()),
1930- lns_params , helper, shared));
1930+ lns_params_base, lns_params_stalling , helper, shared));
19311931 }
19321932 const std::vector<std::vector<int >> intervals_in_constraints =
19331933 helper->GetUniqueIntervalSets ();
@@ -1936,7 +1936,7 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
19361936 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19371937 std::make_unique<SchedulingResourceWindowsNeighborhoodGenerator>(
19381938 helper, intervals_in_constraints, name_filter.LastName ()),
1939- lns_params , helper, shared));
1939+ lns_params_base, lns_params_stalling , helper, shared));
19401940 }
19411941 }
19421942
@@ -1948,31 +1948,31 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
19481948 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19491949 std::make_unique<RandomRectanglesPackingNeighborhoodGenerator>(
19501950 helper, name_filter.LastName ()),
1951- lns_params , helper, shared));
1951+ lns_params_base, lns_params_stalling , helper, shared));
19521952 }
19531953 if (name_filter.Keep (" packing_square_lns" )) {
19541954 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19551955 std::make_unique<RectanglesPackingRelaxOneNeighborhoodGenerator>(
19561956 helper, name_filter.LastName ()),
1957- lns_params , helper, shared));
1957+ lns_params_base, lns_params_stalling , helper, shared));
19581958 }
19591959 if (name_filter.Keep (" packing_swap_lns" )) {
19601960 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19611961 std::make_unique<RectanglesPackingRelaxTwoNeighborhoodsGenerator>(
19621962 helper, name_filter.LastName ()),
1963- lns_params , helper, shared));
1963+ lns_params_base, lns_params_stalling , helper, shared));
19641964 }
19651965 if (name_filter.Keep (" packing_precedences_lns" )) {
19661966 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19671967 std::make_unique<RandomPrecedencesPackingNeighborhoodGenerator>(
19681968 helper, name_filter.LastName ()),
1969- lns_params , helper, shared));
1969+ lns_params_base, lns_params_stalling , helper, shared));
19701970 }
19711971 if (name_filter.Keep (" packing_slice_lns" )) {
19721972 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19731973 std::make_unique<SlicePackingNeighborhoodGenerator>(
19741974 helper, name_filter.LastName ()),
1975- lns_params , helper, shared));
1975+ lns_params_base, lns_params_stalling , helper, shared));
19761976 }
19771977 }
19781978
@@ -1982,13 +1982,10 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
19821982 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19831983 std::make_unique<RandomPrecedenceSchedulingNeighborhoodGenerator>(
19841984 helper, name_filter.LastName ()),
1985- lns_params , helper, shared));
1985+ lns_params_base, lns_params_stalling , helper, shared));
19861986 }
19871987 }
19881988
1989- // For routing, the LP relaxation seems pretty important, so we prefer an
1990- // high linearization level to solve LNS subproblems.
1991- const int routing_lin_level = 2 ;
19921989 const int num_circuit = static_cast <int >(
19931990 helper->TypeToConstraints (ConstraintProto::kCircuit ).size ());
19941991 const int num_routes = static_cast <int >(
@@ -1998,21 +1995,21 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
19981995 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
19991996 std::make_unique<RoutingRandomNeighborhoodGenerator>(
20001997 helper, name_filter.LastName ()),
2001- lns_params, helper, shared, routing_lin_level ));
1998+ lns_params_routing, lns_params_stalling, helper, shared ));
20021999 }
20032000 if (name_filter.Keep (" routing_path_lns" )) {
20042001 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
20052002 std::make_unique<RoutingPathNeighborhoodGenerator>(
20062003 helper, name_filter.LastName ()),
2007- lns_params, helper, shared, routing_lin_level ));
2004+ lns_params_routing, lns_params_stalling, helper, shared ));
20082005 }
20092006 }
20102007 if (num_routes > 0 || num_circuit > 1 ) {
20112008 if (name_filter.Keep (" routing_full_path_lns" )) {
20122009 reentrant_interleaved_subsolvers.push_back (std::make_unique<LnsSolver>(
20132010 std::make_unique<RoutingFullPathNeighborhoodGenerator>(
20142011 helper, name_filter.LastName ()),
2015- lns_params, helper, shared, routing_lin_level ));
2012+ lns_params_routing, lns_params_stalling, helper, shared ));
20162013 }
20172014 }
20182015 }
0 commit comments