Skip to content

Commit

Permalink
Merge branch 'enhancement/reserve-all-the-things'
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoupey committed Aug 14, 2023
2 parents 6766a03 + f609029 commit 891bf0f
Show file tree
Hide file tree
Showing 24 changed files with 127 additions and 63 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- Reduce `compute_best_route_split_choice` complexity (#962)
- `Eval::operator<` sorts on cost, then duration (#914)
- Improved `vrptw::PDShift` implementation (#852)
- Reserve `vector` capacity whenever possible (#915)

### Fixed

Expand Down
24 changes: 20 additions & 4 deletions src/algorithms/heuristics/heuristics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ template <class T>
T basic(const Input& input, INIT init, double lambda, SORT sort) {
const auto nb_vehicles = input.vehicles.size();
T routes;
routes.reserve(nb_vehicles);

for (Index v = 0; v < nb_vehicles; ++v) {
routes.emplace_back(input, v, input.zero_amount().size());
}
Expand Down Expand Up @@ -346,7 +348,10 @@ T basic(const Input& input, INIT init, double lambda, SORT sort) {
}

// Build replacement sequence for current insertion.
std::vector<Index> modified_with_pd({job_rank});
std::vector<Index> modified_with_pd;
modified_with_pd.reserve(current_r.size() - pickup_r + 2);
modified_with_pd.push_back(job_rank);

Amount modified_delivery = input.zero_amount();

for (Index delivery_r = pickup_r; delivery_r <= current_r.size();
Expand Down Expand Up @@ -431,7 +436,10 @@ T basic(const Input& input, INIT init, double lambda, SORT sort) {
keep_going = true;
}
if (input.jobs[best_job_rank].type == JOB_TYPE::PICKUP) {
std::vector<Index> modified_with_pd({best_job_rank});
std::vector<Index> modified_with_pd;
modified_with_pd.reserve(best_delivery_r - best_pickup_r + 2);
modified_with_pd.push_back(best_job_rank);

std::copy(current_r.route.begin() + best_pickup_r,
current_r.route.begin() + best_delivery_r,
std::back_inserter(modified_with_pd));
Expand Down Expand Up @@ -463,6 +471,8 @@ T dynamic_vehicle_choice(const Input& input,
SORT sort) {
const auto nb_vehicles = input.vehicles.size();
T routes;
routes.reserve(nb_vehicles);

for (Index v = 0; v < nb_vehicles; ++v) {
routes.emplace_back(input, v, input.zero_amount().size());
}
Expand Down Expand Up @@ -777,7 +787,10 @@ T dynamic_vehicle_choice(const Input& input,
}

// Build replacement sequence for current insertion.
std::vector<Index> modified_with_pd({job_rank});
std::vector<Index> modified_with_pd;
modified_with_pd.reserve(current_r.size() - pickup_r + 2);
modified_with_pd.push_back(job_rank);

Amount modified_delivery = input.zero_amount();

for (Index delivery_r = pickup_r; delivery_r <= current_r.size();
Expand Down Expand Up @@ -859,7 +872,10 @@ T dynamic_vehicle_choice(const Input& input,
keep_going = true;
}
if (input.jobs[best_job_rank].type == JOB_TYPE::PICKUP) {
std::vector<Index> modified_with_pd({best_job_rank});
std::vector<Index> modified_with_pd;
modified_with_pd.reserve(best_delivery_r - best_pickup_r + 2);
modified_with_pd.push_back(best_job_rank);

std::copy(current_r.route.begin() + best_pickup_r,
current_r.route.begin() + best_delivery_r,
std::back_inserter(modified_with_pd));
Expand Down
4 changes: 3 additions & 1 deletion src/algorithms/kruskal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ UndirectedGraph<T> minimum_spanning_tree(const UndirectedGraph<T>& graph) {

// Storing the edges of the minimum spanning tree.
std::vector<Edge<T>> mst;
mst.reserve(graph.size() - 1);

// During Kruskal algorithm, the number of connected components will
// decrease until we obtain a single component (the final tree). We
Expand Down Expand Up @@ -55,8 +56,9 @@ UndirectedGraph<T> minimum_spanning_tree(const UndirectedGraph<T>& graph) {
}
}
}
assert(mst.size() == graph.size() - 1);

return UndirectedGraph<T>(mst);
return UndirectedGraph<T>(std::move(mst));
}

template UndirectedGraph<UserCost>
Expand Down
7 changes: 6 additions & 1 deletion src/algorithms/local_search/insertion_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,12 @@ RouteInsertion compute_best_insertion_pd(const Input& input,
}

// Build replacement sequence for current insertion.
std::vector<Index> modified_with_pd({j});
std::vector<Index> modified_with_pd;
if (pickup_r <= end_d_rank) {
modified_with_pd.reserve(end_d_rank - pickup_r + 2);
}
modified_with_pd.push_back(j);

Amount modified_delivery = input.zero_amount();

// No need to use begin_d_rank here thanks to
Expand Down
13 changes: 12 additions & 1 deletion src/algorithms/local_search/local_search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ void LocalSearch<Route,
bool job_added;

std::vector<std::vector<RouteInsertion>> route_job_insertions;
route_job_insertions.reserve(routes.size());

for (std::size_t i = 0; i < routes.size(); ++i) {
route_job_insertions.emplace_back(_input.jobs.size(),
Expand Down Expand Up @@ -258,7 +259,11 @@ void LocalSearch<Route,
} else {
assert(best_job.type == JOB_TYPE::PICKUP);

std::vector<Index> modified_with_pd({best_job_rank});
std::vector<Index> modified_with_pd;
modified_with_pd.reserve(best_insertion.delivery_rank -
best_insertion.pickup_rank + 2);
modified_with_pd.push_back(best_job_rank);

std::copy(_sol[best_route].route.begin() + best_insertion.pickup_rank,
_sol[best_route].route.begin() + best_insertion.delivery_rank,
std::back_inserter(modified_with_pd));
Expand Down Expand Up @@ -348,6 +353,8 @@ void LocalSearch<Route,
// List of source/target pairs we need to test (all related vehicles
// at first).
std::vector<std::pair<Index, Index>> s_t_pairs;
s_t_pairs.reserve(_nb_vehicles * _nb_vehicles);

for (unsigned s_v = 0; s_v < _nb_vehicles; ++s_v) {
for (unsigned t_v = 0; t_v < _nb_vehicles; ++t_v) {
if (_input.vehicle_ok_with_vehicle(s_v, t_v)) {
Expand Down Expand Up @@ -1630,7 +1637,10 @@ void LocalSearch<Route,
!_input.has_homogeneous_profiles() or !_input.has_homogeneous_costs()) {
// RouteSplit stuff
std::vector<Index> empty_route_ranks;
empty_route_ranks.reserve(_input.vehicles.size());
std::vector<std::reference_wrapper<Route>> empty_route_refs;
empty_route_refs.reserve(_input.vehicles.size());

for (Index v = 0; v < _input.vehicles.size(); ++v) {
if (_sol[v].empty()) {
empty_route_ranks.push_back(v);
Expand Down Expand Up @@ -2191,6 +2201,7 @@ void LocalSearch<Route,

// Remove best node candidate from all routes.
std::vector<std::pair<Index, Index>> routes_and_ranks;
routes_and_ranks.reserve(_sol.size());

for (std::size_t v = 0; v < _sol.size(); ++v) {
if (_sol[v].empty()) {
Expand Down
3 changes: 3 additions & 0 deletions src/algorithms/local_search/swap_star_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,15 @@ inline InsertionRange get_insert_range(const std::vector<Index>& s_route,
insert.last_rank = s_rank + 1;
} else {
if (s_rank < insertion_rank) {
insert.range.reserve(insertion_rank - s_rank);
std::copy(s_route.begin() + s_rank + 1,
s_route.begin() + insertion_rank,
std::back_inserter(insert.range));
insert.range.push_back(job_rank);
insert.first_rank = s_rank;
insert.last_rank = insertion_rank;
} else {
insert.range.reserve(s_rank - insertion_rank + 1);
insert.range.push_back(job_rank);
std::copy(s_route.begin() + insertion_rank,
s_route.begin() + s_rank,
Expand Down Expand Up @@ -295,6 +297,7 @@ SwapChoice compute_best_swap_star_choice(const Input& input,
s_rank);

std::vector<SwapChoice> swap_choice_options;
swap_choice_options.reserve(16);

// Options for in-place insertion in source route include
// in-place insertion in target route and other relevant
Expand Down
4 changes: 3 additions & 1 deletion src/algorithms/validation/check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ Solution check_and_set_ETA(const Input& input, unsigned nb_thread) {
};

std::vector<std::thread> solving_threads;

solving_threads.reserve(thread_ranks.size());

for (const auto& v_ranks : thread_ranks) {
solving_threads.emplace_back(run_check, v_ranks);
}
Expand All @@ -93,6 +93,8 @@ Solution check_and_set_ETA(const Input& input, unsigned nb_thread) {

// Handle unassigned jobs.
std::vector<Job> unassigned_jobs;
unassigned_jobs.reserve(input.jobs.size() - assigned_ranks.size());

for (Index j = 0; j < input.jobs.size(); ++j) {
if (assigned_ranks.find(j) == assigned_ranks.end()) {
unassigned_jobs.push_back(input.jobs[j]);
Expand Down
16 changes: 16 additions & 0 deletions src/algorithms/validation/choose_ETA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ Route choose_ETA(const Input& input,
std::vector<unsigned> B;
std::vector<Duration> durations;
std::vector<Duration> action_times;
J.reserve(n + 1);
B.reserve(n + 1);
durations.reserve(n + 1);
action_times.reserve(n + 1);

// Lower bound for timestamps in input in order to scale the MIP
// matrix values.
Duration horizon_start = std::numeric_limits<Duration>::max();
Expand All @@ -87,6 +92,8 @@ Route choose_ETA(const Input& input,
unsigned default_job_tw = 0;
Duration relative_arrival = 0;
std::vector<Duration> relative_ETA;
relative_ETA.reserve(steps.size());

std::optional<Index> previous_index;
std::optional<Location> first_location;
std::optional<Location> last_location;
Expand Down Expand Up @@ -395,6 +402,10 @@ Route choose_ETA(const Input& input,
std::vector<unsigned> first_relevant_tw_rank;
Index rank_in_J = 0;

t_i_LB.reserve(steps.size());
t_i_UB.reserve(steps.size());
first_relevant_tw_rank.reserve(n);

for (const auto& step : steps) {
// Derive basic bounds from user input.
Duration LB = horizon_start;
Expand Down Expand Up @@ -1043,6 +1054,9 @@ Route choose_ETA(const Input& input,

std::vector<Duration> task_ETA;
std::vector<Duration> task_travels;
task_ETA.reserve(n);
task_travels.reserve(n);

for (unsigned i = 0; i < n; ++i) {
task_ETA.push_back(horizon_start +
get_duration(glp_mip_col_val(lp, i + 2)));
Expand All @@ -1053,6 +1067,7 @@ Route choose_ETA(const Input& input,
// Populate vector storing picked time window ranks.
current_X_rank = start_X_col;
std::vector<Index> task_tw_ranks;
task_tw_ranks.reserve(n);

for (const auto& step : steps) {
switch (step.type) {
Expand Down Expand Up @@ -1130,6 +1145,7 @@ Route choose_ETA(const Input& input,
[](const auto& b) { return b.id; });

std::vector<Step> sol_steps;
sol_steps.reserve(steps.size());

assert(v.has_start() or start_travel == 0);

Expand Down
2 changes: 1 addition & 1 deletion src/problems/cvrp/cvrp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Solution CVRP::solve(unsigned exploration_level,
std::vector<Index> job_ranks(_input.jobs.size());
std::iota(job_ranks.begin(), job_ranks.end(), 0);

TSP p(_input, job_ranks, 0);
TSP p(_input, std::move(job_ranks), 0);

RawRoute r(_input, 0, 0);
r.set_route(_input, p.raw_solve(nb_threads, timeout));
Expand Down
5 changes: 4 additions & 1 deletion src/problems/cvrp/operators/pd_shift.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ bool PDShift::is_valid() {
}

void PDShift::apply() {
std::vector<Index> target_with_pd({s_route[_s_p_rank]});
std::vector<Index> target_with_pd;
target_with_pd.reserve(_best_t_d_rank - _best_t_p_rank + 2);
target_with_pd.push_back(s_route[_s_p_rank]);

std::copy(t_route.begin() + _best_t_p_rank,
t_route.begin() + _best_t_d_rank,
std::back_inserter(target_with_pd));
Expand Down
13 changes: 7 additions & 6 deletions src/problems/tsp/heuristics/christofides.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ All rights reserved (see LICENSE).
*/

#include <cassert>
#include <set>
#include <unordered_set>

#include "algorithms/kruskal.h"
#include "algorithms/munkres.h"
Expand All @@ -22,10 +22,10 @@ std::list<Index> christofides(const Matrix<UserCost>& sym_matrix) {
// vertices.

// Compute symmetric graph from the matrix.
auto sym_graph = utils::UndirectedGraph<UserCost>(sym_matrix);
const auto sym_graph = utils::UndirectedGraph<UserCost>(sym_matrix);

// Work on a minimum spanning tree seen as a graph.
auto mst_graph = utils::minimum_spanning_tree(sym_graph);
const auto mst_graph = utils::minimum_spanning_tree(sym_graph);

// Getting minimum spanning tree of associated graph under the form
// of an adjacency list.
Expand Down Expand Up @@ -86,7 +86,7 @@ std::list<Index> christofides(const Matrix<UserCost>& sym_matrix) {
// Adding edges from minimum weight perfect matching (with the
// original vertices index). Edges appear twice in matching so we
// need to remember the one already added.
std::set<Index> already_added;
std::unordered_set<Index> already_added;
for (const auto& edge : mwpm_final) {
Index first_index = mst_odd_vertices[edge.first];
Index second_index = mst_odd_vertices[edge.second];
Expand All @@ -99,7 +99,8 @@ std::list<Index> christofides(const Matrix<UserCost>& sym_matrix) {
}

// Building Eulerian graph from the edges.
utils::UndirectedGraph<UserCost> eulerian_graph(eulerian_graph_edges);
utils::UndirectedGraph<UserCost> eulerian_graph(
std::move(eulerian_graph_edges));
assert(eulerian_graph.size() >= 2);

// Hierholzer's algorithm: building and joining closed tours with
Expand Down Expand Up @@ -155,7 +156,7 @@ std::list<Index> christofides(const Matrix<UserCost>& sym_matrix) {
}
} while (!complete_tour);

std::set<Index> already_visited;
std::unordered_set<Index> already_visited;
std::list<Index> tour;
for (const auto& vertex : eulerian_path) {
auto ret = already_visited.insert(vertex);
Expand Down
Loading

0 comments on commit 891bf0f

Please sign in to comment.