diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d3dcc6e..c510ac3b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - 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) ## [v1.13.0] - 2023-01-31 diff --git a/src/algorithms/heuristics/heuristics.cpp b/src/algorithms/heuristics/heuristics.cpp index b5bd52d27..54b1183d6 100644 --- a/src/algorithms/heuristics/heuristics.cpp +++ b/src/algorithms/heuristics/heuristics.cpp @@ -909,8 +909,13 @@ template 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 previous_index; + if (vehicle.has_start()) { + previous_index = vehicle.start.value().index(); + } std::vector job_ranks; job_ranks.reserve(vehicle.steps.size()); @@ -930,6 +935,13 @@ template 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: { @@ -963,6 +975,17 @@ template 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) + "."); @@ -973,8 +996,8 @@ template 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,