@@ -951,22 +951,23 @@ NeighborhoodGeneratorHelper::GetSchedulingPrecedences(
951951}
952952
953953std::vector<std::vector<int >>
954- NeighborhoodGeneratorHelper::GetRoutingPathLiterals (
954+ NeighborhoodGeneratorHelper::GetRoutingPathBooleanVariables (
955955 const CpSolverResponse& initial_solution) const {
956- struct HeadAndArcLiteral {
956+ struct HeadAndArcBooleanVariable {
957957 int head;
958- int literal ;
958+ int bool_var ;
959959 };
960960
961961 std::vector<std::vector<int >> result;
962- absl::flat_hash_map<int , HeadAndArcLiteral> tail_to_head_and_arc_literal;
962+ absl::flat_hash_map<int , HeadAndArcBooleanVariable>
963+ tail_to_head_and_arc_bool_var;
963964
964965 for (const int i : TypeToConstraints (ConstraintProto::kCircuit )) {
965966 const CircuitConstraintProto& ct = ModelProto ().constraints (i).circuit ();
966967
967968 // Collect arcs.
968969 int min_node = std::numeric_limits<int >::max ();
969- tail_to_head_and_arc_literal .clear ();
970+ tail_to_head_and_arc_bool_var .clear ();
970971 for (int i = 0 ; i < ct.literals_size (); ++i) {
971972 const int literal = ct.literals (i);
972973 const int head = ct.heads (i);
@@ -977,27 +978,27 @@ NeighborhoodGeneratorHelper::GetRoutingPathLiterals(
977978 if (RefIsPositive (literal) == (value == 0 )) continue ;
978979 // Ignore self loops.
979980 if (head == tail) continue ;
980- tail_to_head_and_arc_literal [tail] = {head, bool_var};
981+ tail_to_head_and_arc_bool_var [tail] = {head, bool_var};
981982 min_node = std::min (tail, min_node);
982983 }
983- if (tail_to_head_and_arc_literal .empty ()) continue ;
984+ if (tail_to_head_and_arc_bool_var .empty ()) continue ;
984985
985986 // Unroll the path.
986987 int current_node = min_node;
987988 std::vector<int > path;
988989 do {
989- auto it = tail_to_head_and_arc_literal .find (current_node);
990- CHECK (it != tail_to_head_and_arc_literal .end ());
990+ auto it = tail_to_head_and_arc_bool_var .find (current_node);
991+ CHECK (it != tail_to_head_and_arc_bool_var .end ());
991992 current_node = it->second .head ;
992- path.push_back (it->second .literal );
993+ path.push_back (it->second .bool_var );
993994 } while (current_node != min_node);
994995 result.push_back (std::move (path));
995996 }
996997
997- std::vector<HeadAndArcLiteral > route_starts;
998+ std::vector<HeadAndArcBooleanVariable > route_starts;
998999 for (const int i : TypeToConstraints (ConstraintProto::kRoutes )) {
9991000 const RoutesConstraintProto& ct = ModelProto ().constraints (i).routes ();
1000- tail_to_head_and_arc_literal .clear ();
1001+ tail_to_head_and_arc_bool_var .clear ();
10011002 route_starts.clear ();
10021003
10031004 // Collect route starts and arcs.
@@ -1014,20 +1015,20 @@ NeighborhoodGeneratorHelper::GetRoutingPathLiterals(
10141015 if (tail == 0 ) {
10151016 route_starts.push_back ({head, bool_var});
10161017 } else {
1017- tail_to_head_and_arc_literal [tail] = {head, bool_var};
1018+ tail_to_head_and_arc_bool_var [tail] = {head, bool_var};
10181019 }
10191020 }
10201021
10211022 // Unroll all routes.
1022- for (const HeadAndArcLiteral & head_var : route_starts) {
1023+ for (const HeadAndArcBooleanVariable & head_var : route_starts) {
10231024 std::vector<int > path;
10241025 int current_node = head_var.head ;
1025- path.push_back (head_var.literal );
1026+ path.push_back (head_var.bool_var );
10261027 do {
1027- auto it = tail_to_head_and_arc_literal .find (current_node);
1028- CHECK (it != tail_to_head_and_arc_literal .end ());
1028+ auto it = tail_to_head_and_arc_bool_var .find (current_node);
1029+ CHECK (it != tail_to_head_and_arc_bool_var .end ());
10291030 current_node = it->second .head ;
1030- path.push_back (it->second .literal );
1031+ path.push_back (it->second .bool_var );
10311032 } while (current_node != 0 );
10321033 result.push_back (std::move (path));
10331034 }
@@ -2598,39 +2599,50 @@ Neighborhood RoutingRandomNeighborhoodGenerator::Generate(
25982599 const CpSolverResponse& initial_solution, SolveData& data,
25992600 absl::BitGenRef random) {
26002601 const std::vector<std::vector<int >> all_paths =
2601- helper_.GetRoutingPathLiterals (initial_solution);
2602+ helper_.GetRoutingPathBooleanVariables (initial_solution);
26022603
26032604 // Collect all unique variables.
2604- absl::flat_hash_set <int > all_path_variables ;
2605- for (auto & path : all_paths) {
2606- all_path_variables .insert (path.begin (), path.end ());
2605+ std::vector <int > variables_to_fix ;
2606+ for (const auto & path : all_paths) {
2607+ variables_to_fix .insert (variables_to_fix. end (), path.begin (), path.end ());
26072608 }
2608- std::vector<int > fixed_variables (all_path_variables.begin (),
2609- all_path_variables.end ());
2610- std::sort (fixed_variables.begin (), fixed_variables.end ());
2611- GetRandomSubset (1.0 - data.difficulty , &fixed_variables, random);
2609+ gtl::STLSortAndRemoveDuplicates (&variables_to_fix);
2610+ GetRandomSubset (1.0 - data.difficulty , &variables_to_fix, random);
26122611
26132612 Bitset64<int > to_fix (helper_.NumVariables ());
2614- for (const int var : fixed_variables ) to_fix.Set (var);
2613+ for (const int var : variables_to_fix ) to_fix.Set (var);
26152614 return helper_.FixGivenVariables (initial_solution, to_fix);
26162615}
26172616
26182617Neighborhood RoutingPathNeighborhoodGenerator::Generate (
26192618 const CpSolverResponse& initial_solution, SolveData& data,
26202619 absl::BitGenRef random) {
26212620 std::vector<std::vector<int >> all_paths =
2622- helper_.GetRoutingPathLiterals (initial_solution);
2621+ helper_.GetRoutingPathBooleanVariables (initial_solution);
2622+
2623+ // Remove a corner case where all paths are empty.
2624+ if (all_paths.empty ()) {
2625+ return helper_.NoNeighborhood ();
2626+ }
26232627
26242628 // Collect all unique variables.
2625- absl::flat_hash_set<int > all_path_variables;
2629+ std::vector<int > all_path_variables;
2630+ int sum_of_path_sizes = 0 ;
2631+ for (const auto & path : all_paths) {
2632+ sum_of_path_sizes += path.size ();
2633+ }
2634+ all_path_variables.reserve (sum_of_path_sizes);
26262635 for (const auto & path : all_paths) {
2627- all_path_variables.insert (path.begin (), path.end ());
2636+ all_path_variables.insert (all_path_variables.end (), path.begin (),
2637+ path.end ());
26282638 }
2639+ gtl::STLSortAndRemoveDuplicates (&all_path_variables);
26292640
2630- // Select variables to relax.
2641+ // Select target number of variables to relax.
26312642 const int num_variables_to_relax =
26322643 static_cast <int >(all_path_variables.size () * data.difficulty );
26332644 absl::flat_hash_set<int > relaxed_variables;
2645+
26342646 while (relaxed_variables.size () < num_variables_to_relax) {
26352647 DCHECK (!all_paths.empty ());
26362648 const int path_index = absl::Uniform<int >(random, 0 , all_paths.size ());
@@ -2665,57 +2677,54 @@ Neighborhood RoutingFullPathNeighborhoodGenerator::Generate(
26652677 const CpSolverResponse& initial_solution, SolveData& data,
26662678 absl::BitGenRef random) {
26672679 std::vector<std::vector<int >> all_paths =
2668- helper_.GetRoutingPathLiterals (initial_solution);
2680+ helper_.GetRoutingPathBooleanVariables (initial_solution);
2681+
26692682 // Remove a corner case where all paths are empty.
26702683 if (all_paths.empty ()) {
26712684 return helper_.NoNeighborhood ();
26722685 }
26732686
26742687 // Collect all unique variables.
2675- absl::flat_hash_set<int > all_path_variables;
2688+ std::vector<int > all_path_variables;
2689+ int sum_of_path_sizes = 0 ;
26762690 for (const auto & path : all_paths) {
2677- all_path_variables. insert (path. begin (), path.end () );
2691+ sum_of_path_sizes += path.size ( );
26782692 }
2693+ all_path_variables.reserve (sum_of_path_sizes);
2694+ for (const auto & path : all_paths) {
2695+ all_path_variables.insert (all_path_variables.end (), path.begin (),
2696+ path.end ());
2697+ }
2698+ gtl::STLSortAndRemoveDuplicates (&all_path_variables);
26792699
2680- // Select variables to relax.
2700+ // Select target number of variables to relax.
26812701 const int num_variables_to_relax =
26822702 static_cast <int >(all_path_variables.size () * data.difficulty );
26832703 absl::flat_hash_set<int > relaxed_variables;
26842704
26852705 // Relax the start and end of each path to ease relocation.
2706+ // TODO(user): Restrict this if the difficulty is very low.
26862707 for (const auto & path : all_paths) {
26872708 relaxed_variables.insert (path.front ());
26882709 relaxed_variables.insert (path.back ());
26892710 }
26902711
2691- // Randomize paths.
2692- for (auto & path : all_paths) {
2693- std::shuffle (path.begin (), path.end (), random);
2694- }
2695-
2696- // Relax all variables (if possible) in one random path.
2697- const int path_to_clean = absl::Uniform<int >(random, 0 , all_paths.size ());
2712+ // Relax all variables, if possible, of one random path.
2713+ const int path_index = absl::Uniform<int >(random, 0 , all_paths.size ());
2714+ std::shuffle (all_paths[path_index].begin (), all_paths[path_index].end (),
2715+ random);
26982716 while (relaxed_variables.size () < num_variables_to_relax &&
2699- !all_paths[path_to_clean].empty ()) {
2700- relaxed_variables.insert (all_paths[path_to_clean].back ());
2701- all_paths[path_to_clean].pop_back ();
2702- }
2703- if (all_paths[path_to_clean].empty ()) {
2704- std::swap (all_paths[path_to_clean], all_paths.back ());
2705- all_paths.pop_back ();
2717+ !all_paths[path_index].empty ()) {
2718+ relaxed_variables.insert (all_paths[path_index].back ());
2719+ all_paths[path_index].pop_back ();
27062720 }
27072721
27082722 // Relax more variables until the target is reached.
2709- while (relaxed_variables.size () < num_variables_to_relax) {
2710- DCHECK (!all_paths.empty ());
2711- const int path_index = absl::Uniform<int >(random, 0 , all_paths.size ());
2712- relaxed_variables.insert (all_paths[path_index].back ());
2713-
2714- // Remove variable and clean up empty paths.
2715- all_paths[path_index].pop_back ();
2716- if (all_paths[path_index].empty ()) {
2717- std::swap (all_paths[path_index], all_paths.back ());
2718- all_paths.pop_back ();
2723+ if (relaxed_variables.size () < num_variables_to_relax) {
2724+ std::shuffle (all_path_variables.begin (), all_path_variables.end (), random);
2725+ while (relaxed_variables.size () < num_variables_to_relax) {
2726+ relaxed_variables.insert (all_path_variables.back ());
2727+ all_path_variables.pop_back ();
27192728 }
27202729 }
27212730
0 commit comments