Skip to content
159 changes: 0 additions & 159 deletions src/algorithms/heuristics/heuristics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,157 +711,6 @@ Eval dynamic_vehicle_choice(const Input& input,
return sol_eval;
}

template <class Route>
void set_route(const Input& input,
Route& route,
std::unordered_set<Index>& assigned) {
assert(route.empty());
const auto& vehicle = input.vehicles[route.v_rank];

// Startup load is the sum of deliveries for (single) jobs.
Amount single_jobs_deliveries(input.zero_amount());
for (const auto& step : vehicle.steps) {
if (step.type == STEP_TYPE::JOB) {
assert(step.job_type.has_value());

if (step.job_type.value() == JOB_TYPE::SINGLE) {
single_jobs_deliveries += input.jobs[step.rank].delivery;
}
}
}
if (!(single_jobs_deliveries <= vehicle.capacity)) {
throw InputException(
std::format("Route over capacity for vehicle {}.", vehicle.id));
}

// 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) {
continue;
}

const auto job_rank = step.rank;
const auto& job = input.jobs[job_rank];
job_ranks.push_back(job_rank);

assert(!assigned.contains(job_rank));
assigned.insert(job_rank);

if (!input.vehicle_ok_with_job(route.v_rank, job_rank)) {
throw InputException(
std::format("Missing skill or step out of reach for vehicle {} and "
"job {}.",
vehicle.id,
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: {
current_load += job.pickup;
current_load -= job.delivery;
break;
}
case JOB_TYPE::PICKUP: {
expected_delivery_ranks.insert(job_rank + 1);

current_load += job.pickup;
break;
}
case JOB_TYPE::DELIVERY: {
auto search = expected_delivery_ranks.find(job_rank);
if (search == expected_delivery_ranks.end()) {
throw InputException(
std::format("Invalid shipment in route for vehicle {}.", vehicle.id));
}
expected_delivery_ranks.erase(search);

current_load -= job.delivery;
break;
}
default:
assert(false);
}

// Check validity after this step wrt capacity.
if (!(current_load <= vehicle.capacity)) {
throw InputException(
std::format("Route over capacity for vehicle {}.", vehicle.id));
}
}

if (vehicle.has_end() && !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(
std::format("Route over max_travel_time for vehicle {}.", vehicle.id));
}
if (!vehicle.ok_for_distance(eval_sum.distance)) {
throw InputException(
std::format("Route over max_distance for vehicle {}.", vehicle.id));
}

if (vehicle.max_tasks < job_ranks.size()) {
throw InputException(
std::format("Too many tasks for vehicle {}.", vehicle.id));
}

if (!expected_delivery_ranks.empty()) {
throw InputException(
std::format("Invalid shipment in route for vehicle {}.", vehicle.id));
}

// Now route is OK with regard to capacity, max_travel_time,
// max_tasks, precedence and skills constraints.
if (!job_ranks.empty()) {
if (!route.is_valid_addition_for_tw(input,
single_jobs_deliveries,
job_ranks.begin(),
job_ranks.end(),
0,
0)) {
throw InputException(
std::format("Infeasible route for vehicle {}.", vehicle.id));
}

route.replace(input,
single_jobs_deliveries,
job_ranks.begin(),
job_ranks.end(),
0,
0);
}
}

template <class Route>
void set_initial_routes(const Input& input,
std::vector<Route>& routes,
std::unordered_set<Index>& assigned) {
std::ranges::for_each(routes,
[&](auto& r) { set_route(input, r, assigned); });
}

using RawSolution = std::vector<RawRoute>;
using TWSolution = std::vector<TWRoute>;

Expand All @@ -881,10 +730,6 @@ template Eval dynamic_vehicle_choice(const Input& input,
double lambda,
SORT sort);

template void set_initial_routes(const Input& input,
RawSolution& routes,
std::unordered_set<Index>& assigned);

template Eval basic(const Input& input,
TWSolution& routes,
std::set<Index> unassigned,
Expand All @@ -901,8 +746,4 @@ template Eval dynamic_vehicle_choice(const Input& input,
double lambda,
SORT sort);

template void set_initial_routes(const Input& input,
TWSolution& routes,
std::unordered_set<Index>& assigned);

} // namespace vroom::heuristics
2 changes: 1 addition & 1 deletion src/algorithms/local_search/route_split_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ compute_best_route_split_choice(const Input& input,
std::vector<Route> empty_routes;
empty_routes.reserve(empty_route_ranks.size());
for (auto v : empty_route_ranks) {
empty_routes.emplace_back(input, v, input.zero_amount().size());
empty_routes.emplace_back(input, v);
}

for (Index r = 1; r < source.size(); ++r) {
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 @@ -157,7 +157,7 @@ Solution CVRP::solve(const unsigned nb_searches,

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

RawRoute r(_input, 0, 0);
RawRoute r(_input, 0);
r.set_route(_input, p.raw_solve(nb_threads, timeout));

return utils::format_solution(_input, {r});
Expand Down
2 changes: 1 addition & 1 deletion src/problems/cvrp/operators/tsp_fix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ bool TSPFix::is_valid() {
bool valid = is_valid_for_source_range_bounds();

if (valid) {
const RawRoute route(_input, s_vehicle, _input.zero_amount().size());
const RawRoute route(_input, s_vehicle);

valid = route.is_valid_addition_for_capacity_inclusion(_input,
_s_delivery,
Expand Down
2 changes: 1 addition & 1 deletion src/problems/tsp/tsp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ Solution TSP::solve(unsigned,
unsigned,
unsigned nb_threads,
const Timeout& timeout) const {
RawRoute r(_input, 0, 0);
RawRoute r(_input, 0);
r.set_route(_input, raw_solve(nb_threads, timeout));
return utils::format_solution(_input, {r});
}
Expand Down
21 changes: 10 additions & 11 deletions src/problems/vrp.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,18 @@ All rights reserved (see LICENSE).

namespace vroom {

template <class Route>
std::vector<Route> set_init_sol(const Input& input,
std::unordered_set<Index>& init_assigned) {
template <class Route> std::vector<Route> set_init_sol(const Input& input) {
std::vector<Route> init_sol;
init_sol.reserve(input.vehicles.size());

for (Index v = 0; v < input.vehicles.size(); ++v) {
init_sol.emplace_back(input, v, input.zero_amount().size());
}

if (input.has_initial_routes()) {
heuristics::set_initial_routes<Route>(input, init_sol, init_assigned);
init_sol.emplace_back(input, v).populate_from_steps(input);
}

return init_sol;
}

template <class Route> struct SolvingContext {
std::unordered_set<Index> init_assigned;
const std::vector<Route> init_sol;
std::set<Index> unassigned;
std::vector<Index> vehicles_ranks;
Expand All @@ -55,15 +48,21 @@ template <class Route> struct SolvingContext {
std::mutex heuristic_indicators_m;

SolvingContext(const Input& input, unsigned nb_searches)
: init_sol(set_init_sol<Route>(input, init_assigned)),
: init_sol(set_init_sol<Route>(input)),
vehicles_ranks(input.vehicles.size()),
solutions(nb_searches, init_sol),
sol_indicators(nb_searches) {

// Deduce unassigned jobs from initial solution.
std::unordered_set<Index> init_assigned;
for (const auto& r : init_sol) {
for (const Index i : r.route) {
init_assigned.insert(i);
}
}
std::ranges::copy_if(std::views::iota(0u, input.jobs.size()),
std::inserter(unassigned, unassigned.begin()),
[this](const Index j) {
[&](const Index j) {
return !init_assigned.contains(j);
});

Expand Down
6 changes: 1 addition & 5 deletions src/structures/vroom/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,6 @@ bool Input::has_homogeneous_costs() const {
return _homogeneous_costs;
}

bool Input::has_initial_routes() const {
return _has_initial_routes;
}

bool Input::vehicle_ok_with_vehicle(Index v1_index, Index v2_index) const {
return _vehicle_to_vehicle_compatibility[v1_index][v2_index];
}
Expand Down Expand Up @@ -551,7 +547,7 @@ void Input::set_extra_compatibility() {
compatible_vehicles_for_job = std::vector<std::vector<Index>>(jobs.size());

for (std::size_t v = 0; v < vehicles.size(); ++v) {
const TWRoute empty_route(*this, v, _zero.size());
const TWRoute empty_route(*this, v);
for (Index j = 0; j < jobs.size(); ++j) {
if (!_vehicle_to_job_compatibility[v][j]) {
continue;
Expand Down
2 changes: 0 additions & 2 deletions src/structures/vroom/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,6 @@ class Input {

bool has_homogeneous_costs() const;

bool has_initial_routes() const;

bool vehicle_ok_with_job(size_t v_index, size_t j_index) const {
return static_cast<bool>(_vehicle_to_job_compatibility[v_index][j_index]);
}
Expand Down
Loading
Loading