Skip to content

Commit

Permalink
Merge branch 'fix/max-travel-time'
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoupey committed Aug 12, 2023
2 parents dea3333 + 966a03f commit 0e002b5
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- Switch to C++20 (#851)
- Improved error messages for file-related IO errors (#553)
- Add job id to error message for unreachable step (#946)
- Reduce `compute_best_route_split_choice` complexity (#962)

### Fixed

Expand All @@ -27,6 +28,8 @@
- Comparison of index-based and coordinates-based locations (#935)
- `max_travel_time` parameter not taken into account in edge case (#884)
- Meaningless `location_index` provided in output for break steps (#877)
- `max_travel_time` not accounted for with vehicle steps in solving mode (#954)
- `max_travel_time` not accounted for in `RouteSplit` (#941)

## [v1.13.0] - 2023-01-31

Expand Down
31 changes: 28 additions & 3 deletions src/algorithms/heuristics/heuristics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,7 @@ T dynamic_vehicle_choice(const Input& input,

template <class T> T initial_routes(const Input& input) {
T routes;
routes.reserve(input.vehicles.size());
for (Index v = 0; v < input.vehicles.size(); ++v) {
routes.emplace_back(input, v, input.zero_amount().size());

Expand All @@ -908,10 +909,16 @@ template <class T> T initial_routes(const Input& input) {
std::to_string(vehicle.id) + ".");
}

// Startup load is the sum of deliveries for (single) jobs.
// Track load and travel time during the route for validity.
Amount current_load = single_jobs_deliveries;
Eval eval_sum;
std::optional<Index> previous_index;
if (vehicle.has_start()) {
previous_index = vehicle.start.value().index();
}

std::vector<Index> job_ranks;
job_ranks.reserve(vehicle.steps.size());
std::unordered_set<Index> expected_delivery_ranks;
for (const auto& step : vehicle.steps) {
if (step.type != STEP_TYPE::JOB) {
Expand All @@ -928,6 +935,13 @@ template <class T> T initial_routes(const Input& input) {
std::to_string(job.id) + ".");
}

// Update current travel time.
if (previous_index.has_value()) {
eval_sum += vehicle.eval(previous_index.value(), job.index());
}
previous_index = job.index();

// Handle load.
assert(step.job_type.has_value());
switch (step.job_type.value()) {
case JOB_TYPE::SINGLE: {
Expand Down Expand Up @@ -961,6 +975,17 @@ template <class T> T initial_routes(const Input& input) {
}
}

if (vehicle.has_end() and !job_ranks.empty()) {
// Update with last route leg.
assert(previous_index.has_value());
eval_sum +=
vehicle.eval(previous_index.value(), vehicle.end.value().index());
}
if (!vehicle.ok_for_travel_time(eval_sum.duration)) {
throw InputException("Route over max_travel_time for vehicle " +
std::to_string(vehicle.id) + ".");
}

if (vehicle.max_tasks < job_ranks.size()) {
throw InputException("Too many tasks for vehicle " +
std::to_string(vehicle.id) + ".");
Expand All @@ -971,8 +996,8 @@ template <class T> T initial_routes(const Input& input) {
std::to_string(vehicle.id) + ".");
}

// Now route is OK with regard to capacity, precedence and skills
// constraints.
// Now route is OK with regard to capacity, max_travel_time,
// max_tasks, precedence and skills constraints.
if (!job_ranks.empty()) {
if (!current_r.is_valid_addition_for_tw(input,
single_jobs_deliveries,
Expand Down
41 changes: 31 additions & 10 deletions src/algorithms/local_search/route_split_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,21 @@ compute_best_route_split_choice(const Input& input,
continue;
}

Eval current_end_eval =
utils::route_eval_for_vehicle(input,
v,
source.route.begin() + r,
source.route.end());
Eval current_end_eval(end_v.fixed_cost(), 0);
current_end_eval += sol_state.fwd_costs[s_vehicle][v].back() -
sol_state.fwd_costs[s_vehicle][v][r];
if (end_v.has_start()) {
current_end_eval += end_v.eval(end_v.start.value().index(),
input.jobs[source.route[r]].index());
}
if (end_v.has_end()) {
current_end_eval += end_v.eval(input.jobs[source.route.back()].index(),
end_v.end.value().index());
}

if (!end_v.ok_for_travel_time(current_end_eval.duration)) {
continue;
}

if (current_end_eval < second_best_end_eval) {
// Worth checking end route full validity.
Expand Down Expand Up @@ -133,11 +143,22 @@ compute_best_route_split_choice(const Input& input,
continue;
}

Eval current_begin_eval =
utils::route_eval_for_vehicle(input,
v,
source.route.begin(),
source.route.begin() + r);
Eval current_begin_eval(begin_v.fixed_cost(), 0);
current_begin_eval += sol_state.fwd_costs[s_vehicle][v][r - 1];
if (begin_v.has_start()) {
current_begin_eval +=
begin_v.eval(begin_v.start.value().index(),
input.jobs[source.route.front()].index());
}
if (begin_v.has_end()) {
current_begin_eval +=
begin_v.eval(input.jobs[source.route[r - 1]].index(),
begin_v.end.value().index());
}

if (!begin_v.ok_for_travel_time(current_begin_eval.duration)) {
continue;
}

if (current_begin_eval < second_best_begin_eval) {
// Worth checking begin route full validity.
Expand Down

0 comments on commit 0e002b5

Please sign in to comment.